Roles & Access Control
SkyBridge V2 uses OpenZeppelin AccessControl on both contracts. The role sets are distinct.
Diamond — 6 roles
The Diamond's role model is defined in AccessControlInternal.sol:
| Role | bytes32 hash | Purpose |
|---|---|---|
DEFAULT_ADMIN_ROLE | bytes32(0) | Grant and revoke all other roles |
MULTISIG_ROLE | keccak256("MULTISIG_ROLE") | Finalize or reject Diamond upgrades; manage CCIP chain/sender allowlists; execute timelocked withdrawals |
PROPOSER_ROLE | keccak256("PROPOSER_ROLE") | Propose Diamond upgrades (facet cuts) |
CCIP_OPERATOR_ROLE | keccak256("CCIP_OPERATOR_ROLE") | Mint/burn bridge-deployed tokens; manage CCIP token admin |
OPERATOR_ROLE | keccak256("OPERATOR_ROLE") | Set neverWrapTokens flag on canonical tokens |
PAUSER_ROLE | keccak256("PAUSER_ROLE") | Pause/unpause ERC-20 bridging in BridgeFacet |
Role topology (post-handoff)
| Role | Diamond | EntryPoint |
|---|---|---|
DEFAULT_ADMIN_ROLE / MULTISIG_ROLE / CCIP_OPERATOR_ROLE / OPERATOR_ROLE | 0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb | 0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb |
PAUSER_ROLE | 0x1cFd452EB369a7B9475B07D1457dd1d0500fD788 + 0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb | 0x1cFd452EB369a7B9475B07D1457dd1d0500fD788 + 0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb |
PROPOSER_ROLE | 0x7966D48F5c0f14A33Bf325ceABdE87893F1677F7 (only role this address holds anywhere) | — |
Diamond upgrade flow
Upgrades require two parties:
PROPOSER_ROLE ──► diamondCut(...) ──► proposal queued (7-day TTL)
MULTISIG_ROLE ──► finalizeUpgrade(id) ──► change applied
rejectUpgrade(id) ──► proposal cancelled
MULTISIG can also call rejectAllUpgrades() or rejectRange(start, end) to bulk-cancel proposals in an emergency.
EntryPoint — 3 roles
Defined on SkyBridgeEntryPoint itself (OpenZeppelin AccessControlUpgradeable):
| Role | bytes32 hash | Purpose |
|---|---|---|
DEFAULT_ADMIN_ROLE | bytes32(0) | All admin functions: fee, diamond address, token messenger, fee collector, chain registry, upgrade authorization |
PAUSER_ROLE | keccak256("aviator.pauser_role") | Call setPaused(true/false) |
OPERATOR_ROLE | keccak256("OPERATOR_ROLE") | Register/remove OP Standard Bridge L1→L2 token mappings |
Note: The EntryPoint PAUSER_ROLE uses a different hash ("aviator.pauser_role") from the Diamond's PAUSER_ROLE ("PAUSER_ROLE"). They are separate roles on separate contracts.
Fee custody — not a role
There is no FEE_COLLECTOR_ROLE. It was retired in V5.3.
Fee custody is a stored address, feeCollector, set by DEFAULT_ADMIN_ROLE via changeFeeCollector(address). The current fee collector is the Fee Safe 0xA953B9DF3b081709eA75895cF5a8fAf7DCC29354 (Gnosis Safe, 2-of-3).
Fees are collected permissionlessly — anyone can call:
collectFees()→ sweeps all accumulated ETH tofeeCollectorcollectTokenFees(address token)→ sweeps all accumulated ERC-20 (e.g., USDC from fast CCTP) tofeeCollector
Neither caller nor msg.sender retains any fees; the full balance always goes to feeCollector.
Role constants comparison
| Diamond | EntryPoint | |
|---|---|---|
DEFAULT_ADMIN_ROLE | bytes32(0) | bytes32(0) |
PAUSER_ROLE | keccak256("PAUSER_ROLE") | keccak256("aviator.pauser_role") |
OPERATOR_ROLE | keccak256("OPERATOR_ROLE") | keccak256("OPERATOR_ROLE") |
MULTISIG_ROLE | keccak256("MULTISIG_ROLE") | — |
PROPOSER_ROLE | keccak256("PROPOSER_ROLE") | — |
CCIP_OPERATOR_ROLE | keccak256("CCIP_OPERATOR_ROLE") | — |
See also
- Admin addresses — Safe addresses and deployer
- EntryPoint — admin function reference
- Diamond & Facets — which functions each role gates