#!/usr/bin/env bash # Wrap ETH to WETH9 and bridge to Ethereum Mainnet # Usage: ./wrap-and-bridge-to-ethereum.sh [amount_in_eth] [private_key] # Example: ./wrap-and-bridge-to-ethereum.sh 1.0 0x... # Or set PRIVATE_KEY in .env file: ./wrap-and-bridge-to-ethereum.sh 1.0 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' 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"; } # 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:-}" PRIVATE_KEY_ARG="${2:-}" # Use provided private key or from environment if [ -n "$PRIVATE_KEY_ARG" ]; then PRIVATE_KEY="$PRIVATE_KEY_ARG" elif [ -z "${PRIVATE_KEY:-}" ]; then log_error "PRIVATE_KEY not provided. Usage: $0 [private_key]" log_info "Or set PRIVATE_KEY in .env file" exit 1 fi if [ -z "$AMOUNT" ]; then log_error "Amount not provided. Usage: $0 [private_key]" log_info "Example: $0 1.0 0x..." exit 1 fi # Validate amount is a positive number if ! echo "$AMOUNT" | grep -qE '^[0-9]+\.?[0-9]*$' || (( $(echo "$AMOUNT <= 0" | bc -l 2>/dev/null || echo 1) )); then log_error "Invalid amount: $AMOUNT. Must be a positive number." exit 1 fi log_info "=========================================" log_info "Wrap ETH to WETH9 and Bridge to Ethereum Mainnet" log_info "=========================================" log_info "" log_info "Configuration:" log_info " Amount: $AMOUNT ETH" log_info " WETH9 Address: $WETH9_ADDRESS" log_info " Bridge Address: $WETH9_BRIDGE" log_info " Destination: Ethereum Mainnet (Selector: $ETHEREUM_MAINNET_SELECTOR)" log_info " RPC URL: $RPC_URL" log_info "" # Get deployer address from private key 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" exit 1 fi log_info "Wallet Address: $DEPLOYER" log_info "" # Get optimal gas price function get_optimal_gas() { if [ -f "$SCRIPT_DIR/get-optimal-gas-from-api.sh" ]; then api_gas=$("$SCRIPT_DIR/get-optimal-gas-from-api.sh" "proposed" 2>/dev/null || echo "") if [ -n "$api_gas" ] && [ "$api_gas" != "0" ]; then echo "scale=0; $api_gas * 1.5 / 1" | bc 2>/dev/null || echo "$api_gas" return 0 fi fi current_gas=$(cast gas-price --rpc-url "$RPC_URL" 2>/dev/null || echo "1000000000") echo "scale=0; $current_gas * 1.5 / 1" | bc 2>/dev/null || echo "$current_gas" } # Step 1: Check ETH balance log_info "Step 1: Checking ETH balance..." ETH_BALANCE=$(cast balance "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") ETH_BALANCE_ETH=$(echo "scale=6; $ETH_BALANCE / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "ETH Balance: $ETH_BALANCE_ETH ETH" # 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 # Check if sufficient balance (need amount + gas fees, estimate 0.01 ETH for gas) REQUIRED_ETH=$(echo "scale=6; $AMOUNT + 0.01" | bc 2>/dev/null || echo "$AMOUNT") if (( $(echo "$ETH_BALANCE_ETH < $REQUIRED_ETH" | bc -l 2>/dev/null || echo 1) )); then log_error "Insufficient ETH balance. Need at least $REQUIRED_ETH ETH (including gas fees)" log_info "Current balance: $ETH_BALANCE_ETH ETH" exit 1 fi log_success "✓ Sufficient ETH balance" log_info "" # Step 2: Check WETH9 balance log_info "Step 2: Checking WETH9 balance..." WETH9_BAL=$(cast call "$WETH9_ADDRESS" "balanceOf(address)" "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") WETH9_BAL_ETH=$(echo "scale=6; $WETH9_BAL / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "WETH9 Balance: $WETH9_BAL_ETH WETH" log_info "" # Step 3: Wrap ETH to WETH9 if needed if [ "$WETH9_BAL" = "0" ] || (( $(echo "$WETH9_BAL < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_info "Step 3: Wrapping ETH to WETH9..." # Calculate how much to wrap if [ "$WETH9_BAL" = "0" ]; then WRAP_AMOUNT_WEI="$AMOUNT_WEI" WRAP_AMOUNT_ETH="$AMOUNT" else NEEDED_WEI=$(echo "$AMOUNT_WEI - $WETH9_BAL" | bc 2>/dev/null || echo "$AMOUNT_WEI") NEEDED_ETH=$(echo "scale=6; $NEEDED_WEI / 1000000000000000000" | bc 2>/dev/null || echo "$AMOUNT") WRAP_AMOUNT_WEI="$NEEDED_WEI" WRAP_AMOUNT_ETH="$NEEDED_ETH" log_info "Need to wrap $NEEDED_ETH ETH (have $WETH9_BAL_ETH WETH, need $AMOUNT WETH)" fi # Get current nonce CURRENT_NONCE=$(cast nonce "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") # Get optimal gas price OPTIMAL_GAS=$(get_optimal_gas) # Wrap ETH by calling deposit() with value log_info "Calling WETH9.deposit() with $WRAP_AMOUNT_ETH ETH..." WRAP_TX=$(cast send "$WETH9_ADDRESS" "deposit()" \ --value "$WRAP_AMOUNT_WEI" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$OPTIMAL_GAS" \ --nonce "$CURRENT_NONCE" \ 2>&1 || echo "") if echo "$WRAP_TX" | grep -qE "transactionHash"; then TX_HASH=$(echo "$WRAP_TX" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}') log_success "✓ Wrap transaction sent: $TX_HASH" log_info "Waiting for confirmation..." sleep 15 # Verify WETH9 balance after wrap and check 1:1 ratio WETH9_BAL_AFTER=$(cast call "$WETH9_ADDRESS" "balanceOf(address)" "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") WETH9_BAL_AFTER_ETH=$(echo "scale=6; $WETH9_BAL_AFTER / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "WETH9 Balance after wrap: $WETH9_BAL_AFTER_ETH WETH" # Verify 1:1 ratio WETH9_RECEIVED=$(echo "$WETH9_BAL_AFTER - $WETH9_BAL" | bc 2>/dev/null || echo "0") if [ "$WETH9_RECEIVED" = "$WRAP_AMOUNT_WEI" ]; then log_success "✓ 1:1 ratio verified: Received exactly $WRAP_AMOUNT_ETH WETH9 for $WRAP_AMOUNT_ETH ETH" else log_warn "⚠ Ratio verification: Expected $WRAP_AMOUNT_WEI wei, received $WETH9_RECEIVED wei" log_warn " This may indicate a non-1:1 ratio. Please investigate." log_info " Run ./scripts/verify-weth9-ratio.sh for detailed verification" fi else log_error "Failed to wrap ETH" log_info "Transaction output: $WRAP_TX" exit 1 fi else log_success "✓ WETH9 balance sufficient ($WETH9_BAL_ETH WETH)" fi log_info "" # Step 4: Check and approve bridge if needed log_info "Step 4: Checking bridge allowance..." ALLOW=$(cast call "$WETH9_ADDRESS" "allowance(address,address)" "$DEPLOYER" "$WETH9_BRIDGE" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") if [ "$ALLOW" = "0" ] || (( $(echo "$ALLOW < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then log_info "Approving bridge to spend $AMOUNT WETH9..." # Get current nonce CURRENT_NONCE=$(cast nonce "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") # Get optimal gas price OPTIMAL_GAS=$(get_optimal_gas) # Approve bridge (approve max amount to avoid future approvals) MAX_UINT256="115792089237316195423570985008687907853269984665640564039457584007913129639935" APPROVE_TX=$(cast send "$WETH9_ADDRESS" "approve(address,uint256)" "$WETH9_BRIDGE" "$MAX_UINT256" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$OPTIMAL_GAS" \ --nonce "$CURRENT_NONCE" \ 2>&1 || echo "") if echo "$APPROVE_TX" | grep -qE "transactionHash"; then TX_HASH=$(echo "$APPROVE_TX" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}') log_success "✓ Approval transaction sent: $TX_HASH" log_info "Waiting for confirmation..." sleep 15 else log_error "Failed to approve bridge" log_info "Transaction output: $APPROVE_TX" exit 1 fi else log_success "✓ Bridge already approved" fi log_info "" # Step 5: Calculate CCIP fee log_info "Step 5: Calculating CCIP bridge fee..." 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 fee, proceeding anyway..." FEE_ETH="0" else FEE_ETH=$(echo "scale=10; $FEE / 1000000000000000000" | bc 2>/dev/null || echo "0") log_info "CCIP Fee: $FEE_ETH ETH ($FEE wei)" fi log_info "" # Step 6: Send cross-chain transfer to Ethereum Mainnet log_info "Step 6: Sending cross-chain transfer to Ethereum Mainnet..." log_info " Recipient: $DEPLOYER (same address on Ethereum Mainnet)" log_info " Amount: $AMOUNT WETH9" log_info " Destination Chain Selector: $ETHEREUM_MAINNET_SELECTOR" # Get current nonce CURRENT_NONCE=$(cast nonce "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") # Get optimal gas price OPTIMAL_GAS=$(get_optimal_gas) # Send cross-chain transfer SEND_TX=$(cast send "$WETH9_BRIDGE" "sendCrossChain(uint64,address,uint256)" \ "$ETHEREUM_MAINNET_SELECTOR" \ "$DEPLOYER" \ "$AMOUNT_WEI" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$OPTIMAL_GAS" \ --nonce "$CURRENT_NONCE" \ 2>&1 || echo "") if echo "$SEND_TX" | grep -qE "transactionHash"; then TX_HASH=$(echo "$SEND_TX" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}') log_success "✓ Cross-chain transfer sent: $TX_HASH" log_info "" log_info "Transaction Details:" log_info " Transaction Hash: $TX_HASH" log_info " Amount: $AMOUNT WETH9" log_info " Destination: Ethereum Mainnet" log_info " Recipient: $DEPLOYER" log_info "" log_info "You can monitor the transaction at:" log_info " https://explorer.d-bis.org/tx/$TX_HASH" log_info "" log_success "Process completed successfully!" log_info "" log_info "Note: The bridge transfer may take a few minutes to complete on Ethereum Mainnet." log_info "Monitor the destination chain for the receipt of WETH9 tokens." else log_error "Failed to send cross-chain transfer" log_info "Transaction output: $SEND_TX" exit 1 fi