- 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
317 lines
11 KiB
Bash
Executable File
317 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Wire one generic Chain 138 canonical c* asset to its cW* mirror on a public chain.
|
|
# Dry-run by default; pass --execute to broadcast writes.
|
|
#
|
|
# Examples:
|
|
# ./scripts/deployment/configure-cstar-cw-bridge-pair.sh --chain MAINNET --asset cUSDT
|
|
# ./scripts/deployment/configure-cstar-cw-bridge-pair.sh --chain POLYGON --asset cWEURC --freeze --execute
|
|
# ./scripts/deployment/configure-cstar-cw-bridge-pair.sh --chain AVALANCHE --asset cUSDC --max-outstanding 1000000000000 --freeze --execute
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138"
|
|
CONFIG_FILE="${PROJECT_ROOT}/config/token-mapping-multichain.json"
|
|
|
|
CHAIN=""
|
|
ASSET=""
|
|
MAX_OUTSTANDING=""
|
|
FREEZE=false
|
|
EXECUTE=false
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
./scripts/deployment/configure-cstar-cw-bridge-pair.sh --chain <CHAIN> --asset <c*> [options]
|
|
|
|
Required:
|
|
--chain <CHAIN> MAINNET | CRONOS | BSC | POLYGON | GNOSIS | AVALANCHE | BASE | ARBITRUM | OPTIMISM | CELO | ALL
|
|
--asset <c*> cUSDT | cUSDC | cAUSDT | cUSDW | cEURC | cEURT | cGBPC | cGBPT | cAUDC | cJPYC | cCHFC | cCADC | cXAUC | cXAUT
|
|
|
|
Options:
|
|
--max-outstanding <raw> Set L1 maxOutstanding(canonical, selector, rawAmount)
|
|
--freeze Freeze the L2 token pair and the 138 destination after wiring
|
|
--execute Broadcast writes; default is dry-run
|
|
--help Show this message
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--chain) CHAIN="${2:-}"; shift 2 ;;
|
|
--asset) ASSET="${2:-}"; shift 2 ;;
|
|
--max-outstanding) MAX_OUTSTANDING="${2:-}"; shift 2 ;;
|
|
--freeze) FREEZE=true; shift ;;
|
|
--execute) EXECUTE=true; shift ;;
|
|
--help|-h) usage; exit 0 ;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$CHAIN" && -n "$ASSET" ]] || { usage >&2; exit 2; }
|
|
|
|
if [[ -f "${SMOM_ROOT}/scripts/lib/deployment/dotenv.sh" ]]; then
|
|
# shellcheck disable=SC1090
|
|
source "${SMOM_ROOT}/scripts/lib/deployment/dotenv.sh"
|
|
load_deployment_env --repo-root "$SMOM_ROOT"
|
|
else
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
source "${SMOM_ROOT}/.env"
|
|
set +a
|
|
fi
|
|
|
|
command -v cast >/dev/null 2>&1 || { echo "cast (foundry) required" >&2; exit 1; }
|
|
command -v node >/dev/null 2>&1 || { echo "node required" >&2; exit 1; }
|
|
|
|
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY required in ${SMOM_ROOT}/.env" >&2; exit 1; }
|
|
[[ -f "$CONFIG_FILE" ]] || { echo "Missing $CONFIG_FILE" >&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
|
|
[ALL]=651940
|
|
)
|
|
|
|
declare -A CHAIN_NAME_TO_SELECTOR_VAR=(
|
|
[MAINNET]=ETH_MAINNET_SELECTOR
|
|
[CRONOS]=CRONOS_SELECTOR
|
|
[BSC]=BSC_SELECTOR
|
|
[POLYGON]=POLYGON_SELECTOR
|
|
[GNOSIS]=GNOSIS_SELECTOR
|
|
[AVALANCHE]=AVALANCHE_SELECTOR
|
|
[BASE]=BASE_SELECTOR
|
|
[ARBITRUM]=ARBITRUM_SELECTOR
|
|
[OPTIMISM]=OPTIMISM_SELECTOR
|
|
[CELO]=CELO_SELECTOR
|
|
)
|
|
|
|
declare -A ASSET_TO_MAPPING_KEY=(
|
|
[cUSDT]=Compliant_USDT_cW
|
|
[cUSDC]=Compliant_USDC_cW
|
|
[cAUSDT]=Compliant_AUSDT_cW
|
|
[cUSDW]=Compliant_USDW_cW
|
|
[cEURC]=Compliant_EURC_cW
|
|
[cEURT]=Compliant_EURT_cW
|
|
[cGBPC]=Compliant_GBPC_cW
|
|
[cGBPT]=Compliant_GBPT_cW
|
|
[cAUDC]=Compliant_AUDC_cW
|
|
[cJPYC]=Compliant_JPYC_cW
|
|
[cCHFC]=Compliant_CHFC_cW
|
|
[cCADC]=Compliant_CADC_cW
|
|
[cXAUC]=Compliant_XAUC_cW
|
|
[cXAUT]=Compliant_XAUT_cW
|
|
)
|
|
|
|
declare -A ASSET_TO_CW_PREFIX=(
|
|
[cUSDT]=CWUSDT
|
|
[cUSDC]=CWUSDC
|
|
[cAUSDT]=CWAUSDT
|
|
[cUSDW]=CWUSDW
|
|
[cEURC]=CWEURC
|
|
[cEURT]=CWEURT
|
|
[cGBPC]=CWGBPC
|
|
[cGBPT]=CWGBPT
|
|
[cAUDC]=CWAUDC
|
|
[cJPYC]=CWJPYC
|
|
[cCHFC]=CWCHFC
|
|
[cCADC]=CWCADC
|
|
[cXAUC]=CWXAUC
|
|
[cXAUT]=CWXAUT
|
|
)
|
|
|
|
chain_id="${CHAIN_NAME_TO_ID[$CHAIN]:-}"
|
|
[[ -n "$chain_id" ]] || { echo "Unsupported chain: $CHAIN" >&2; exit 2; }
|
|
|
|
mapping_key="${ASSET_TO_MAPPING_KEY[$ASSET]:-}"
|
|
cw_prefix="${ASSET_TO_CW_PREFIX[$ASSET]:-}"
|
|
[[ -n "$mapping_key" && -n "$cw_prefix" ]] || { echo "Unsupported asset: $ASSET" >&2; exit 2; }
|
|
|
|
selector_var="${CHAIN_NAME_TO_SELECTOR_VAR[$CHAIN]:-}"
|
|
selector="${selector_var:+${!selector_var:-}}"
|
|
if [[ "$CHAIN" != "ALL" && -z "$selector" ]]; then
|
|
echo "Missing selector env for $CHAIN ($selector_var)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
resolve_chain_rpc() {
|
|
case "$1" in
|
|
MAINNET) printf '%s' "${ETH_MAINNET_RPC_URL:-${ETHEREUM_MAINNET_RPC:-}}" ;;
|
|
CRONOS) printf '%s' "${CRONOS_RPC_URL:-${CRONOS_RPC:-}}" ;;
|
|
BSC) printf '%s' "${BSC_RPC_URL:-}" ;;
|
|
POLYGON) printf '%s' "${POLYGON_MAINNET_RPC:-${POLYGON_RPC_URL:-}}" ;;
|
|
GNOSIS) printf '%s' "${GNOSIS_RPC:-${GNOSIS_MAINNET_RPC:-}}" ;;
|
|
AVALANCHE) printf '%s' "${AVALANCHE_RPC_URL:-}" ;;
|
|
BASE) printf '%s' "${BASE_MAINNET_RPC:-}" ;;
|
|
ARBITRUM) printf '%s' "${ARBITRUM_MAINNET_RPC:-${ARBITRUM_MAINNET_RPC_URL:-${ARBITRUM_RPC_URL:-}}}" ;;
|
|
OPTIMISM) printf '%s' "${OPTIMISM_MAINNET_RPC:-}" ;;
|
|
CELO) printf '%s' "${CELO_RPC:-${CELO_MAINNET_RPC:-}}" ;;
|
|
ALL) printf '%s' "${ALL_MAINNET_RPC_URL:-${ALL_RPC_URL:-}}" ;;
|
|
*) printf '' ;;
|
|
esac
|
|
}
|
|
|
|
CHAIN_RPC="$(resolve_chain_rpc "$CHAIN")"
|
|
[[ -n "${RPC_URL_138:-}" ]] || { echo "RPC_URL_138 required" >&2; exit 1; }
|
|
[[ -n "$CHAIN_RPC" ]] || { echo "Missing RPC for $CHAIN" >&2; exit 1; }
|
|
|
|
CHAIN138_L1_BRIDGE="${CW_L1_BRIDGE_CHAIN138:-${CHAIN138_L1_BRIDGE:-}}"
|
|
[[ -n "$CHAIN138_L1_BRIDGE" ]] || { echo "Set CW_L1_BRIDGE_CHAIN138 (or CHAIN138_L1_BRIDGE) in .env" >&2; exit 1; }
|
|
|
|
CW_BRIDGE_VAR="CW_BRIDGE_${CHAIN}"
|
|
CHAIN_L2_BRIDGE="${!CW_BRIDGE_VAR:-}"
|
|
[[ -n "$CHAIN_L2_BRIDGE" ]] || { echo "Set ${CW_BRIDGE_VAR} in .env" >&2; exit 1; }
|
|
|
|
MIRRORED_ENV_VAR="${cw_prefix}_${CHAIN}"
|
|
MIRRORED_ADDRESS_VAR="${cw_prefix}_ADDRESS_${chain_id}"
|
|
CHAIN_MIRRORED_TOKEN="${!MIRRORED_ENV_VAR:-${!MIRRORED_ADDRESS_VAR:-}}"
|
|
|
|
map_info="$(
|
|
node - <<'NODE' "$CONFIG_FILE" "$chain_id" "$mapping_key"
|
|
const fs = require('fs');
|
|
const [configFile, chainIdRaw, mappingKey] = process.argv.slice(2);
|
|
const chainId = Number(chainIdRaw);
|
|
const json = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
const pair = (json.pairs || []).find((entry) => entry.fromChainId === 138 && entry.toChainId === chainId);
|
|
if (!pair) {
|
|
process.exit(10);
|
|
}
|
|
const token = (pair.tokens || []).find((entry) => entry.key === mappingKey);
|
|
if (!token) {
|
|
process.exit(11);
|
|
}
|
|
process.stdout.write([
|
|
token.addressFrom || '',
|
|
token.addressTo || '',
|
|
token.name || '',
|
|
pair.notes || ''
|
|
].join('\n'));
|
|
NODE
|
|
)" || {
|
|
echo "Failed to resolve $ASSET / $CHAIN from $CONFIG_FILE" >&2
|
|
exit 1
|
|
}
|
|
|
|
canonical_address="$(sed -n '1p' <<<"$map_info")"
|
|
mapping_mirrored_address="$(sed -n '2p' <<<"$map_info")"
|
|
mapping_name="$(sed -n '3p' <<<"$map_info")"
|
|
|
|
[[ -n "$canonical_address" && "$canonical_address" != "0x0000000000000000000000000000000000000000" ]] || {
|
|
echo "Canonical address missing for $ASSET -> $CHAIN in $CONFIG_FILE" >&2
|
|
exit 1
|
|
}
|
|
|
|
if [[ -z "$CHAIN_MIRRORED_TOKEN" || "$CHAIN_MIRRORED_TOKEN" == "0x0000000000000000000000000000000000000000" ]]; then
|
|
if [[ -n "$mapping_mirrored_address" && "$mapping_mirrored_address" != "0x0000000000000000000000000000000000000000" ]]; then
|
|
CHAIN_MIRRORED_TOKEN="$mapping_mirrored_address"
|
|
else
|
|
echo "Mirrored token for $ASSET on $CHAIN is not configured in .env or $CONFIG_FILE" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
send_cast() {
|
|
local rpc="$1"
|
|
local to="$2"
|
|
local sig="$3"
|
|
shift 3
|
|
if $EXECUTE; then
|
|
cast send "$to" "$sig" "$@" --rpc-url "$rpc" --private-key "$PRIVATE_KEY" --legacy
|
|
else
|
|
printf 'cast send %q %q' "$to" "$sig"
|
|
for arg in "$@"; do
|
|
printf ' %q' "$arg"
|
|
done
|
|
printf ' --rpc-url %q --private-key "$PRIVATE_KEY" --legacy\n' "$rpc"
|
|
fi
|
|
}
|
|
|
|
read_struct_field() {
|
|
local value="$1"
|
|
tr '\n' ' ' <<<"$value" | xargs 2>/dev/null || true
|
|
}
|
|
|
|
pair_current="$(cast call "$CHAIN_L2_BRIDGE" "canonicalToMirrored(address)(address)" "$canonical_address" --rpc-url "$CHAIN_RPC" 2>/dev/null || true)"
|
|
l1_dest_current="$(cast call "$CHAIN138_L1_BRIDGE" "destinations(address,uint64)((address,bool))" "$canonical_address" "${selector:-0}" --rpc-url "$RPC_URL_138" 2>/dev/null || true)"
|
|
l2_dest_current="$(cast call "$CHAIN_L2_BRIDGE" "destinations(uint64)((address,bool))" 138 --rpc-url "$CHAIN_RPC" 2>/dev/null || true)"
|
|
allowlisted_current="$(cast call "$CHAIN138_L1_BRIDGE" "supportedCanonicalToken(address)(bool)" "$canonical_address" --rpc-url "$RPC_URL_138" 2>/dev/null || true)"
|
|
freeze_pair_current="$(cast call "$CHAIN_L2_BRIDGE" "tokenPairFrozen(address)(bool)" "$canonical_address" --rpc-url "$CHAIN_RPC" 2>/dev/null || true)"
|
|
freeze_dest_current="$(cast call "$CHAIN_L2_BRIDGE" "destinationFrozen(uint64)(bool)" 138 --rpc-url "$CHAIN_RPC" 2>/dev/null || true)"
|
|
|
|
echo "=== Generic c* -> cW* bridge wiring ==="
|
|
echo "Chain: $CHAIN (chainId $chain_id)"
|
|
echo "Asset: $ASSET"
|
|
echo "Mapping key: $mapping_key"
|
|
echo "Lane: $mapping_name"
|
|
echo "Canonical (138): $canonical_address"
|
|
echo "Mirrored ($CHAIN): $CHAIN_MIRRORED_TOKEN"
|
|
echo "L1 bridge: $CHAIN138_L1_BRIDGE"
|
|
echo "L2 bridge: $CHAIN_L2_BRIDGE"
|
|
if [[ -n "$selector" ]]; then
|
|
echo "Chain selector: $selector"
|
|
fi
|
|
echo "Mode: $([[ "$EXECUTE" == "true" ]] && echo "execute" || echo "dry-run")"
|
|
echo
|
|
|
|
echo "Current state:"
|
|
echo " L2 canonicalToMirrored: $(read_struct_field "$pair_current")"
|
|
echo " L1 destinations(): $(read_struct_field "$l1_dest_current")"
|
|
echo " L2 destinations(138): $(read_struct_field "$l2_dest_current")"
|
|
echo " L1 allowlisted: ${allowlisted_current:-unavailable}"
|
|
if [[ -n "$MAX_OUTSTANDING" ]]; then
|
|
current_max="$(cast call "$CHAIN138_L1_BRIDGE" "maxOutstanding(address,uint64)(uint256)" "$canonical_address" "${selector:-0}" --rpc-url "$RPC_URL_138" 2>/dev/null || true)"
|
|
echo " L1 maxOutstanding: ${current_max:-unavailable}"
|
|
fi
|
|
echo " L2 tokenPairFrozen: ${freeze_pair_current:-unavailable}"
|
|
echo " L2 destinationFrozen: ${freeze_dest_current:-unavailable}"
|
|
echo
|
|
|
|
echo "Planned actions:"
|
|
echo "1. Configure L2 token pair"
|
|
send_cast "$CHAIN_RPC" "$CHAIN_L2_BRIDGE" "configureTokenPair(address,address)" "$canonical_address" "$CHAIN_MIRRORED_TOKEN"
|
|
|
|
if [[ "$CHAIN" != "ALL" ]]; then
|
|
echo "2. Configure L1 destination to L2 bridge"
|
|
send_cast "$RPC_URL_138" "$CHAIN138_L1_BRIDGE" "configureDestination(address,uint64,address,bool)" "$canonical_address" "$selector" "$CHAIN_L2_BRIDGE" true
|
|
|
|
echo "3. Configure L2 destination back to Chain 138"
|
|
send_cast "$CHAIN_RPC" "$CHAIN_L2_BRIDGE" "configureDestination(uint64,address,bool)" 138 "$CHAIN138_L1_BRIDGE" true
|
|
else
|
|
echo "2. ALL Mainnet uses a non-CCIP adapter lane; no selector-driven CWMultiTokenBridge destination writes were generated."
|
|
fi
|
|
|
|
echo "4. Allowlist canonical token on L1"
|
|
send_cast "$RPC_URL_138" "$CHAIN138_L1_BRIDGE" "configureSupportedCanonicalToken(address,bool)" "$canonical_address" true
|
|
|
|
if [[ -n "$MAX_OUTSTANDING" && "$CHAIN" != "ALL" ]]; then
|
|
echo "5. Set L1 maxOutstanding"
|
|
send_cast "$RPC_URL_138" "$CHAIN138_L1_BRIDGE" "setMaxOutstanding(address,uint64,uint256)" "$canonical_address" "$selector" "$MAX_OUTSTANDING"
|
|
fi
|
|
|
|
if $FREEZE && [[ "$CHAIN" != "ALL" ]]; then
|
|
echo "6. Freeze L2 token pair"
|
|
send_cast "$CHAIN_RPC" "$CHAIN_L2_BRIDGE" "freezeTokenPair(address)" "$canonical_address"
|
|
|
|
echo "7. Freeze L2 destination back to Chain 138"
|
|
send_cast "$CHAIN_RPC" "$CHAIN_L2_BRIDGE" "freezeDestination(uint64)" 138
|
|
fi
|
|
|
|
echo
|
|
if ! $EXECUTE; then
|
|
echo "Dry-run only. Re-run with --execute to broadcast."
|
|
fi
|