244 lines
8.2 KiB
Bash
Executable File
244 lines
8.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Verify the native DODO read surfaces on Chain 138.
|
|
#
|
|
# Scope:
|
|
# - DODO PMM pools:
|
|
# * getVaultReserve()
|
|
# * getPMMStateForCall()
|
|
# - D3MM pilot pool:
|
|
# * getTokenReserve(address)
|
|
# * querySellTokens(address,address,uint256)
|
|
#
|
|
# The script prints explicit PASS / FAIL lines per surface and exits non-zero
|
|
# if any required surface is missing or returns an empty / invalid result.
|
|
#
|
|
# Default RPC comes from the project env when available, then falls back to the
|
|
# standard Chain 138 core RPC used elsewhere in the repo.
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
|
|
if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then
|
|
# shellcheck source=/dev/null
|
|
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
|
fi
|
|
|
|
require_command() {
|
|
command -v "$1" >/dev/null 2>&1 || {
|
|
printf '[fail] missing required command: %s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
require_command cast
|
|
require_command timeout
|
|
|
|
RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-${CHAIN138_RPC:-http://192.168.11.211:8545}}}"
|
|
PROBE_AMOUNT_PMM="${CHAIN138_DODO_PMM_PROBE_AMOUNT:-1000000}"
|
|
PROBE_AMOUNT_D3="${CHAIN138_D3_PROBE_SELL_AMOUNT:-100000000000000000}"
|
|
TRADER_ADDRESS="${CHAIN138_DODO_READ_TRADER:-${DEPLOYER_ADDRESS:-0x4A666F96fC8764181194447A7dFdb7d471b301C8}}"
|
|
|
|
PMM_POOLS=(
|
|
"cUSDT/cUSDC|0x9e89bAe009adf128782E19e8341996c596ac40dC|0x93E66202A11B1772E55407B32B44e5Cd8eda7f22|0xf22258f57794CC8E06237084b353Ab30fFfa640b|6|6"
|
|
"cUSDT/USDT|0x866Cb44b59303d8dc5f4F9E3E7A8e8b0bf238d66|0x93E66202A11B1772E55407B32B44e5Cd8eda7f22|0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1|6|6"
|
|
"cUSDC/USDC|0xc39B7D0F40838cbFb54649d327f49a6DAC964062|0xf22258f57794CC8E06237084b353Ab30fFfa640b|0x71D6687F38b93CCad569Fa6352c876eea967201b|6|6"
|
|
)
|
|
|
|
D3_POOL="0x6550a3a59070061a262a893a1d6f3f490afFDBDA"
|
|
D3_WETH10="0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f"
|
|
D3_USDT="0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1"
|
|
|
|
pass_count=0
|
|
fail_count=0
|
|
LAST_CALL_OUTPUT=""
|
|
|
|
pass() {
|
|
printf '[PASS] %s\n' "$*"
|
|
pass_count=$((pass_count + 1))
|
|
}
|
|
|
|
fail() {
|
|
printf '[FAIL] %s\n' "$*" >&2
|
|
fail_count=$((fail_count + 1))
|
|
}
|
|
|
|
run_cast_call() {
|
|
local label="$1"
|
|
shift
|
|
|
|
LAST_CALL_OUTPUT=""
|
|
|
|
local output
|
|
if ! output="$(timeout 20s cast call --rpc-url "${RPC_URL}" "$@" 2>&1)"; then
|
|
fail "${label}: call failed"
|
|
printf ' %s\n' "${output}" >&2
|
|
LAST_CALL_OUTPUT="${output}"
|
|
return 1
|
|
fi
|
|
|
|
if [[ -z "${output}" ]]; then
|
|
fail "${label}: empty response"
|
|
return 1
|
|
fi
|
|
|
|
printf '%s\n' "${output}"
|
|
LAST_CALL_OUTPUT="${output}"
|
|
}
|
|
|
|
parse_first_uint() {
|
|
awk 'NR==1 { print $1 }'
|
|
}
|
|
|
|
check_gt_zero() {
|
|
local label="$1"
|
|
local value="$2"
|
|
if [[ ! "${value}" =~ ^[0-9]+$ ]] || (( value <= 0 )); then
|
|
fail "${label}: expected > 0, got ${value:-<empty>}"
|
|
return 1
|
|
fi
|
|
pass "${label}: ${value}"
|
|
}
|
|
|
|
check_pmm_pool() {
|
|
local label="$1"
|
|
local pool="$2"
|
|
local base="$3"
|
|
local quote="$4"
|
|
|
|
printf '\n=== PMM: %s ===\n' "${label}"
|
|
printf 'pool=%s\n' "${pool}"
|
|
|
|
local reserves
|
|
if ! run_cast_call "${label} getVaultReserve" "${pool}" 'getVaultReserve()(uint256,uint256)'; then
|
|
return 1
|
|
fi
|
|
reserves="${LAST_CALL_OUTPUT}"
|
|
|
|
local reserve_base reserve_quote
|
|
reserve_base="$(printf '%s\n' "${reserves}" | sed -n '1p' | parse_first_uint)"
|
|
reserve_quote="$(printf '%s\n' "${reserves}" | sed -n '2p' | parse_first_uint)"
|
|
|
|
check_gt_zero "${label} getVaultReserve base" "${reserve_base}" || true
|
|
check_gt_zero "${label} getVaultReserve quote" "${reserve_quote}" || true
|
|
|
|
local state
|
|
if ! run_cast_call "${label} getPMMStateForCall" "${pool}" 'getPMMStateForCall()(uint256,uint256,uint256,uint256,uint256,uint256,uint256)'; then
|
|
return 1
|
|
fi
|
|
state="${LAST_CALL_OUTPUT}"
|
|
|
|
local state_i state_k state_b state_q state_b0 state_q0 state_r
|
|
state_i="$(printf '%s\n' "${state}" | sed -n '1p' | parse_first_uint)"
|
|
state_k="$(printf '%s\n' "${state}" | sed -n '2p' | parse_first_uint)"
|
|
state_b="$(printf '%s\n' "${state}" | sed -n '3p' | parse_first_uint)"
|
|
state_q="$(printf '%s\n' "${state}" | sed -n '4p' | parse_first_uint)"
|
|
state_b0="$(printf '%s\n' "${state}" | sed -n '5p' | parse_first_uint)"
|
|
state_q0="$(printf '%s\n' "${state}" | sed -n '6p' | parse_first_uint)"
|
|
state_r="$(printf '%s\n' "${state}" | sed -n '7p' | parse_first_uint)"
|
|
|
|
check_gt_zero "${label} getPMMStateForCall i" "${state_i}" || true
|
|
check_gt_zero "${label} getPMMStateForCall B" "${state_b}" || true
|
|
check_gt_zero "${label} getPMMStateForCall Q" "${state_q}" || true
|
|
if [[ "${state_k}" =~ ^[0-9]+$ ]]; then
|
|
pass "${label} getPMMStateForCall K: ${state_k}"
|
|
else
|
|
fail "${label} getPMMStateForCall K: invalid value ${state_k:-<empty>}"
|
|
fi
|
|
if [[ "${state_r}" =~ ^[0-9]+$ ]]; then
|
|
pass "${label} getPMMStateForCall R: ${state_r}"
|
|
else
|
|
fail "${label} getPMMStateForCall R: invalid value ${state_r:-<empty>}"
|
|
fi
|
|
printf ' stateB0=%s stateQ0=%s\n' "${state_b0:-<empty>}" "${state_q0:-<empty>}"
|
|
|
|
local query_base query_quote
|
|
if ! run_cast_call "${label} querySellBase" "${pool}" "querySellBase(address,uint256)(uint256,uint256)" "${TRADER_ADDRESS}" "${PROBE_AMOUNT_PMM}"; then
|
|
return 1
|
|
fi
|
|
query_base="${LAST_CALL_OUTPUT}"
|
|
if ! run_cast_call "${label} querySellQuote" "${pool}" "querySellQuote(address,uint256)(uint256,uint256)" "${TRADER_ADDRESS}" "${PROBE_AMOUNT_PMM}"; then
|
|
return 1
|
|
fi
|
|
query_quote="${LAST_CALL_OUTPUT}"
|
|
|
|
local base_out quote_out
|
|
base_out="$(printf '%s\n' "${query_base}" | sed -n '1p' | parse_first_uint)"
|
|
quote_out="$(printf '%s\n' "${query_quote}" | sed -n '1p' | parse_first_uint)"
|
|
|
|
check_gt_zero "${label} querySellBase out" "${base_out}" || true
|
|
check_gt_zero "${label} querySellQuote out" "${quote_out}" || true
|
|
|
|
printf ' tokens=%s/%s\n' "${base}" "${quote}"
|
|
}
|
|
|
|
check_d3_pool() {
|
|
printf '\n=== D3MM: canonical WETH10/USDT pilot ===\n'
|
|
printf 'pool=%s\n' "${D3_POOL}"
|
|
|
|
local weth_reserve usdt_reserve
|
|
if ! run_cast_call "D3MM getTokenReserve(WETH10)" "${D3_POOL}" 'getTokenReserve(address)(uint256)' "${D3_WETH10}"; then
|
|
return 1
|
|
fi
|
|
weth_reserve="${LAST_CALL_OUTPUT}"
|
|
if ! run_cast_call "D3MM getTokenReserve(USDT)" "${D3_POOL}" 'getTokenReserve(address)(uint256)' "${D3_USDT}"; then
|
|
return 1
|
|
fi
|
|
usdt_reserve="${LAST_CALL_OUTPUT}"
|
|
|
|
local weth_raw usdt_raw
|
|
weth_raw="$(printf '%s\n' "${weth_reserve}" | parse_first_uint)"
|
|
usdt_raw="$(printf '%s\n' "${usdt_reserve}" | parse_first_uint)"
|
|
check_gt_zero "D3MM getTokenReserve WETH10" "${weth_raw}" || true
|
|
check_gt_zero "D3MM getTokenReserve USDT" "${usdt_raw}" || true
|
|
|
|
local quote
|
|
if ! run_cast_call "D3MM querySellTokens(WETH10->USDT)" "${D3_POOL}" 'querySellTokens(address,address,uint256)(uint256,uint256,uint256,uint256,uint256)' "${D3_WETH10}" "${D3_USDT}" "${PROBE_AMOUNT_D3}"; then
|
|
return 1
|
|
fi
|
|
quote="${LAST_CALL_OUTPUT}"
|
|
|
|
local pay_from receive_to vusd_amount swap_fee mt_fee
|
|
pay_from="$(printf '%s\n' "${quote}" | sed -n '1p' | parse_first_uint)"
|
|
receive_to="$(printf '%s\n' "${quote}" | sed -n '2p' | parse_first_uint)"
|
|
vusd_amount="$(printf '%s\n' "${quote}" | sed -n '3p' | parse_first_uint)"
|
|
swap_fee="$(printf '%s\n' "${quote}" | sed -n '4p' | parse_first_uint)"
|
|
mt_fee="$(printf '%s\n' "${quote}" | sed -n '5p' | parse_first_uint)"
|
|
|
|
if [[ "${pay_from}" != "${PROBE_AMOUNT_D3}" ]]; then
|
|
fail "D3MM querySellTokens payFrom mismatch: expected ${PROBE_AMOUNT_D3}, got ${pay_from:-<empty>}"
|
|
else
|
|
pass "D3MM querySellTokens payFrom: ${pay_from}"
|
|
fi
|
|
check_gt_zero "D3MM querySellTokens receiveTo" "${receive_to}" || true
|
|
printf ' vusd=%s swapFee=%s mtFee=%s\n' "${vusd_amount:-<empty>}" "${swap_fee:-<empty>}" "${mt_fee:-<empty>}"
|
|
}
|
|
|
|
main() {
|
|
printf 'Chain 138 native DODO read-surface verifier\n'
|
|
printf 'rpc=%s\n' "${RPC_URL}"
|
|
printf 'probeAmountPmm=%s\n' "${PROBE_AMOUNT_PMM}"
|
|
printf 'probeAmountD3=%s\n' "${PROBE_AMOUNT_D3}"
|
|
printf 'trader=%s\n' "${TRADER_ADDRESS}"
|
|
|
|
local row
|
|
for row in "${PMM_POOLS[@]}"; do
|
|
IFS='|' read -r label pool base quote _ _ <<<"${row}"
|
|
if ! check_pmm_pool "${label}" "${pool}" "${base}" "${quote}"; then
|
|
:
|
|
fi
|
|
done
|
|
|
|
if ! check_d3_pool; then
|
|
:
|
|
fi
|
|
|
|
printf '\nSummary: %s passed, %s failed.\n' "${pass_count}" "${fail_count}"
|
|
if (( fail_count > 0 )); then
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
main "$@"
|