Skip to main content

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:

Rolebytes32 hashPurpose
DEFAULT_ADMIN_ROLEbytes32(0)Grant and revoke all other roles
MULTISIG_ROLEkeccak256("MULTISIG_ROLE")Finalize or reject Diamond upgrades; manage CCIP chain/sender allowlists; execute timelocked withdrawals
PROPOSER_ROLEkeccak256("PROPOSER_ROLE")Propose Diamond upgrades (facet cuts)
CCIP_OPERATOR_ROLEkeccak256("CCIP_OPERATOR_ROLE")Mint/burn bridge-deployed tokens; manage CCIP token admin
OPERATOR_ROLEkeccak256("OPERATOR_ROLE")Set neverWrapTokens flag on canonical tokens
PAUSER_ROLEkeccak256("PAUSER_ROLE")Pause/unpause ERC-20 bridging in BridgeFacet

Role topology (post-handoff)​

RoleDiamondEntryPoint
DEFAULT_ADMIN_ROLE / MULTISIG_ROLE / CCIP_OPERATOR_ROLE / OPERATOR_ROLE0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb
PAUSER_ROLE0x1cFd452EB369a7B9475B07D1457dd1d0500fD788 + 0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb0x1cFd452EB369a7B9475B07D1457dd1d0500fD788 + 0x1Bd922A1Dc99303CF8a683a5a5C9215045873Ddb
PROPOSER_ROLE0x7966D48F5c0f14A33Bf325ceABdE87893F1677F7 (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):

Rolebytes32 hashPurpose
DEFAULT_ADMIN_ROLEbytes32(0)All admin functions: fee, diamond address, token messenger, fee collector, chain registry, upgrade authorization
PAUSER_ROLEkeccak256("PAUSER_ROLE")Call setPaused(true/false)
OPERATOR_ROLEkeccak256("OPERATOR_ROLE")Register/remove OP Standard Bridge L1→L2 token mappings

Note: Since EntryPoint 6.5.0 (app version 2.2.2, October 2026), the EntryPoint PAUSER_ROLE uses the same hash as the Diamond's, keccak256("PAUSER_ROLE"). Earlier EntryPoints used keccak256("aviator.pauser_role"). They are still separate roles on separate contracts, and the same two addresses hold both.


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 to feeCollector
  • collectTokenFees(address token) → sweeps all accumulated ERC-20 (e.g., USDC from fast CCTP) to feeCollector

Neither caller nor msg.sender retains any fees; the full balance always goes to feeCollector.


Role constants comparison​

DiamondEntryPoint
DEFAULT_ADMIN_ROLEbytes32(0)bytes32(0)
PAUSER_ROLEkeccak256("PAUSER_ROLE")keccak256("PAUSER_ROLE") (since 6.5.0)
OPERATOR_ROLEkeccak256("OPERATOR_ROLE")keccak256("OPERATOR_ROLE")
MULTISIG_ROLEkeccak256("MULTISIG_ROLE")-
PROPOSER_ROLEkeccak256("PROPOSER_ROLE")-
CCIP_OPERATOR_ROLEkeccak256("CCIP_OPERATOR_ROLE")-

See also​