- Resolve stash: merge load_deployment_env path with secure-secrets and CR/LF RPC strip - create-pmm-full-mesh-chain138.sh delegates to sync-chain138-pmm-pools-from-json.sh - env.additions.example: canonical PMM pool defaults (cUSDT/USDT per crosscheck) - Include Chain138 scripts, official mirror deploy scaffolding, and prior staged changes Made-with: Cursor
125 lines
5.9 KiB
Markdown
125 lines
5.9 KiB
Markdown
# CCIP Relay Service
|
||
|
||
Off-chain relay for forwarding Chain 138 `MessageSent` events to destination relay routers/bridges.
|
||
|
||
## Current Topology
|
||
|
||
Source (Chain 138) — match `.env.bsc` / operator deploy:
|
||
- Router: `0x42DAb7b888Dd382bD5Adcf9E038dBF1fD03b4817`
|
||
- WETH9 bridge: `0xcacfd227A040002e49e2e01626363071324f820a`
|
||
|
||
Destinations:
|
||
- BSC relay router: `0x4d9Bc6c74ba65E37c4139F0aEC9fc5Ddff28Dcc4`
|
||
- BSC relay bridge: `0x886C6A4ABC064dbf74E7caEc460b7eeC31F1b78C`
|
||
- AVAX relay router: `0x2a0023Ad5ce1Ac6072B454575996DfFb1BB11b16`
|
||
- AVAX relay bridge: `0x3f8C409C6072a2B6a4Ff17071927bA70F80c725F`
|
||
|
||
## Env Profiles
|
||
|
||
Use the prebuilt env files in this folder:
|
||
- `.env.bsc` (template: `.env.bsc.example`)
|
||
- `.env.avax`
|
||
- `.env` (default/fallback)
|
||
|
||
Each profile sets destination RPC, selector, relay router/bridge, and destination WETH token.
|
||
|
||
### `START_BLOCK` after catch-up
|
||
|
||
When historical `MessageSent` logs are fully relayed, set **`START_BLOCK=latest`** in `.env.bsc` (or your profile) so a cold start only scans from **~current head − 1** instead of re-queuing the whole backfill range. To replay from an old height again, set an explicit decimal block (e.g. `3012930`) and restart.
|
||
|
||
**BSC RPC:** Prefer a node that accepts short `eth_getLogs` windows (e.g. `https://bsc.publicnode.com`). Some Binance seeds return `-32005` for log queries the relay uses for destination checks.
|
||
|
||
### Fund BSC relay bridge (WETH)
|
||
|
||
From repo root (loads `smom-dbis-138/.env` and relay `.env.bsc` for addresses):
|
||
|
||
```bash
|
||
./scripts/bridge/fund-bsc-relay-bridge.sh --dry-run
|
||
./scripts/bridge/fund-bsc-relay-bridge.sh # full deployer WETH → bridge
|
||
# ./scripts/bridge/fund-bsc-relay-bridge.sh 1000000000000000 # 0.001 WETH wei
|
||
```
|
||
|
||
Wrap BNB to WETH on the deployer first (`cast send <WETH> "deposit()" --value ...` on BSC) if needed.
|
||
|
||
### Fund Mainnet relay bridge (WETH)
|
||
|
||
From repo root:
|
||
|
||
```bash
|
||
./scripts/bridge/fund-mainnet-relay-bridge.sh --dry-run
|
||
./scripts/bridge/fund-mainnet-relay-bridge.sh # full deployer WETH → bridge
|
||
# ./scripts/bridge/fund-mainnet-relay-bridge.sh 1000000000000000 # 0.001 WETH wei
|
||
```
|
||
|
||
## Relay shedding (save destination gas)
|
||
|
||
When **no** 138→Mainnet (or configured destination) relay deliveries are needed, pause **destination-chain** transactions so the relayer does not spend native gas on `relayMessage` / direct `ccipReceive`:
|
||
|
||
| Variable | Meaning |
|
||
|----------|---------|
|
||
| `RELAY_SHEDDING=1` | **On** — shedding active (`true` / `yes` / `on` also work). |
|
||
| `RELAY_DELIVERY_ENABLED=0` | Same as shedding on (`false` / `no` / `off`). |
|
||
| `RELAY_SHEDDING_SOURCE_POLL_INTERVAL_MS` | Source router log poll interval while shedding (default **60000** ms, min 5000). Reduces Chain 138 RPC usage. |
|
||
| `RELAY_SHEDDING_QUEUE_POLL_MS` | Idle interval for the queue loop while shedding (default **5000** ms, min 1000). |
|
||
|
||
**Behavior:** Source `MessageSent` logs are still ingested and messages **queue in memory**. When you set `RELAY_SHEDDING=0` (and `RELAY_DELIVERY_ENABLED=1`) and **restart** the service, pending messages are delivered as usual. For production, plan shedding around low bridge traffic so the queue stays small (in-memory queue is lost on process crash).
|
||
|
||
### On-chain pause (`CCIPRelayRouter`)
|
||
|
||
The destination **CCIPRelayRouter** inherits OpenZeppelin **`Pausable`**: admins with `DEFAULT_ADMIN_ROLE` may call **`pause()`** / **`unpause()`**. While paused, **`relayMessage` reverts** (no delivery through the router).
|
||
|
||
**Relay service:** Before sending `relayMessage`, the worker calls **`paused()`** on the destination router (router mode only). If paused, it **re-queues** the message and waits 15s instead of broadcasting a reverting tx. Older routers without `paused()` skip this check (call errors are logged at debug).
|
||
|
||
**Important:** If you `pause()` the router but leave the relay **process** running **without** `RELAY_SHEDDING=1`, failed txs are much less likely thanks to the check above, but off-chain activity (source polling, queue growth) still runs. Prefer **`RELAY_SHEDDING=1`** (or stop the service) whenever the router is paused for an extended period.
|
||
|
||
**Direct-delivery** mode (`DEST_DELIVERY_MODE=direct`) calls the bridge’s `ccipReceive` directly and **does not** go through the router—pause the router alone does not stop that path; use shedding or revoke `ROUTER_ROLE` on the bridge as appropriate.
|
||
|
||
## Start Relay
|
||
|
||
```bash
|
||
cd /home/intlc/projects/proxmox/smom-dbis-138/services/relay
|
||
npm install
|
||
|
||
# BSC relay profile
|
||
./start-relay.sh bsc
|
||
|
||
# AVAX relay profile
|
||
./start-relay.sh avax
|
||
|
||
# Default profile
|
||
./start-relay.sh
|
||
```
|
||
|
||
`start-relay.sh` loads env in this order:
|
||
1. `.env.<profile>` (if profile argument provided)
|
||
2. `.env.local`
|
||
3. `.env`
|
||
|
||
If parent project `.env` defines `PRIVATE_KEY`, `${PRIVATE_KEY}` references in relay env files are expanded.
|
||
|
||
## Critical Requirements
|
||
|
||
- Relayer key must hold native gas on destination chain.
|
||
- Destination relay bridge must hold enough WETH for payouts.
|
||
- Source bridge destination mapping must point to the correct destination relay bridge.
|
||
- Source router `feeToken()` must be a deployed ERC20 with sufficient deployer balance.
|
||
|
||
## Fast Status Checks
|
||
|
||
Check source destination mappings:
|
||
```bash
|
||
cast call 0xcacfd227A040002e49e2e01626363071324f820a "destinations(uint64)" 11344663589394136015 --rpc-url https://rpc.public-0138.defi-oracle.io
|
||
cast call 0xcacfd227A040002e49e2e01626363071324f820a "destinations(uint64)" 6433500567565415381 --rpc-url https://rpc.public-0138.defi-oracle.io
|
||
```
|
||
|
||
Check message settlement:
|
||
```bash
|
||
cast call 0x886C6A4ABC064dbf74E7caEc460b7eeC31F1b78C "processedTransfers(bytes32)(bool)" <bsc_message_id> --rpc-url https://bsc.publicnode.com
|
||
cast call 0x3f8C409C6072a2B6a4Ff17071927bA70F80c725F "processedTransfers(bytes32)(bool)" <avax_message_id> --rpc-url https://avalanche-c-chain.publicnode.com
|
||
```
|
||
|
||
Check destination bridge liquidity:
|
||
```bash
|
||
cast call <dest_weth> "balanceOf(address)(uint256)" <dest_relay_bridge> --rpc-url <dest_rpc>
|
||
```
|