Files
proxmox/docs/07-ccip/CCIP_BRIDGE_MAINNET_CONNECTION.md
defiQUG bea1903ac9
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
Sync all local changes: docs, config, scripts, submodule refs, verification evidence
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-21 15:46:06 -08:00

5.6 KiB
Raw Permalink Blame History

CCIP Bridge ↔ Ethereum Mainnet Connection

Last Updated: 2026-02-12
Status: Active


Overview

Chain 138 does not use Chainlinks public CCIP network (custom chain). Cross-chain sends from Chain 138 to Ethereum mainnet use:

  1. Chain 138: Custom router + WETH9 bridge (emits MessageSent).
  2. Mainnet: Deployed CCIPRelayRouter and CCIPRelayBridge that accept relayed messages.
  3. Relay service: Off-chain process that watches Chain 138 for MessageSent and calls mainnet relay router to deliver.

Mainnet Contracts (Ethereum)

Contract Address Role
CCIPRelayRouter 0xAd9A228CcEB4cbB612cD165FFB72fE090ff10Afb Receives relayed messages; calls bridge ccipReceive. Relayer must have RELAYER_ROLE.
CCIPRelayBridge 0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939 Holds WETH; releases to recipient when relay router calls ccipReceive. Must be funded with WETH for payouts. WETH9-only — no other tokens accepted.
WETH9 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 Canonical mainnet WETH.

Token mapping: Chain 138 → Mainnet address mapping and which tokens the relay bridge supports are in TOKEN_MAPPING_AND_MAINNET_ADDRESSES.md. Source of truth: config/token-mapping.json.


Chain 138 Setup

Role Address Notes
Router (LINK fee) 0x42DAb7b888Dd382bD5Adcf9E038dBF1fD03b4817 Emits MessageSent; relay service listens here.
Bridge (LINK fee) 0xcacfd227A040002e49e2e01626363071324f820a Pay fee in Chain 138 LINK. Default in CCIPWETH9_BRIDGE_CHAIN138.
Bridge (native ETH fee) 0x63cbeE010D64ab7F1760ad84482D6cC380435ab5 Pay fee in native ETH.

Both bridges have mainnet destination set to CCIPRelayBridge (0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939), so all 138→mainnet sends are delivered via the relay.


End-to-End Flow

  1. User on Chain 138 calls bridge sendCrossChain(mainnetSelector, recipient, amount) (e.g. via scripts/bridge/run-send-cross-chain.sh).
  2. Bridge pulls WETH from user, calls router ccipSend(...) with receiver = abi.encode(CCIPRelayBridge).
  3. Router emits MessageSent (no Chainlink relayer).
  4. Relay service (Node) watches the Chain 138 router for MessageSent, builds Any2EVMMessage, and calls mainnet CCIPRelayRouter.relayMessage(CCIPRelayBridge, message).
  5. Relay router calls CCIPRelayBridge.ccipReceive(message); bridge transfers WETH to recipient on mainnet.

Running the Relay Service

  1. Fund mainnet CCIPRelayBridge with WETH so it can pay recipients:

    # Option A: Script (transfers deployer's full WETH balance by default)
    ./scripts/bridge/fund-mainnet-relay-bridge.sh
    # Option B: Specific amount (wei)
    ./scripts/bridge/fund-mainnet-relay-bridge.sh 1000000000000000000
    
    # Or manually:
    cast send 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
      "transfer(address,uint256)" \
      0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939 \
      <amount_wei> \
      --rpc-url $ETHEREUM_MAINNET_RPC --private-key $PRIVATE_KEY --legacy
    

    If the default RPC rate-limits (429), set ETHEREUM_MAINNET_RPC to Infura or Alchemy in smom-dbis-138/.env.

  2. Grant relayer role (if not already): The relay tx will revert with "transaction execution reverted" (no revert data) until the relayer address has RELAYER_ROLE on the mainnet router. As the router's admin (deployer), run:

    ./scripts/bridge/grant-relayer-role-mainnet.sh
    

    Or manually: cast send 0xAd9A228CcEB4cbB612cD165FFB72fE090ff10Afb "grantRelayerRole(address)" 0x4A666F96fC8764181194447A7dFdb7d471b301C8 --rpc-url $ETHEREUM_MAINNET_RPC --private-key $PRIVATE_KEY --legacy

  3. Start the relay service:

    cd smom-dbis-138/services/relay
    # .env: RPC_URL_138, RPC_URL_MAINNET or ETHEREUM_MAINNET_RPC (Infura/Alchemy recommended to avoid 429), PRIVATE_KEY (relayer), CCIP_RELAY_*
    npm start
    

    For mainnet RPC, set RPC_URL_MAINNET in services/relay/.env or ETHEREUM_MAINNET_RPC in smom-dbis-138/.env. Prefer Infura (https://mainnet.infura.io/v3/<PROJECT_ID>) or Alchemy; see RPC_ENDPOINTS_MASTER.md.

Config defaults in services/relay/src/config.js point to the router and bridges above; override with env vars if needed.

If relay tx reverts with "transaction execution reverted"

  1. Relayer role: Ensure the relayer has RELAYER_ROLE: run ./scripts/bridge/grant-relayer-role-mainnet.sh (use RPC_URL_MAINNET=https://ethereum.publicnode.com if Infura returns 403).
  2. Bridge WETH: The mainnet CCIPRelayBridge must hold at least the amount being relayed. If the bridge balance is lower than the transfer amount, fund it:
    RPC_URL_MAINNET=https://ethereum.publicnode.com ./scripts/bridge/fund-mainnet-relay-bridge.sh 1000000000000000
    
    (1e15 wei = 0.001 WETH.)

References