#!/usr/bin/env bash # Verify Ethereum Mainnet CWMultiTokenBridgeL2 (CW_BRIDGE_MAINNET) on Etherscan. # # Constructor: (sendRouter, receiveRouter, feeToken) — read from chain if unset. # # Usage: # cd smom-dbis-138 && ./scripts/deployment/verify-mainnet-cw-bridge-etherscan.sh # ./scripts/deployment/verify-mainnet-cw-bridge-etherscan.sh --dry-run set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" cd "$PROJECT_ROOT" DRY_RUN=false for a in "$@"; do case "$a" in --dry-run) DRY_RUN=true ;; esac done if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 source "$SCRIPT_DIR/../lib/deployment/dotenv.sh" load_deployment_env --repo-root "${PROJECT_ROOT}" elif [[ -f "$PROJECT_ROOT/.env" ]]; then set -a # shellcheck disable=SC1090 source "$PROJECT_ROOT/.env" set +a fi [[ -n "${ETHERSCAN_API_KEY:-}" ]] || { echo "ETHERSCAN_API_KEY not set" >&2 exit 1 } RPC="${ETHEREUM_MAINNET_RPC:-${ETH_MAINNET_RPC_URL:-https://ethereum-rpc.publicnode.com}}" BRIDGE="${CW_BRIDGE_MAINNET:-0x2bF74583206A49Be07E0E8A94197C12987AbD7B5}" fetch_creation_ctor() { python3 - "$BRIDGE" "$ETHERSCAN_API_KEY" <<'PY' import json, sys, urllib.request bridge, api_key = sys.argv[1:3] url = ( "https://api.etherscan.io/v2/api?chainid=1&module=contract&action=getcontractcreation" f"&contractaddresses={bridge}&apikey={api_key}" ) with urllib.request.urlopen(url, timeout=30) as resp: doc = json.load(resp) rows = doc.get("result") or [] if not rows: raise SystemExit("Etherscan getcontractcreation returned no rows") creation = (rows[0].get("creationBytecode") or "").lower().removeprefix("0x") if len(creation) < 192: raise SystemExit("creationBytecode too short") # constructor args are last 3 x 32-byte words args_hex = creation[-192:] words = [args_hex[i : i + 64] for i in range(0, 192, 64)] for w in words: print("0x" + w[-40:]) PY } SEND="${CW_BRIDGE_MAINNET_SEND_ROUTER:-}" RECV="${CW_BRIDGE_MAINNET_RECEIVE_ROUTER:-}" FEE="${CW_BRIDGE_MAINNET_FEE_TOKEN:-}" if [[ -z "$SEND" || -z "$RECV" || -z "$FEE" ]]; then mapfile -t _CTOR_ADDRS < <(fetch_creation_ctor 2>/dev/null || true) if [[ ${#_CTOR_ADDRS[@]} -eq 3 ]]; then SEND="${_CTOR_ADDRS[0]}" RECV="${_CTOR_ADDRS[1]}" FEE="${_CTOR_ADDRS[2]}" echo "Using deployment-time constructor args from Etherscan creation tx" else SEND="$(cast call "$BRIDGE" 'sendRouter()(address)' --rpc-url "$RPC")" RECV="$(cast call "$BRIDGE" 'receiveRouter()(address)' --rpc-url "$RPC")" FEE="$(cast call "$BRIDGE" 'feeToken()(address)' --rpc-url "$RPC")" echo "WARN: using live on-chain router fields (may differ from deploy immutables)" >&2 fi fi CTOR="$(cast abi-encode 'constructor(address,address,address)' "$SEND" "$RECV" "$FEE")" echo "=== Verify CWMultiTokenBridgeL2 (CW_BRIDGE_MAINNET) ===" echo " bridge=$BRIDGE" echo " sendRouter=$SEND" echo " receiveRouter=$RECV" echo " feeToken=$FEE" export FOUNDRY_SRC="contracts/bridge,contracts/interfaces" export FOUNDRY_OUT="out/scopes/bridge" export FOUNDRY_CACHE_PATH="cache/scopes/bridge" if $DRY_RUN; then echo "forge verify-contract --chain-id 1 --num-of-optimizations 200 --via-ir \\" echo " --constructor-args \"$CTOR\" --etherscan-api-key \"\$ETHERSCAN_API_KEY\" \\" echo " \"$BRIDGE\" contracts/bridge/CWMultiTokenBridgeL2.sol:CWMultiTokenBridgeL2" exit 0 fi bash "$PROJECT_ROOT/scripts/forge/scope.sh" build bridge -q set +e out="$(forge verify-contract \ --chain-id 1 \ --num-of-optimizations 200 \ --via-ir \ --constructor-args "$CTOR" \ --etherscan-api-key "$ETHERSCAN_API_KEY" \ "$BRIDGE" \ "contracts/bridge/CWMultiTokenBridgeL2.sol:CWMultiTokenBridgeL2" 2>&1)" rc=$? set -e echo "$out" if [[ $rc -eq 0 ]] || echo "$out" | grep -qiE 'already verified|Contract source code already verified'; then echo "OK: https://etherscan.io/address/$BRIDGE#code" exit 0 fi exit "$rc"