#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" if [[ -f "$REPO_ROOT/scripts/load-env.sh" ]]; then # shellcheck disable=SC1090 source "$REPO_ROOT/scripts/load-env.sh" >/dev/null elif [[ -f "$REPO_ROOT/../scripts/lib/load-project-env.sh" ]]; then # shellcheck disable=SC1090 source "$REPO_ROOT/../scripts/lib/load-project-env.sh" >/dev/null fi APPLY=false CHAIN_FILTER="" while [[ $# -gt 0 ]]; do case "$1" in --apply) APPLY=true ;; --chain=*) CHAIN_FILTER="${1#*=}" ;; --chain) CHAIN_FILTER="${2:-}" shift ;; *) echo "Unknown arg: $1" >&2 echo "Usage: $0 [--apply] [--chain ]" >&2 exit 1 ;; esac shift done declare -A CHAIN_NAME=( [1]="Ethereum Mainnet" [10]="Optimism" [25]="Cronos" [56]="BSC" [100]="Gnosis" [137]="Polygon" [8453]="Base" [42161]="Arbitrum" [42220]="Celo" [43114]="Avalanche" ) declare -A CHAIN_SELECTOR=( [1]="5009297550715157269" [10]="3734403246176062136" [25]="1456215246176062136" [56]="11344663589394136015" [100]="465200170687744372" [137]="4051577828743386545" [8453]="15971525489660198786" [42161]="4949039107694359620" [42220]="1346049177634351622" [43114]="6433500567565415381" ) rpc_for_chain() { case "$1" in 1) echo "${MAINNET_RPC_URL:-${ETHEREUM_MAINNET_RPC:-${ETHEREUM_RPC_URL:-}}}" ;; 10) echo "${OPTIMISM_RPC_URL:-${OPTIMISM_MAINNET_RPC:-}}" ;; 25) echo "${CRONOS_RPC_URL:-}" ;; 56) echo "${BSC_RPC_URL:-${BSC_MAINNET_RPC:-}}" ;; 100) echo "${GNOSIS_RPC_URL:-${GNOSIS_MAINNET_RPC:-${GNOSIS_RPC:-}}}" ;; 137) echo "${POLYGON_RPC_URL:-${POLYGON_MAINNET_RPC:-}}" ;; 8453) echo "${BASE_RPC_URL:-${BASE_MAINNET_RPC:-}}" ;; 42161) echo "${ARBITRUM_RPC_URL:-${ARBITRUM_MAINNET_RPC:-}}" ;; 42220) echo "${CELO_RPC_URL:-}" ;; 43114) echo "${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-}}" ;; *) echo "" ;; esac } bridge_for_chain() { case "$1" in 1) echo "${CW_BRIDGE_MAINNET:-}" ;; 10) echo "${CW_BRIDGE_OPTIMISM:-}" ;; 25) echo "${CW_BRIDGE_CRONOS:-}" ;; 56) echo "${CW_BRIDGE_BSC:-}" ;; 100) echo "${CW_BRIDGE_GNOSIS:-}" ;; 137) echo "${CW_BRIDGE_POLYGON:-}" ;; 8453) echo "${CW_BRIDGE_BASE:-}" ;; 42161) echo "${CW_BRIDGE_ARBITRUM:-}" ;; 42220) echo "${CW_BRIDGE_CELO:-}" ;; 43114) echo "${CW_BRIDGE_AVALANCHE:-}" ;; *) echo "" ;; esac } probe_generation() { local bridge="$1" rpc="$2" if timeout 10 cast call "$bridge" 'sendRouter()(address)' --rpc-url "$rpc" >/dev/null 2>&1; then echo "new" return fi if timeout 10 cast call "$bridge" 'ccipRouter()(address)' --rpc-url "$rpc" >/dev/null 2>&1; then echo "old" return fi echo "unknown" } old_has_key() { local bridge="$1" rpc="$2" key="$3" local destinations destinations="$(timeout 12 cast call "$bridge" 'getDestinationChains()(uint64[])' --rpc-url "$rpc" 2>/dev/null || true)" [[ -z "$destinations" ]] && return 1 DESTINATIONS_PAYLOAD="$destinations" python3 - "$key" <<'PY' import re import os import sys target = sys.argv[1] payload = os.environ.get("DESTINATIONS_PAYLOAD", "") numbers = re.findall(r'\d+', payload) sys.exit(0 if target in numbers else 1) PY } new_read_destination() { local bridge="$1" rpc="$2" key="$3" timeout 12 cast call "$bridge" 'destinations(uint64)((address,bool))' "$key" --rpc-url "$rpc" 2>/dev/null || true } normalize_addr() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]' } new_matches() { local raw="$1" expected="$2" local lower_raw lower_expected lower_raw="$(normalize_addr "$raw")" lower_expected="$(normalize_addr "$expected")" [[ "$lower_raw" == *"$lower_expected"* && "$lower_raw" == *"true"* ]] } send_tx() { local rpc="$1" bridge="$2" signature="$3" shift 3 cast send "$bridge" "$signature" "$@" --rpc-url "$rpc" --private-key "$PRIVATE_KEY" } configure_old() { local source_chain="$1" target_key="$2" target_bridge="$3" local rpc bridge op rpc="$(rpc_for_chain "$source_chain")" bridge="$(bridge_for_chain "$source_chain")" if old_has_key "$bridge" "$rpc" "$target_key"; then op="updateDestination(uint64,address)" else op="addDestination(uint64,address)" fi if [[ "$APPLY" == true ]]; then send_tx "$rpc" "$bridge" "$op" "$target_key" "$target_bridge" else echo "DRY-RUN old chain=$source_chain key=$target_key bridge=$target_bridge op=$op" fi } configure_new() { local source_chain="$1" target_key="$2" target_bridge="$3" local rpc bridge raw rpc="$(rpc_for_chain "$source_chain")" bridge="$(bridge_for_chain "$source_chain")" raw="$(new_read_destination "$bridge" "$rpc" "$target_key")" if new_matches "$raw" "$target_bridge"; then echo "SKIP new chain=$source_chain key=$target_key already=$raw" return fi if [[ "$APPLY" == true ]]; then send_tx "$rpc" "$bridge" 'configureDestination(uint64,address,bool)' "$target_key" "$target_bridge" true else echo "DRY-RUN new chain=$source_chain key=$target_key bridge=$target_bridge" fi } configure_key() { local source_chain="$1" target_key="$2" target_bridge="$3" generation="$4" case "$generation" in old) configure_old "$source_chain" "$target_key" "$target_bridge" ;; new) configure_new "$source_chain" "$target_key" "$target_bridge" ;; *) echo "ERROR unknown generation for chain $source_chain" >&2 return 1 ;; esac } echo "Public cW bridge mesh configuration" echo "Apply mode: $APPLY" echo declare -A GENERATION=() for chain_id in 1 10 25 56 100 137 8453 42161 42220 43114; do [[ -n "$CHAIN_FILTER" && "$CHAIN_FILTER" != "$chain_id" ]] && continue rpc="$(rpc_for_chain "$chain_id")" bridge="$(bridge_for_chain "$chain_id")" if [[ -z "$rpc" || -z "$bridge" ]]; then echo "WARN chain=$chain_id missing rpc or bridge env; skipping" continue fi generation="$(probe_generation "$bridge" "$rpc")" GENERATION["$chain_id"]="$generation" echo "chain=$chain_id name='${CHAIN_NAME[$chain_id]}' generation=$generation bridge=$bridge" done echo for source_chain in 1 10 25 56 100 137 8453 42161 42220 43114; do [[ -n "$CHAIN_FILTER" && "$CHAIN_FILTER" != "$source_chain" ]] && continue [[ -z "${GENERATION[$source_chain]:-}" ]] && continue for target_chain in 1 10 25 56 100 137 8453 42161 42220 43114; do [[ "$source_chain" == "$target_chain" ]] && continue target_bridge="$(bridge_for_chain "$target_chain")" [[ -z "$target_bridge" ]] && continue # Outbound path on source uses the target CCIP selector. configure_key "$source_chain" "${CHAIN_SELECTOR[$target_chain]}" "$target_bridge" "${GENERATION[$source_chain]}" # Inbound receive path on source uses the remote public chain id. configure_key "$source_chain" "$target_chain" "$target_bridge" "${GENERATION[$source_chain]}" done done echo echo "Done."