#!/usr/bin/env bash set -euo pipefail # Deploy and seed a first-tier Mainnet DODO PMM Wave 1 cW*/USDC pool. # # Amount arguments are base units (6 decimals for the current cW* / USDC suite). # # Example: # bash scripts/deployment/deploy-mainnet-public-dodo-wave1-pool.sh \ # --pair=cweurc-usdc \ # --initial-price=1151700000000000000 \ # --base-amount=1250000 \ # --quote-amount=1439625 \ # --mint-base-amount=1300000 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="" MINT_BASE_AMOUNT="0" FEE_BPS="10" 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#*=}" ;; --mint-base-amount=*) MINT_BASE_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" 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_SYMBOL="" BASE_TOKEN="" POOL_ENV_KEY="" PAIR_LABEL="" case "$PAIR" in cweurc-usdc) BASE_SYMBOL="cWEURC" BASE_TOKEN="${CWEURC_MAINNET:-}" POOL_ENV_KEY="POOL_CWEURC_USDC_MAINNET" PAIR_LABEL="cWEURC/USDC" ;; cweurt-usdc) BASE_SYMBOL="cWEURT" BASE_TOKEN="${CWEURT_MAINNET:-}" POOL_ENV_KEY="POOL_CWEURT_USDC_MAINNET" PAIR_LABEL="cWEURT/USDC" ;; cwgbpc-usdc) BASE_SYMBOL="cWGBPC" BASE_TOKEN="${CWGBPC_MAINNET:-}" POOL_ENV_KEY="POOL_CWGBPC_USDC_MAINNET" PAIR_LABEL="cWGBPC/USDC" ;; cwgbpt-usdc) BASE_SYMBOL="cWGBPT" BASE_TOKEN="${CWGBPT_MAINNET:-}" POOL_ENV_KEY="POOL_CWGBPT_USDC_MAINNET" PAIR_LABEL="cWGBPT/USDC" ;; cwaudc-usdc) BASE_SYMBOL="cWAUDC" BASE_TOKEN="${CWAUDC_MAINNET:-}" POOL_ENV_KEY="POOL_CWAUDC_USDC_MAINNET" PAIR_LABEL="cWAUDC/USDC" ;; cwjpyc-usdc) BASE_SYMBOL="cWJPYC" BASE_TOKEN="${CWJPYC_MAINNET:-}" POOL_ENV_KEY="POOL_CWJPYC_USDC_MAINNET" PAIR_LABEL="cWJPYC/USDC" ;; cwchfc-usdc) BASE_SYMBOL="cWCHFC" BASE_TOKEN="${CWCHFC_MAINNET:-}" POOL_ENV_KEY="POOL_CWCHFC_USDC_MAINNET" PAIR_LABEL="cWCHFC/USDC" ;; cwcadc-usdc) BASE_SYMBOL="cWCADC" BASE_TOKEN="${CWCADC_MAINNET:-}" POOL_ENV_KEY="POOL_CWCADC_USDC_MAINNET" PAIR_LABEL="cWCADC/USDC" ;; cwxauc-usdc) BASE_SYMBOL="cWXAUC" BASE_TOKEN="${CWXAUC_MAINNET:-}" POOL_ENV_KEY="POOL_CWXAUC_USDC_MAINNET" PAIR_LABEL="cWXAUC/USDC" ;; cwxaut-usdc) BASE_SYMBOL="cWXAUT" BASE_TOKEN="${CWXAUT_MAINNET:-}" POOL_ENV_KEY="POOL_CWXAUT_USDC_MAINNET" PAIR_LABEL="cWXAUT/USDC" ;; *) echo "[fail] unsupported pair: $PAIR" >&2 exit 2 ;; esac if [[ -z "$BASE_TOKEN" ]]; then echo "[fail] base token address missing in .env for pair: $PAIR" >&2 exit 1 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" } bool_to_cli() { if [[ "$1" == "true" ]]; then printf 'true' else printf 'false' fi } existing_pool="$(cast call "$INTEGRATION" 'pools(address,address)(address)' "$BASE_TOKEN" "$USDC_MAINNET" --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 "$USDC_MAINNET" '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 "$USDC_MAINNET" '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")" create_gas="0" if [[ "$existing_pool" == "0x0000000000000000000000000000000000000000" ]]; then create_gas="$(cast estimate "$INTEGRATION" \ 'createPool(address,address,uint256,uint256,uint256,bool)(address)' \ "$BASE_TOKEN" "$USDC_MAINNET" "$FEE_BPS" "$INITIAL_PRICE" "$K_VALUE" "$(bool_to_cli "$OPEN_TWAP")" \ --from "$DEPLOYER" \ --rpc-url "$RPC_URL")" fi if (( base_balance_before < BASE_AMOUNT )); then base_balance_after_mint=$(( base_balance_before + MINT_BASE_AMOUNT )) if (( MINT_BASE_AMOUNT == 0 || base_balance_after_mint < BASE_AMOUNT )); then echo "[fail] insufficient ${BASE_SYMBOL} balance: have=$base_balance_before need=$BASE_AMOUNT mint_base_amount=$MINT_BASE_AMOUNT" >&2 exit 1 fi fi if (( quote_balance_before < QUOTE_AMOUNT )); then echo "[fail] insufficient USDC balance: have=$quote_balance_before need=$QUOTE_AMOUNT" >&2 exit 1 fi if (( DRY_RUN == 1 )); then echo "pair=$PAIR_LABEL" echo "baseToken=$BASE_TOKEN" echo "quoteToken=$USDC_MAINNET" echo "integration=$INTEGRATION" echo "existingPool=$existing_pool" echo "poolEnvKey=$POOL_ENV_KEY" echo "initialPrice=$INITIAL_PRICE" echo "feeBps=$FEE_BPS" echo "k=$K_VALUE" echo "openTwap=$OPEN_TWAP" echo "createGas=$create_gas" echo "baseAmount=$BASE_AMOUNT" echo "quoteAmount=$QUOTE_AMOUNT" echo "mintBaseAmount=$MINT_BASE_AMOUNT" echo "baseBalanceBefore=$base_balance_before" echo "quoteBalanceBefore=$quote_balance_before" echo "baseAllowanceBefore=$base_allowance_before" echo "quoteAllowanceBefore=$quote_allowance_before" exit 0 fi mint_tx="" create_tx="" approve_base_tx="" approve_quote_tx="" add_liquidity_tx="" if (( MINT_BASE_AMOUNT > 0 )); then mint_output="$( cast send "$BASE_TOKEN" \ 'mint(address,uint256)' \ "$DEPLOYER" "$MINT_BASE_AMOUNT" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" mint_tx="$(parse_tx_hash "$mint_output")" fi if [[ "$existing_pool" == "0x0000000000000000000000000000000000000000" ]]; then create_output="$( cast send "$INTEGRATION" \ 'createPool(address,address,uint256,uint256,uint256,bool)(address)' \ "$BASE_TOKEN" "$USDC_MAINNET" "$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")" existing_pool="$(cast call "$INTEGRATION" 'pools(address,address)(address)' "$BASE_TOKEN" "$USDC_MAINNET" --rpc-url "$RPC_URL" | awk '{print $1}')" fi if [[ "$existing_pool" == "0x0000000000000000000000000000000000000000" ]]; then echo "[fail] pool creation did not yield a pool address" >&2 exit 1 fi 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 "$USDC_MAINNET" \ '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_liquidity_output="$( cast send "$INTEGRATION" \ 'addLiquidity(address,uint256,uint256)(uint256,uint256,uint256)' \ "$existing_pool" "$BASE_AMOUNT" "$QUOTE_AMOUNT" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" )" add_liquidity_tx="$(parse_tx_hash "$add_liquidity_output")" reserves="$(cast call "$existing_pool" 'getVaultReserve()(uint256,uint256)' --rpc-url "$RPC_URL")" base_reserve="$(printf '%s\n' "$reserves" | sed -n '1p' | awk '{print $1}')" quote_reserve="$(printf '%s\n' "$reserves" | 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 "$USDC_MAINNET" 'balanceOf(address)(uint256)' "$DEPLOYER" --rpc-url "$RPC_URL" | awk '{print $1}')" echo "pair=$PAIR_LABEL" echo "poolEnvKey=$POOL_ENV_KEY" echo "pool=$existing_pool" echo "baseToken=$BASE_TOKEN" echo "quoteToken=$USDC_MAINNET" 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 "mintBaseAmount=$MINT_BASE_AMOUNT" echo "mintTx=${mint_tx:-none}" echo "createTx=${create_tx:-none}" echo "approveBaseTx=${approve_base_tx:-none}" echo "approveQuoteTx=${approve_quote_tx:-none}" echo "addLiquidityTx=$add_liquidity_tx" echo "baseReserve=$base_reserve" echo "quoteReserve=$quote_reserve" echo "baseBalanceBefore=$base_balance_before" echo "baseBalanceAfter=$base_balance_after" echo "quoteBalanceBefore=$quote_balance_before" echo "quoteBalanceAfter=$quote_balance_after"