# 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 1. **Copy environment template**: ```bash cp .env.example .env ``` 2. **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 3. **Verify Foundry installation**: ```bash forge --version # Should be >= 0.2.0 ``` 4. **Install dependencies** (if using Hardhat for CCIPLogger): ```bash npm install npm install @openzeppelin/contracts@5.0.2 npm install @chainlink/contracts-ccip ``` ### 2. Verify Configuration Check that all environment variables are set: ```bash # 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: ```bash # 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: ```bash # 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](./GAS_AND_TOKEN_REQUIREMENTS.md) 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**: ```bash # 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**: ```bash # If deployed via Foundry, verification is automatic with --verify flag # If deployed via Hardhat: npx hardhat verify --network mainnet \ \ "$CCIP_ETH_ROUTER" \ "$AUTHORIZED_SIGNER" \ "$CHAIN138_SELECTOR" ``` --- ### Cronos (Chain ID 25) **Deploy all contracts**: ```bash 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): ```bash # WETH9 forge verify-contract \ --chain-id 25 \ --num-of-optimizations 200 \ --watch \ \ contracts/tokens/WETH.sol:WETH \ $CRONOSCAN_API_KEY # WETH10 forge verify-contract \ --chain-id 25 \ --num-of-optimizations 200 \ --watch \ \ contracts/tokens/WETH10.sol:WETH10 \ $CRONOSCAN_API_KEY # CCIPWETH9Bridge forge verify-contract \ --chain-id 25 \ --num-of-optimizations 200 \ --watch \ \ 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 \ \ 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**: ```bash 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): ```bash # Similar to Cronos, but use BSCSCAN_API_KEY forge verify-contract \ --chain-id 56 \ --num-of-optimizations 200 \ --watch \ \ : \ $BSCSCAN_API_KEY \ --constructor-args ``` --- ### Polygon PoS (Chain ID 137) **Deploy all contracts**: ```bash 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): ```bash # Use POLYGONSCAN_API_KEY forge verify-contract \ --chain-id 137 \ --num-of-optimizations 200 \ --watch \ \ : \ $POLYGONSCAN_API_KEY \ --constructor-args ``` **Note**: Polygon CCIP Router is available at `0x3C3D92629A02a8D95D5CB9650fe49C3544f69B43` --- ### Gnosis Chain (Chain ID 100) **Deploy all contracts**: ```bash 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): ```bash # Use GNOSISSCAN_API_KEY forge verify-contract \ --chain-id 100 \ --num-of-optimizations 200 \ --watch \ \ : \ $GNOSISSCAN_API_KEY \ --constructor-args ``` --- ## Post-Deployment Steps ### 1. Save Deployment Addresses After each deployment, save the addresses to your `.env` file: ```bash # Example for Cronos echo "WETH9_CRONOS=" >> .env echo "WETH10_CRONOS=" >> .env echo "CCIPWETH9BRIDGE_CRONOS=" >> .env echo "CCIPWETH10BRIDGE_CRONOS=" >> .env echo "CCIPLOGGER_CRONOS=" >> .env ``` ### 2. Verify All Contracts Verify all contracts on their respective explorers: - [Etherscan](https://etherscan.io) (Mainnet) - [Cronoscan](https://cronoscan.com) (Cronos) - [BscScan](https://bscscan.com) (BSC) - [Polygonscan](https://polygonscan.com) (Polygon) - [Gnosisscan](https://gnosisscan.io) (Gnosis) ### 3. Configure Bridge Destinations For each bridge contract, configure destination chains: ```bash # Example: Configure WETH9 Bridge on Cronos to send to Mainnet cast send \ "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: ```bash # Example: Send WETH9 from Cronos to Mainnet cast send \ "approve(address,uint256)" \ \ 1000000000000000000 \ --rpc-url cronos \ --private-key $PRIVATE_KEY cast send \ "sendCrossChain(uint64,address,uint256)" \ $ETH_MAINNET_SELECTOR \ \ 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](./GAS_AND_TOKEN_REQUIREMENTS.md) ### 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 ```bash # 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 1. **Check compiler settings match**: ```bash # Verify optimizer settings grep optimizer foundry.toml grep optimizer_runs foundry.toml ``` 2. **Verify constructor arguments**: ```bash # Encode constructor args manually cast abi-encode "constructor(address,address,address)" \ $ROUTER $WETH $LINK ``` 3. **Use explicit verification**: ```bash forge verify-contract \ --chain-id \ --num-of-optimizations 200 \ --watch \
\ : \ \ --constructor-args ``` ### CCIPLogger Deployment Issues If CCIPLogger fails to deploy via Foundry: 1. Use Hardhat script instead: `npm run deploy:logger:mainnet` 2. Ensure OpenZeppelin v5.0.2+ is installed 3. 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 --- ## References - [Foundry Documentation](https://book.getfoundry.sh/) - [Chainlink CCIP Documentation](https://docs.chain.link/ccip) - [Etherscan API](https://docs.etherscan.io/) - [Multichain Deployment Script](../script/DeployAll.s.sol) - [CCIPLogger Deployment Script](../script/DeployCCIPLoggerOnly.s.sol)