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

Closed
opened 2026-05-21 04:41:42 +00:00 by PlasticDigits · 8 comments
PlasticDigits commented 2026-05-21 04:41:42 +00:00 (Migrated from gitlab.com)

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) 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).

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).

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
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)
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).
  • 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.
## 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`](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`](frontend/src/pages/TimeCurveProtocolPage.tsx) | Mount new section after **Sale state** or before **Immutable parameters** | | Subnav | [`frontend/src/pages/timecurve/TimeCurveSubnav.tsx`](frontend/src/pages/timecurve/TimeCurveSubnav.tsx) | Route `/timecurve/protocol`, label **AUDIT** | | Protocol reads | [`frontend/src/pages/timecurve/TimeCurveProtocolDataContext.tsx`](frontend/src/pages/timecurve/TimeCurveProtocolDataContext.tsx) | Multicall already returns `totalRaised`, `totalTokensForSale`, `totalCharmWeight`, `currentPricePerCharmWad` | | Projection math (shared) | [`frontend/src/lib/timeCurvePodiumMath.ts`](frontend/src/lib/timeCurvePodiumMath.ts) | `doubPerCharmAtLaunchWad`, `projectedReservePerDoubWad`, `launchLiquidityAnchorWad`, `kumbayaBandLowerWad` | | Accordion mirrors | [`frontend/src/pages/timecurve/useTimecurveProtocolRawAccordion.ts`](frontend/src/pages/timecurve/useTimecurveProtocolRawAccordion.ts) | Already builds `liquidityAnchors` from onchain totals | | Simple rate board | [`frontend/src/pages/TimeCurveSimplePage.tsx`](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`](frontend/src/pages/timecurve/timecurveUi.tsx) `StatCard` + `.stats-grid` | Match Arena / WarBow stat grids | | Empty states (#200) | [`EmptyDataPlaceholder`](frontend/src/components/EmptyDataPlaceholder.tsx), `statFromContractRead` | No bare em dashes for loading/gated values | | Redemption economics | [`docs/product/primitives.md`](docs/product/primitives.md#timecurve-redemption-cl8y-density-no-referral) | 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). ## Recommended solution ### 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). ### 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 | | **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) | | **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). - [ ] 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. ### E2E (optional but recommended) - [ ] Extend [`frontend/e2e/timecurve.spec.ts`](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) - [ ] One-line cross-link in [`docs/frontend/timecurve-views.md`](docs/frontend/timecurve-views.md) under protocol/AUDIT section. - [ ] Optional `INV-FRONTEND-*` row in [`docs/testing/invariants-and-business-logic.md`](docs/testing/invariants-and-business-logic.md) if maintainers want guardrail coverage. ## 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.
PlasticDigits commented 2026-05-21 05:42:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #231

mentioned in issue #231
PlasticDigits commented 2026-05-21 11:59:34 +00:00 (Migrated from gitlab.com)

251m is updated supply, with 1m for airdrops
marketcap should use launch anchor (27.5% higher than current cl8y/doub ratio)
No should not appear while sale start pending.

251m is updated supply, with 1m for airdrops marketcap should use launch anchor (27.5% higher than current cl8y/doub ratio) No should not appear while sale start pending.
PlasticDigits commented 2026-05-21 12:02:49 +00:00 (Migrated from gitlab.com)

mentioned in commit b0f3447ede

mentioned in commit b0f3447ede02b4a2a4e3c40646a8d07a0ec06830
PlasticDigits commented 2026-05-21 12:02:59 +00:00 (Migrated from gitlab.com)

Implementation summary (pushed to main @ b0f3447)

Added a DOUB projection section on /timecurve/protocol (AUDIT tab), visible only while the sale is live (hidden during saleStartPending per product sign-off).

What changed

  • TimeCurveProtocolDoubProjectionSection — stats-grid of operator-facing launch economics (data-testid="timecurve-protocol-doub-projection").
  • doubProjectionStats.ts — pure helpers reusing timeCurvePodiumMath (clearing, 1.275× launch anchor, Kumbaya floor, CHARM→DOUB).
  • Policy: 251M projected supply (250M genesis table + 1M airdrops); implied market cap uses launch-anchor CL8Y/DOUB (not clearing alone).
  • Docs / guardrails: INV-FRONTEND-229-DOUB-PROJECTION, timecurve-views §229, manual QA #229, launchplan-timecurve.md §4 footnote, skills/README.md, .cursor/skills/yieldomega-guardrails item 55.

Tests run

  • npx vitest run src/lib/doubProjectionStats.test.ts src/lib/timeCurvePodiumMath.test.ts — 18 passed
  • Pre-commit tsc -b on commit

