#!/usr/bin/env bash # Fund the mainnet CCIPRelayBridge with WETH from the deployer wallet. # Usage: # ./scripts/bridge/fund-mainnet-relay-bridge.sh [amount_wei] [--dry-run] # ./scripts/bridge/fund-mainnet-relay-bridge.sh --target-bridge-balance-wei 10000000000000000 [--dry-run] # If amount_wei is omitted, transfers the deployer's full WETH balance. # Env: PRIVATE_KEY, ETHEREUM_MAINNET_RPC or RPC_URL_MAINNET (use Infura/Alchemy if llamarpc rate-limits) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # shellcheck source=/dev/null source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" >/dev/null 2>&1 || true DEPLOYER="${DEPLOYER_ADDRESS:-0x4A666F96fC8764181194447A7dFdb7d471b301C8}" WETH="${WETH9_MAINNET:-0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2}" BRIDGE="${CCIP_RELAY_BRIDGE_MAINNET:-0xF9A32F37099c582D28b4dE7Fca6eaC1e5259f939}" RPC="${RPC_URL_MAINNET:-${ETHEREUM_MAINNET_RPC:-https://ethereum.publicnode.com}}" DRY_RUN=0 TARGET_BRIDGE_BALANCE_WEI="" AMOUNT_WEI="" while [[ $# -gt 0 ]]; do case "$1" in --dry-run) DRY_RUN=1 shift ;; --target-bridge-balance-wei) TARGET_BRIDGE_BALANCE_WEI="${2:-}" shift 2 ;; *) if [[ -z "$AMOUNT_WEI" ]]; then AMOUNT_WEI="$1" shift else echo "Usage: $0 [amount_wei] [--target-bridge-balance-wei WEI] [--dry-run]" >&2 exit 1 fi ;; esac done command -v cast &>/dev/null || { echo "cast not found (install Foundry)"; exit 1; } normalize_uint() { awk '{print $1}' } DEPLOYER_BALANCE="$( (cast call "$WETH" "balanceOf(address)(uint256)" "$DEPLOYER" --rpc-url "$RPC" 2>/dev/null || echo "0") | normalize_uint )" BRIDGE_BALANCE="$( (cast call "$WETH" "balanceOf(address)(uint256)" "$BRIDGE" --rpc-url "$RPC" 2>/dev/null || echo "0") | normalize_uint )" echo "Deployer WETH balance (mainnet): $DEPLOYER_BALANCE wei" echo "Bridge WETH balance (mainnet): $BRIDGE_BALANCE wei" if [[ -n "$TARGET_BRIDGE_BALANCE_WEI" ]]; then AMOUNT_WEI="$(node -e 'const target=BigInt(process.argv[1]); const current=BigInt(process.argv[2]); const delta=target>current?target-current:0n; process.stdout.write(delta.toString())' "$TARGET_BRIDGE_BALANCE_WEI" "$BRIDGE_BALANCE")" echo "Target bridge balance: $TARGET_BRIDGE_BALANCE_WEI wei" echo "Calculated transfer: $AMOUNT_WEI wei" fi if [[ -z "$AMOUNT_WEI" ]]; then AMOUNT_WEI="$DEPLOYER_BALANCE" echo "Transferring full deployer balance: $AMOUNT_WEI wei" else echo "Transferring: $AMOUNT_WEI wei" fi if [[ -z "$AMOUNT_WEI" ]] || [[ "$AMOUNT_WEI" = "0" ]]; then echo "Nothing to transfer." exit 0 fi if [[ "$DRY_RUN" = "1" ]]; then if node -e 'const amount=BigInt(process.argv[1]); const deployer=BigInt(process.argv[2]); process.exit(amount > deployer ? 1 : 0)' "$AMOUNT_WEI" "$DEPLOYER_BALANCE"; then : else echo "[dry-run] Warning: requested transfer exceeds current deployer balance." fi echo "[dry-run] Would execute:" echo "cast send $WETH \"transfer(address,uint256)\" $BRIDGE \"$AMOUNT_WEI\" --rpc-url \"$RPC\" --private-key \"\$PRIVATE_KEY\" --legacy" exit 0 fi [[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY required unless --dry-run is used"; exit 1; } node -e 'const amount=BigInt(process.argv[1]); const deployer=BigInt(process.argv[2]); if (amount > deployer) { console.error(`Requested transfer ${amount} exceeds deployer balance ${deployer}.`); process.exit(2); }' "$AMOUNT_WEI" "$DEPLOYER_BALANCE" cast send "$WETH" "transfer(address,uint256)" "$BRIDGE" "$AMOUNT_WEI" \ --rpc-url "$RPC" \ --private-key "$PRIVATE_KEY" \ --legacy FINAL_BRIDGE_BALANCE="$( (cast call "$WETH" "balanceOf(address)(uint256)" "$BRIDGE" --rpc-url "$RPC" 2>/dev/null || echo "0") | normalize_uint )" echo "Done. Bridge WETH balance: $FINAL_BRIDGE_BALANCE wei"