Files
proxmox/scripts/verify/print-mainnet-cwusdc-external-exit-quote.sh
defiQUG dbd517b279 Sync workspace: config, docs, scripts, CI, operator rules, and submodule pointers.
- 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
2026-04-12 06:12:20 -07:00

176 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Print one number: hosted **gross USDC per cWUSDC** for selling `base_raw` minimal units
# on Ethereum mainnet, using either **DODO SmartTrade** or **1inch v6** quote APIs.
# Intended for `pmm-flash-push-break-even.mjs --external-exit-price-cmd` (exit becomes "live").
#
# Dependencies: curl, python3 (no jq).
#
# Usage:
# source scripts/lib/load-project-env.sh
# export ONEINCH_API_KEY=... # or DODO_API_KEY / DODO_SECRET_KEY / DODO_DEVELOPER_API_KEY
# bash scripts/verify/print-mainnet-cwusdc-external-exit-quote.sh 1inch 6187975
# bash scripts/verify/print-mainnet-cwusdc-external-exit-quote.sh dodo 6187975
#
# Env (optional):
# EXIT_QUOTE_ENGINE — default engine if $1 omitted: dodo | 1inch
# EXIT_QUOTE_BASE_RAW — default size if $2 omitted (raw 6dp cWUSDC)
# CWUSDC_MAINNET, MAINNET_USDC — token overrides
# DODO_QUOTE_URL — default https://api.dodoex.io/route-service/developer/swap
# DODO_SLIPPAGE — default 0.005
# DODO_USER_ADDRESS / USER_ADDR / DEPLOYER_ADDRESS — DODO userAddr; else derived from PRIVATE_KEY
# ONEINCH_API_URL — default https://api.1inch.dev/swap/v6.0
#
# Notes:
# - Quotes are **not** guaranteed executable at execution time; refresh per tranche.
# - DODO and 1inch may not route thin cW*; failures exit non-zero with stderr detail.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# shellcheck disable=SC1091
source "$ROOT/scripts/lib/load-project-env.sh" 2>/dev/null || true
require_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "[fail] missing command: $1" >&2
exit 1
}
}
require_cmd curl
require_cmd python3
ENGINE="${1:-${EXIT_QUOTE_ENGINE:-dodo}}"
BASE_RAW="${2:-${EXIT_QUOTE_BASE_RAW:-6187975}}"
ENGINE_LC="$(printf '%s' "$ENGINE" | tr '[:upper:]' '[:lower:]')"
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
USDC="${MAINNET_USDC:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
CHAIN_ID=1
DEC_OUT=6
if ! [[ "$BASE_RAW" =~ ^[0-9]+$ ]] || ((BASE_RAW < 1)); then
echo "[fail] base_raw must be a positive integer (cWUSDC raw, 6 decimals)" >&2
exit 1
fi
quote_dodo() {
local api_key url slippage user_addr body code
api_key="${DODO_API_KEY:-${DODO_SECRET_KEY:-${DODO_DEVELOPER_API_KEY:-}}}"
if [[ -z "$api_key" ]]; then
echo "[fail] DODO quote needs DODO_API_KEY, DODO_SECRET_KEY, or DODO_DEVELOPER_API_KEY" >&2
return 1
fi
url="${DODO_QUOTE_URL:-https://api.dodoex.io/route-service/developer/swap}"
slippage="${DODO_SLIPPAGE:-0.005}"
user_addr="${DODO_USER_ADDRESS:-${USER_ADDR:-${DEPLOYER_ADDRESS:-}}}"
if [[ -z "$user_addr" && -n "${PRIVATE_KEY:-}" ]] && command -v cast >/dev/null 2>&1; then
user_addr="$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null || true)"
fi
user_addr="${user_addr:-0x0000000000000000000000000000000000000001}"
code="$(
curl -sS -G -o "$tmp" -w "%{http_code}" --max-time 45 "$url" \
--data-urlencode "chainId=${CHAIN_ID}" \
--data-urlencode "fromAmount=${BASE_RAW}" \
--data-urlencode "fromTokenAddress=${CWUSDC}" \
--data-urlencode "toTokenAddress=${USDC}" \
--data-urlencode "apikey=${api_key}" \
--data-urlencode "slippage=${slippage}" \
--data-urlencode "userAddr=${user_addr}"
)" || code="000"
if [[ "$code" != "200" ]]; then
echo "[fail] DODO HTTP ${code}: $(head -c 400 "$tmp" 2>/dev/null || true)" >&2
return 1
fi
python3 - "$BASE_RAW" "$DEC_OUT" <"$tmp" <<'PY'
import json, sys, decimal
base_in = int(sys.argv[1])
dec_out = int(sys.argv[2])
j = json.load(sys.stdin)
data = j.get("data") if isinstance(j.get("data"), dict) else {}
msg = (data.get("msgError") or data.get("message") or "").strip()
if msg:
print(f"[fail] DODO msgError={msg}", file=sys.stderr)
sys.exit(1)
raw = data.get("resAmount") or data.get("toTokenAmount") or j.get("resAmount")
if raw is None or raw == "":
print("[fail] DODO missing resAmount / toTokenAmount", file=sys.stderr)
sys.exit(1)
s = str(raw).strip()
try:
if "." in s:
out_raw = int((decimal.Decimal(s) * (decimal.Decimal(10) ** dec_out)).to_integral_value(rounding=decimal.ROUND_DOWN))
else:
out_raw = int(s)
except Exception as e:
print(f"[fail] DODO parse resAmount={raw!r}: {e}", file=sys.stderr)
sys.exit(1)
if out_raw <= 0 or base_in <= 0:
print("[fail] DODO non-positive amounts", file=sys.stderr)
sys.exit(1)
ratio = out_raw / base_in
out = f"{ratio:.12f}".rstrip("0").rstrip(".")
print(out or "0")
PY
}
quote_oneinch() {
local key base url code
key="${ONEINCH_API_KEY:-}"
if [[ -z "$key" ]]; then
echo "[fail] 1inch quote needs ONEINCH_API_KEY (see .env.master.example)" >&2
return 1
fi
base="${ONEINCH_API_URL:-https://api.1inch.dev/swap/v6.0}"
base="${base%/}"
url="${base}/${CHAIN_ID}/quote?src=${CWUSDC}&dst=${USDC}&amount=${BASE_RAW}"
code="$(
curl -sS -o "$tmp" -w "%{http_code}" --max-time 45 \
-H "Authorization: Bearer ${key}" \
-H "Accept: application/json" \
"$url"
)" || code="000"
if [[ "$code" != "200" ]]; then
echo "[fail] 1inch HTTP ${code}: $(head -c 400 "$tmp" 2>/dev/null || true)" >&2
return 1
fi
python3 - "$BASE_RAW" <"$tmp" <<'PY'
import json, sys
base_in = int(sys.argv[1])
j = json.load(sys.stdin)
dst = j.get("dstAmount") or j.get("toAmount") or j.get("toTokenAmount")
if not dst:
print("[fail] 1inch missing dstAmount", file=sys.stderr)
sys.exit(1)
out_raw = int(str(dst).strip())
if out_raw <= 0:
print("[fail] 1inch non-positive dstAmount", file=sys.stderr)
sys.exit(1)
ratio = out_raw / base_in
out = f"{ratio:.12f}".rstrip("0").rstrip(".")
print(out or "0")
PY
}
tmp="$(mktemp)"
trap 'rm -f "$tmp"' EXIT
case "$ENGINE_LC" in
dodo)
quote_dodo
;;
1inch | oneinch)
quote_oneinch
;;
*)
echo "[fail] engine must be dodo or 1inch (got: $ENGINE)" >&2
exit 2
;;
esac