Verification checklist (please confirm)

  • Open /timecurve/protocol with live sale — projection card visible without expanding raw accordion
  • Pre-open (saleStartPending) — card not shown
  • Projected total supply = 251M DOUB; sale bucket ≈ 200M on DeployDev
  • Before first buy — CHARM → DOUB shows empty placeholder (not 0 / Infinity)
  • After buys — CHARM→DOUB decreases; clearing CL8Y/DOUB flat or rises; launch anchor = 1.275× clearing
  • Market cap (CL8Y) uses launch anchor; USD line has illustrative disclosure (#192)
  • Accordion Reserve routing and launch anchors matches card rows
  • Mobile ≤479px — no horizontal overflow on stat grid
  • Playwright AUDIT route asserts timecurve-protocol-doub-projection (when Anvil E2E stack available)

@nullvector_ux — could you run through the checklist above on Anvil/devnet and confirm UX/copy?

Issue left open until verified.

## Implementation summary (pushed to `main` @ `b0f3447`) Added a **DOUB projection** section on **`/timecurve/protocol`** (AUDIT tab), visible only while the sale is **live** (hidden during `saleStartPending` per product sign-off). ### What changed - **`TimeCurveProtocolDoubProjectionSection`** — `stats-grid` of operator-facing launch economics (`data-testid="timecurve-protocol-doub-projection"`). - **`doubProjectionStats.ts`** — pure helpers reusing `timeCurvePodiumMath` (clearing, **1.275×** launch anchor, Kumbaya floor, CHARM→DOUB). - **Policy:** **251M** projected supply (250M genesis table + **1M airdrops**); **implied market cap** uses **launch-anchor** CL8Y/DOUB (not clearing alone). - **Docs / guardrails:** `INV-FRONTEND-229-DOUB-PROJECTION`, [timecurve-views §229](docs/frontend/timecurve-views.md#timecurve-protocol-doub-projection-gitlab-229), [manual QA #229](docs/testing/manual-qa-checklists.md#manual-qa-issue-229), `launchplan-timecurve.md` §4 footnote, `skills/README.md`, `.cursor/skills/yieldomega-guardrails` item **55**. ### Tests run - `npx vitest run src/lib/doubProjectionStats.test.ts src/lib/timeCurvePodiumMath.test.ts` — **18 passed** - Pre-commit **`tsc -b`** on commit ### Verification checklist (please confirm) - [ ] Open **`/timecurve/protocol`** with live sale — projection card visible **without** expanding raw accordion - [ ] **Pre-open** (`saleStartPending`) — card **not** shown - [ ] **Projected total supply** = **251M DOUB**; sale bucket ≈ **200M** on DeployDev - [ ] Before first buy — **CHARM → DOUB** shows empty placeholder (not `0` / `Infinity`) - [ ] After buys — CHARM→DOUB **decreases**; clearing CL8Y/DOUB **flat or rises**; launch anchor = **1.275×** clearing - [ ] **Market cap (CL8Y)** uses launch anchor; **USD** line has illustrative disclosure (#192) - [ ] Accordion **Reserve routing and launch anchors** matches card rows - [ ] Mobile ≤479px — no horizontal overflow on stat grid - [ ] Playwright AUDIT route asserts `timecurve-protocol-doub-projection` (when Anvil E2E stack available) @nullvector_ux — could you run through the checklist above on Anvil/devnet and confirm UX/copy? Issue left **open** until verified.
nullvector_ux commented 2026-05-21 13:18:49 +00:00 (Migrated from gitlab.com)

Verification checklist (please confirm) @PlasticDigits

  • Open /timecurve/protocol with live sale — projection card visible without expanding raw accordion
  • Pre-open (saleStartPending) — card not shown
  • Projected total supply = 251M DOUB; sale bucket ≈ 200M on DeployDev
  • Before first buy — CHARM → DOUB shows empty placeholder (not 0 / Infinity)
  • After buys — CHARM→DOUB decreases; clearing CL8Y/DOUB flat or rises; launch anchor = 1.275× clearing
  • Market cap (CL8Y) uses launch anchor; USD line has illustrative disclosure (#192)
  • Accordion Reserve routing and launch anchors matches card rows
  • Mobile ≤479px — no horizontal overflow on stat grid
  • Playwright AUDIT route asserts timecurve-protocol-doub-projection (when Anvil E2E stack available)
### Verification checklist (please confirm) @PlasticDigits * [x] Open **`/timecurve/protocol`** with live sale — projection card visible **without** expanding raw accordion * [x] **Pre-open** (`saleStartPending`) — card **not** shown * [x] **Projected total supply** = **251M DOUB**; sale bucket ≈ **200M** on DeployDev * [x] Before first buy — **CHARM → DOUB** shows empty placeholder (not `0` / `Infinity`) * [x] After buys — CHARM→DOUB **decreases**; clearing CL8Y/DOUB **flat or rises**; launch anchor = **1.275×** clearing * [x] **Market cap (CL8Y)** uses launch anchor; **USD** line has illustrative disclosure (#192) * [x] Accordion **Reserve routing and launch anchors** matches card rows * [x] Mobile ≤479px — no horizontal overflow on stat grid * [x] Playwright AUDIT route asserts `timecurve-protocol-doub-projection` (when Anvil E2E stack available)
PlasticDigits commented 2026-05-21 13:21:02 +00:00 (Migrated from gitlab.com)

mentioned in issue #234

mentioned in issue #234
PlasticDigits commented 2026-05-21 13:21:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #235

mentioned in issue #235
PlasticDigits commented 2026-05-21 13:21:14 +00:00 (Migrated from gitlab.com)

marked as related to #235

marked as related to #235
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-22 05:40:16 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#229
No description provided.