Skip to main content

Admin

The admin is whoever holds DEFAULT_ADMIN_ROLE on a contract set's IssuerRegistry and StatusRegistry. It decides which institutions may issue, restarts the system after a pause, lifts issuer suspensions, can place a hold on a single credential, and manages the guardian role. It is the most powerful role in the system, so it is held by a multi-signature wallet and, once the handover is finished, exercised only through a timelock that makes every change visible before it runs.

Words used here:

  • Safe: a multi-signature smart account. On Sepolia the operator's Safe needs 2 of its 3 owners to sign.
  • Timelock: CertichainTimelock, an OpenZeppelin TimelockController. The Safe is its proposer and canceller, anyone may execute, and it has no admin of its own. An action is scheduled, waits the minimum delay, then runs.
  • Delayed admin transfer: both registries use OpenZeppelin AccessControlDefaultAdminRules. A new admin is nominated with beginDefaultAdminTransfer, waits the admin delay, then accepts with acceptDefaultAdminTransfer.

See Access control and governance and the Timelock contract page.

Who holds it (as of 2026-10-24)​

Contract setAdmin of IssuerRegistry and StatusRegistryNotes
0.3.0 (active on Sepolia)The Safe, which accepted the role from the deployer on 2026-10-17Admin delay 3 days. The timelock was nominated, with acceptance possible from 2026-10-20; the handbook's last recorded status leaves the accept open.
0.5.0 (deployed on Sepolia, not active)The timelockTaken over in the 2026-10-17 rehearsal; timelock delay 3600 s on Sepolia (2 days planned for production).
Local chainThe first Hardhat account (the deployer)Tests and E2E use it directly.

Read the live answer with cd blockchain && npm run governance:v03:sepolia (read only) or on /admin.

How the app recognises the admin​

On v0.3, IssuerRegistry.isGuardian(address) is true for the admin, so accessOf(...).isAdmin is true and the Admin workspace appears. In practice the admin never uses it: a Safe or a timelock is a contract and cannot connect to the site as a browser wallet (the site has no WalletConnect support). The /admin page is a read-only view of the admin's state for everyone with the guardian role, and it sends no admin transaction. See Guardian for what the page shows.

What the admin controls​

ActionContract and functionNotes
Register an institutionIssuerRegistry.addIssuer(issuer, name)Name unique, 1 to 128 bytes; a retired key cannot be re-added
Remove an institutionIssuerRegistry.removeIssuer(issuer)Its credentials stay on chain and StatusRegistry.isValid does not change; the VC, disclosure and API checks then report the issuer as not registered (the lookup page does not check registration)
RenameIssuerRegistry.setIssuerName(issuer, name)
Retire an issuer keyIssuerRegistry.retireIssuer(retired, successor)Contract version 0.5.0 onward. The successor must be an active issuer; a lineage is at most 8 keys long
Restart after a pauseIssuerRegistry.unpause()On 0.5.0 sets a guardian may also unpause
PauseIssuerRegistry.pause()The admin counts as a guardian
Grant or revoke the guardian roleIssuerRegistry.grantRole or revokeRole with GUARDIAN_ROLE()
Suspend an issuer, or lift a suspensionStatusRegistry.setIssuerSuspended(issuer, suspended, reason)Suspending is open to guardians; lifting is admin only
Hold a single credentialStatusRegistry.suspend(id, reason, noteHash) called by the adminSets adminHold; the issuer can then only revoke, not reinstate or supersede
Lift a holdStatusRegistry.reinstate(id, noteHash)Only the admin can lift its own hold
Hand the role onbeginDefaultAdminTransfer, acceptDefaultAdminTransfer (by the nominee), cancelDefaultAdminTransfer, changeDefaultAdminDelayEvery change waits for the admin delay
Wire a new set onceStatusRegistry.bindCredentialRegistry(registry)Done at deployment; refuses a second binding

The VersionAnnouncer (which announces new contract sets) has its own default admin and is not moved by the timelock handover script. See Version announcer and Contract set upgrade.

How an admin action is carried out​

