Files
explorer-monorepo/scripts/dry-run-bridge-to-ethereum.sh
2026-03-02 12:14:13 -08:00

392 lines
14 KiB
Bash
Executable File

#!/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 ""