#!/usr/bin/env bash set -euo pipefail # Replace a legacy Mainnet public DODO cW/USD pool in the integration mapping, # create a canonical factory-backed replacement, and seed it with matched liquidity. # # Example: # bash scripts/deployment/replace-mainnet-public-dodo-cw-pool.sh \ # --pair=cwusdc-usdc \ # --initial-price=1000000000000000000 \ # --base-amount=100000000 \ # --quote-amount=100000000 \ # --dry-run SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" source "${PROJECT_ROOT}/smom-dbis-138/scripts/load-env.sh" >/dev/null 2>&1 require_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "[fail] missing required command: $1" >&2 exit 1 } } uint_lt() { python3 - "$1" "$2" <<'PY' import sys print("1" if int(sys.argv[1]) < int(sys.argv[2]) else "0") PY } require_cmd cast PAIR="" INITIAL_PRICE="" BASE_AMOUNT="" QUOTE_AMOUNT="" FEE_BPS="3" K_VALUE="0" OPEN_TWAP="false" DRY_RUN=0 for arg in "$@"; do case "$arg" in --pair=*) PAIR="${arg#*=}" ;; --initial-price=*) INITIAL_PRICE="${arg#*=}" ;; --base-amount=*) BASE_AMOUNT="${arg#*=}" ;; --quote-amount=*) QUOTE_AMOUNT="${arg#*=}" ;; --fee-bps=*) FEE_BPS="${arg#*=}" ;; --k=*) K_VALUE="${arg#*=}" ;; --open-twap=*) OPEN_TWAP="${arg#*=}" ;; --dry-run) DRY_RUN=1 ;; *) echo "[fail] unknown arg: $arg" >&2 exit 2 ;; esac done if [[ -z "$PAIR" || -z "$INITIAL_PRICE" || -z "$BASE_AMOUNT" || -z "$QUOTE_AMOUNT" ]]; then echo "[fail] required args: --pair, --initial-price, --base-amount, --quote-amount" >&2 exit 1 fi RPC_URL="${ETHEREUM_MAINNET_RPC:-}" PRIVATE_KEY="${PRIVATE_KEY:-}" INTEGRATION="${DODO_PMM_INTEGRATION_MAINNET:-}" USDC_MAINNET="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" USDT_MAINNET="0xdAC17F958D2ee523a2206206994597C13D831ec7" if [[ -z "$RPC_URL" || -z "$PRIVATE_KEY" || -z "$INTEGRATION" ]]; then echo "[fail] ETHEREUM_MAINNET_RPC, PRIVATE_KEY, and DODO_PMM_INTEGRATION_MAINNET are required" >&2 exit 1 fi DEPLOYER="$(cast wallet address --private-key "$PRIVATE_KEY")" BASE_TOKEN="" QUOTE_TOKEN="" LEGACY_POOL="" PAIR_LABEL="" ENV_KEY="" case "$PAIR" in cwusdc-usdc) BASE_TOKEN="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}" QUOTE_TOKEN="$USDC_MAINNET" LEGACY_POOL="${POOL_CWUSDC_USDC_MAINNET:-0xB227dDA4e89E2EA63A1345509C9AC02644e8d526}" PAIR_LABEL="cWUSDC/USDC" ENV_KEY="POOL_CWUSDC_USDC_MAINNET" ;; cwusdt-usdc) BASE_TOKEN="${CWUSDT_MAINNET:-0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE}" QUOTE_TOKEN="$USDC_MAINNET" LEGACY_POOL="${POOL_CWUSDT_USDC_MAINNET:-0x27f3aE7EE71Be3d77bAf17d4435cF8B895DD25D2}" PAIR_LABEL="cWUSDT/USDC" ENV_KEY="POOL_CWUSDT_USDC_MAINNET" ;; cwusdt-usdt) BASE_TOKEN="${CWUSDT_MAINNET:-0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE}" QUOTE_TOKEN="$USDT_MAINNET" LEGACY_POOL="${POOL_CWUSDT_USDT_MAINNET:-0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC}" PAIR_LABEL="cWUSDT/USDT" ENV_KEY="POOL_CWUSDT_USDT_MAINNET" ;; cwusdc-usdt) BASE_TOKEN="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}" QUOTE_TOKEN="$USDT_MAINNET" LEGACY_POOL="${POOL_CWUSDC_USDT_MAINNET:-0xCC0fd27A40775c9AfcD2BBd3f7c902b0192c247A}" PAIR_LABEL="cWUSDC/USDT" ENV_KEY="POOL_CWUSDC_USDT_MAINNET" ;; *) echo "[fail] unsupported pair: $PAIR" >&2 exit 2 ;; esac bool_to_cli() { if [[ "$1" == "true" ]]; then printf 'true' else printf 'false' fi } parse_tx_hash() { local output="$1" local tx_hash tx_hash="$(printf '%s\n' "$output" | grep -E '^0x[0-9a-fA-F]{64}$' | tail -n1 || true)" if [[ -z "$tx_hash" ]]; then tx_hash="$(printf '%s\n' "$output" | grep -E '^transactionHash[[:space:]]+0x[0-9a-fA-F]{64}$' | awk '{print $2}' | tail -n1 || true)" fi if [[ -z "$tx_hash" ]]; then return 1 fi printf '%s\n' "$tx_hash" } mapped_pool_before="$(cast call "$INTEGRATION" 'pools(address,address)(address)' "$BASE_TOKEN" "$QUOTE_TOKEN" --rpc-url "$RPC_URL" | awk '{print $1}')" base_balance_before="$(cast call "$BASE_TOKEN" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL" | awk '{print $1}')" quote_balance_before="$(cast call "$QUOTE_TOKEN" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL" | awk '{print $1}')" base_allowance_before="$(cast call "$BASE_TOKEN" 'allowance(address,address)(uint256)' "$DEPLOYER" "$INTEGRATION" --rpc-url "$RPC_URL" | awk '{print $1}')" quote_allowance_before="$(cast call "$QUOTE_TOKEN" 'allowance(address,address)(uint256)' "$DEPLOYER" "$INTEGRATION" --rpc-url "$RPC_URL" | awk '{print $1}')" base_approval_required="$(uint_lt "$base_allowance_before" "$BASE_AMOUNT")" quote_approval_required="$(uint_lt "$quote_allowance_before" "$QUOTE_AMOUNT")" if (( base_balance_before < BASE_AMOUNT )); then echo "[fail] insufficient base balance: have=$base_balance_before need=$BASE_AMOUNT" >&2 exit 1 fi if (( quote_balance_before < QUOTE_AMOUNT )); then echo "[fail] insufficient quote balance: have=$quote_balance_before need=$QUOTE_AMOUNT" >&2 exit 1 fi remove_gas="$(cast estimate --from "$DEPLOYER" "$INTEGRATION" 'removePool(address)' "$LEGACY_POOL" --rpc-url "$RPC_URL")" create_gas="post-remove estimate not available while current mapping exists" if (( DRY_RUN == 1 )); then echo "pair=$PAIR_LABEL" echo "envKey=$ENV_KEY" echo "legacyPool=$LEGACY_POOL" echo "mappedPoolBefore=$mapped_pool_before" echo "baseToken=$BASE_TOKEN" echo "quoteToken=$QUOTE_TOKEN" echo "initialPrice=$INITIAL_PRICE" echo "feeBps=$FEE_BPS" echo "k=$K_VALUE" echo "openTwap=$OPEN_TWAP" echo "baseAmount=$BASE_AMOUNT" echo "quoteAmount=$QUOTE_AMOUNT" echo "removeGas=$remove_gas" echo "createGas=$create_gas" echo "baseBalanceBefore=$base_balance_before" echo "quoteBalanceBefore=$quote_balance_before" echo "baseAllowanceBefore=$base_allowance_before" echo "quoteAllowanceBefore=$quote_allowance_before" exit 0 fi remove_output="$( cast send "$INTEGRATION" \ 'removePool(address)' \ "$LEGACY_POOL" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" remove_tx="$(parse_tx_hash "$remove_output")" create_output="$( cast send "$INTEGRATION" \ 'createPool(address,address,uint256,uint256,uint256,bool)(address)' \ "$BASE_TOKEN" "$QUOTE_TOKEN" "$FEE_BPS" "$INITIAL_PRICE" "$K_VALUE" "$(bool_to_cli "$OPEN_TWAP")" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" create_tx="$(parse_tx_hash "$create_output")" new_pool="$(cast call "$INTEGRATION" 'pools(address,address)(address)' "$BASE_TOKEN" "$QUOTE_TOKEN" --rpc-url "$RPC_URL" | awk '{print $1}')" if [[ "$new_pool" == "0x0000000000000000000000000000000000000000" ]]; then echo "[fail] replacement pool mapping is empty after createPool" >&2 exit 1 fi approve_base_tx="" approve_quote_tx="" if [[ "$base_approval_required" == "1" ]]; then approve_base_output="$( cast send "$BASE_TOKEN" \ 'approve(address,uint256)(bool)' \ "$INTEGRATION" "$BASE_AMOUNT" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" approve_base_tx="$(parse_tx_hash "$approve_base_output")" fi if [[ "$quote_approval_required" == "1" ]]; then approve_quote_output="$( cast send "$QUOTE_TOKEN" \ 'approve(address,uint256)(bool)' \ "$INTEGRATION" "$QUOTE_AMOUNT" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" approve_quote_tx="$(parse_tx_hash "$approve_quote_output")" fi add_output="$( cast send "$INTEGRATION" \ 'addLiquidity(address,uint256,uint256)(uint256,uint256,uint256)' \ "$new_pool" "$BASE_AMOUNT" "$QUOTE_AMOUNT" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" add_liquidity_tx="$(parse_tx_hash "$add_output")" reserves_after="$(cast call "$new_pool" 'getVaultReserve()(uint256,uint256)' --rpc-url "$RPC_URL")" base_reserve_after="$(printf '%s\n' "$reserves_after" | sed -n '1p' | awk '{print $1}')" quote_reserve_after="$(printf '%s\n' "$reserves_after" | sed -n '2p' | awk '{print $1}')" base_balance_after="$(cast call "$BASE_TOKEN" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL" | awk '{print $1}')" quote_balance_after="$(cast call "$QUOTE_TOKEN" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL" | awk '{print $1}')" echo "pair=$PAIR_LABEL" echo "envKey=$ENV_KEY" echo "legacyPool=$LEGACY_POOL" echo "newPool=$new_pool" echo "removeTx=$remove_tx" echo "createTx=$create_tx" echo "approveBaseTx=${approve_base_tx:-none}" echo "approveQuoteTx=${approve_quote_tx:-none}" echo "addLiquidityTx=$add_liquidity_tx" echo "baseReserveAfter=$base_reserve_after" echo "quoteReserveAfter=$quote_reserve_after" echo "baseBalanceBefore=$base_balance_before" echo "baseBalanceAfter=$base_balance_after" echo "quoteBalanceBefore=$quote_balance_before" echo "quoteBalanceAfter=$quote_balance_after"