Repository navigation
feat: add GET /snapshot whole-network summary - #395
Conversation
One cached, network-scoped call that answers "what does this network look like right now": every venue's liveness, AMM liquidity (per-asset reserves and per-pool detail), 24h traded volume, the busiest pairs with their price direction, stablecoin peg readings, and data freshness — as a single timestamped object. Everything is read in one SQL statement with a single `as_of` clock taken from the database, so every 24h cutoff and every `ageSeconds` is measured from the same instant rather than four queries landing on four clocks. Unknowns are reported, never invented: a venue with no rows is silent, a cross-pair volume total is null with a reason unless the pairs share one unit, a peg with no fiat-target quote is `no_reference`, and the endpoint always returns 200. Asset identities keep their issuers. Cached per network for a few seconds (SNAPSHOT_CACHE_TTL), with `cache.ageSeconds` republished on a hit so a cached copy never claims to be fresher than it is. Public, and not x402-gated.
|
@aliyuHabibu Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
@Miracle656 Please review again. Thank you |
|
Needs a rebase — Worth knowing before you rebase: #402 replaced every Push the rebase and I will pick it up; nothing is queued ahead of it. |
|
@Miracle656 Done |
Merging current main produced two import lines from './config' in
src/redis.ts — this branch's, which also pulls in `type NetworkName`, and
main's narrower one:
error TS2300: Duplicate identifier 'config'.
error TS2300: Duplicate identifier 'activeNetwork'.
Kept the superset. tsc clean, 696 tests passing.
Claude-Session: https://claude.ai/code/session_01USgemLt4Rnz4SGB1Srf3GB
Miracle656
left a comment
There was a problem hiding this comment.
The header comment on src/routes/snapshot.ts is the best statement of design intent in this repo, and every rule in it is honoured by the code.
One query, one clock.
Everything is read in ONE SQL statement with a single
as_oftimestamp taken from the database. Four separate queries could land on four different clocks, and then the response would describe an instant that never existed.
I counted: exactly one pgPool.query. That is the difference between a snapshot and a collage. Four round-trips would give you TVL from one moment, volume from another, and a peg reading from a third — and the composite would look perfectly consistent while describing no instant that ever occurred. Taking as_of from the database rather than Date.now() is the other half: the app's clock and the database's are not the same clock.
Absent data is reported, never invented. A silent venue is listed as silent; a pair with no trades gets no volume figure rather than a zero; the peg check says no_reference; a cross-pair total is null with a reason when the pairs do not share a unit. For a summary endpoint this is the whole ballgame — a dashboard cannot tell a real zero from a missing one, and "0" renders as confidently as any other number.
The cache reports its own age.
ageSeconds: storedAt ? ageSeconds(Date.now(), storedAt) : nulla hit never pretends to be fresher than it is
This is the detail almost everyone misses. Caching a response that contains its own freshness fields and serving it unchanged means the response lies for the length of the TTL — it says "as of now" while being seconds old. Recomputing cache.ageSeconds on the way out, with an X-Cache: HIT header, keeps it honest.
Always 200. "No data yet" is state, not a client error, and a summary that 404s is useless to the dashboard that polls it. Agreed — and it pairs correctly with the point above, because the way you say "nothing here" is in the body, not the status.
And issuers are never elided, because a coin called USDC is a different asset per issuer. That rule exists here for a reason and you did not need telling.
I pushed one commit to your branch. The merge with current main left two import lines from ./config in src/redis.ts — yours (which also pulls type NetworkName) and main's narrower one — so tsc refused with TS2300: Duplicate identifier. Kept the superset.
src/__tests__/snapshot.test.ts: 17 passed. Suite: 696 passed, tsc --noEmit clean. The single remaining local failure is graphqlSchemaDrift from CRLF in my working copy — git diff shows the committed blob untouched, and CI passes it.
Merging once CI confirms.
One cached, network-scoped call that answers "what does this network look like right now": every venue's liveness, AMM liquidity (per-asset reserves and per-pool detail), 24h traded volume, the busiest pairs with their price direction, stablecoin peg readings, and data freshness — as a single timestamped object.
Everything is read in one SQL statement with a single
as_ofclock taken from the database, so every 24h cutoff and everyageSecondsis measured from the same instant rather than four queries landing on four clocks. Unknowns are reported, never invented: a venue with no rows is silent, a cross-pair volume total is null with a reason unless the pairs share one unit, a peg with no fiat-target quote isno_reference, and the endpoint always returns 200. Asset identities keep their issuers.Cached per network for a few seconds (SNAPSHOT_CACHE_TTL), with
cache.ageSecondsrepublished on a hit so a cached copy never claims to be fresher than it is. Public, and not x402-gated.Summary
Type of change
Checklist
npx tsc --noEmitpassesnpm run buildpassesClose #299