Before the handover: the Safe calls the registry​

Two Safe owners build the call in the Safe's Transaction Builder (or import a batch file a script wrote), read the decoded call, sign, and execute. The runbook docs/process/runbooks/admin-keys.md lists the everyday calls.

After the handover: schedule, wait, execute​

The proposal script reads the timelock's minimum delay and the active set from the manifest, and only writes files: TARGET=IssuerRegistry FUNCTION=addIssuer ARGS='["0x...","Institution name"]' npm run timelock:propose:sepolia. Targets are IssuerRegistry, StatusRegistry (of the active set, or SET=<label>) and Timelock. Admitting an institution under the draft consortium charter also passes SIGNOFF_FILE, so the salt is the hash of the accreditor's sign-off, and npm run admission:check:sepolia confirms the match. Flow: Governance.

What the admin cannot do​

  • Issue, revoke, reinstate or supersede someone else's credential. Revoking and superseding check the issuer key in charge. The admin's only credential-level power is the hold.
  • Act instantly on a transfer. Changing who is admin, and changing the admin delay, wait for the delay. After the handover, every admin action waits for the timelock delay too.
  • Rewrite history. Anchors, signatures and status events are permanent; removing an issuer does not delete its credentials.
  • Read personal data. The chain holds none.
  • Use the site's buttons. Admin actions are prepared as Safe batches; the governance screen is read only.

Keys behind the admin​

KeyHolderNotes
Safe owner keysThree named peopleTwo sign each batch. Losing one leaves two; losing two leaves the admin unable to act until a recovery described in the runbook.
Deployer keyThe operatorAdmin only until the Safe accepts; retired on Sepolia on 2026-10-17.

The monitor (when configured) reads the admin and pending admin of every watched registry and warns when a transfer is pending, when registries disagree, or when a registry is not yet administered by the recorded timelock. It also watches CallScheduled, CallExecuted and Cancelled on the timelock. See Monitoring.

Checklist​

  • Before signing in the Safe, compare the decoded call with what the proposal script printed.
  • Keep the salt the script prints; it is needed to execute.
  • After scheduling, check /admin shows the operation as Waiting, and later Ready.
  • Restart after a pause in the order the incident runbook gives (revoke a suspected guardian first, then unpause, then lift suspensions), in one batch.
  • Record every admission and removal in the governance log; run npm run governance:log:check.
  • Never sign an admin change that was not announced to the institutions in advance, unless it is an emergency.

Source files​

  • blockchain/contracts/v03/IssuerRegistry.sol, blockchain/contracts/v03/StatusRegistry.sol, blockchain/contracts/v03/CertichainTimelock.sol, blockchain/contracts/v03/VersionAnnouncer.sol
  • blockchain/scripts/handover-v03.ts, governance-status.ts, deploy-timelock.ts, nominate-timelock.ts, timelock-handover.ts, timelock-propose.ts, admission-check.ts, governance-log-check.ts
  • blockchain/scripts/lib/timelock-proposal.ts, blockchain/scripts/lib/timelock-handover.ts
  • src/app/admin/GovernancePage.tsx, src/app/admin/GovernancePanel.tsx, src/app/admin/TimelockSection.tsx
  • src/services/domain/platform-governance-service.ts
  • src/lib/server/ops/checks/governance.ts, src/lib/server/ops/checks/chain-events.ts

Tests​

  • Contracts: blockchain/test/v03/Governance.test.ts, SafeGovernance.test.ts, Handover.test.ts, Timelock.test.ts, TimelockDeploy.test.ts, TimelockHandover.test.ts, TimelockProposal.test.ts, TimelockTargets.test.ts, KeyLineage.test.ts, GovernanceLog.test.ts
  • Server: src/lib/server/ops/checks/governance.test.ts
  • Rendered: src/app/admin/GovernancePanel.test.tsx
  • E2E: e2e/journeys/pause-and-restart.journey.ts (the admin restart is done by the harness helper unpauseAsAdmin), e2e/journeys/key-retirement.journey.ts (the harness helper replaceIssuerKey plays the admin)