Files
proxmox/scripts/deployment/grant-cw-bridge-roles-on-chain.sh
defiQUG dbd517b279 Sync workspace: config, docs, scripts, CI, operator rules, and submodule pointers.
- Update dbis_core, cross-chain-pmm-lps, explorer-monorepo, metamask-integration, pr-workspace/chains
- Omit embedded publish git dirs and empty placeholders from index

Made-with: Cursor
2026-04-12 06:12:20 -07:00

199 lines
6.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Grant MINTER_ROLE and BURNER_ROLE on CompliantWrappedToken (cW*) to the chain CW bridge
# when the deployer still has DEFAULT_ADMIN_ROLE and roles are not frozen.
#
# Use after DeployCWTokens or when verify shows MINTER=false BURNER=false for some symbols.
# See: docs/07-ccip/CW_DEPLOY_AND_WIRE_RUNBOOK.md
#
# Usage (repo root):
# ./scripts/deployment/grant-cw-bridge-roles-on-chain.sh AVALANCHE [--dry-run]
# ./scripts/deployment/grant-cw-bridge-roles-on-chain.sh MAINNET [--dry-run]
#
# Env: PRIVATE_KEY, CW_BRIDGE_<CHAIN>, <CHAIN>_RPC from smom-dbis-138/.env (via dotenv).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
SMOM="${PROJECT_ROOT}/smom-dbis-138"
CHAIN="${1:-}"
DRY_RUN=false
[[ "${2:-}" == "--dry-run" ]] && DRY_RUN=true
if [[ -z "$CHAIN" ]]; then
echo "Usage: $0 <CHAIN_NAME> [--dry-run]" >&2
echo " CHAIN_NAME: MAINNET CRONOS BSC POLYGON GNOSIS AVALANCHE BASE ARBITRUM OPTIMISM CELO WEMIX" >&2
exit 2
fi
if [[ ! -f "$SMOM/.env" ]]; then
echo "Missing $SMOM/.env" >&2
exit 1
fi
if [[ -f "$SMOM/scripts/lib/deployment/dotenv.sh" ]]; then
# shellcheck disable=SC1090
source "$SMOM/scripts/lib/deployment/dotenv.sh"
load_deployment_env --repo-root "$SMOM"
else
set -a
# shellcheck disable=SC1090
source "$SMOM/.env"
set +a
fi
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY required in smom-dbis-138/.env" >&2; exit 1; }
command -v cast >/dev/null 2>&1 || { echo "cast (foundry) required" >&2; exit 1; }
command -v python3 >/dev/null 2>&1 || { echo "python3 required (gas bump)" >&2; exit 1; }
declare -A CHAIN_NAME_TO_ID=(
[MAINNET]=1 [CRONOS]=25 [BSC]=56 [POLYGON]=137 [GNOSIS]=100
[AVALANCHE]=43114 [BASE]=8453 [ARBITRUM]=42161 [OPTIMISM]=10 [CELO]=42220 [WEMIX]=1111
)
chain_id="${CHAIN_NAME_TO_ID[$CHAIN]:-}"
if [[ -z "$chain_id" ]]; then
echo "Unknown chain: $CHAIN" >&2
exit 2
fi
bridge_var="CW_BRIDGE_${CHAIN}"
bridge="${!bridge_var:-}"
if [[ -z "$bridge" ]]; then
echo "SKIP: CW_BRIDGE_${CHAIN} is not set (nothing to grant on this chain)."
exit 0
fi
rpc=""
case "$CHAIN" 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:-${ARBITRUM_MAINNET_RPC_URL:-${ARBITRUM_RPC_URL:-}}}" ;;
OPTIMISM) rpc="${OPTIMISM_MAINNET_RPC:-}" ;;
CELO) rpc="${CELO_RPC:-${CELO_MAINNET_RPC:-}}" ;;
WEMIX) rpc="${WEMIX_RPC:-${WEMIX_MAINNET_RPC:-}}" ;;
esac
if [[ -z "$rpc" ]]; then
echo "No RPC URL for $CHAIN (set e.g. AVALANCHE_RPC_URL)" >&2
exit 1
fi
# Busy networks: base fee can exceed cast defaults — bump legacy gas price (percent, default 150%).
CW_GRANT_GAS_BUMP_PCT="${CW_GRANT_GAS_BUMP_PCT:-150}"
_gas_price_wei() {
local base
base="$(cast gas-price --rpc-url "$rpc" 2>/dev/null | head -1 | tr -d '[:space:]')"
[[ -z "$base" || ! "$base" =~ ^[0-9]+$ ]] && base="50000000000"
python3 -c "import sys; b=int(sys.argv[1]); p=int(sys.argv[2]); print(max(b * p // 100, b + 10**9))" "$base" "$CW_GRANT_GAS_BUMP_PCT"
}
GAS_PRICE_WEI="${CW_GRANT_GAS_PRICE_WEI:-$(_gas_price_wei)}"
DEPLOYER="$(cast wallet address "$PRIVATE_KEY" 2>/dev/null)" || { echo "Invalid PRIVATE_KEY" >&2; exit 1; }
MINTER_ROLE="$(cast keccak "MINTER_ROLE")"
BURNER_ROLE="$(cast keccak "BURNER_ROLE")"
# OpenZeppelin AccessControl DEFAULT_ADMIN_ROLE
DEFAULT_ADMIN_ROLE="0x0000000000000000000000000000000000000000000000000000000000000000"
CW_TOKEN_PREFIXES=(CWUSDT CWUSDC CWAUSDT CWEURC CWEURT CWGBPC CWGBPT CWAUDC CWJPYC CWCHFC CWCADC CWXAUC CWXAUT)
resolve_token() {
local prefix="$1"
local chain_var="${prefix}_${CHAIN}"
local address_var="${prefix}_ADDRESS_${chain_id}"
if [[ -n "${!chain_var:-}" ]]; then
printf '%s' "${!chain_var}"
return
fi
if [[ -n "${!address_var:-}" ]]; then
printf '%s' "${!address_var}"
return
fi
printf ''
}
echo "=== Grant cW* bridge roles: $CHAIN (chainId $chain_id) ==="
echo "RPC: $rpc"
echo "Bridge: $bridge"
echo "From: $DEPLOYER"
echo "Gas: legacy wei=$GAS_PRICE_WEI (override CW_GRANT_GAS_PRICE_WEI or bump CW_GRANT_GAS_BUMP_PCT)"
if $DRY_RUN; then echo "MODE: dry-run (no transactions)"; fi
echo ""
granted=0
skipped=0
failed=0
for prefix in "${CW_TOKEN_PREFIXES[@]}"; do
token="$(resolve_token "$prefix")"
[[ -z "$token" ]] && continue
# Some proxies revert on operationalRolesFrozen(); skip that probe and rely on grantRole + admin check.
is_admin="$(cast call "$token" "hasRole(bytes32,address)(bool)" "$DEFAULT_ADMIN_ROLE" "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null || echo "false")"
if [[ "$is_admin" != "true" ]]; then
echo " SKIP $prefix $token — deployer lacks DEFAULT_ADMIN_ROLE"
skipped=$((skipped + 1))
continue
fi
hm="$(cast call "$token" "hasRole(bytes32,address)(bool)" "$MINTER_ROLE" "$bridge" --rpc-url "$rpc" 2>/dev/null || echo "false")"
hb="$(cast call "$token" "hasRole(bytes32,address)(bool)" "$BURNER_ROLE" "$bridge" --rpc-url "$rpc" 2>/dev/null || echo "false")"
if [[ "$hm" == "true" && "$hb" == "true" ]]; then
skipped=$((skipped + 1))
continue
fi
echo " FIX $prefix $token MINTER=$hm BURNER=$hb"
if $DRY_RUN; then
[[ "$hm" != "true" ]] && echo " would: grantRole(MINTER_ROLE, bridge)"
[[ "$hb" != "true" ]] && echo " would: grantRole(BURNER_ROLE, bridge)"
granted=$((granted + 1))
continue
fi
_after_minter() {
cast call "$token" "hasRole(bytes32,address)(bool)" "$MINTER_ROLE" "$bridge" --rpc-url "$rpc" 2>/dev/null | grep -q true
}
_after_burner() {
cast call "$token" "hasRole(bytes32,address)(bool)" "$BURNER_ROLE" "$bridge" --rpc-url "$rpc" 2>/dev/null | grep -q true
}
if [[ "$hm" != "true" ]]; then
cast send "$token" "grantRole(bytes32,address)" "$MINTER_ROLE" "$bridge" \
--rpc-url "$rpc" --private-key "$PRIVATE_KEY" --legacy --gas-price "$GAS_PRICE_WEI" >/dev/null 2>&1 || true
sleep 2
if _after_minter; then
echo " OK MINTER_ROLE"
else
echo " FAIL MINTER_ROLE" >&2
failed=$((failed + 1))
fi
fi
if [[ "$hb" != "true" ]]; then
cast send "$token" "grantRole(bytes32,address)" "$BURNER_ROLE" "$bridge" \
--rpc-url "$rpc" --private-key "$PRIVATE_KEY" --legacy --gas-price "$GAS_PRICE_WEI" >/dev/null 2>&1 || true
sleep 2
if _after_burner; then
echo " OK BURNER_ROLE"
else
echo " FAIL BURNER_ROLE" >&2
failed=$((failed + 1))
fi
fi
granted=$((granted + 1))
done
echo ""
echo "Summary: chains=$CHAIN fixed_tokens=$granted skipped=$skipped tx_failures=$failed"
if [[ "$failed" -gt 0 ]]; then
exit 1
fi