# AccessRouter and roles

> The protocol separates two kinds of state change:

The protocol separates two kinds of state change:

-   **User operations** (deposit, transact, ragequit) are authorized by zero-knowledge proofs the contracts verify on-chain, so no privileged account can move a user's funds.
-   **Administrative changes** (pausing the pool, upgrading a contract, swapping a verifier, updating asset config, publishing a new ASP root) are authorized by roles instead.

Every contract delegates those role checks to a single AccessRouter.

## AccessRouter

AccessRouter is the one contract that holds the role assignments. Every other contract carries a `checkAccess(ROLE)` modifier that asks the router whether `msg.sender` holds the required role, so roles are granted and revoked in one place rather than per contract. The router uses a two-tier admin model that separates fast operational response from slow custodial governance:

`DEFAULT_ADMIN_ROLE` Slow-governance tier, intended for timelocked governance (Canon Guard). It administers `OPS_ADMIN_ROLE` and every role not delegated to the ops tier, and it is the only role that can replace a compromised ops multisig.
`OPS_ADMIN_ROLE` Fast operational tier, intended for a multisig without a timelock. It administers only the roles designated at deploy time, and the constructor rejects any attempt to delegate `DEFAULT_ADMIN_ROLE` or `OPS_ADMIN_ROLE` itself to this tier, so the asymmetry cannot be configured away by mistake.

## Roles and what they gate

`DEPOSITOR_ROLE` Gates [`PoolVault`](/protocol/contracts/pool-vault)`.deposit`. Held by the [Entrypoint](/protocol/contracts/entrypoint), so deposits flow through the Entrypoint's fee and asset-config layer rather than calling the vault directly.
`PAUSER_ROLE` Gates `PoolVault.pause`, which halts deposits and transacts (both carry `whenNotPaused`). Can be held by several guardians.
`UNPAUSER_ROLE` Gates `PoolVault.unpause`, which resumes operation.
`UPGRADER_ROLE` Gates the UUPS upgrade authorization on every contract, plus the parameter setters: `PoolVault.setAspRegistry`, `setKeystore`, `setRagequitVerifier`, `setDepositVerifier`, and `setMaxStateTreeSize`; [`Keystore`](/protocol/contracts/keystore)`.setKeystoreRootLiveness` and `setMaxKeystoreTreeSize`; and `Entrypoint.setPoolVault`.
`ENTRYPOINT_MANAGER_ROLE` Gates `Entrypoint.sweep`, which withdraws collected vetting fees, and the Entrypoint asset configuration.
`POSTMAN_ROLE` Gates [`ASPRegistry`](/protocol/contracts/asp-registry)`.updateASPRoot`, the call that publishes a new association-set root and its IPFS CID.

## Verifier contracts

The proofs behind user operations are checked by generated Groth16 verifier contracts, kept separate from the logic contracts. PoolVault holds a deposit verifier and a ragequit verifier, and routes transact proofs through the transact verifier for the `transact_NxM` variant in use. Swapping any of these is an `UPGRADER_ROLE` operation (`setDepositVerifier`, `setRagequitVerifier`), which is why a verifier change and the matching circuit change must land together as one deployment set.

## User operations versus administrative state

This split is what the trust model rests on. A deposit, transfer, withdrawal, or ragequit changes pool state only when its circuit proof verifies, so the role holders above cannot forge or redirect a user operation. What the roles control is the surrounding machinery: whether the pool is paused, which verifier and registry addresses the vault points at, what assets the Entrypoint accepts, and which ASP root is current. Pausing blocks new deposits and transacts but never seizes funds, and because `ragequit` is not gated by `whenNotPaused`, a registered owner can still exit an unspent note even while the pool is paused.

Source: `v2-monorepo/packages/contracts/src/contracts/AccessRouter.sol`, `v2-monorepo/packages/contracts/src/utils/RolesConstants.sol`
