#!/usr/bin/env bash # Verify CompliantWrappedToken (cW*) on all chains where addresses exist in .env. # Skips CW*_MAINNET (use verify-mainnet-cw-etherscan.sh). Same constructor as DeployCWTokens. # # Requires: ETHERSCAN_API_KEY (Etherscan v2 / unified explorers); CRONOSCAN_API_KEY for Cronos. # CW_VERIFY_ADMIN or PRIVATE_KEY for constructor admin address. # # Usage: cd smom-dbis-138 && ./scripts/deployment/verify-multichain-cw-etherscan.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" cd "$PROJECT_ROOT" 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 if [[ -z "${ETHERSCAN_API_KEY:-}" ]]; then echo "ETHERSCAN_API_KEY not set" >&2 exit 1 fi ADMIN="${CW_VERIFY_ADMIN:-}" if [[ -z "$ADMIN" && -n "${PRIVATE_KEY:-}" ]]; then ADMIN="$(cast wallet address --private-key "$PRIVATE_KEY")" fi if [[ -z "$ADMIN" || "$ADMIN" == "0x0000000000000000000000000000000000000000" ]]; then echo "Set CW_VERIFY_ADMIN or PRIVATE_KEY" >&2 exit 1 fi # Uppercase chain suffix -> forge --chain name (Foundry) forge_chain() { case "$1" in BSC) echo bsc ;; POLYGON) echo polygon ;; GNOSIS) echo gnosis ;; OPTIMISM) echo optimism ;; BASE) echo base ;; ARBITRUM) echo arbitrum ;; AVALANCHE) echo avalanche ;; CELO) echo celo ;; CRONOS) echo cronos ;; *) echo "" ;; esac } # API key for forge (Cronos uses cronoscan) api_key_for() { case "$1" in CRONOS) echo "${CRONOSCAN_API_KEY:-}" ;; *) echo "${ETHERSCAN_API_KEY}" ;; esac } # cWUSDT -> Wrapped cUSDT / cWUSDT name_sym_from_cw() { local cw="$1" local core="${cw#CW}" echo "Wrapped c${core}|cW${core}" } OK=0 SKIP=0 FAIL=0 while IFS= read -r line; do [[ "$line" =~ ^CW[A-Z0-9]+_[A-Z0-9]+= ]] || continue key="${line%%=*}" addr="${line#*=}" [[ -z "$addr" || "$addr" == "0x0000000000000000000000000000000000000000" ]] && continue chain="${key##*_}" [[ "$chain" == "MAINNET" ]] && continue # Cronos: Foundry + Etherscan API v2 often errors ("chainid"); use verify-cronos-contracts.sh or explorer.cronos.org manual upload. [[ "$chain" == "CRONOS" ]] && { echo " skip $key (Cronos: use verify-cronos-contracts.sh or CRONOS_VERIFICATION_RUNBOOK)"; SKIP=$((SKIP + 1)); continue; } fc="$(forge_chain "$chain")" if [[ -z "$fc" ]]; then echo " skip $key (unknown chain suffix $chain)" SKIP=$((SKIP + 1)) continue fi api="$(api_key_for "$chain")" if [[ -z "$api" ]]; then echo " skip $key (no API key for $chain; set CRONOSCAN_API_KEY for Cronos)" >&2 SKIP=$((SKIP + 1)) continue fi cwpart="${key%_*}" IFS='|' read -r cname sym <<< "$(name_sym_from_cw "$cwpart")" enc="$(cast abi-encode "constructor(string,string,uint8,address)" "$cname" "$sym" 6 "$ADMIN")" echo "[$fc] $sym $addr ..." set +e out="$(forge verify-contract \ --chain "$fc" \ --num-of-optimizations 200 \ --via-ir \ --constructor-args "$enc" \ --etherscan-api-key "$api" \ "$addr" \ "contracts/tokens/CompliantWrappedToken.sol:CompliantWrappedToken" 2>&1)" rc=$? set -e if [[ $rc -eq 0 ]]; then echo " ok" OK=$((OK + 1)) elif echo "$out" | grep -qiE 'already verified|Already Verified|Contract source code already verified'; then echo " already verified" OK=$((OK + 1)) else echo " FAILED (exit $rc)" >&2 echo "$out" >&2 FAIL=$((FAIL + 1)) fi sleep 1 done < <(env | grep '^CW[A-Z0-9]*_' | sort) echo "" echo "=== multichain cW*: ok/already=$OK skipped=$SKIP failed=$FAIL ==="