#!/usr/bin/env bash # Dry run: Simulate bridging WETH9 from ChainID 138 to Ethereum Mainnet # This script checks everything without sending any transactions # Usage: ./dry-run-bridge-to-ethereum.sh [amount_in_eth] [private_key_or_address] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_dryrun() { echo -e "${CYAN}[DRY RUN]${NC} $1"; } # Load environment variables if .env exists if [ -f "$PROJECT_ROOT/.env" ]; then source "$PROJECT_ROOT/.env" elif [ -f "$PROJECT_ROOT/../.env" ]; then source "$PROJECT_ROOT/../.env" fi # Configuration RPC_URL="${RPC_URL_138:-http://192.168.11.250:8545}" WETH9_ADDRESS="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" WETH9_BRIDGE="0x971cD9D156f193df8051E48043C476e53ECd4693" ETHEREUM_MAINNET_SELECTOR="5009297550715157269" # Parse arguments AMOUNT="${1:-1.0}" PRIVATE_KEY_OR_ADDRESS="${2:-}" log_info "=========================================" log_info "DRY RUN: Bridge WETH9 to Ethereum Mainnet" log_info "=========================================" log_info "" log_info "This is a DRY RUN - no transactions will be sent" log_info "" # Determine if input is private key or address if [ -n "$PRIVATE_KEY_OR_ADDRESS" ]; then if echo "$PRIVATE_KEY_OR_ADDRESS" | grep -qE "^0x[0-9a-fA-F]{40}$"; then # It's an address DEPLOYER="$PRIVATE_KEY_OR_ADDRESS" log_info "Using provided address: $DEPLOYER" else # Try as private key DEPLOYER=$(cast wallet address --private-key "$PRIVATE_KEY_OR_ADDRESS" 2>/dev/null || echo "") if [ -z "$DEPLOYER" ]; then log_error "Invalid private key or address: $PRIVATE_KEY_OR_ADDRESS" exit 1 fi log_info "Using address from private key: $DEPLOYER" fi elif [ -n "${PRIVATE_KEY:-}" ]; then DEPLOYER=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null || echo "") if [ -z "$DEPLOYER" ]; then log_error "Failed to get address from PRIVATE_KEY in .env" exit 1 fi log_info "Using address from PRIVATE_KEY in .env: $DEPLOYER" else log_error "No address or private key provided" log_info "Usage: $0 [amount_in_eth] [private_key_or_address]" log_info "Or set PRIVATE_KEY in .env file" exit 1 fi log_info "" log_info "Configuration:" log_info " Amount to Bridge: $AMOUNT ETH" log_info " Source Address: $DEPLOYER" log_info " Destination: Ethereum Mainnet (Selector: $ETHEREUM_MAINNET_SELECTOR)" log_info " WETH9 Address: $WETH9_ADDRESS" log_info " Bridge Address: $WETH9_BRIDGE" log_info " RPC URL: $RPC_URL" log_info "" # Convert amount to wei AMOUNT_WEI=$(cast --to-wei "$AMOUNT" ether 2>/dev/null || echo "") if [ -z "$AMOUNT_WEI" ]; then log_error "Failed to convert amount to wei" exit 1 fi log_dryrun "=========================================" log_dryrun "Step 1: Check ETH Balance" log_dryrun "=========================================" ETH_BALANCE=$(cast balance "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") ETH_BALANCE_ETH=$(echo "scale=18; $ETH_BALANCE / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "Current ETH Balance: $ETH_BALANCE_ETH ETH ($ETH_BALANCE wei)" # Estimate gas costs (approximate) ESTIMATED_GAS_WRAP=50000 ESTIMATED_GAS_APPROVE=50000 ESTIMATED_GAS_BRIDGE=300000 GAS_PRICE=5000000000 # 5 gwei TOTAL_GAS_ESTIMATE=$((ESTIMATED_GAS_WRAP + ESTIMATED_GAS_APPROVE + ESTIMATED_GAS_BRIDGE)) GAS_COST_WEI=$(echo "$TOTAL_GAS_ESTIMATE * $GAS_PRICE" | bc 2>/dev/null || echo "0") GAS_COST_ETH=$(echo "scale=18; $GAS_COST_WEI / 1000000000000000000" | bc 2>/dev/null || echo "0") REQUIRED_ETH=$(echo "scale=18; $AMOUNT + $GAS_COST_ETH + 0.01" | bc 2>/dev/null || echo "$AMOUNT") log_info "Estimated Gas Costs:" log_info " Wrap: ~$ESTIMATED_GAS_WRAP gas" log_info " Approve: ~$ESTIMATED_GAS_APPROVE gas" log_info " Bridge: ~$ESTIMATED_GAS_BRIDGE gas" log_info " Total: ~$TOTAL_GAS_ESTIMATE gas" log_info " Gas Cost: ~$GAS_COST_ETH ETH (at 5 gwei)" if (( $(echo "$ETH_BALANCE_ETH < $REQUIRED_ETH" | bc -l 2>/dev/null || echo 1) )); then log_error "✗ Insufficient ETH balance" log_error " Required: $REQUIRED_ETH ETH (amount + gas + buffer)" log_error " Available: $ETH_BALANCE_ETH ETH" log_warn " Action needed: Add more ETH to address" else log_success "✓ Sufficient ETH balance" log_info " Available: $ETH_BALANCE_ETH ETH" log_info " Required: $REQUIRED_ETH ETH" log_info " Remaining after: $(echo "scale=18; $ETH_BALANCE_ETH - $REQUIRED_ETH" | bc) ETH" fi log_info "" log_dryrun "=========================================" log_dryrun "Step 2: Check WETH9 Balance" log_dryrun "=========================================" WETH9_BAL=$(cast call "$WETH9_ADDRESS" "balanceOf(address)" "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") # Convert hex to decimal if needed if echo "$WETH9_BAL" | grep -q "^0x"; then WETH9_BAL_DEC=$(cast --to-dec "$WETH9_BAL" 2>/dev/null || echo "0") else WETH9_BAL_DEC="$WETH9_BAL" fi WETH9_BAL_ETH=$(echo "scale=18; $WETH9_BAL_DEC / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "Current WETH9 Balance: $WETH9_BAL_ETH WETH ($WETH9_BAL_DEC wei)" if [ "$WETH9_BAL_DEC" = "0" ] || (( $(echo "$WETH9_BAL_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_warn "⚠ Insufficient WETH9 balance" log_info " Required: $AMOUNT WETH" log_info " Available: $WETH9_BAL_ETH WETH" if [ "$WETH9_BAL_DEC" = "0" ]; then NEEDED_ETH="$AMOUNT" else NEEDED_ETH=$(echo "scale=18; $AMOUNT - $WETH9_BAL_ETH" | bc 2>/dev/null || echo "$AMOUNT") fi log_dryrun " Would need to wrap: $NEEDED_ETH ETH" log_info " Action needed: Wrap ETH to WETH9 first" else log_success "✓ Sufficient WETH9 balance" log_info " Available: $WETH9_BAL_ETH WETH" log_info " Required: $AMOUNT WETH" log_info " Remaining after: $(echo "scale=18; $WETH9_BAL_ETH - $AMOUNT" | bc) WETH" fi log_info "" log_dryrun "=========================================" log_dryrun "Step 3: Check Bridge Allowance" log_dryrun "=========================================" ALLOW=$(cast call "$WETH9_ADDRESS" "allowance(address,address)" "$DEPLOYER" "$WETH9_BRIDGE" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") # Convert hex to decimal if needed if echo "$ALLOW" | grep -q "^0x"; then ALLOW_DEC=$(cast --to-dec "$ALLOW" 2>/dev/null || echo "0") else ALLOW_DEC="$ALLOW" fi ALLOW_ETH=$(echo "scale=18; $ALLOW_DEC / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "Current Bridge Allowance: $ALLOW_ETH WETH ($ALLOW_DEC wei)" if [ "$ALLOW_DEC" = "0" ] || (( $(echo "$ALLOW_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_warn "⚠ Insufficient bridge allowance" log_info " Required: $AMOUNT WETH" log_info " Current: $ALLOW_ETH WETH" log_dryrun " Would need to approve: $AMOUNT WETH (or max uint256)" log_info " Action needed: Approve bridge to spend WETH9" else log_success "✓ Sufficient bridge allowance" log_info " Current: $ALLOW_ETH WETH" log_info " Required: $AMOUNT WETH" fi log_info "" log_dryrun "=========================================" log_dryrun "Step 4: Calculate CCIP Bridge Fee" log_dryrun "=========================================" FEE=$(cast call "$WETH9_BRIDGE" "calculateFee(uint64,uint256)" "$ETHEREUM_MAINNET_SELECTOR" "$AMOUNT_WEI" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") if [ "$FEE" = "0" ] || [ -z "$FEE" ]; then log_warn "⚠ Could not calculate CCIP fee" log_info " This may require LINK tokens for fees" log_info " Check bridge contract for fee requirements" else FEE_ETH=$(echo "scale=18; $FEE / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "CCIP Bridge Fee: $FEE_ETH ETH ($FEE wei)" # Check if fee is in native token or LINK if (( $(echo "$FEE_ETH > 0" | bc -l 2>/dev/null || echo 0) )); then log_info " Fee will be paid in native ETH" else log_warn " Fee may be paid in LINK tokens" log_info " Check LINK balance if required" fi fi log_info "" log_dryrun "=========================================" log_dryrun "Step 5: Verify Bridge Configuration" log_dryrun "=========================================" # Check if Ethereum Mainnet is configured as destination DESTINATION=$(cast call "$WETH9_BRIDGE" "destinations(uint64)" "$ETHEREUM_MAINNET_SELECTOR" --rpc-url "$RPC_URL" 2>&1 || echo "ERROR") # Clean up the result (remove any error messages, get just the address) DESTINATION_CLEAN=$(echo "$DESTINATION" | grep -oE "^0x[0-9a-fA-F]{40}$" | head -1 || echo "") if [ -n "$DESTINATION_CLEAN" ] && ! echo "$DESTINATION_CLEAN" | grep -qE "^0x0+$"; then log_success "✓ Ethereum Mainnet is configured as destination" log_info " Destination Bridge: $DESTINATION_CLEAN" else log_error "✗ Ethereum Mainnet is NOT configured as destination" log_info " Current value: ${DESTINATION_CLEAN:-Not configured}" log_info " Action needed: Configure destination bridge address" log_info " Fix script: ./scripts/fix-bridge-errors.sh [private_key] [bridge_address]" fi log_info "" log_dryrun "=========================================" log_dryrun "Step 6: Transaction Simulation" log_dryrun "=========================================" log_info "Simulated Transaction Sequence:" log_info "" # Transaction 1: Wrap ETH (if needed) if [ "$WETH9_BAL_DEC" = "0" ] || (( $(echo "$WETH9_BAL_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_dryrun "1. Wrap ETH to WETH9" log_info " Function: deposit()" log_info " Value: $NEEDED_ETH ETH" log_info " Gas: ~$ESTIMATED_GAS_WRAP" log_info " Status: ⏳ Would execute" else log_info "1. Wrap ETH to WETH9" log_info " Status: ⏭️ Skipped (sufficient balance)" fi # Transaction 2: Approve Bridge (if needed) if [ "$ALLOW_DEC" = "0" ] || (( $(echo "$ALLOW_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_dryrun "2. Approve Bridge" log_info " Function: approve(address,uint256)" log_info " Spender: $WETH9_BRIDGE" log_info " Amount: $AMOUNT WETH (or max)" log_info " Gas: ~$ESTIMATED_GAS_APPROVE" log_info " Status: ⏳ Would execute" else log_info "2. Approve Bridge" log_info " Status: ⏭️ Skipped (already approved)" fi # Transaction 3: Bridge log_dryrun "3. Bridge to Ethereum Mainnet" log_info " Function: sendCrossChain(uint64,address,uint256)" log_info " Destination: Ethereum Mainnet ($ETHEREUM_MAINNET_SELECTOR)" log_info " Recipient: $DEPLOYER" log_info " Amount: $AMOUNT WETH" log_info " Gas: ~$ESTIMATED_GAS_BRIDGE" log_info " Status: ⏳ Would execute" log_info "" log_dryrun "=========================================" log_dryrun "Step 7: Cost Summary" log_dryrun "=========================================" log_info "Estimated Total Costs:" log_info " Amount to Bridge: $AMOUNT WETH" log_info " Gas Costs: ~$GAS_COST_ETH ETH" if [ -n "$FEE" ] && [ "$FEE" != "0" ]; then FEE_ETH=$(echo "scale=18; $FEE / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info " CCIP Fee: $FEE_ETH ETH" TOTAL_COST=$(echo "scale=18; $AMOUNT + $GAS_COST_ETH + $FEE_ETH" | bc 2>/dev/null || echo "$AMOUNT") else TOTAL_COST=$(echo "scale=18; $AMOUNT + $GAS_COST_ETH" | bc 2>/dev/null || echo "$AMOUNT") fi log_info " Total Cost: ~$TOTAL_COST ETH" log_info "" log_dryrun "=========================================" log_dryrun "Step 8: Final Checks" log_dryrun "=========================================" ALL_CHECKS_PASS=true # Check 1: ETH Balance if (( $(echo "$ETH_BALANCE_ETH < $REQUIRED_ETH" | bc -l 2>/dev/null || echo 1) )); then log_error "✗ Check 1: Insufficient ETH balance" ALL_CHECKS_PASS=false else log_success "✓ Check 1: Sufficient ETH balance" fi # Check 2: WETH9 Balance or ability to wrap if [ "$WETH9_BAL_DEC" = "0" ] || (( $(echo "$WETH9_BAL_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then if (( $(echo "$ETH_BALANCE_ETH >= $NEEDED_ETH" | bc -l 2>/dev/null || echo 0) )); then log_success "✓ Check 2: Can wrap sufficient ETH to WETH9" else log_error "✗ Check 2: Cannot wrap sufficient ETH to WETH9" ALL_CHECKS_PASS=false fi else log_success "✓ Check 2: Sufficient WETH9 balance" fi # Check 3: Bridge Allowance if [ "$ALLOW_DEC" = "0" ] || (( $(echo "$ALLOW_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_warn "⚠ Check 3: Bridge allowance needed (will be approved)" else log_success "✓ Check 3: Bridge already approved" fi # Check 4: Destination Configuration DESTINATION_CLEAN=$(echo "$DESTINATION" | grep -oE "^0x[0-9a-fA-F]{40}$" | head -1 || echo "") if [ -n "$DESTINATION_CLEAN" ] && ! echo "$DESTINATION_CLEAN" | grep -qE "^0x0+$"; then log_success "✓ Check 4: Destination configured" else log_error "✗ Check 4: Destination not configured" ALL_CHECKS_PASS=false fi log_info "" log_dryrun "=========================================" log_dryrun "DRY RUN SUMMARY" log_dryrun "=========================================" log_info "" if [ "$ALL_CHECKS_PASS" = true ]; then log_success "✓ All checks passed!" log_info "" log_info "Ready to bridge:" log_info " Amount: $AMOUNT WETH" log_info " Destination: Ethereum Mainnet" log_info " Recipient: $DEPLOYER" log_info "" log_info "To execute (not dry run), use:" log_info " ./scripts/wrap-and-bridge-to-ethereum.sh $AMOUNT [private_key]" else log_error "✗ Some checks failed" log_info "" log_info "Issues to resolve:" if (( $(echo "$ETH_BALANCE_ETH < $REQUIRED_ETH" | bc -l 2>/dev/null || echo 1) )); then log_info " - Add more ETH to address" fi if [ "$WETH9_BAL_DEC" = "0" ] || (( $(echo "$WETH9_BAL_DEC < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then if (( $(echo "$ETH_BALANCE_ETH < $NEEDED_ETH" | bc -l 2>/dev/null || echo 1) )); then log_info " - Add more ETH to wrap to WETH9" fi fi if [ -z "$DESTINATION_CLEAN" ] || echo "$DESTINATION_CLEAN" | grep -qE "^0x0+$" || [ "$DESTINATION_CLEAN" = "0x0000000000000000000000000000000000000000" ]; then log_info " - Configure Ethereum Mainnet destination in bridge" fi fi log_info "" log_info "This was a DRY RUN - no transactions were sent" log_info ""