Skip to content

feat(stats): add public protocol stats page, JSON API and CSV - #151

Open
Ayush7614 wants to merge 1 commit into
Twigpine:mainfrom
Ayush7614:feat/protocol-stats
Open

Ayush7614 wants to merge 1 commit into
Twigpine:mainfrom
Ayush7614:feat/protocol-stats

Conversation

@Ayush7614

Copy link
Copy Markdown
Contributor

What

Adds a public protocol stats page and machine-readable API:

  • GET /stats — cards, two server-rendered daily charts, per-chain table and top launches, with window/chain filters.
  • GET /api/stats?window=7d|30d|90d|all&chain=base|robinhood|arc|elysium&format=json|csv — the same aggregates.
  • format=csv downloads the daily series (text/csv, one row per UTC day).

The page and the API share one 30-second memo per window/chain. No new dependencies, no new environment variables, no new external hosts.

What is measured

All figures are aggregates of the existing index (bb_launches, bb_launch_swaps, bb_launch_fee_events):

  • launches and distinct launcher wallets
  • trades and distinct trader wallets
  • trade-time USD volume
  • collected fees, burned fees and fees to creators
  • unpriced_trades / unpriced_fee_events when an event has no price for its own hour

USD is trade-time USD, not today's price applied to old volume: it is the value the indexer stored in the event's own UTC hour. Events without an hourly price are excluded and counted, never guessed; the page shows a warning and the API returns usd_partial: true. Token-side fee burns are not valued in USD. The home hero additionally falls back to the current price for unpriced events, so the two can differ exactly by those counts — this is documented on the page and in docs/stats.md.

Implementation notes

  • Three aggregate reads use GROUPING SETS ((chain_id), ()) to return per-chain and global rows in one pass; distinct wallet counts are therefore correct per chain and globally.
  • Daily series are bucketed with date_trunc('day', block_time AT TIME ZONE 'UTC') and gap-filled from since through today with zeros, not holes.
  • available: false means the database is unset or the aggregate read failed. The page says so instead of drawing a zero chart; it does not pretend empty shapes are facts.
  • The charts are server-rendered SVG with <title> per bar and a <details> table of the exact numbers, so there is no client chart dependency and the data is accessible.

Docs / discoverability

  • docs/stats.md: field meanings, SQL sources, trade-time USD rules, response shape, CSV, and why the home totals can differ.
  • /llms.txt gains the endpoint and the /stats page.
  • STATIC_SITEMAP_ROUTES (and its test) gains /stats.

Verification

cd app
npm run lint                  # clean
npx tsc --noEmit -p .         # clean
npm test                      # 1498 pass, 11 skipped, 0 fail
npm run build                 # clean; /stats and /api/stats compiled

The SQL was also exercised against a temporary seeded Postgres 18 (schema applied with db/schema.sql; 5 launches, 7 swaps and 6 fee events across Base/Robinhood/Arc, including a 60-day-old launch and an unpriced trade/fee). With the built app running against it:

  • 30d → 4 launches, 3 launchers, 6 trades, 3 traders, $425 volume, $16 collected, $3 burned, $13 to creators, 1 unpriced trade, 1 unpriced fee; Base $400 / Robinhood $25; top ALPHA $300, BETA $100, GAMMA $25.
  • 7d → 3 launches, 4 trades, $325 volume, 7 daily points including zero days.
  • all → 5 launches, 7 trades, $1425 volume, 61 daily points; top ECHO $5000.
  • format=csv → correct header plus one row per day.
  • /stats rendered the cards, both charts, the by-chain table and the warning at 133 KB HTML.

node .github/scripts/pr-guard.mjs --base upstream/main --head HEAD → pass (0 blocking, 0 for review).

Scope

Additive: new files under app/src/lib/stats/, app/src/app/stats/, app/src/app/api/stats/ and app/src/components/stats/, plus the small sitemap/llms/docs changes above. No existing route or read model is modified, so it does not overlap the open security/indexer, bridge, i18n or fee PRs.

There was no public, machine-readable view of what the launchpad has actually done. Add /stats and /api/stats: launches, distinct launchers, trades, distinct traders, trade-time USD volume, creator fees and burns, per chain and per UTC day, with a CSV export. Every USD figure is the value the indexer stored in the event's own hour; events without an hourly price are excluded and counted instead of being valued at today's price. The three aggregate reads use GROUPING SETS to return per-chain and global rows in one pass, share one 30-second memo between the page and the API, and fail soft to available:false rather than showing fake zeros. Verified against a seeded Postgres with 7d/30d/all windows.
@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

This review ran on the open-source allowance, not this organization's plan, because the pull request author doesn't have an assigned seat. Waiting won't change this — ask an organization admin to assign them a seat, or add seats in Billing if every seat is already assigned, then retry.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 14eacd55-d152-460c-8148-b695cc6c8b26
Commits

Reviewing files that changed from the base of the PR and between afcf935 and 74c4256.

Files selected for processing: 12

  • app/src/app/api/stats/route.test.ts
  • app/src/app/api/stats/route.ts
  • app/src/app/llms.txt/route.ts
  • app/src/app/stats/page.tsx
  • app/src/components/stats/Stats.module.css
  • app/src/components/stats/StatsChart.tsx
  • app/src/lib/seo.test.ts
  • app/src/lib/seo.ts
  • app/src/lib/stats/server.ts
  • app/src/lib/stats/stats.test.ts
  • app/src/lib/stats/stats.ts
  • docs/stats.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@Ayush7614

Copy link
Copy Markdown
Contributor Author

@coderabbitai please review the PR

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

@Ayush7614 I’ll start a review of the PR.


I couldn't check this conversation for new learnings, so no new learning was saved.

Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant