392 lines
14 KiB
Bash
Executable File
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 ""
|
|
|