Technical Reference
SkyBridge V2 is built on two contracts per chain: a SkyBridgeEntryPoint (UUPS proxy) that users interact with, and a shared Diamond (EIP-2535 proxy) that holds the bridge logic across 12 facets.
Two-contract stack
User
└─► SkyBridgeEntryPoint (UUPS proxy, per-chain)
├─► L1StandardBridge Rail 1 - OP Standard
├─► Diamond/BridgeFacet Rail 3 - Chainlink CCIP
└─► TokenMessengerV2 Rail 4 - Circle CCTP
The EntryPoint is the only contract users call. It collects a flat native-currency fee, validates parameters, and forwards to the appropriate downstream. The Diamond is infrastructure-only: every bridge function on the Diamond is gated by onlyEntryPoint.
Diamond architecture (EIP-2535)
The Diamond proxy (0x14fbb1eD5BC098B4Ea236dcE0941EDB02e967b44, same on all 11 chains) delegates calls to 12 facets by function selector - 65 selectors total. Facets are added, replaced, or removed via a two-step propose → finalize flow:
PROPOSER_ROLEcallsdiamondCut(...)→ proposal queued with an ID and a 7-day TTL.MULTISIG_ROLEcallsfinalizeUpgrade(id)→ change applied.
MULTISIG_ROLE can also reject or bulk-reject proposals before they are finalized. A finalized proposal cannot be re-executed (replay guard).
Storage convention
All Diamond storage uses namespaced keccak256 positions to avoid slot collisions between facets:
| Namespace | Slot constant |
|---|---|
| Bridge (ERC-20) | keccak256("diamond.bridge.storage") |
| CCIP | keccak256("diamond.ccip.storage") |
| Withdrawal timelock | keccak256("skybridge.withdrawal.timelock.storage") |
| Receiver selector whitelist | keccak256("skybridge.receiver.whitelist.storage") |
| Access control | keccak256("openzeppelin.accesscontrol.storage") |
In this section
- EntryPoint - UUPS proxy, fee model, rail routing, admin functions
- Diamond & Facets - all 12 facets, their purposes and key functions
- Token Model - SkyToken and SkyNFT: CREATE3 deployment, ownership, CCIP admin
- Roles - Diamond roles (6) and EntryPoint roles (3); fee custody model