SkyBridgeEntryPoint
SkyBridgeEntryPoint is the user-facing contract on every chain. It is deployed as an ERC-1967 / UUPS upgradeable proxy. Per-chain addresses are listed in Official Addresses.
Version: 6.3.0 (constant version on the implementation). 6.3.0 added Rail 5 (Arbitrum Canonical); it is only active on the L1 EntryPoints (Ethereum, Sepolia) - the arbitrumInboxes registry simply stays empty elsewhere.
Roles
The EntryPoint has three roles:
| Role | bytes32 identifier | Purpose |
|---|---|---|
DEFAULT_ADMIN_ROLE | bytes32(0) | Grant/revoke all roles; set fee, diamond, token messenger, fee collector; add/remove chains; upgrade |
PAUSER_ROLE | keccak256("aviator.pauser_role") | Call setPaused(true/false) |
OPERATOR_ROLE | keccak256("OPERATOR_ROLE") | Register/remove OP Standard Bridge L1→L2 token mappings |
DEFAULT_ADMIN_ROLE can also call setPaused directly.
Fee model
Every bridge transaction pays a flat fee in native currency (ETH, POL, AVAX, or BNB depending on chain). The fee is set by the admin via setFlatFee(uint256) and readable as flatFee.
Individual tokens can be exempt from the flat fee (setTokenFeeExempt). The effective fee for a given token is returned by getEffectiveFee(address token) (returns 0 if exempt, flatFee otherwise).
CCTP fast route charges an additional percentage fee retained as USDC in the EntryPoint: fastCctpFeeBps basis points (currently 25 = 0.25%). This is separate from the flat native fee.
Accumulated fees are collected permissionlessly by anyone calling collectFees() (ETH) or collectTokenFees(address token) (ERC-20). Both functions sweep the full balance to the feeCollector address (the Fee Safe 0xA953B9DF3b081709eA75895cF5a8fAf7DCC29354). There is no FEE_COLLECTOR_ROLE - fee custody is a stored address, not a role.
Rail routing
Rail 1 - OP Standard Bridge
Forwards ETH or listed ERC-20s to the OP L1StandardBridge on OP-stack L2s (Base, Optimism, Unichain, Soneium, Ink). The contract source comments label this rail "legacy" and recommend CCIP for new integrations, but it remains an available, supported rail.
Key functions:
| Function | Description |
|---|---|
bridgeOPStandardETH(chainId, minGasLimit, extraData) | Bridge ETH to an OP-stack L2 |
bridgeOPStandardETHTo(chainId, to, ...) | Bridge ETH to a specific recipient |
bridgeOPStandardERC20(chainId, l1Token, amount, ...) | Bridge an ERC-20 (must be registered in the L1→L2 token registry) |
bridgeOPStandardERC20To(chainId, l1Token, to, ...) | Bridge ERC-20 to a specific recipient |
The L2 token for each l1Token is resolved from an on-chain registry (opBridgeL2Tokens); the caller cannot specify the L2 token directly.
Rail 3 - Chainlink CCIP
Routes through the Diamond (BridgeFacet / ERC721BridgeFacet). Works for any CCIP-supported ERC-20 and ERC-721 across all 11 chains.
Key functions:
| Function | Returns | Description |
|---|---|---|
bridgeCCIP(token, amount, chainSelector, receiver) | bytes32 messageId | Bridge an ERC-20 via CCIP |
bridgeCCIPNativeETH(amount, chainSelector, receiver) | bytes32 messageId | Bridge native ETH (Diamond wraps to WETH internally; only works on chains with a registered WETH CCIP pool) |
bridgeCCIPNFT(token, tokenId, chainSelector, receiver) | bytes32 messageId | Bridge a single ERC-721 |
bridgeCCIPNFTBatch(token, tokenIds[], chainSelector, receiver) | bytes32 messageId | Bridge multiple NFTs from the same collection |
getBridgeCCIPQuote(token, amount, chainSelector, receiver) | (ccipFee, protocolFee, totalFee) | Get fee quote before bridging |
getBridgeCCIPNFTQuote(token, tokenId, chainSelector, receiver) | (ccipFee, protocolFee, totalFee) | Get NFT fee quote |
Fee-on-transfer tokens are rejected automatically (pre/post balance check). Blacklisted tokens revert with TokenBlacklisted.
Rail 4 - Circle CCTP
Burns USDC via Circle's TokenMessengerV2 using the Forwarding Service hook, which instructs Circle's relayer to auto-mint on the destination chain.
Key function:
| Parameter | Description |
|---|---|
token | USDC address on this chain |
amount | Total USDC (protocol fee deducted before burn on fast route) |
destinationDomain | Circle CCTP destination domain ID |
mintRecipient | Recipient (bytes32-padded) |
maxFee | Maximum fee for Circle's Forwarding Service market maker |
minFinalityThreshold | 1000 = Fast, 2000 = Standard |
The 0.25% fast-route fee is retained as USDC in the EntryPoint (swept later via collectTokenFees(usdc)). burnAmount must exceed maxFee after the deduction.
Rail 5 - Arbitrum Canonical (native ETH)
Deposits native ETH into an Arbitrum-stack chain by calling that chain's canonical Delayed Inbox directly (IArbitrumInbox.createRetryableTicket) - no Diamond involvement. Deposits only (Ethereum → destination) and native ETH only; this rail is only active on the L1 EntryPoints.
Key function:
| Function | Description |
|---|---|
bridgeArbitrumETHTo(chainId, to, amount, maxSubmissionCost, gasLimit, maxFeePerGas) | Deposit native ETH to a specific recipient on an Arbitrum-stack chain via a retryable ticket |
getBridgeArbitrumETHQuote(chainId, gasLimit, maxFeePerGas) | Returns (submissionFee, gasFunds, protocolFee, totalExtra) - quote everything except the deposit amount itself |
bridgeArbitrumETHTo requires exact msg.value: flatFee + amount + maxSubmissionCost + gasLimit * maxFeePerGas. Any mismatch reverts InsufficientETHForFee - unlike Rail 3's CCIP fee, there is no overpayment-as-dust allowance on this rail, because all gas surplus is refunded to the user automatically on L2 by the retryable-ticket mechanism.
Both the excess-fee refund address and the call-value refund address (the ticket's beneficiary, who can cancel or reclaim funds on a 7-day expiry) are set to _to - never the EntryPoint. gasLimit and maxFeePerGas must both be greater than 1 (the values 0/1 are Arbitrum's reserved gas-estimation sentinels) or the call reverts InvalidRetryableGasParams.
Emits ArbitrumETHBridgeInitiated(sender, to, chainId, amount, maxSubmissionCost, gasLimit, maxFeePerGas, ticketNumber, fee), where ticketNumber is the L1 message number returned by the Inbox.
Chain registry (Rail 1)
OP-stack chain registrations are managed via addChain / updateChain / removeChain (admin). L1→L2 token mappings for Rail 1 are batch-registered via setOpBridgeTokens (operator) and queried via getOpBridgeL2Token(chainId, l1Token).
Inbox registry (Rail 5)
Arbitrum Delayed Inbox addresses are managed per destination chainId via setArbitrumInbox(chainId, inbox) (DEFAULT_ADMIN_ROLE) - setting the inbox to address(0) removes the entry. Registered inboxes are readable via the public arbitrumInboxes(chainId) mapping. Admin changes emit ArbitrumInboxChanged(chainId, previousInbox, newInbox, executedBy).
Unlike Rail 1's chain registry, there is no on-chain enumeration of registered chain IDs - the API and UI already know the supported pair list, mirroring the minimal design of Rail 1's registry.
Upgradeability
_authorizeUpgrade is restricted to DEFAULT_ADMIN_ROLE. The reinitializer(2) slot is reserved for the first post-launch state migration and must not be used for no-op upgrades.
Emergency recovery
Admin-only functions recoverETH, recoverERC20, and recoverERC721 allow retrieving assets stuck in the EntryPoint.