- 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
176 lines
5.8 KiB
Bash
Executable File
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
|