docs(indexer): OpenAPI/path pack + curls for swaps, pools, fees, burns, windows #1204
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#1204
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Publish a single indexer HTTP docs pack so integrators and research agents can hit the live read API without reverse-engineering
docs/indexer-invariants.mdor the utoipa derive.Bundle (do not split):
GET /api-docs/openapi.json, Swagger UI/swagger-ui/) or a checked-in path list generated from the sameApiDocsource.24h/7d/30dvs UTC calendar-day series vs DeFiLlama UTC day — so agents do not mix them.ApiDoc.This is docs + OpenAPI completeness. No new business endpoints, no indexer ingest change, no frontend.
Related (do not merge into this ticket): #707 (execute-path integrator warning: pool-only
pair.swapvs solver/hybrid). #216 hybrid volume. #577 trailing-window decay. #586 / #614 protocol fees. #652 / #668 volume series. #631 DeFiLlama UTC-day.Current codebase
The indexer already has an HTTP surface and a generated spec. What is missing is a pack a human or agent can copy in one sitting.
OpenAPI is live, not a pack
indexer/src/api/mod.rsApiDoc(utoipa::OpenApi) is mounted as:GET /api-docs/openapi.jsonGET /swagger-ui/Regression:
indexer/tests/security.rsopenapi_spec_available,swagger_ui_available. QA checklist mentions both (QA_TEMPLATE.md13.7.x).There is no committed
openapi.json/ path markdown underdocs/. Integrators are told “see Swagger” in passing (docs/integrators.md,docs/integrators-hybrid-volume.md) but not given curls for the five surfaces below.ApiDoc.pathsomits existing Axum routes (handlers may still have#[utoipa::path]):GET /healthGET /api/v1/health/fee-discountGET /api/v1/compliance/blacklist-check(LCD-heavy;compliance.rs)Those stay out of the five-surface pack except as a one-line “also on the router / LCD-heavy” note. Closing the
ApiDocgap is in scope so the spec matchesbuild_router.Docs today are the wrong shape for copy-paste HTTP
docs/indexer-invariants.mddocs/integrators.mddocs/route-solver.mddocs/DEFILLAMA.mdsuspicious-activity-queries.md,launch-monitoring.md, …)skills/AGENTS_INDEXER_*.mddocs/README.mdas HTTP catalogThe five surfaces (already implemented)
Swaps (tape / quote — not execute)
/api/v1/pairs/{addr}/tradesswap_events; optionalpool_leg_volume/book_leg_volume; raw amount strings +offer_decimals/ask_decimals(#557)/api/v1/traders/{addr}/tradespair=,format=json|csv,limit/before(CSV formula prefix #432)/api/v1/route/solveamount_in→ global best execution.pool_only=trueis pool-only./gt/events?fromBlock=&toBlock=Headline volume = one parent
swap_eventsrow (L10). Do not sumlimit_order_fillsinto pair volume.Pools
/api/v1/pairssort=volume_24h(raw quote) vsvolume_usd_24h/liquidity_usd(NULLS LAST). Additivevolume_usd_24h,liquidity_usd,created_at./api/v1/pairs/{addr}code_id_frozenmay be true while still listed./api/v1/pairs/{addr}/liquidity-eventslimit/beforelike trades./api/v1/pairs/{addr}/statsvolume_usd.volume_base/volume_quotestay raw integers./api/v1/tokens/{addr}/pairsFees (protocol treasury — not Terra Classic burn tax)
/api/v1/protocol/fees?window=24h|7d|30delse 400. O(1) rollup, 60s cache.by_source/by_token./api/v1/protocol/fees/dailygrain=hourly|daily|monthly+ cappedlimit. Extrafrom/to/window/days→ 400./api/v1/overviewtotal_fees_{24h,7d,30d}_usd(idle"0", activity+unpricednull)./api/v1/defillama/daily?timestamp=unix % 86400 == 0). Not trailing 24h.Parser explicitly does not count Terra Classic burn tax /
tax_amountas treasury fees (protocol_fees.rs).Burns (post-swap hooks)
There is no
/burnsroute. Burns areGET /api/v1/hooks:actionvalues that start withafter_swap_(parser.rsparse_hook_events). Tests useafter_swap_burn.burn_amount/burn_token(fallbacktax_amount/tax_token).hook_address,limitclamped 1–200 (default 50).smartcontracts/contracts/hooks/burn-hook,lp-burn-hook. LP mint/burn pool events stay onliquidity-events, not hooks.Volume windows
GET /api/v1/overviewUtc::now() − Nfor 24h/7d/30d volume and fees. Not midnight UTC reset (#576).GET /api/v1/tokens/{addr}→volume_stats[].window24h/7d/30drollup; idle windows zero (#577). Lifetime totals are not zeroed.GET /api/v1/pairs?sort=volume_usd_24h,GET .../pairs/{addr}/statsSUM(swap_events).GET /api/v1/protocol/volume/daily?days=7|30orgrain=+limit=from/to→ 400.GET /api/v1/defillama/daily?timestamp=Trader
volume_24h/7d/30dexist on profile JSON but are raw; retail USD istotal_volume_usd. Do not document trader rolling windows as human USD.Rate limits and read-only
POST /api/v1/route/solvewrites nothing to indexer DB (JSON merge + optional LCD sim). Other POST → 405.Retry-After.Why the work is needed
/api-docs/openapi.json. A path list (generated fromApiDoc) plus curls indocs/is usable offline.volume_quote_24hraw vsvolume_usd_24h).route/solveexamples for volume research.build_routerwithoutApiDoc.pathssilently disappear from Swagger. The pack should fail CI if the five-surface paths (and the known health/compliance gaps once closed) leave the spec.This does not change quotes, ingest, or the dApp.
Constraints / guardrails
/burns,/swaps, or/api/v1/listings. Burns =/hooks. Pools =/pairs.$INDEXER,$PAIR,$TOKEN,$TRADER,$HOOK. Never paste real wallets, tx hashes, or private captures. Default$INDEXERin docs:https://indexer.dex.cl8y.com(already public) andhttp://127.0.0.1:3001for local.URLSearchParams/-G --data-urlencode— never concatenate user strings into the path or query.window=1h,window=ust1-window,grain=week, extrafrom/toon fee/volume daily. Do not suggest those params.GET /protocol/feesis notafter_swap_burnand not LUNC burn tax.volume_quote_24h/ pair statsvolume_baseare raw integers. USD fields may be JSONnull(unpriced),"0"(idle), or a decimal string. Document that.format=csvonly on trader history; mention leading=/+/-/@prefix. No CSV on/protocol/fees./gtfor the pool table; official pool list is/api/v1/pairs. Gem pairs omitted from/cg/cmc/gt.DATABASE_URL, LCD URLs beyond “configured upstream,” or operator runbook host names.Relevant files
indexer/src/api/mod.rsApiDoc,build_router, Swagger mount, governorsindexer/src/api/pairs.rsindexer/src/api/hooks.rsindexer/src/api/protocol_fees.rsindexer/src/api/protocol_fee_series.rsindexer/src/api/protocol_volume.rsindexer/src/api/overview.rsindexer/src/api/tokens.rsvolume_statswindowsindexer/src/api/defillama.rsindexer/src/api/gt.rsindexer/src/api/route_solver.rsindexer/src/api/compliance.rsApiDoc.pathsindexer/src/indexer/parser.rsafter_swap_*/burn_amountindexer/src/indexer/volume_aggregator.rsindexer/tests/security.rsindexer/tests/api_hooks.rsdocs/indexer-invariants.mddocs/README.mddocs/integrators.mdRecommended direction
docs/indexer-http.md(name may bedocs/indexer-http-pack.mdif that matches local docs style). Structure:Accept: application/json.curl -sS "$INDEXER/api-docs/openapi.json"and/swagger-ui/.limit, 400/404 notes, invariant link.-sSandjqfilters on documented fields only (items[0].pair_address,window,action,volume_usd).protocol/volume/dailyvs/defillama/daily.window, unknown pair 404,POSTto a GET route 405.docs/README.md(Architecture) and a short paragraph at the top ofdocs/integrators.md(“read API pack” vs “execute hybrid”).ApiDocgaps for/health,/api/v1/health/fee-discount,/api/v1/compliance/blacklist-checkso Swagger matchesbuild_router. Tag Compliance/Health. Do not add new JSON fields.openapi_spec_available(or a new test) to assert the five-surface paths exist inApiDoc::openapi()JSONpaths. Optional:make verify-issue-<id>greps thatdocs/indexer-http.mdcontains each path string and the three clock labels.GET /api/v1/route/solve?token_in=&token_out=&amount_in=with LCD-heavy warning. Do not put it in the default five-surface list as “swaps history.”Land as one MR. Do not rewrite
indexer-invariants.mdinto the pack.Acceptance criteria
docs/indexer-http.md(or agreed name) exists and is linked fromdocs/README.md./api-docs/openapi.json) and Swagger UI (/swagger-ui/).24h|7d|30d, UTC seriesprotocol/volume/daily/protocol/fees/daily, DeFiLlama UTC day. At least one curl each.GET /api/v1/hooks(after_swap_burn); treasury fees areGET /api/v1/protocol/fees; Terra Classic burn tax is neither.nullvs"0"vs string.limit_order_fillsinto pair volume.ApiDoc.pathsincludes/health,/api/v1/health/fee-discount,/api/v1/compliance/blacklist-check(existing handlers only).make verify-issue-<id>fails if a five-surface path disappears from OpenAPI JSON or from the markdown pack.Test plan (functional paths)
GET $INDEXER/api-docs/openapi.jsonpathsincludes/api/v1/pairs,/api/v1/pairs/{addr}/trades,/api/v1/hooks,/api/v1/protocol/fees,/api/v1/overview,/api/v1/protocol/volume/daily,/api/v1/tokens/{addr}GET $INDEXER/swagger-ui/GET /api/v1/pairs?sort=volume_usd_24h&order=desc&limit=5itemslength ≤ 5GET /api/v1/pairs/{known}/statsvolume_base/volume_quotedigit strings;volume_usdstring or nullGET /api/v1/pairs/{known}/trades?limit=20GET /api/v1/pairs/{known}/liquidity-events?limit=20GET /api/v1/overviewGET /api/v1/tokens/{known}volume_stats[].windowin24h,7d,30dGET /api/v1/protocol/fees?window=24hwindowecho;by_sourceGET /api/v1/protocol/fees?window=7dand30dGET /api/v1/protocol/fees?window=1hGET /api/v1/protocol/fees/daily?grain=daily&limit=14GET /api/v1/protocol/volume/daily?days=7timezoneUTCGET /api/v1/protocol/volume/daily?grain=hourly&limit=24GET /api/v1/hooks?limit=50actionmay beafter_swap_burnGET /api/v1/hooks?hook_address={known}GET /api/v1/pairs/not-a-pair/tradesPOST /api/v1/pairsGET /health{"status":"ok"}; listed in OpenAPI after AC8docs/indexer-http.mdapi_hooks,indexer_protocol_fees,indexer_protocol_volume,api_pairs,securityOpenAPI tests still greenVitest/Playwright not required. Indexer:
cargo testslice +make verify-issue-<id>greps. Optional livecurlagainst local indexer in the verify script when the process is up; skip-live if not.Test plan (attack, hack, and abuse)
window=24h;DROP%20TABLE/window=javascript:alert(1)grain=hourly;DROP/grain=weekon volume/fees dailyfrom/to/windowon/protocol/fees/dailyhook_addressSQL metacharacterslimit=-1/limit=0on hooks, trades, pairsLIMIT500limit=999999offset=10001on/pairs/api/v1/pairs/<script>/ overlong bech32"$INDEXER/api/v1/pairs/" + userwithout encode-G --data-urlencodeor{addr}as whole path segment after checksumGET /api/v1/route/solveor/limit-bookSUMs/limit-fillsas volume/protocol/feesby_sourceas burn-hook burnsformat=csvcell=cmd'; pack mentions it if CSV curl is includeddescriptionfrom queryApiDoc; no query reflectionPOST /api/v1/route/solvebody > 128 KiB/gt/events//cg/pairsAuthorization/ DB URL / LCD hostGET /api/v1/compliance/blacklist-check?tokens=17 addrsExisting coverage to keep green:
security.rs,api_hooks.rs,indexer_protocol_fees.rs,indexer_protocol_fees_series.rs,api_limit_lower_bound.rs.Verification criteria
make verify-issue-<id>(new): markdown greps for the five families, three clocks,/api-docs/openapi.json,/api/v1/hooks, allowlist24h|7d|30d; OpenAPI unit test includes the five-surface paths + health/compliance after AC8.cargo test -p cl8y-dex-indexer --test security --test api_hooks --test api_pairs --test indexer_protocol_fees --test indexer_protocol_volume -- --test-threads=1(adjust binary names to match crate) stays green.curlthe spec keys; run the happy curls against local indexer or the public read API with placeholders filled fromGET /api/v1/pairs?limit=1(no wallet). Invalidwindowreturns 400./hooksreturns JSON array.docs/README.mdlists the pack; no secret strings; #707 still owns execute-path wording.Out of scope
/burns,/swaps,/volume-windows)./route/solve.docs/CG_CMC_COMPLIANCE.md/docs/DEFILLAMA.md).Market overnight 2026-09-06: fee-ledger work is home on this repo (new intakes for pair_creation / SKU+settings invoices / actor-cohort). This docs/OpenAPI pack remains the integrator path for Market to pull fee facts once those sources land — already
ready+agent:implement. New fee intakes: #1209, #1210, #1211, #1212./agent implement
cl8y-agent-control: queued
design_authorjob85d4b800-34f5-440d-b1ee-b594e6a5bd84(not executed; no Hetzner VM).cl8y-agent-control: queued
implementjob6341f1c9-5d61-4bde-8fb2-dfd0d5365cbe(not executed; no Hetzner VM).cl8y-agent-control: fix-cycle cap reached; human required.
cl8y-agent-control: needs_human inbox card POST failed. Job stays parked.