diff --git a/CLAUDE.md b/CLAUDE.md index 7bab26b..534af79 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -52,11 +52,11 @@ make deploy-idcard # IdCard contract to Base | Contract | Both Chains | |---|---| | Semaphore | `0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D` | -| CredentialRegistry | `0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db` | -| DefaultScorer | `0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c` | -| ScorerFactory | `0xAa03996D720C162Fdff246E1D3CEecc792986750` | +| CredentialRegistry | `0x17a22f130d4e1c4ba5C20a679a5a29F227083A62` | +| DefaultScorer | `0x6791B588dAdeb4323bc1C3d987130bC13cBe3625` | +| ScorerFactory | `0x016bC46169533a8d3284c5D8DD590C91783C8C06` | -Owner: `0x6F0CDcd334BA91A5E221582665Cce0431aD4Fc0b` +Owner: `0x677112864ED447866f8D461ABe284E5e907bB4F8` Trusted verifier (Sepolia): `0x3c50f7055D804b51e506Bc1EA7D082cB1548376C` Trusted verifier (mainnet): `0x9186aA65288bFfa67fB58255AeeaFfc4515535d9` diff --git a/README.md b/README.md index 070008c..588fd99 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,18 @@ Contract addresses are identical on both chains (same deployer, same nonce). | Contract | Address | |---|---| | Semaphore | [`0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D`](https://basescan.org/address/0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D) | -| CredentialRegistry | [`0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db`](https://basescan.org/address/0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db) | -| DefaultScorer | [`0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c`](https://basescan.org/address/0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c) | -| ScorerFactory | [`0xAa03996D720C162Fdff246E1D3CEecc792986750`](https://basescan.org/address/0xAa03996D720C162Fdff246E1D3CEecc792986750) | +| CredentialRegistry | [`0x17a22f130d4e1c4ba5C20a679a5a29F227083A62`](https://basescan.org/address/0x17a22f130d4e1c4ba5C20a679a5a29F227083A62) | +| DefaultScorer | [`0x6791B588dAdeb4323bc1C3d987130bC13cBe3625`](https://basescan.org/address/0x6791B588dAdeb4323bc1C3d987130bC13cBe3625) | +| ScorerFactory | [`0x016bC46169533a8d3284c5D8DD590C91783C8C06`](https://basescan.org/address/0x016bC46169533a8d3284c5D8DD590C91783C8C06) | ### Base Sepolia (chain ID 84532) | Contract | Address | |---|---| | Semaphore | [`0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D`](https://sepolia.basescan.org/address/0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D) | -| CredentialRegistry | [`0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db`](https://sepolia.basescan.org/address/0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db) | -| DefaultScorer | [`0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c`](https://sepolia.basescan.org/address/0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c) | -| ScorerFactory | [`0xAa03996D720C162Fdff246E1D3CEecc792986750`](https://sepolia.basescan.org/address/0xAa03996D720C162Fdff246E1D3CEecc792986750) | +| CredentialRegistry | [`0x17a22f130d4e1c4ba5C20a679a5a29F227083A62`](https://sepolia.basescan.org/address/0x17a22f130d4e1c4ba5C20a679a5a29F227083A62) | +| DefaultScorer | [`0x6791B588dAdeb4323bc1C3d987130bC13cBe3625`](https://sepolia.basescan.org/address/0x6791B588dAdeb4323bc1C3d987130bC13cBe3625) | +| ScorerFactory | [`0x016bC46169533a8d3284c5D8DD590C91783C8C06`](https://sepolia.basescan.org/address/0x016bC46169533a8d3284c5D8DD590C91783C8C06) | ### Credential Groups diff --git a/docs/app-manager-specs.md b/docs/app-manager-specs.md index 82b8ce7..7c5af8b 100644 --- a/docs/app-manager-specs.md +++ b/docs/app-manager-specs.md @@ -14,7 +14,7 @@ A web dashboard for third-party app developers to self-manage their BringID inte All interactions go to two contracts on Base (mainnet 8453 / Sepolia 84532): -### CredentialRegistry (`0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db`) +### CredentialRegistry (`0x17a22f130d4e1c4ba5C20a679a5a29F227083A62`) | Function | Access | Description | |---|---|---| @@ -31,7 +31,7 @@ All interactions go to two contracts on Base (mainnet 8453 / Sepolia 84532): | `credentialGroups(uint256 id)` | View | Returns `(status, validityDuration, familyId)`. | | `getCredentialGroupIds()` | View | Returns all registered credential group IDs. | -### DefaultScorer (`0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c`) +### DefaultScorer (`0x6791B588dAdeb4323bc1C3d987130bC13cBe3625`) Read-only from the dashboard's perspective (only BringID owner can write): @@ -41,7 +41,7 @@ Read-only from the dashboard's perspective (only BringID owner can write): | `getScores(uint256[] credentialGroupIds)` | View | Scores for multiple groups. | | `getAllScores()` | View | All group IDs + scores. | -### ScorerFactory (`0xAa03996D720C162Fdff246E1D3CEecc792986750`) +### ScorerFactory (`0x016bC46169533a8d3284c5D8DD590C91783C8C06`) Deploys DefaultScorer instances owned by the caller. Same address on both chains. diff --git a/docs/fetching-scores.md b/docs/fetching-scores.md index c9d71f7..17812fa 100644 --- a/docs/fetching-scores.md +++ b/docs/fetching-scores.md @@ -2,7 +2,7 @@ The `DefaultScorer` contract stores global scores for each credential group. Scores can be read on-chain in a single call — no iteration or multicall needed. -**DefaultScorer address (Base mainnet & Sepolia):** `0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c` +**DefaultScorer address (Base mainnet & Sepolia):** `0x6791B588dAdeb4323bc1C3d987130bC13cBe3625` ## Get All Scores @@ -11,7 +11,7 @@ The `DefaultScorer` contract stores global scores for each credential group. Sco ### cast (Foundry) ```bash -cast call 0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c \ +cast call 0x6791B588dAdeb4323bc1C3d987130bC13cBe3625 \ "getAllScores()(uint256[],uint256[])" \ --rpc-url $BASE_RPC_URL ``` @@ -20,7 +20,7 @@ cast call 0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c \ ```js const scorer = new ethers.Contract( - "0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c", + "0x6791B588dAdeb4323bc1C3d987130bC13cBe3625", ["function getAllScores() view returns (uint256[], uint256[])"], provider ); @@ -33,7 +33,7 @@ const [groupIds, scores] = await scorer.getAllScores(); ```js const [groupIds, scores] = await publicClient.readContract({ - address: "0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c", + address: "0x6791B588dAdeb4323bc1C3d987130bC13cBe3625", abi: [{ name: "getAllScores", type: "function", diff --git a/docs/integration-test/test-verifier-prompt.md b/docs/integration-test/test-verifier-prompt.md index ef6dcb0..a72307a 100644 --- a/docs/integration-test/test-verifier-prompt.md +++ b/docs/integration-test/test-verifier-prompt.md @@ -45,7 +45,7 @@ const signature = await wallet.signMessage(ethers.getBytes(hash)); const body = { message: message, signature: signature, - registry: "0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db", + registry: "0x17a22f130d4e1c4ba5C20a679a5a29F227083A62", chain_id: "84532", // Base Sepolia credential_group_id: "5", // github.com, min score 30 app_id: "1", @@ -66,7 +66,7 @@ The response should be: ```json { "attestation": { - "registry": "0xbf9b2556e6dd64d60e08e3669cef2a4293e006db", + "registry": "0x17a22f130d4e1c4ba5c20a679a5a29f227083a62", "chain_id": 84532, "credential_group_id": "...", "credential_id": "0x...", diff --git a/docs/migration-guide-v2.md b/docs/migration-guide-v2.md index aaca279..f684f3d 100644 --- a/docs/migration-guide-v2.md +++ b/docs/migration-guide-v2.md @@ -9,11 +9,11 @@ Contract addresses are identical on both chains (same deployer, same nonce). | Contract | Address | Chains | |---|---|---| | Semaphore | `0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D` | mainnet (8453), Sepolia (84532) | -| CredentialRegistry | `0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db` | mainnet (8453), Sepolia (84532) | -| DefaultScorer | `0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c` | mainnet (8453), Sepolia (84532) | -| ScorerFactory | `0xAa03996D720C162Fdff246E1D3CEecc792986750` | mainnet (8453), Sepolia (84532) | +| CredentialRegistry | `0x17a22f130d4e1c4ba5C20a679a5a29F227083A62` | mainnet (8453), Sepolia (84532) | +| DefaultScorer | `0x6791B588dAdeb4323bc1C3d987130bC13cBe3625` | mainnet (8453), Sepolia (84532) | +| ScorerFactory | `0x016bC46169533a8d3284c5D8DD590C91783C8C06` | mainnet (8453), Sepolia (84532) | -Owner: `0x6F0CDcd334BA91A5E221582665Cce0431aD4Fc0b` +Owner: `0x677112864ED447866f8D461ABe284E5e907bB4F8` Trusted verifier (Sepolia): `0x3c50f7055D804b51e506Bc1EA7D082cB1548376C` Trusted verifier (mainnet): `0x9186aA65288bFfa67fB58255AeeaFfc4515535d9` diff --git a/docs/migration-instructions/task-manager.md b/docs/migration-instructions/task-manager.md index 118fea3..c1fda31 100644 --- a/docs/migration-instructions/task-manager.md +++ b/docs/migration-instructions/task-manager.md @@ -138,7 +138,7 @@ Update user-facing error messages: ### 9. Environment Variables Add or update: -- `REGISTRY_ADDRESS` — new CredentialRegistry address: `0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db` (same on both Base mainnet 8453 and Sepolia 84532) +- `REGISTRY_ADDRESS` — new CredentialRegistry address: `0x17a22f130d4e1c4ba5C20a679a5a29F227083A62` (same on both Base mainnet 8453 and Sepolia 84532) ## No Changes Required diff --git a/docs/migration-instructions/verify-proof-api.md b/docs/migration-instructions/verify-proof-api.md index f9f0505..359259e 100644 --- a/docs/migration-instructions/verify-proof-api.md +++ b/docs/migration-instructions/verify-proof-api.md @@ -96,8 +96,8 @@ Contract addresses are identical on both chains (same deployer, same nonce). ```diff export const chainRegistries: Record = { - 84532: ['0x0b2Ab187a6FD2d2F05fACc158611838c284E3a9c'], -+ 84532: ['0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db'], -+ 8453: ['0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db'], ++ 84532: ['0x17a22f130d4e1c4ba5C20a679a5a29F227083A62'], ++ 8453: ['0x17a22f130d4e1c4ba5C20a679a5a29F227083A62'], } ``` diff --git a/docs/migration-v3/app-manager.md b/docs/migration-v3/app-manager.md new file mode 100644 index 0000000..d54ed47 --- /dev/null +++ b/docs/migration-v3/app-manager.md @@ -0,0 +1,271 @@ +# Migration Instructions — BringID App Manager Dashboard (v2 → v3) + +## Overview + +The App Manager is a Next.js web dashboard for third-party app developers to self-manage their BringID integration. App admins connect their wallet and manage their app's settings, custom scoring, and lifecycle via direct contract calls. See `docs/app-manager-specs.md` for the full spec. + +## Required Changes + +### 1. Contract Addresses + +Update all hardcoded or configured contract addresses: + +```diff +- REGISTRY_ADDRESS=0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe ++ REGISTRY_ADDRESS=0x17a22f130d4e1c4ba5C20a679a5a29F227083A62 + +- DEFAULT_SCORER_ADDRESS=0x6a0b5ba649C7667A0C4Cd7FE8a83484AEE6C5345 ++ DEFAULT_SCORER_ADDRESS=0x6791B588dAdeb4323bc1C3d987130bC13cBe3625 + +- SCORER_FACTORY_ADDRESS=0x05321FAAD6315a04d5024Ee5b175AB1C62a3fd44 ++ SCORER_FACTORY_ADDRESS=0x016bC46169533a8d3284c5D8DD590C91783C8C06 +``` + +Contract ABIs have changed — re-extract from `out/CredentialRegistry.sol/CredentialRegistry.json` and `out/DefaultScorer.sol/DefaultScorer.json` after building the v3 contracts. + +### 2. App ID Generation — Hash-Based, Non-Sequential (CRITICAL) + +**Affects:** My Apps list, app enumeration, Register App page + +App IDs are no longer sequential auto-increment integers. They are now derived from a hash: + +```diff +- appId = nextAppId++ // v2: sequential 1, 2, 3, … ++ appId = uint256(keccak256(abi.encodePacked(chainId, sender, nonce))) // v3: hash-based +``` + +The `nextAppId` storage variable still exists but it is now a **nonce counter** used as an input to the hash, not the next app ID itself. You cannot enumerate apps by iterating `1..nextAppId`. + +**Impact on "My Apps" list:** The enumeration strategy from the specs (using `nextAppId()` to bound iteration) no longer works. You **must** rely on event indexing to discover app IDs: + +```diff + // Old: iterate 1..nextAppId and check admin +- for (let id = 1; id < nextAppId; id++) { +- const app = await registry.read.apps([id]) +- if (app.admin === connectedAddress) myApps.push(id) +- } + + // New: index AppRegistered + AppAdminTransferred events ++ const created = await publicClient.getLogs({ ++ address: REGISTRY_ADDRESS, ++ event: parseAbiItem('event AppRegistered(uint256 indexed appId, address indexed admin, uint256 recoveryTimelock)'), ++ args: { admin: connectedAddress }, ++ fromBlock: DEPLOY_BLOCK, ++ }) ++ const received = await publicClient.getLogs({ ++ address: REGISTRY_ADDRESS, ++ event: parseAbiItem('event AppAdminTransferred(uint256 indexed appId, address indexed oldAdmin, address indexed newAdmin)'), ++ args: { newAdmin: connectedAddress }, ++ fromBlock: DEPLOY_BLOCK, ++ }) +``` + +The `registerApp()` return value is still the assigned `appId` — capture it from the transaction receipt. + +### 3. Admin Transfer — Two-Step Process (CRITICAL) + +**Affects:** App Detail / Settings page (Admin Transfer section) + +`setAppAdmin()` has been replaced with a two-step transfer pattern: + +```diff +- function setAppAdmin(uint256 appId, address newAdmin) external; ++ function transferAppAdmin(uint256 appId, address newAdmin) external; // Step 1: initiate ++ function acceptAppAdmin(uint256 appId) external; // Step 2: accept +``` + +**UI changes required:** + +- **Initiating admin (current admin):** Call `transferAppAdmin(appId, newAdmin)`. The warning "This is irreversible" is no longer accurate — the transfer is pending until accepted. +- **Accepting admin (new admin):** Add a new UI section for pending incoming transfers. Query `pendingAppAdmin(appId)` to check if the connected wallet has pending transfers to accept. +- **New event:** `AppAdminTransferInitiated(appId, currentAdmin, newAdmin)` fires on `transferAppAdmin()`. The existing `AppAdminTransferred(appId, oldAdmin, newAdmin)` fires on `acceptAppAdmin()`. + +```diff + // Old: single transaction +- await registry.write.setAppAdmin([appId, newAdmin]) + + // New: two-step ++ // Current admin initiates: ++ await registry.write.transferAppAdmin([appId, newAdmin]) ++ // New admin accepts: ++ await registry.write.acceptAppAdmin([appId]) +``` + +**Event indexing update** — add `AppAdminTransferInitiated` to track pending transfers: + +```diff + // Events to index + AppRegistered(appId, admin, recoveryTimelock) ++ AppAdminTransferInitiated(appId, currentAdmin, newAdmin) // NEW: pending transfers + AppAdminTransferred(appId, oldAdmin, newAdmin) + AppStatusChanged(appId, status) + AppScorerSet(appId, scorer) + AppRecoveryTimelockSet(appId, timelock) +``` + +### 4. Event Names — `AppStatusChanged` Replaces Separate Events + +**Affects:** My Apps list, App Detail page, event indexing + +The separate `AppSuspended` and `AppActivated` events have been replaced with a single `AppStatusChanged` event carrying an `AppStatus` enum: + +```diff +- event AppSuspended(uint256 indexed appId); +- event AppActivated(uint256 indexed appId); ++ event AppStatusChanged(uint256 indexed appId, ICredentialRegistry.AppStatus status); +``` + +`AppStatus` enum values: `UNDEFINED (0)`, `ACTIVE (1)`, `SUSPENDED (2)`. + +Update event indexing: + +```diff +- const suspended = await publicClient.getLogs({ +- event: parseAbiItem('event AppSuspended(uint256 indexed appId)'), +- }) +- const activated = await publicClient.getLogs({ +- event: parseAbiItem('event AppActivated(uint256 indexed appId)'), +- }) + ++ const statusChanges = await publicClient.getLogs({ ++ event: parseAbiItem('event AppStatusChanged(uint256 indexed appId, uint8 status)'), ++ fromBlock: DEPLOY_BLOCK, ++ }) ++ // status === 1 → ACTIVE, status === 2 → SUSPENDED +``` + +### 5. Scorer Validation — ERC165 On-Chain Check + +**Affects:** App Detail / Scorer Configuration section, Deploy Custom Scorer page + +`setAppScorer()` now validates the scorer contract on-chain via `ERC165Checker.supportsInterface()`. If the scorer does not implement the `IScorer` interface ID, the transaction reverts with `InvalidScorerContract()`. + +The specs recommended a client-side `getAllScores()` try-call before submitting. This is still useful for UX (prevents wasting gas), but the contract now enforces validation regardless: + +```diff + // Client-side validation (unchanged, still recommended for UX) + try { + await scorer.read.getAllScores() + } catch { + showError('This address does not implement the IScorer interface.') + return + } + + // Contract-side validation (NEW in v3 — will revert if scorer is invalid) + await registry.write.setAppScorer([appId, scorerAddress]) ++ // Reverts with InvalidScorerContract() if scorer doesn't support IScorer interface +``` + +**Custom scorer deployment** — scorers deployed via `ScorerFactory.create()` already implement `IERC165` and will pass validation. If app admins deploy custom scorer contracts manually, they **must** implement `supportsInterface()`: + +```solidity +import {IScorer} from "@bringid/contracts/interfaces/IScorer.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +contract MyScorer is IScorer { + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IScorer).interfaceId || interfaceId == type(IERC165).interfaceId; + } + // ... getScore, getScores, getAllScores implementations +} +``` + +### 6. Error Handling — Custom Errors Replace Strings + +**Affects:** All pages with contract interactions + +All `"BID::..."` error strings have been replaced with typed custom errors. Update error parsing throughout the dashboard: + +```diff +- if (error.message.includes('BID::app not active')) { +- showError('This app is currently suspended.') +- } + ++ // Decode custom error from revert data ++ import { decodeErrorResult } from 'viem' ++ const decoded = decodeErrorResult({ abi: registryAbi, data: error.data }) ++ switch (decoded.errorName) { ++ case 'AppNotActive': ++ showError('This app is currently suspended.') ++ break ++ case 'NotAppAdmin': ++ showError('You are not the admin of this app.') ++ break ++ case 'AppNotSuspended': ++ showError('This app is already active.') ++ break ++ } +``` + +App management error mapping: + +| Old (string) | New (custom error) | User Message | +|---|---|---| +| _(string match)_ | `NotAppAdmin()` | You are not the admin of this app. | +| _(string match)_ | `AppNotActive()` | This app is currently suspended. | +| _(string match)_ | `AppNotSuspended()` | This app is already active. | +| _(new)_ | `InvalidAdminAddress()` | Invalid admin address (cannot be zero). | +| _(new)_ | `NotPendingAdmin()` | You are not the pending admin for this app. | +| _(new)_ | `InvalidScorerContract()` | This address does not implement the IScorer interface. | +| _(new)_ | `InvalidScorerAddress()` | Invalid scorer address (cannot be zero). | + +### 7. New Feature — Merkle Tree Duration Configuration + +**Affects:** App Detail / Settings page (new section) + +v3 adds per-app Merkle tree duration configuration. App admins can override the registry-level default: + +```typescript +// Read current per-app override (0 = using registry default) +const appDuration = await registry.read.appMerkleTreeDuration([appId]) + +// Read registry default +const defaultDuration = await registry.read.defaultMerkleTreeDuration() + +// Set per-app override (admin-only) +await registry.write.setAppMerkleTreeDuration([appId, durationInSeconds]) + +// Clear override (revert to registry default) +await registry.write.setAppMerkleTreeDuration([appId, 0n]) +``` + +The dashboard should add a "Merkle Tree Duration" section to the App Detail page: +- Show current effective duration (per-app override if set, otherwise registry default) +- Input field for seconds with human-readable preview +- Note: setting to 0 reverts to the registry default +- Note: updating propagates to all existing Semaphore groups for the app + +New event to index: `AppMerkleTreeDurationSet(uint256 indexed appId, uint256 merkleTreeDuration)`. + +### 8. New View Function — `getAppSemaphoreGroupIds` + +**Affects:** App Detail page (optional enhancement) + +v3 adds a view function to retrieve all Semaphore group IDs for an app: + +```typescript +const groupIds = await registry.read.getAppSemaphoreGroupIds([appId]) +``` + +This can be used to show how many credential groups have active Semaphore groups for the app, or for debugging purposes. + +### 9. Re-registration + +All apps must be re-registered on the new contract. Existing app IDs from the previous deployment (`0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe`) are not valid on the new contract. + +The dashboard should: +- Clear any cached/stored app IDs from the old contract +- Re-index events starting from the new contract's deployment block +- Prompt returning users to re-register their apps + +## No Changes Required + +- Wallet connection flow (wagmi + viem + ConnectKit/RainbowKit) +- Chain configuration (Base mainnet 8453 + Base Sepolia 84532) +- `registerApp(recoveryTimelock)` function signature (unchanged) +- `suspendApp(appId)` / `activateApp(appId)` function signatures (unchanged) +- `setAppRecoveryTimelock(appId, timelock)` function signature (unchanged) +- `ScorerFactory.create()` flow (unchanged) +- `DefaultScorer` read functions (`getScore`, `getScores`, `getAllScores`) +- Score Explorer page (credential group IDs and structure unchanged) +- General architecture (no backend, direct contract calls, event-based indexing) diff --git a/docs/migration-v3/bringid.md b/docs/migration-v3/bringid.md index 866c5c9..87b17d9 100644 --- a/docs/migration-v3/bringid.md +++ b/docs/migration-v3/bringid.md @@ -12,13 +12,13 @@ Update all hardcoded or configured contract addresses: ```diff - CredentialRegistry: '0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe' -+ CredentialRegistry: '0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db' ++ CredentialRegistry: '0x17a22f130d4e1c4ba5C20a679a5a29F227083A62' - DefaultScorer: '0x6a0b5ba649C7667A0C4Cd7FE8a83484AEE6C5345' -+ DefaultScorer: '0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c' ++ DefaultScorer: '0x6791B588dAdeb4323bc1C3d987130bC13cBe3625' - ScorerFactory: '0x05321FAAD6315a04d5024Ee5b175AB1C62a3fd44' -+ ScorerFactory: '0xAa03996D720C162Fdff246E1D3CEecc792986750' ++ ScorerFactory: '0x016bC46169533a8d3284c5D8DD590C91783C8C06' ``` Semaphore address is unchanged: `0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D`. @@ -155,7 +155,7 @@ Rename the proof type to match the contract: All apps must re-register on the new contract via `registerApp()`. Existing app IDs from the old contract are not valid on the new contract. Store the new `appId` values. -All user credentials must be re-registered. Existing registrations on `0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe` are not accessible from `0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db`. +All user credentials must be re-registered. Existing registrations on `0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe` are not accessible from `0x17a22f130d4e1c4ba5C20a679a5a29F227083A62`. ## No Changes Required diff --git a/docs/migration-v3/overview.md b/docs/migration-v3/overview.md index d484849..9d01b92 100644 --- a/docs/migration-v3/overview.md +++ b/docs/migration-v3/overview.md @@ -1,6 +1,6 @@ # Migration Guide — Credential Registry v3 (Redeployment) -This guide covers breaking changes between the previous deployment (`0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe`) and the current deployment (`0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db`). All consuming apps must update. +This guide covers breaking changes between the previous deployment (`0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe`) and the current deployment (`0x17a22f130d4e1c4ba5C20a679a5a29F227083A62`). All consuming apps must update. ## Deployed Contracts @@ -19,11 +19,11 @@ Contract addresses are identical on both chains (same deployer, same nonce). | Contract | Address | Chains | |---|---|---| | Semaphore | `0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D` | mainnet (8453), Sepolia (84532) | -| CredentialRegistry | `0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db` | mainnet (8453), Sepolia (84532) | -| DefaultScorer | `0x315044578dd9480Dd25427E4a4d94b0fc2Fa4f8c` | mainnet (8453), Sepolia (84532) | -| ScorerFactory | `0xAa03996D720C162Fdff246E1D3CEecc792986750` | mainnet (8453), Sepolia (84532) | +| CredentialRegistry | `0x17a22f130d4e1c4ba5C20a679a5a29F227083A62` | mainnet (8453), Sepolia (84532) | +| DefaultScorer | `0x6791B588dAdeb4323bc1C3d987130bC13cBe3625` | mainnet (8453), Sepolia (84532) | +| ScorerFactory | `0x016bC46169533a8d3284c5D8DD590C91783C8C06` | mainnet (8453), Sepolia (84532) | -Owner: `0x6F0CDcd334BA91A5E221582665Cce0431aD4Fc0b` +Owner: `0x677112864ED447866f8D461ABe284E5e907bB4F8` Trusted verifier (Sepolia): `0x3c50f7055D804b51e506Bc1EA7D082cB1548376C` Trusted verifier (mainnet): `0x9186aA65288bFfa67fB58255AeeaFfc4515535d9` diff --git a/docs/migration-v3/relayer.md b/docs/migration-v3/relayer.md index 901979d..9140cb7 100644 --- a/docs/migration-v3/relayer.md +++ b/docs/migration-v3/relayer.md @@ -12,7 +12,7 @@ The Relayer executes blockchain operations via a relayer wallet with transaction ```diff - REGISTRY_ADDRESS=0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe -+ REGISTRY_ADDRESS=0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db ++ REGISTRY_ADDRESS=0x17a22f130d4e1c4ba5C20a679a5a29F227083A62 ``` Semaphore address is unchanged: `0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D`. diff --git a/docs/migration-v3/semaphore-indexer.md b/docs/migration-v3/semaphore-indexer.md index 9f79f2b..378aff2 100644 --- a/docs/migration-v3/semaphore-indexer.md +++ b/docs/migration-v3/semaphore-indexer.md @@ -12,7 +12,7 @@ Update the CredentialRegistry address used for event monitoring or group discove ```diff - REGISTRY_ADDRESS=0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe -+ REGISTRY_ADDRESS=0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db ++ REGISTRY_ADDRESS=0x17a22f130d4e1c4ba5C20a679a5a29F227083A62 ``` Semaphore address is unchanged: `0x8A1fd199516489B0Fb7153EB5f075cDAC83c693D`. diff --git a/docs/migration-v3/task-manager.md b/docs/migration-v3/task-manager.md index 7094fb3..7629845 100644 --- a/docs/migration-v3/task-manager.md +++ b/docs/migration-v3/task-manager.md @@ -12,7 +12,7 @@ The Task Manager accepts, schedules, and batches verification/claim tasks before ```diff - REGISTRY_ADDRESS=0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe -+ REGISTRY_ADDRESS=0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db ++ REGISTRY_ADDRESS=0x17a22f130d4e1c4ba5C20a679a5a29F227083A62 ``` ### 2. Attestation Struct — `chainId` Field in Calldata (CRITICAL) diff --git a/docs/migration-v3/verifier.md b/docs/migration-v3/verifier.md index 2d29db9..32a5bda 100644 --- a/docs/migration-v3/verifier.md +++ b/docs/migration-v3/verifier.md @@ -56,7 +56,7 @@ Update the `registry` field in all attestations to the new contract address: ```diff - registry: '0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe' -+ registry: '0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db' ++ registry: '0x17a22f130d4e1c4ba5C20a679a5a29F227083A62' ``` The contract enforces `attestation.registry == address(this)` and reverts with `WrongRegistryAddress()` on mismatch. @@ -149,7 +149,7 @@ Update or add: ```diff - REGISTRY_ADDRESS=0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe -+ REGISTRY_ADDRESS=0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db ++ REGISTRY_ADDRESS=0x17a22f130d4e1c4ba5C20a679a5a29F227083A62 ``` Ensure `CHAIN_ID` or equivalent config is available if the verifier serves multiple chains. @@ -161,7 +161,7 @@ import { ethers } from 'ethers' const chainId = 84532 // Base Sepolia const attestation = { - registry: '0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db', + registry: '0x17a22f130d4e1c4ba5C20a679a5a29F227083A62', chainId, credentialGroupId, credentialId, diff --git a/docs/migration-v3/verify-proof-api.md b/docs/migration-v3/verify-proof-api.md index 1262127..539baeb 100644 --- a/docs/migration-v3/verify-proof-api.md +++ b/docs/migration-v3/verify-proof-api.md @@ -16,8 +16,8 @@ Update the registry whitelist: export const chainRegistries: Record = { - 84532: ['0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe'], - 8453: ['0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe'], -+ 84532: ['0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db'], -+ 8453: ['0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db'], ++ 84532: ['0x17a22f130d4e1c4ba5C20a679a5a29F227083A62'], ++ 8453: ['0x17a22f130d4e1c4ba5C20a679a5a29F227083A62'], } ``` diff --git a/docs/migration-v3/widget.md b/docs/migration-v3/widget.md index 036e178..cff990e 100644 --- a/docs/migration-v3/widget.md +++ b/docs/migration-v3/widget.md @@ -12,7 +12,7 @@ Update any hardcoded or configured contract addresses: ```diff - REGISTRY_ADDRESS=0xfd600B14Dc5A145ec9293Fd5768ae10Ccc1E91Fe -+ REGISTRY_ADDRESS=0xbF9b2556e6Dd64D60E08E3669CeF2a4293e006db ++ REGISTRY_ADDRESS=0x17a22f130d4e1c4ba5C20a679a5a29F227083A62 ``` ### 2. Scope Formula — `appId` Included (CRITICAL)