AccessManager
TheAccessManager contract (Solidity name NotareumAccessManager) is the single source of role and timelock authority for the Notareum protocol. Every other contract inherits from OpenZeppelin’s AccessManagedUpgradeable and defers role checks to this central manager. Consolidating authority here gives one auditable surface for every privileged operation in the system: who can call what function, on which contract, after which delay.
Notareum uses OpenZeppelin’s AccessManager (v5.x API) directly with protocol-specific configuration; no custom forks.
Why a central manager
The olderAccessControl pattern distributes role state across every contract. This is operationally costly: granting a cross-contract role change requires coordinated governance proposals on each contract, and changes to timelock semantics require contract-by-contract migration. AccessManager inverts the model:
- Every protected function declares a single
uint64 roleIdrequired to call it. AccessManagerstores the mapping from(address accountOrContract, roleId) → membershipand the mapping from(targetContract, selector) → requiredRoleId.- Per-target delays are stored in the same contract.
- A single governance action can change role memberships, function targets, or delays across the entire protocol.
Defined roles
All roles except
FEE_MANAGER are intended to be held by timelocked governance executors. FEE_MANAGER is held by the FeeManager contract address.
Delay schedule
Role grants, target function updates, and proxy upgrades all go through delays configured inAccessManager. Default delays:
Governance proposals schedule operations through the manager; execution is permissionless after the delay elapses.
Function selector gating
For each protocol function that should be role-gated,AccessManager stores the required role:
restricted modifier on each protocol function reads the selector and consults AccessManager.hasRole(currentRole(selector), msg.sender).
Integration pattern
A protected function on a downstream contract:restricted resolves the required role for the current call via AccessManager and checks that msg.sender has it. No local role state is kept.
Governance cycle
TheGovernor contract is the only address granted all timelocked admin roles in production. Off-chain multisigs can hold subsets during bootstrap.
Emergency pause
A narrow subset of functions is pausable with delay 0 to respond to active incidents:NotaRegistry.pause()VerificationEngine.pause()ValidatorStaking.pause()
Reading role state
executionDelay > 0 indicates the account needs to schedule the call in advance rather than executing inline.
SDK helpers
Events
Standard OZ events:Security posture
- Single manager, many targets. Compromise of
AccessManagercompromises the stack. Its upgrade path is gated by itself with a 14-day delay: a malicious upgrade must survive 14 days of observation and governance intervention. - No address-based back doors. No contract holds an owner field bypassing the manager. Every privileged path flows through
restricted+AccessManager. - Timelocks are non-negotiable. Delays are part of the role definition; granting a role does not grant instant execution.
- Public scheduling. Every scheduled operation is visible on-chain via
OperationScheduledevents before execution.
Invariants
- Every
restrictedfunction maps to exactly one role inAccessManager. - Execution of a scheduled operation requires
block.timestamp >= schedule. - Proxy upgrades cannot be executed without the
UPGRADERrole, and the role is held only by timelocked governance. - The manager itself can be upgraded only through the same role and delay it enforces for others.

