> ## Documentation Index
> Fetch the complete documentation index at: https://docs.notareum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Access manager

# AccessManager

The `AccessManager` 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 older `AccessControl` 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:

1. Every protected function declares a single `uint64 roleId` required to call it.
2. `AccessManager` stores the mapping from `(address accountOrContract, roleId) → membership` and the mapping from `(targetContract, selector) → requiredRoleId`.
3. Per-target delays are stored in the same contract.
4. A single governance action can change role memberships, function targets, or delays across the entire protocol.

## Defined roles

| Role              | `uint64 roleId` | Purpose                                                       |
| ----------------- | --------------: | ------------------------------------------------------------- |
| `PROTOCOL_ADMIN`  |             `1` | Pause/unpause, rate table changes, high-level protocol config |
| `VALIDATOR_ADMIN` |             `2` | Stake minima, cooldown, daily caps, reward multipliers        |
| `TREASURY_ADMIN`  |             `3` | Fee tables, split ratios, treasury and validator pool routing |
| `UPGRADER`        |             `4` | UUPS `upgradeTo` across all proxies                           |
| `SLASHER`         |             `5` | Manual slashing invocations (dispute judge, watchdog)         |
| `MINTER`          |             `6` | `NOTA.mint` post-genesis (held by governance timelock)        |
| `FEE_MANAGER`     |             `7` | `NOTA.protocolBurn` (held by FeeManager contract)             |
| `PUBLIC_ROLE`     |             `0` | Reserved by OZ for unrestricted functions                     |

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 in `AccessManager`. Default delays:

| Operation               |         Delay |
| ----------------------- | ------------: |
| Grant `PROTOCOL_ADMIN`  |       14 days |
| Grant `VALIDATOR_ADMIN` |       14 days |
| Grant `TREASURY_ADMIN`  |       14 days |
| Grant `UPGRADER`        |       14 days |
| Grant `SLASHER`         |        7 days |
| Grant `MINTER`          |       14 days |
| Pause (emergency)       | 0 (immediate) |
| Unpause                 |      24 hours |
| Fee table change        |       14 days |
| Slashing rate change    |       14 days |
| Proxy upgrade           |        7 days |

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:

```solidity theme={"system"}
// At deployment
acc.setTargetFunctionRole(
    address(notaRegistry),
    [NotaRegistry.pause.selector, NotaRegistry.unpause.selector],
    PROTOCOL_ADMIN
);
acc.setTargetFunctionRole(
    address(feeManager),
    [FeeManager.setFeeTable.selector, FeeManager.setSplit.selector],
    TREASURY_ADMIN
);
acc.setTargetFunctionRole(
    address(validatorStaking),
    [ValidatorStaking.setTierMinimum.selector, ValidatorStaking.setCooldown.selector],
    VALIDATOR_ADMIN
);
```

The `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:

```solidity theme={"system"}
contract NotareumFeeManager is AccessManagedUpgradeable, UUPSUpgradeable {
    function setFeeTable(FeeTable calldata table) external restricted {
        _feeTable = table;
        emit FeeTableUpdated(table);
    }

    function _authorizeUpgrade(address newImpl) internal override restricted {}
}
```

`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

```mermaid theme={"system"}
sequenceDiagram
    participant veHolder as veNOTA holder
    participant Gov as Governor
    participant AM as AccessManager
    participant Target as Target contract

    veHolder->>Gov: propose(schedule(target, data, delay))
    veHolder->>Gov: vote
    Gov->>AM: schedule(target, data, eta)
    Note over AM: wait delay
    Gov->>AM: execute(target, data, eta)
    AM->>Target: (authorized call)
    Target-->>AM: ok
```

The `Governor` 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()`

Pause is an emergency-brake, not a governance action: it freezes mutations but does not drain or move any funds. Unpausing takes 24 hours via standard delay, which constrains the ability to abuse emergency access.

## Reading role state

```solidity theme={"system"}
// OZ interface
function hasRole(uint64 roleId, address account)
    external view returns (bool isMember, uint32 executionDelay);
```

`executionDelay > 0` indicates the account needs to schedule the call in advance rather than executing inline.

## SDK helpers

```typescript theme={"system"}
import { Notareum, Role } from "@notareum/sdk";

const ntm = Notareum({ provider, contracts });

// Is governance executor a PROTOCOL_ADMIN?
const { isMember, executionDelay } = await ntm.access.hasRole(
  Role.PROTOCOL_ADMIN,
  governanceExecutor
);

// Which role is required for this selector?
const role = await ntm.access.getTargetFunctionRole(
  ntm.fee.address,
  ntm.fee.interface.getSighash("setFeeTable")
);

// Schedule a governance call
await ntm.access.schedule(
  ntm.fee.address,
  ntm.fee.interface.encodeFunctionData("setFeeTable", [newTable]),
  etaTimestamp
);
```

## Events

Standard OZ events:

```solidity theme={"system"}
event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember);
event RoleRevoked(uint64 indexed roleId, address indexed account);
event TargetFunctionRoleUpdated(address indexed target, bytes4 indexed selector, uint64 indexed roleId);
event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since);
event OperationScheduled(bytes32 indexed operationId, uint32 nonce, uint48 schedule, address caller, address target, bytes data);
event OperationExecuted(bytes32 indexed operationId, uint32 nonce);
event OperationCanceled(bytes32 indexed operationId, uint32 nonce);
```

Indexers subscribe to these events to maintain live dashboards of who can do what, pending operations, and delay changes.

## Security posture

1. **Single manager, many targets.** Compromise of `AccessManager` compromises 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.
2. **No address-based back doors.** No contract holds an owner field bypassing the manager. Every privileged path flows through `restricted` + `AccessManager`.
3. **Timelocks are non-negotiable.** Delays are part of the role definition; granting a role does not grant instant execution.
4. **Public scheduling.** Every scheduled operation is visible on-chain via `OperationScheduled` events before execution.

## Invariants

1. Every `restricted` function maps to exactly one role in `AccessManager`.
2. Execution of a scheduled operation requires `block.timestamp >= schedule`.
3. Proxy upgrades cannot be executed without the `UPGRADER` role, and the role is held only by timelocked governance.
4. The manager itself can be upgraded only through the same role and delay it enforces for others.

## Related pages

* [Smart Contracts Overview](overview.md)
* [FeeManager](fee-manager.md)
* [SlashingManager](slashing-manager.md)
* [Governance protocol doc](../protocol/governance.md)
