- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
12 KiB
Multichain Deployment Runbook
Last Updated: 2025-01-27 Purpose: Comprehensive guide for deploying smart contracts to multiple chains using Foundry
Overview
This runbook covers deployment of the complete contract suite to:
- Ethereum Mainnet (chainId 1): Only CCIPLogger (other contracts already deployed)
- Cronos (chainId 25): All contracts
- BSC (chainId 56): All contracts
- Polygon PoS (chainId 137): All contracts
- Gnosis Chain (chainId 100): All contracts
Prerequisites
1. Environment Setup
-
Copy environment template:
cp .env.example .env -
Fill in all required variables in
.env:PRIVATE_KEY: Your deployer private key- RPC URLs for all chains
- Explorer API keys for verification
- CCIP router addresses per chain
- LINK token addresses per chain
-
Verify Foundry installation:
forge --version # Should be >= 0.2.0 -
Install dependencies (if using Hardhat for CCIPLogger):
npm install npm install @openzeppelin/contracts@5.0.2 npm install @chainlink/contracts-ccip
2. Verify Configuration
Check that all environment variables are set:
# Check mainnet config
echo $ETH_MAINNET_RPC_URL
echo $CCIP_ETH_ROUTER
echo $CCIP_ETH_LINK_TOKEN
# Check other chains
echo $CRONOS_RPC_URL
echo $BSC_RPC_URL
echo $POLYGON_RPC_URL
echo $GNOSIS_RPC_URL
3. Get Real-Time Gas Prices
Before checking balances, fetch real-time gas prices:
# Fetch real-time gas prices for all chains
./scripts/deployment/get-multichain-gas-prices.sh
# Update documentation with real-time prices
./scripts/deployment/update-gas-estimates.sh
This will:
- Fetch current gas prices from configured APIs
- Calculate deployment costs for all chains
- Update documentation with real-time estimates
- Show you exactly how much you need
4. Verify Wallet Balance
Ensure your deployer wallet has sufficient native tokens for gas:
# Check balances (adjust RPC URLs as needed)
cast balance $DEPLOYER_ADDRESS --rpc-url $ETH_MAINNET_RPC_URL
cast balance $DEPLOYER_ADDRESS --rpc-url $CRONOS_RPC_URL
cast balance $DEPLOYER_ADDRESS --rpc-url $BSC_RPC_URL
cast balance $DEPLOYER_ADDRESS --rpc-url $POLYGON_RPC_URL
cast balance $DEPLOYER_ADDRESS --rpc-url $GNOSIS_RPC_URL
Recommended minimum balances (see Gas and Token Requirements for details):
- Ethereum Mainnet: 0.20 ETH (for CCIPLogger deployment)
- Cronos: 15 CRO (for all 5 contracts)
- BSC: 0.06 BNB (for all 5 contracts)
- Polygon: 1.0 MATIC (for all 5 contracts)
- Gnosis: 0.05 xDAI (for all 5 contracts)
Total Estimated Cost: ~$520 USD (with buffers)
Deployment Commands
Ethereum Mainnet - CCIPLogger Only
Status: WETH9, WETH10, CCIPWETH9Bridge, CCIPWETH10Bridge are already deployed.
Deploy CCIPLogger:
# Option 1: Using Foundry (if CCIPLogger is compatible)
forge script script/DeployCCIPLoggerOnly.s.sol:DeployCCIPLoggerOnly \
--rpc-url mainnet \
--chain-id 1 \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
-vvvv
# Option 2: Using Hardhat (recommended for CCIPLogger)
npm install @openzeppelin/contracts@5.0.2
npx hardhat run scripts/ccip-deployment/deploy-ccip-logger.js --network mainnet
Verify CCIPLogger:
# If deployed via Foundry, verification is automatic with --verify flag
# If deployed via Hardhat:
npx hardhat verify --network mainnet \
<CCIPLOGGER_ADDRESS> \
"$CCIP_ETH_ROUTER" \
"$AUTHORIZED_SIGNER" \
"$CHAIN138_SELECTOR"
Cronos (Chain ID 25)
Deploy all contracts:
forge script script/DeployAll.s.sol:DeployAll \
--rpc-url cronos \
--chain-id 25 \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
-vvvv
Verify contracts (if automatic verification fails):
# WETH9
forge verify-contract \
--chain-id 25 \
--num-of-optimizations 200 \
--watch \
<WETH9_ADDRESS> \
contracts/tokens/WETH.sol:WETH \
$CRONOSCAN_API_KEY
# WETH10
forge verify-contract \
--chain-id 25 \
--num-of-optimizations 200 \
--watch \
<WETH10_ADDRESS> \
contracts/tokens/WETH10.sol:WETH10 \
$CRONOSCAN_API_KEY
# CCIPWETH9Bridge
forge verify-contract \
--chain-id 25 \
--num-of-optimizations 200 \
--watch \
<BRIDGE_ADDRESS> \
contracts/ccip/CCIPWETH9Bridge.sol:CCIPWETH9Bridge \
$CRONOSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(address,address,address)" $CCIP_CRONOS_ROUTER $WETH9_ADDRESS $CCIP_CRONOS_LINK_TOKEN)
# CCIPWETH10Bridge
forge verify-contract \
--chain-id 25 \
--num-of-optimizations 200 \
--watch \
<BRIDGE_ADDRESS> \
contracts/ccip/CCIPWETH10Bridge.sol:CCIPWETH10Bridge \
$CRONOSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(address,address,address)" $CCIP_CRONOS_ROUTER $WETH10_ADDRESS $CCIP_CRONOS_LINK_TOKEN)
BSC (Chain ID 56)
Deploy all contracts:
forge script script/DeployAll.s.sol:DeployAll \
--rpc-url bsc \
--chain-id 56 \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
-vvvv
Verify contracts (if automatic verification fails):
# Similar to Cronos, but use BSCSCAN_API_KEY
forge verify-contract \
--chain-id 56 \
--num-of-optimizations 200 \
--watch \
<CONTRACT_ADDRESS> \
<CONTRACT_PATH>:<CONTRACT_NAME> \
$BSCSCAN_API_KEY \
--constructor-args <ENCODED_ARGS>
Polygon PoS (Chain ID 137)
Deploy all contracts:
forge script script/DeployAll.s.sol:DeployAll \
--rpc-url polygon \
--chain-id 137 \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
-vvvv
Verify contracts (if automatic verification fails):
# Use POLYGONSCAN_API_KEY
forge verify-contract \
--chain-id 137 \
--num-of-optimizations 200 \
--watch \
<CONTRACT_ADDRESS> \
<CONTRACT_PATH>:<CONTRACT_NAME> \
$POLYGONSCAN_API_KEY \
--constructor-args <ENCODED_ARGS>
Note: Polygon CCIP Router is available at 0x3C3D92629A02a8D95D5CB9650fe49C3544f69B43
Gnosis Chain (Chain ID 100)
Deploy all contracts:
forge script script/DeployAll.s.sol:DeployAll \
--rpc-url gnosis \
--chain-id 100 \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
-vvvv
Verify contracts (if automatic verification fails):
# Use GNOSISSCAN_API_KEY
forge verify-contract \
--chain-id 100 \
--num-of-optimizations 200 \
--watch \
<CONTRACT_ADDRESS> \
<CONTRACT_PATH>:<CONTRACT_NAME> \
$GNOSISSCAN_API_KEY \
--constructor-args <ENCODED_ARGS>
Post-Deployment Steps
1. Save Deployment Addresses
After each deployment, save the addresses to your .env file:
# Example for Cronos
echo "WETH9_CRONOS=<deployed_address>" >> .env
echo "WETH10_CRONOS=<deployed_address>" >> .env
echo "CCIPWETH9BRIDGE_CRONOS=<deployed_address>" >> .env
echo "CCIPWETH10BRIDGE_CRONOS=<deployed_address>" >> .env
echo "CCIPLOGGER_CRONOS=<deployed_address>" >> .env
2. Verify All Contracts
Verify all contracts on their respective explorers:
- Etherscan (Mainnet)
- Cronoscan (Cronos)
- BscScan (BSC)
- Polygonscan (Polygon)
- Gnosisscan (Gnosis)
3. Configure Bridge Destinations
For each bridge contract, configure destination chains:
# Example: Configure WETH9 Bridge on Cronos to send to Mainnet
cast send <CCIPWETH9BRIDGE_CRONOS> \
"addDestination(uint64,address)" \
$ETH_MAINNET_SELECTOR \
$CCIPWETH9BRIDGE_MAINNET \
--rpc-url cronos \
--private-key $PRIVATE_KEY
4. Test Cross-Chain Transfers
Test a small cross-chain transfer to verify everything works:
# Example: Send WETH9 from Cronos to Mainnet
cast send <WETH9_CRONOS> \
"approve(address,uint256)" \
<CCIPWETH9BRIDGE_CRONOS> \
1000000000000000000 \
--rpc-url cronos \
--private-key $PRIVATE_KEY
cast send <CCIPWETH9BRIDGE_CRONOS> \
"sendCrossChain(uint64,address,uint256)" \
$ETH_MAINNET_SELECTOR \
<RECIPIENT_ADDRESS> \
1000000000000000000 \
--rpc-url cronos \
--private-key $PRIVATE_KEY
Gas and Token Requirements
📊 For detailed gas cost breakdowns and token requirements, see: Gas and Token Requirements
Quick Reference: Minimum Balances
| Chain | Token | Minimum | Recommended |
|---|---|---|---|
| Mainnet | ETH | 0.15 ETH | 0.20 ETH |
| Cronos | CRO | 8.76 CRO | 15 CRO |
| BSC | BNB | 0.044 BNB | 0.06 BNB |
| Polygon | MATIC | 0.44 MATIC | 1.0 MATIC |
| Gnosis | xDAI | 0.0175 xDAI | 0.05 xDAI |
Total Gas Requirements
- Ethereum Mainnet: 3,000,000 gas (CCIPLogger only)
- Other Chains: 8,760,000 gas (all 5 contracts: WETH9, WETH10, 2 Bridges, CCIPLogger)
Gas Price Strategies
Ethereum Mainnet
- Strategy: Use EIP-1559 (automatic)
- Max Fee: Check current gas prices
- Priority Fee: 2-5 gwei
Cronos
- Strategy: Fixed gas price
- Gas Price: ~500 gwei (very low)
- Note: Cronos uses CRO for gas
BSC
- Strategy: Fixed gas price
- Gas Price: ~3-5 gwei
- Note: BSC uses BNB for gas
Polygon
- Strategy: Fixed gas price
- Gas Price: ~30-100 gwei
- Note: Polygon uses MATIC for gas
Gnosis
- Strategy: Fixed gas price
- Gas Price: ~1 gwei
- Note: Gnosis uses xDAI for gas
Network-Specific Caveats
Cronos
- Finality: ~6 seconds
- CCIP Support: Verify CCIP router availability
- RPC: May have rate limits
BSC
- Finality: ~3 seconds
- CCIP Support: Verify CCIP router availability
- Gas: Very cheap, but watch for congestion
Polygon
- Finality: ~2 seconds
- CCIP Support: ✅ Available
- Router:
0x3C3D92629A02a8D95D5CB9650fe49C3544f69B43 - LINK Token:
0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39
Gnosis
- Finality: ~5 seconds
- CCIP Support: Verify CCIP router availability
- Gas: Very cheap
Troubleshooting
RPC Connection Issues
# Test RPC connectivity
cast block-number --rpc-url $ETH_MAINNET_RPC_URL
cast block-number --rpc-url $CRONOS_RPC_URL
cast block-number --rpc-url $BSC_RPC_URL
cast block-number --rpc-url $POLYGON_RPC_URL
cast block-number --rpc-url $GNOSIS_RPC_URL
Contract Verification Fails
-
Check compiler settings match:
# Verify optimizer settings grep optimizer foundry.toml grep optimizer_runs foundry.toml -
Verify constructor arguments:
# Encode constructor args manually cast abi-encode "constructor(address,address,address)" \ $ROUTER $WETH $LINK -
Use explicit verification:
forge verify-contract \ --chain-id <CHAIN_ID> \ --num-of-optimizations 200 \ --watch \ <ADDRESS> \ <CONTRACT_PATH>:<CONTRACT_NAME> \ <API_KEY> \ --constructor-args <ENCODED_ARGS>
CCIPLogger Deployment Issues
If CCIPLogger fails to deploy via Foundry:
- Use Hardhat script instead:
npm run deploy:logger:mainnet - Ensure OpenZeppelin v5.0.2+ is installed
- Check that CCIP contracts are available
Deployment Checklist
Pre-Deployment
- Environment variables configured
- Wallet balances sufficient
- RPC endpoints tested
- Contracts compile successfully
- Tests pass
Deployment
- Ethereum Mainnet: CCIPLogger deployed
- Cronos: All contracts deployed
- BSC: All contracts deployed
- Polygon: All contracts deployed
- Gnosis: All contracts deployed
Post-Deployment
- All contracts verified on explorers
- Deployment addresses saved to
.env - Bridge destinations configured
- Cross-chain transfers tested
- Monitoring set up
Support
For issues or questions:
- Check deployment logs
- Review contract documentation
- Verify configuration
- Check troubleshooting section above