#!/usr/bin/env bash # Run remaining cW* steps: deploy (or dry-run), update token-mapping from .env, optional verify. # See docs/07-ccip/CW_DEPLOY_AND_WIRE_RUNBOOK.md and docs/00-meta/CW_BRIDGE_TASK_LIST.md. # # Usage: # ./scripts/deployment/run-cw-remaining-steps.sh [--dry-run] [--deploy] [--update-mapping] [--verify] # --dry-run Run deploy-cw in dry-run mode (print commands only). # --deploy Run deploy-cw on all chains (requires RPC/PRIVATE_KEY in smom-dbis-138/.env). # --update-mapping Update config/token-mapping-multichain.json from CWUSDT_*/CWUSDC_* in .env. # --verify For each chain with CWUSDT_* set, check MINTER_ROLE/BURNER_ROLE on cW* for CW_BRIDGE_*. # With no options, runs --dry-run then --update-mapping (if any CWUSDT_* in .env). set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" SMOM="${PROJECT_ROOT}/smom-dbis-138" CONFIG="${PROJECT_ROOT}/config/token-mapping-multichain.json" DRY_RUN=false DO_DEPLOY=false DO_UPDATE_MAPPING=false DO_VERIFY=false for a in "$@"; do case "$a" in --dry-run) DRY_RUN=true ;; --deploy) DO_DEPLOY=true ;; --update-mapping) DO_UPDATE_MAPPING=true ;; --verify) DO_VERIFY=true ;; esac done if ! $DRY_RUN && ! $DO_DEPLOY && ! $DO_UPDATE_MAPPING && ! $DO_VERIFY; then DRY_RUN=true DO_UPDATE_MAPPING=true fi if [[ ! -f "$SMOM/.env" ]]; then echo "Missing $SMOM/.env" >&2 exit 1 fi set -a source "$SMOM/.env" set +a # Chain name (env suffix) -> chainId for 138 -> chain pairs declare -A CHAIN_NAME_TO_ID=( [MAINNET]=1 [CRONOS]=25 [BSC]=56 [POLYGON]=137 [GNOSIS]=100 [AVALANCHE]=43114 [BASE]=8453 [ARBITRUM]=42161 [OPTIMISM]=10 [ALL]=651940 ) if $DO_DEPLOY; then echo "=== Deploy cW* (DeployCWTokens) on all chains ===" (cd "$SMOM" && ./scripts/deployment/deploy-tokens-and-weth-all-chains-skip-canonical.sh --deploy-cw) echo "→ Set CWUSDT_ and CWUSDC_ in $SMOM/.env from script output; then run with --update-mapping" fi if $DRY_RUN; then echo "=== Dry-run: deploy cW* (commands only) ===" (cd "$SMOM" && ./scripts/deployment/deploy-tokens-and-weth-all-chains-skip-canonical.sh --deploy-cw --dry-run) fi update_mapping() { local env_file="$SMOM/.env" local config_file="$CONFIG" [[ -f "$config_file" ]] || { echo "Missing $config_file" >&2; return 1; } node -e " const fs = require('fs'); const path = require('path'); function loadEnv(f) { const c = fs.readFileSync(f, 'utf8'); const out = {}; c.split('\n').forEach(line => { const m = line.match(/^([A-Za-z_0-9]+)=(.*)$/); if (m) out[m[1]] = m[2].replace(/^[\"']|[\"']\$/g, '').trim(); }); return out; } const env = loadEnv('$env_file'); const chainToId = { MAINNET: 1, CRONOS: 25, BSC: 56, POLYGON: 137, GNOSIS: 100, AVALANCHE: 43114, BASE: 8453, ARBITRUM: 42161, OPTIMISM: 10, ALL: 651940 }; const keyToEnv = { Compliant_USDT_cW: 'CWUSDT', Compliant_USDC_cW: 'CWUSDC', Compliant_EURC_cW: 'CWEURC', Compliant_EURT_cW: 'CWEURT', Compliant_GBPC_cW: 'CWGBPC', Compliant_GBPT_cW: 'CWGBPT', Compliant_AUDC_cW: 'CWAUDC', Compliant_JPYC_cW: 'CWJPYC', Compliant_CHFC_cW: 'CWCHFC', Compliant_CADC_cW: 'CWCADC', Compliant_XAUC_cW: 'CWXAUC', Compliant_XAUT_cW: 'CWXAUT' }; const j = JSON.parse(fs.readFileSync('$config_file', 'utf8')); let updated = 0; for (const [name, chainId] of Object.entries(chainToId)) { const pair = j.pairs.find(p => p.fromChainId === 138 && p.toChainId === chainId); if (!pair) continue; for (const t of pair.tokens) { const envKey = keyToEnv[t.key]; if (!envKey) continue; const addr = env[envKey + '_' + name]; if (addr && t.addressTo !== addr) { t.addressTo = addr; updated++; } } } if (updated) { fs.writeFileSync('$config_file', JSON.stringify(j, null, 2) + '\n'); console.log('Updated', updated, 'addressTo entries in token-mapping-multichain.json'); } else { console.log('No cW* addresses set in .env for mapped chains, or already up to date'); } " } if $DO_UPDATE_MAPPING; then echo "=== Update token-mapping from .env ===" update_mapping fi if $DO_VERIFY; then echo "=== Verify MINTER/BURNER roles on cW* for each chain ===" MINTER_ROLE=$(cast keccak "MINTER_ROLE" 2>/dev/null || echo "0x") BURNER_ROLE=$(cast keccak "BURNER_ROLE" 2>/dev/null || echo "0x") for name in MAINNET CRONOS BSC POLYGON GNOSIS AVALANCHE BASE ARBITRUM OPTIMISM; do cwusdt_var="CWUSDT_${name}" bridge_var="CW_BRIDGE_${name}" cwusdt="${!cwusdt_var:-}" bridge="${!bridge_var:-}" rpc_var="${name}_RPC_URL" [[ -z "$rpc_var" ]] && rpc_var="${name}_RPC" rpc="${!rpc_var:-}" if [[ -z "$cwusdt" || -z "$bridge" ]]; then continue; fi if [[ -z "$rpc" ]]; then case "$name" in MAINNET) rpc="${ETH_MAINNET_RPC_URL:-${ETHEREUM_MAINNET_RPC:-}}";; CRONOS) rpc="${CRONOS_RPC_URL:-${CRONOS_RPC:-}}";; BSC) rpc="${BSC_RPC_URL:-}";; POLYGON) rpc="${POLYGON_MAINNET_RPC:-${POLYGON_RPC_URL:-}}";; GNOSIS) rpc="${GNOSIS_RPC:-}";; AVALANCHE) rpc="${AVALANCHE_RPC_URL:-}";; BASE) rpc="${BASE_MAINNET_RPC:-}";; ARBITRUM) rpc="${ARBITRUM_MAINNET_RPC:-}";; OPTIMISM) rpc="${OPTIMISM_MAINNET_RPC:-}";; esac fi if [[ -z "$rpc" ]]; then echo " Skip $name: no RPC"; continue; fi m=$(cast call "$cwusdt" "hasRole(bytes32,address)(bool)" "$MINTER_ROLE" "$bridge" --rpc-url "$rpc" 2>/dev/null || echo "false") b=$(cast call "$cwusdt" "hasRole(bytes32,address)(bool)" "$BURNER_ROLE" "$bridge" --rpc-url "$rpc" 2>/dev/null || echo "false") echo " $name: MINTER=$m BURNER=$b (cWUSDT=$cwusdt bridge=$bridge)" done fi echo "Done. See docs/07-ccip/CW_DEPLOY_AND_WIRE_RUNBOOK.md for Phase E (relay and E2E)."