AUDIT page: DOUB projection card (supply, market cap, CHARM rate)

Context

The TimeCurve AUDIT surface (/timecurve/protocol, subnav label AUDIT) is the operator-facing protocol view (TimeCurveProtocolPage). It already exposes semilive sale reads, total raise, immutable parameters, and a collapsed Raw contract and operator context accordion with liquidity anchors and a charm redemption curve — but those projection economics are buried and not summarized for quick scanning.

Product ask: add a prominent “DOUB projection” card on this page showing projected full supply, implied market cap, price per DOUB, CHARM→DOUB conversion, and related launch economics.

Note on supply figure: Request cites 251M projected supply. Canonical genesis policy in launchplan-timecurve.md §4 is 250M DOUB (200M TimeCurve sale + 21.5M presale + 28.5M V3 LP). Confirm with product whether the UI constant should be 250M (doc-aligned) or 251M (updated policy) before hard-coding.

Current codebase (research)

Area Location Relevance
AUDIT page shell frontend/src/pages/TimeCurveProtocolPage.tsx Mount new section after Sale state or before Immutable parameters
Subnav frontend/src/pages/timecurve/TimeCurveSubnav.tsx Route /timecurve/protocol, label AUDIT
Protocol reads frontend/src/pages/timecurve/TimeCurveProtocolDataContext.tsx Multicall already returns totalRaised, totalTokensForSale, totalCharmWeight, currentPricePerCharmWad
Projection math (shared) frontend/src/lib/timeCurvePodiumMath.ts doubPerCharmAtLaunchWad, projectedReservePerDoubWad, launchLiquidityAnchorWad, kumbayaBandLowerWad
Accordion mirrors frontend/src/pages/timecurve/useTimecurveProtocolRawAccordion.ts Already builds liquidityAnchors from onchain totals
Simple rate board frontend/src/pages/TimeCurveSimplePage.tsx Shows 1 CHARM = N DOUB = M CL8Y at launch — keep formulas aligned
Stat card pattern frontend/src/pages/timecurve/timecurveUi.tsx StatCard + .stats-grid Match Arena / WarBow stat grids
Empty states (#200 (closed)) EmptyDataPlaceholder, statFromContractRead No bare em dashes for loading/gated values
Redemption economics docs/product/primitives.md DOUB/CHARM dilutes; implied CL8Y/DOUB rises with totalRaised

Authoritative rule: Displayed economics must be derivable from onchain views + documented constants — do not invent offchain “market cap” from external oracles on this surface. USD lines may follow existing illustrative pattern (1 CL8Y = $1, same as TOTAL USD on this page — GitLab #192 (closed)).

1. New UI block on TimeCurveProtocolPage

Add a PageSection (or data-panel data-panel--stack) titled “DOUB projection” with a short lede: Live redemption and launch-liquidity economics from onchain sale totals; full-supply figure is policy constant.

Use a stats-grid of StatCard rows (4 sigfig compact formatting via existing formatBuyHubDerivedCompact / formatCompactFromRaw where appropriate — GitLab #191 (closed)).

2. Proposed stat rows

Label Source Formula / notes
Projected total supply Product constant (250M or 251M per sign-off) Whole-token display with checksum footnote linking to launchplan-timecurve.md §4
Sale bucket (onchain) TimeCurve.totalTokensForSale() Should read 200M when deploy follows launch plan
CHARM → DOUB at launch doubPerCharmAtLaunchWad({ totalTokensForSale, totalCharmWeight }) Label as redemption rate (decreases as sale progresses)
Implied CL8Y / DOUB (clearing) projectedReservePerDoubWad(totalRaised, totalTokensForSale) Same as accordion “Projected reserve / DOUB”
Launch anchor CL8Y / DOUB launchLiquidityAnchorWad(clearing) 1.275× clearing — GitLab #158 (closed)
Kumbaya band floor kumbayaBandLowerWad(launchAnchor) 0.8× launch anchor
Implied market cap (CL8Y) projectedSupplyWei × clearingWad / 1e18 Footnote: uses clearing price, not launch anchor
Implied market cap (USD illustrative) marketCapCl8y × static $1/CL8Y Same staleness/disclosure pattern as hero TOTAL USD (#192 (closed))
Per-CHARM price (live) currentPricePerCharmWad() Context for launch CL8Y projection chain
Sale progress totalCharmWeight / totalTokensForSale or % of sale bucket “allocated” via weight Optional; helps operators

Reuse protocol page’s existing totalRaiseSerialized / freshness affordance where market cap should show “seen X ago”.

3. Implementation sketch

  • Extract a small pure helper module, e.g. frontend/src/lib/doubProjectionStats.ts, that takes bigint inputs + projectedSupplyWholeTokens and returns formatted stat payloads (unit-tested).
  • Optional presentational component: TimeCurveProtocolDoubProjectionSection.tsx to keep TimeCurveProtocolPage readable.
  • Wire reads from existing useTimeCurveProtocolData() / get(3..5,8) indices — no new RPC surface unless product requires total ERC20 Doubloon.totalSupply() (not needed for launch projection card).
  • Do not duplicate accordion-only content: link or repeat the three anchor lines consistently with liquidityAnchors in the raw accordion.

4. Out of scope (unless product expands)

  • Wallet-level projected DOUB holdings (Simple stake panel policy — dilution UX).
  • External price feeds / MegaETH indexers for “real” USD market cap.
  • Changing genesis mint policy in contracts (docs-only constant for full supply).

Verification criteria (definition of done)

Automated

  • Unit tests in doubProjectionStats.test.ts (or extend timeCurvePodiumMath.test.ts): fixture totalRaised + totalTokensForSale + totalCharmWeight produce expected CHARM→DOUB, clearing CL8Y/DOUB, launch anchor, market cap at fixed projected supply.
  • Regression: existing timeCurvePodiumMath tests remain green.
  • Vitest for any formatter wiring if extracted.

Manual / visual QA

  • Open /timecurve/protocol (AUDIT tab) with VITE_TIMECURVE_ADDRESS set and sale live on Anvil or devnet.
  • DOUB projection card is visible without expanding “Raw contract and operator context”.
  • As bots/users buy CHARM: CHARM → DOUB decreases; implied CL8Y / DOUB stays flat or increases; cards refresh on ~1s multicall cadence without flicker to em dash (sticky latch behavior preserved).
  • Before first buy (totalCharmWeight == 0): CHARM→DOUB shows intentional empty placeholder per INV-FRONTEND-200, not 0 or Infinity.
  • Projected total supply matches signed-off constant (250M or 251M) and footnote matches launchplan-timecurve.md.
  • Market cap USD line includes illustrative/static-rate disclosure consistent with TOTAL USD block on same page (#192 (closed)).
  • Values in card match expanded accordion Reserve routing and launch anchors rows (clearing / launch / Kumbaya lower) when accordion is opened.
  • Mobile: stats-grid wraps; no horizontal overflow on ≤479px.
  • Extend frontend/e2e/timecurve.spec.ts AUDIT navigation test: assert data-testid="timecurve-protocol-doub-projection" (or section heading) is present after clicking AUDIT.

Docs / invariants (light touch)

Dependencies / decisions needed

  1. Confirm 250M vs 251M projected supply constant.
  2. Confirm market cap uses clearing CL8Y/DOUB vs launch anchor (recommend clearing for “spot implied”, anchor as secondary row — already listed above).
  3. Whether card should appear pre-sale (saleStartPending) with static policy rows only.