Files
smom-dbis-138/services/relay/README.md
2026-03-02 12:14:09 -08:00

218 lines
7.5 KiB
Markdown

# CCIP Relay Service
Custom relay mechanism for delivering CCIP messages from Chain 138 to Ethereum Mainnet.
## Architecture
The relay system consists of:
1. **CCIPRelayRouter** (on Ethereum Mainnet): Receives relayed messages and forwards them to bridge contracts
2. **CCIPRelayBridge** (on Ethereum Mainnet): Receives messages from relay router and transfers tokens to recipients
3. **Relay Service** (off-chain): Monitors MessageSent events on Chain 138 and relays messages to Ethereum Mainnet
## Current Deployment
### Deployed Contracts (Ethereum Mainnet)
- **Relay Router**: `0xAd9A228CcEB4cbB612cD165FFB72fE090ff10Afb`
- **Relay Bridge**: `0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939`
- **WETH9**: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`
### Source Chain (Chain 138)
- **CCIP Router** (emits MessageSent): `0x42DAb7b888Dd382bD5Adcf9E038dBF1fD03b4817`
- **WETH9 Bridge** (LINK fee): `0xcacfd227A040002e49e2e01626363071324f820a`
- **WETH9 Bridge** (native ETH fee): `0x63cbeE010D64ab7F1760ad84482D6cC380435ab5`
- **WETH9**: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`
Both bridges have mainnet destination set to **CCIPRelayBridge** (`0xF9A32F37...`) so the relay service delivers to mainnet.
## Deployment
### 1. Deploy Relay Contracts on Ethereum Mainnet
```bash
cd /home/intlc/projects/proxmox/smom-dbis-138
# Set environment variables
export PRIVATE_KEY=0x...
export RPC_URL_MAINNET=https://mainnet.infura.io/v3/YOUR_PROJECT_ID # or Alchemy; avoid public RPC 429
export WETH9_MAINNET=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
export RELAYER_ADDRESS=0x... # Address that will run relay service
# Deploy
forge script script/DeployCCIPRelay.s.sol:DeployCCIPRelay \
--rpc-url $RPC_URL_MAINNET \
--broadcast \
--legacy \
--via-ir
```
### 2. Configure Environment
The service uses environment variables. Create `.env` file in `services/relay/`:
```bash
# Source Chain (Chain 138)
RPC_URL_138=https://rpc-core.d-bis.org
CCIP_ROUTER_CHAIN138=0x42DAb7b888Dd382bD5Adcf9E038dBF1fD03b4817
CCIPWETH9_BRIDGE_CHAIN138=0xcacfd227A040002e49e2e01626363071324f820a
# Destination Chain (Ethereum Mainnet) — use Infura/Alchemy to avoid 429 rate limits
RPC_URL_MAINNET=https://mainnet.infura.io/v3/YOUR_PROJECT_ID
# Or set ETHEREUM_MAINNET_RPC in smom-dbis-138/.env; relay uses RPC_URL_MAINNET first, then ETHEREUM_MAINNET_RPC
CCIP_RELAY_ROUTER_MAINNET=0xAd9A228CcEB4cbB612cD165FFB72fE090ff10Afb
CCIP_RELAY_BRIDGE_MAINNET=0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939
# Relayer Configuration
PRIVATE_KEY=0x... # Private key for relayer (needs ETH on mainnet for gas)
RELAYER_PRIVATE_KEY=${PRIVATE_KEY} # Alternative name
# Monitoring Configuration
START_BLOCK=latest # or specific block number (e.g., 242500)
POLL_INTERVAL=5000 # milliseconds
CONFIRMATION_BLOCKS=1
# Retry Configuration
MAX_RETRIES=3
RETRY_DELAY=5000 # milliseconds
# Chain Selectors
SOURCE_CHAIN_ID=138
DESTINATION_CHAIN_SELECTOR=5009297550715157269
```
**Important**: If `PRIVATE_KEY` contains variable expansion (e.g., `${PRIVATE_KEY}`), create a `.env.local` file with the expanded value to avoid issues with `dotenv`.
### 3. Install Dependencies
```bash
cd services/relay
npm install
```
### 4. Start Relay Service
```bash
# Start service
npm start
# Or use the wrapper script (recommended)
./start-relay.sh
```
## How It Works
1. **Event Monitoring**: The relay service monitors `MessageSent` events from the CCIP Router on Chain 138
2. **Message Queue**: Detected messages are added to a queue for processing
3. **Token Address Mapping**: Source chain token addresses are mapped to destination chain addresses
4. **Message Relay**: For each message:
- Constructs the `Any2EVMMessage` format with mapped token addresses
- Calls `relayMessage` on the Relay Router contract on Ethereum Mainnet
- Relay Router forwards to Relay Bridge
- Relay Bridge calls `ccipReceive` and transfers tokens to recipient
## Configuration
Key configuration options in `.env`:
- `RPC_URL_138`: RPC endpoint for Chain 138 (default: `http://192.168.11.250:8545`)
- `RPC_URL_MAINNET`: RPC endpoint for Ethereum Mainnet (relay also reads `ETHEREUM_MAINNET_RPC` from smom-dbis-138/.env). Prefer Infura `https://mainnet.infura.io/v3/<PROJECT_ID>` or Alchemy to avoid public RPC rate limits (429). Default fallback: `https://ethereum.publicnode.com`.
- `PRIVATE_KEY` or `RELAYER_PRIVATE_KEY`: Private key for relayer (needs ETH on mainnet for gas)
- `START_BLOCK`: Block number to start monitoring from (default: `latest` or specific block number)
- `POLL_INTERVAL`: How often to poll for new events in milliseconds (default: `5000`)
- `CONFIRMATION_BLOCKS`: Number of confirmations to wait before processing (default: `1`)
- `MAX_RETRIES`: Maximum retry attempts for failed relays (default: `3`)
- `RETRY_DELAY`: Delay between retries in milliseconds (default: `5000`)
## Critical Requirements
### Bridge Funding
**The relay bridge must be funded with WETH9 tokens before it can complete transfers.**
- Bridge Address: `0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939`
- WETH9 Address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`
- Current Status: Bridge must have sufficient WETH9 to cover all transfers
To check bridge balance:
```bash
cast call 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
"balanceOf(address)" \
0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939 \
--rpc-url $RPC_URL_MAINNET
```
To fund the bridge (if you have WETH9):
```bash
cast send 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
"transfer(address,uint256)" \
0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939 \
20000000000000000000000 \
--rpc-url $RPC_URL_MAINNET \
--private-key $PRIVATE_KEY
```
## Security Considerations
- **Relayer Role**: Only addresses with relayer role can call `relayMessage`
- **Bridge Authorization**: Only authorized bridges can receive messages
- **Replay Protection**: Messages are tracked by messageId to prevent duplicate processing
- **Access Control**: Admin can add/remove bridges and relayers
- **Token Address Mapping**: Source chain token addresses are mapped to destination chain addresses
## Monitoring
The service logs all activities. Check logs for:
- `relay-service.log`: Combined log output
- Console output: Real-time status
Monitor key metrics:
- Messages detected per hour
- Messages relayed successfully
- Failed relay attempts
- Bridge WETH9 balance
## Troubleshooting
### Service won't start
1. Check all environment variables are set correctly
2. Verify RPC endpoints are accessible
3. Ensure private key is valid and properly expanded (use `.env.local` if needed)
4. Check Node.js and npm are installed
### Messages not being relayed
1. Check relayer has ETH for gas on mainnet
2. Verify relay router and bridge addresses are correct
3. Ensure relayer address has RELAYER_ROLE
4. Check bridge is authorized in router
5. Verify bridge has sufficient WETH9 balance
### Relay transactions failing
1. **Most common**: Bridge has insufficient WETH9 tokens - fund the bridge
2. Check gas limit is sufficient (default: 1,000,000)
3. Verify message format is correct
4. Review error logs for specific revert reasons
5. Check transaction receipt for revert reason
### High gas costs
- Adjust gas limit in `RelayService.js` if needed
- Monitor gas prices and adjust timing if possible
- Consider message batching for future improvements
## Development
```bash
# Run in development mode with auto-reload
npm run dev
# Run tests (if available)
npm test
```
## Related Documentation
- [Architecture Documentation](../docs/relay/ARCHITECTURE.md)
- [Deployment Guide](DEPLOYMENT_GUIDE.md)
- [Investigation Report](../docs/relay/INVESTIGATION_REPORT.md)