#!/usr/bin/env bash # End-to-end dry-run for Ethereum Mainnet deployment # Validates compilation, parameters, and deployment order without actually deploying set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../lib/init.sh" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" log_info "=== Ethereum Mainnet Deployment Dry-Run ===" # Load environment variables if [ -f "$PROJECT_ROOT/.env" ]; then source "$PROJECT_ROOT/.env" else log_error "Error: .env file not found" exit 1 fi ERRORS=0 WARNINGS=0 # Disable exit on error for arithmetic operations set +e # Function to check if command exists check_command() { if ! command -v "$1" &> /dev/null; then log_error "❌ $1 not found" ((ERRORS++)) return 1 else log_success "✅ $1 found" return 0 fi } # Function to validate address validate_address() { local addr=$1 local name=$2 if [[ ! "$addr" =~ ^0x[0-9a-fA-F]{40}$ ]]; then log_error "❌ Invalid $name address: $addr" ((ERRORS++)) return 1 else log_success "✅ $name address valid: $addr" return 0 fi } # Step 1: Check required tools log_info "Step 1: Checking required tools..." check_command "forge" check_command "cast" check_command "node" check_command "npm" # Step 2: Validate environment variables log_info "Step 2: Validating environment variables..." # Required variables REQUIRED_VARS=("PRIVATE_KEY" "ETHEREUM_MAINNET_RPC") for var in "${REQUIRED_VARS[@]}"; do if [ -z "${!var}" ]; then log_error "❌ Missing required variable: $var" ((ERRORS++)) else log_success "✅ $var is set" fi done # Optional but recommended if [ -z "$CCIP_ETH_ROUTER" ]; then CCIP_ETH_ROUTER="0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D" log_warn "⚠️ CCIP_ETH_ROUTER not set, using default: $CCIP_ETH_ROUTER" ((WARNINGS++)) else validate_address "$CCIP_ETH_ROUTER" "CCIP_ETH_ROUTER" fi if [ -z "$CCIP_FEE_TOKEN" ]; then CCIP_FEE_TOKEN="0x514910771AF9Ca656af840dff83E8264EcF986CA" # LINK token log_warn "⚠️ CCIP_FEE_TOKEN not set, using default: $CCIP_FEE_TOKEN" ((WARNINGS++)) else validate_address "$CCIP_FEE_TOKEN" "CCIP_FEE_TOKEN" fi # Validate private key format if [[ ! "$PRIVATE_KEY" =~ ^0x[0-9a-fA-F]{64}$ ]] && [[ ! "$PRIVATE_KEY" =~ ^[0-9a-fA-F]{64}$ ]]; then log_error "❌ Invalid PRIVATE_KEY format" ((ERRORS++)) else log_success "✅ PRIVATE_KEY format valid" fi # Step 3: Validate contract addresses log_info "Step 3: Validating contract addresses..." WETH9_ADDRESS="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" WETH10_ADDRESS="0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F" validate_address "$WETH9_ADDRESS" "WETH9" validate_address "$WETH10_ADDRESS" "WETH10" # Step 4: Compile contracts log_info "Step 4: Compiling contracts..." cd "$PROJECT_ROOT" # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 source "$SCRIPT_DIR/../lib/deployment/dotenv.sh" load_deployment_env --repo-root "${PROJECT_ROOT:-$REPO_ROOT}" elif [[ -n "${PROJECT_ROOT:-}" && -f "$PROJECT_ROOT/.env" ]]; then set -a # shellcheck disable=SC1090 source "$PROJECT_ROOT/.env" set +a elif [[ -n "${REPO_ROOT:-}" && -f "$REPO_ROOT/.env" ]]; then set -a # shellcheck disable=SC1090 source "$REPO_ROOT/.env" set +a fi echo "Compiling CCIPWETH9Bridge..." if forge build --contracts contracts/ccip/CCIPWETH9Bridge.sol 2>&1 | grep -q "Compiler run successful\|No files changed"; then log_success "✅ CCIPWETH9Bridge compiled" else log_error "❌ CCIPWETH9Bridge compilation failed" ((ERRORS++)) fi echo "Compiling CCIPWETH10Bridge..." if forge build --contracts contracts/ccip/CCIPWETH10Bridge.sol 2>&1 | grep -q "Compiler run successful\|No files changed"; then log_success "✅ CCIPWETH10Bridge compiled" else log_error "❌ CCIPWETH10Bridge compilation failed" ((ERRORS++)) fi echo "Checking CCIPLogger..." if [ -d "node_modules/@chainlink/contracts-ccip" ]; then log_success "✅ Chainlink contracts installed" if [ -f "contracts/ccip-integration/CCIPLogger.sol" ]; then log_success "✅ CCIPLogger contract exists" else log_error "❌ CCIPLogger contract not found" ((ERRORS++)) fi else log_warn "⚠️ @chainlink/contracts-ccip not installed, skipping CCIPLogger check" log_warn " Run: npm install" ((WARNINGS++)) fi # Step 5: Validate deployment scripts log_info "Step 5: Validating deployment scripts..." echo "Checking DeployCCIPWETH9Bridge.s.sol..." if [ -f "script/DeployCCIPWETH9Bridge.s.sol" ]; then log_success "✅ DeployCCIPWETH9Bridge.s.sol exists" else log_error "❌ DeployCCIPWETH9Bridge.s.sol not found" ((ERRORS++)) fi echo "Checking DeployCCIPWETH10Bridge.s.sol..." if [ -f "script/DeployCCIPWETH10Bridge.s.sol" ]; then log_success "✅ DeployCCIPWETH10Bridge.s.sol exists" else log_error "❌ DeployCCIPWETH10Bridge.s.sol not found" ((ERRORS++)) fi echo "Checking deploy-ccip-logger.js..." if [ -f "scripts/ccip-deployment/deploy-ccip-logger.js" ]; then log_success "✅ deploy-ccip-logger.js exists" else log_error "❌ deploy-ccip-logger.js not found" ((ERRORS++)) fi # Step 6: Test RPC connection log_info "Step 6: Testing RPC connection..." if [ -n "$ETHEREUM_MAINNET_RPC" ]; then CHAIN_ID=$(cast chain-id --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null || echo "") if [ "$CHAIN_ID" == "1" ]; then log_success "✅ RPC connected to Ethereum Mainnet (Chain ID: 1)" elif [ -n "$CHAIN_ID" ]; then log_error "❌ RPC connected to wrong chain (Chain ID: $CHAIN_ID, expected: 1)" ((ERRORS++)) else log_warn "⚠️ Could not verify RPC connection" ((WARNINGS++)) fi else log_error "❌ ETHEREUM_MAINNET_RPC not set" ((ERRORS++)) fi # Step 7: Validate deployment order log_info "Step 7: Validating deployment order..." echo " 1. CCIPLogger (no dependencies on new contracts)" echo " 2. CCIPWETH9Bridge (depends on CCIP Router)" echo " 3. CCIPWETH10Bridge (depends on CCIP Router)" log_success "✅ Deployment order is correct" # Step 8: Estimate gas costs log_info "Step 8: Estimating gas costs..." if [ -f "$SCRIPT_DIR/calculate-conservative-costs.sh" ]; then echo "Running gas cost estimation..." "$SCRIPT_DIR/calculate-conservative-costs.sh" 2>&1 | tail -10 else log_warn "⚠️ Gas cost estimation script not found" ((WARNINGS++)) fi # Re-enable exit on error set -e # Summary log_info "=== Dry-Run Summary ===" if [ "$ERRORS" -eq 0 ]; then log_success "✅ All checks passed!" if [ "$WARNINGS" -gt 0 ]; then log_warn "⚠️ $WARNINGS warning(s)" fi log_success "Ready for deployment!" exit 0 else log_error "❌ $ERRORS error(s) found" if [ "$WARNINGS" -gt 0 ]; then log_warn "⚠️ $WARNINGS warning(s)" fi log_error "Please fix errors before deploying" exit 1 fi