#!/usr/bin/env bash # Create Dodoex PMM pools for all tokens on a chain using Token Aggregation API. # Uses GET /tokens and GET /tokens/:address/pools to discover tokens and skip those already with DODO pools. # Calls DODOPMMIntegration.createPool, EnhancedSwapRouter.setDodoPoolAddress, UniversalAssetRegistry.updatePMMPool. set -euo pipefail hex_to_addr() { local value="${1#0x}" [[ ${#value} -ge 40 ]] || return 1 printf '0x%s\n' "${value: -40}" } SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } if [[ -f "$SCRIPT_DIR/lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 source "$SCRIPT_DIR/lib/deployment/dotenv.sh" load_deployment_env --repo-root "$PROJECT_ROOT" elif [ -f "$PROJECT_ROOT/.env" ]; then set -a source "$PROJECT_ROOT/.env" set +a fi TOKEN_API_URL="${TOKEN_AGGREGATION_API_URL:-http://localhost:3000}" CHAIN_ID="${CHAIN_ID:-138}" RPC_URL="${RPC_URL:-}" PRIVATE_KEY="${PRIVATE_KEY:-}" DODO_PMM_INTEGRATION="${DODO_PMM_INTEGRATION:-${DODO_PMM_INTEGRATION_ADDRESS:-}}" ENHANCED_SWAP_ROUTER="${ENHANCED_SWAP_ROUTER_ADDRESS:-}" ASSET_REGISTRY="${UNIVERSAL_ASSET_REGISTRY_ADDRESS:-}" QUOTE_TOKEN="${QUOTE_TOKEN_ADDRESS:-}" # Chain 138 requires an explicit local quote token or an official mirror token address. if [ "$CHAIN_ID" = "138" ]; then QUOTE_TOKEN="${QUOTE_TOKEN:-${OFFICIAL_USDT_ADDRESS:-${COMPLIANT_USDT_ADDRESS:-}}}" fi if [ "$CHAIN_ID" = "651940" ]; then QUOTE_TOKEN="${QUOTE_TOKEN:-${WETH_ADDRESS_651940:-}}" fi LP_FEE_RATE="${LP_FEE_RATE:-3}" INITIAL_PRICE="${INITIAL_PRICE:-1000000000000000000}" K_FACTOR="${K_FACTOR:-500000000000000000}" ENABLE_TWAP="${ENABLE_TWAP:-true}" TWAP_VALUE="$([ "$ENABLE_TWAP" = "true" ] && echo "true" || echo "false")" DRY_RUN="${DRY_RUN:-false}" LIMIT="${TOKEN_PAGE_LIMIT:-500}" for var in RPC_URL PRIVATE_KEY DODO_PMM_INTEGRATION QUOTE_TOKEN; do eval "val=\$$var" if [ -z "$val" ]; then log_error "$var is not set" exit 1 fi done if ! command -v jq &>/dev/null; then log_error "jq is required. Install with: apt-get install jq / brew install jq" exit 1 fi if ! command -v cast &>/dev/null; then log_error "cast (foundry) is required for on-chain calls" exit 1 fi log_info "=========================================" log_info "Create DODO PMM pools from Token API" log_info "=========================================" log_info "Token API: $TOKEN_API_URL" log_info "Chain ID: $CHAIN_ID" log_info "Quote token (WETH/stable): $QUOTE_TOKEN" log_info "DODO PMM Integration: $DODO_PMM_INTEGRATION" log_info "Enhanced Swap Router: ${ENHANCED_SWAP_ROUTER:-not set}" log_info "Asset Registry: ${ASSET_REGISTRY:-not set}" log_info "Dry run: $DRY_RUN" log_info "" offset=0 total_created=0 total_skipped=0 while true; do url="${TOKEN_API_URL}/tokens?chainId=${CHAIN_ID}&limit=${LIMIT}&offset=${offset}" log_info "Fetching tokens: $url" resp=$(curl -sS --fail "$url" 2>/dev/null || true) if [ -z "$resp" ]; then log_warn "No response or empty from Token API; check TOKEN_AGGREGATION_API_URL and that the service is running" break fi count=$(echo "$resp" | jq -r '.tokens | length') if [ -z "$count" ] || [ "$count" = "null" ] || [ "$count" -eq 0 ]; then break fi for i in $(seq 0 $((count - 1))); do token_addr=$(echo "$resp" | jq -r ".tokens[$i].address") if [ -z "$token_addr" ] || [ "$token_addr" = "null" ]; then continue fi # Skip quote token itself if [ "$(echo "$token_addr" | tr '[:upper:]' '[:lower:]')" = "$(echo "$QUOTE_TOKEN" | tr '[:upper:]' '[:lower:]')" ]; then continue fi # Check if token already has a DODO pool pools_url="${TOKEN_API_URL}/tokens/${token_addr}/pools?chainId=${CHAIN_ID}" pools_resp=$(curl -sS "$pools_url" 2>/dev/null || true) has_dodo=false if [ -n "$pools_resp" ]; then dexes=$(echo "$pools_resp" | jq -r '.pools[].dex' 2>/dev/null || true) if echo "$dexes" | grep -q 'dodo'; then has_dodo=true fi fi if [ "$has_dodo" = "true" ]; then total_skipped=$((total_skipped + 1)) continue fi # Create pool: baseToken=token, quoteToken=QUOTE_TOKEN (e.g. WETH) if [ "$DRY_RUN" = "true" ]; then log_info "[DRY RUN] Would createPool base=$token_addr quote=$QUOTE_TOKEN" total_created=$((total_created + 1)) continue fi if ! pool_addr=$(cast call "$DODO_PMM_INTEGRATION" "pools(address,address)(address)" "$token_addr" "$QUOTE_TOKEN" --rpc-url "$RPC_URL" 2>/dev/null | while read -r raw; do hex_to_addr "$raw" 2>/dev/null || true; done); then pool_addr="" fi if [ -n "$pool_addr" ] && [ "$pool_addr" != "0x0000000000000000000000000000000000000000" ]; then log_warn "Pool already exists for $token_addr / $QUOTE_TOKEN: $pool_addr" total_skipped=$((total_skipped + 1)) continue fi log_info "Creating pool: base=$token_addr quote=$QUOTE_TOKEN" if cast send "$DODO_PMM_INTEGRATION" \ "createPool(address,address,uint256,uint256,uint256,bool)" \ "$token_addr" \ "$QUOTE_TOKEN" \ "$LP_FEE_RATE" \ "$INITIAL_PRICE" \ "$K_FACTOR" \ "$TWAP_VALUE" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --legacy \ -q 2>/dev/null; then pool_addr=$(cast call "$DODO_PMM_INTEGRATION" "pools(address,address)(address)" "$token_addr" "$QUOTE_TOKEN" --rpc-url "$RPC_URL" | while read -r raw; do hex_to_addr "$raw"; done) log_success "Pool created: $pool_addr" if [ -n "$ENHANCED_SWAP_ROUTER" ] && [ "$ENHANCED_SWAP_ROUTER" != "0x0000000000000000000000000000000000000000" ]; then cast send "$ENHANCED_SWAP_ROUTER" "setDodoPoolAddress(address,address,address)" "$QUOTE_TOKEN" "$token_addr" "$pool_addr" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy -q 2>/dev/null && log_success "Router set QUOTE->token" || log_warn "Router set failed" cast send "$ENHANCED_SWAP_ROUTER" "setDodoPoolAddress(address,address,address)" "$token_addr" "$QUOTE_TOKEN" "$pool_addr" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy -q 2>/dev/null && log_success "Router set token->QUOTE" || log_warn "Router set failed" fi if [ -n "$ASSET_REGISTRY" ] && [ "$ASSET_REGISTRY" != "0x0000000000000000000000000000000000000000" ]; then cast send "$ASSET_REGISTRY" "updatePMMPool(address,address)" "$token_addr" "$pool_addr" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy -q 2>/dev/null && log_success "Registry updatePMMPool" || log_warn "Registry updatePMMPool failed" fi total_created=$((total_created + 1)) else log_error "Failed to create pool for $token_addr" fi done if [ "$count" -lt "$LIMIT" ]; then break fi offset=$((offset + LIMIT)) done log_info "" log_info "Done. Pools created: $total_created, skipped (already had DODO): $total_skipped"