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

105 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](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:
```bash
# 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:
```bash
./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:**
```bash
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](../04-configuration/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:
```bash
RPC_URL_MAINNET=https://ethereum.publicnode.com ./scripts/bridge/fund-mainnet-relay-bridge.sh 1000000000000000
```
(1e15 wei = 0.001 WETH.)
---
## References
- [TOKEN_MAPPING_AND_MAINNET_ADDRESSES.md](TOKEN_MAPPING_AND_MAINNET_ADDRESSES.md) — Full token mapping (138↔Mainnet), relay-supported tokens, and recommendations.
- [SEND_ETH_TO_MAINNET_REVERT_TRACE.md](SEND_ETH_TO_MAINNET_REVERT_TRACE.md) — Revert history and deployed LINK/native-ETH bridges.
- [scripts/README.md §8](../../scripts/README.md) — Send command and env.
- [services/relay/README.md](../../smom-dbis-138/services/relay/README.md) — Relay service deployment and config.
- [CONTRACT_ADDRESSES_REFERENCE.md](../11-references/CONTRACT_ADDRESSES_REFERENCE.md) — Chain 138 addresses.