methodology_
Every number on screen, its formula and where it is read from. Rendered from metrics.ts, the same file the code computes from. 67 of 74 metrics are live; the rest say why not.
Protocol solvency
| Metric | Formula | Source | Grain | Status |
|---|---|---|---|---|
| Treasury | Exchange.treasury() Cross-checked against the Exchange's HyperCore spot USDC (Alchemy /info spotClearinghouseState); the delta is shown. | eth_call via Multicall3 | live, 5 s | live |
| HyperCore spot USDC | spotClearinghouseState(user = Exchange).balances[USDC].total | Alchemy /info | live, 5 s | live |
| Free LP cash | Exchange.lpBankrollAvailable() Zero whenever anything is queued, by invariant. | eth_call | live, 5 s | live |
| Net LP equity | lpBankrollAvailable() + sideBucket() − totalQueued() Can go negative. The single solvency number. | eth_call | live, 5 s | live |
| LP utilisation | totalLockedMargin() / treasury() | eth_call | live, 5 s | live |
| Worst-case 1% move | Σ over markets of |net exposure| × 1%, where net exposure = Σ long notional − Σ short notional of the open set Raw PnL before deadband, impact haircut and 2% fee, so it overstates what the LP would actually pay. Positions whose bust is crossed by the move are not netted out. | positions table (open set) + live mid | live, 5 s | live |
| Net house exposure | Σ long notional − Σ short notional per market (notional = margin × leverage). The LP is short this. | positions table (open set) | per ingest | live |
| Queue | totalQueued(); length = Σ Enqueued − Σ Harvested with remaining = 0; oldest entry age from Enqueued.ts | eth_call + queue_events | live | live |
| Loss inflow | Σ lpGain (close mint event, word 2) + Σ margin of liquidated positions (PaperMinted.lossBasis) lpGain on closes is net of the 2% fee (loss − fee); the liquidation term is gross margin, as the spec defines it. | positions table | hourly / trailing 1 h | live |
| Staker sweep | Σ StakerLpExcessDistributed.amount (word 1) | flows table | hourly / cumulative | live |
| Cap pin ratio | share of snapshots since launch with trackedLpUsd ≥ 0.98 × $5M | snapshots (archive eth_call every 300 blocks ≈ 5 min) | since launch | live |
| House edge realised | (Σ impact haircut + Σ win fees + Σ loss fees + Σ liquidation fees) / Σ |raw PnL|; haircut = pnlAfterDeadband − pnlAfterImpact on wins | positions table | range | live |
| Deadband kills | count of closes where exit beat entry and pnlAfterDeadband ≤ 0 | positions table | range | live |
| Treasury waterfall | Σ Swept − Σ CoreWithdrawal vs Δ treasury since the first deposit; residual shown Shown in QA on Day 1; the Flows page chart is Day 3. | flows + snapshots | since first deposit | live |
| Treasury decomposition | treasury = totalBalances + totalLockedMargin + lpBankrollAvailable + sideBucket + stakerFeeAccumulator + devFeeAccumulator + residual; totalQueued drawn as a negative band | snapshots (archive eth_call every 300 blocks) | 5 min since launch | live |
| Loss recycler | cumulative Σ gross loss vs cumulative Σ StakerLpExcessDistributed vs trackedLpUsd, hourly | hourly rollup + snapshots | hourly since launch | live |
| Hourly deposits vs withdrawals | Σ Swept.amount and Σ CoreWithdrawal.amount per UTC hour | hourly rollup | hourly | live |
| Withdrawal pressure | Σ withdrawals / Σ deposits over the trailing 1 h and 24 h | hourly rollup | trailing | live |
| LP overflow state | on if trackedLpUsd ≥ 0.98 × $5M; regime start = first hour of the current run of hours with (sweep > 0) == on; last sweep from StakerLpExcessDistributed | eth_call + flows + hourly | live | live |
Positions and risk
| Metric | Formula | Source | Grain | Status |
|---|---|---|---|---|
| Open positions | PositionOpened ids with no PositionClosed or Liquidated Reconciled against Exchange.positions(id) (struct word 8 = open flag) in QA. | positions table | per ingest | live |
| Notional | margin × leverage | PositionOpened | per position | live |
| Zero-equity price | entry × (1 − 1/lev) long; entry × (1 + 1/lev) short | PositionOpened | per position | live |
| Bust price (fitted) | entry × (1 ∓ (a/lev − b)); a, b by least squares of |Liquidated.bustPrice − entry| / entry on 1/lev over all liquidations The fitted a and b, row count and residual are published on this page. | positions table (liquidations) | refit on request, cached | live |
| Distance to bust | |mid − bust| / mid in bps, and in USD of adverse move | open set + live mid | live | live |
| Unrealised PnL | notional × (mid − entry) / entry × dir, before haircut | open set + live mid | live | pending: Take-home after deadband, impact and fee needs the deadband and impact curve constants, which are not yet fitted. Scheduled for Day 2 of the build plan (§9). |
| Liquidation map and ladder | map: each open position as a wall at its fitted bust price from open block to now; confirmed liquidations at (close_ts, Liquidated.price); depth profile by 2 bp bucket on the same price axis; longs below mid, shorts above Price path is 1m candles from Papertrade's own entry and exit prices (the BBO the Exchange settled at); minutes with no trade are gaps. Checked against Hyperliquid 1m closes: mean |diff| 0.28 bp. | open set + live mid + Liquidated + 1m candles from settlement prints | live, 5 s | live |
| Cascade | for a move of ±X bps: Σ notional and Σ margin of positions whose fitted bust is crossed; PAPER = margin × current mint rate; trackedLp after = trackedLp + margin, swept above $5M Static: ignores fees taken out of margin (2%) and second-round effects. The mint rate is held at today's rate across the move. | open set + live state | live | live |
| Leverage distribution | buckets 1–10, 10–50, 50–100, 100–500, 500–1000 by count and notional | positions table | range | live |
| Survival curve | Kaplan–Meier of lifetime by leverage bucket; event = liquidation, censor = close or still open | positions table | since launch | live |
| Realised liquidation probability | liquidations / positions closed, by leverage bucket and market | positions table | range | live |
| MAE / MFE from prints | for a random sample of 1,200 closed positions held 30 s to 2 h: worst (MAE) and best (MFE) excursion from entry in bp, measured on every other settlement print in the same market between open and close Prints are the exact BBO the Exchange settled at, but minutes with no other trade are invisible, so excursions are lower bounds. | positions (entry and exit prints) | 5 min, sampled | live |
| OI vs caps | open long and short notional per market vs latest MarketOiCapsUpdated caps | open set + admin_events | live | pending: Cap units (uint128) not yet confirmed against open notional. Scheduled for Day 2 of the build plan (§9). |
| Papertrade share of Hyperliquid | PT open notional / HL perp OI; PT hourly notional / HL hourly volume | positions + Hyperliquid public API metaAndAssetCtxs | live | pending: Scheduled for Day 2 of the build plan (§9). |
| Outcome funnel | closed positions split into wins (pnlAfterImpact > 0), losses, liquidations | positions | since launch | live |
| Median hold by outcome | median(close_ts − open_ts) for wins, losses and liquidations | positions | since launch | live |
| Open interest history | open notional at each hour end by market and side: baseline open set at the rollup start plus running Σ opened − Σ closed | hourly rollup | hourly | live |
Traders
| Metric | Formula | Source | Grain | Status |
|---|---|---|---|---|
| Realised PnL per wallet | Σ (pnlAfterImpact − fee) on wins + Σ pnlAfterImpact on losing closes − Σ margin on liquidations | positions table | since launch | live |
| Volume | Σ notional opened | positions table | range | live |
| Trades, win rate, liquidations | count of closed positions; wins = closes with pnlAfterImpact > 0; liquidations = Liquidated count | positions table | since launch | live |
| Cost per PAPER | USDC lost (loss inflow) / PAPER minted | positions table | per wallet, protocol-wide per hour | live |
| Revenge index | share of liquidations followed by a new open from the same wallet within 60 s | positions table | per wallet | live |
| Martingale score | slope of margin size within a wallet's consecutive losing sequence | positions table | per wallet | pending: Scheduled for Day 3 of the build plan (§9). |
| Long bias | long notional / total notional | positions table | per wallet | live |
| Time-of-day heatmap | opens and liquidations by UTC hour × weekday | positions table | range | live |
| Cohorts | first-deposit day × days since; retention, net PnL, deposits vs withdrawals | positions + flows | nightly | live |
| Concentration | top 10/50/100 share of volume, losses, PAPER; Lorenz curve and Gini | positions table | range | live |
| Exit-after-win | withdrawals within 10 minutes of a profitable close | positions + flows | range | live |
| HyperCore footprint | clearinghouseState, spotClearinghouseState, openOrders for a wallet | Alchemy /info | live | pending: Scheduled for Day 2 of the build plan (§9). |
| Suspicious closes | wins with move < 5 bps at leverage ≥ 500x, count per wallet; shown as a distribution A distribution, never an accusation. | positions table | range | pending: Scheduled for Day 3 of the build plan (§9). |
| New wallets per hour | count of wallets whose first PositionOpened falls in the hour | hourly rollup | hourly | live |
| Net flow per wallet | Σ deposits − Σ withdrawals per wallet, bucketed on a log scale | flows | since first deposit | live |
| Top stakers: lost vs earned | per wallet: stakedBalance(address) live; rewards = Σ Claimed + pendingReward(address); trading PnL as realised PnL; net cash = Σ CoreWithdrawal − Σ Swept + pendingReward; paid per PAPER = Σ lpGain ÷ Σ paperMinted; income/day = share of staked × trailing-24h Distributed Value at a reference price is a manual input; PAPER has no market. | staking_events, positions, flows, eth_call (Multicall3) | 5 min | live |
| Cost per PAPER by first-trade cohort | wallets grouped by the UTC day of their first PositionOpened: Σ lpGain ÷ Σ paperMinted; payback = Σ Claimed ÷ Σ lpGain | positions, staking_events | 5 min | live |
PAPER and stakers
| Metric | Formula | Source | Grain | Status |
|---|---|---|---|---|
| Mint rate | r(H) = 100 × (S / (S + H))², S = tailDecayScaleUsd() = $120M, H = tailProgressUsd(); 100 flat while trackedLpUsd < lpFlatThresholdUsd() = $2M | eth_call | live | live |
| Realised PAPER per $ | Σ paperMinted / Σ tailDelta per hour, from both mint events | positions table | hourly | live |
| Minted per hour by source | Σ paperMinted, closes vs liquidations | positions table | hourly | live |
| Supply reconciliation | Σ mints from both events vs PaperToken.totalSupply(); residual shown | positions + eth_call | live | live |
| Staked share | PaperStaking.totalStaked() / PaperToken.totalSupply() | eth_call | live | live |
| Stakers count | distinct Staked addresses with positive stakedBalance | staking_events + eth_call | nightly | pending: Scheduled for Day 2 of the build plan (§9). |
| Staker USDC yield | trailing 24 h Σ Distributed.amount × 365 / totalStaked, as USDC per 1M PAPER per year | staking_events + eth_call | trailing 24 h | live |
| Implied PAPER value | annualised staker USDC / totalStaked / discount rate, at 20%, 50%, 100% | derived | trailing 24 h | live |
| Fee split check | cumulative staker fees vs dev fees, expected 1:1 | PositionsClosed, Liquidated | since launch | live |
| Redemption probe | PaperTokenomics.quoteRedemption(1e18) Undocumented path. Currently reverts with selector 0x32aa90b0. | eth_call | live | live |
| Staker income, overflow vs fee share | per UTC day: Σ Distributed.amount; overflow = Σ StakerLpExcessDistributed.amount; fee share = Σ StakerFeesClaimed.amount Distributed is the push to PaperStaking; a day's fee share and overflow sum to it within the hour they were pushed. | hourly rollup | daily | live |
| Staker take | Σ staker USDC ÷ Σ notional opened × 10,000, per UTC day and trailing 24 h | hourly rollup | daily | live |
Operations
| Metric | Formula | Source | Grain | Status |
|---|---|---|---|---|
| Relayer batches | count of BatchExecuted in blocks whose timestamp is within the last 60 s of head | eth_getLogs + block headers | live, 5 s | live |
| Keepers | liquidations per block, blocks from bust crossing to Liquidated, harvest calls | positions + candles | range | live |
| Protocol changes | InstrumentAdded, MarketOiCapsUpdated, ERC1967 Upgraded; implementation slot polled hourly | admin_events + eth_getStorageAt | per ingest | live |
Valuation inputs
| Metric | Formula | Source | Grain | Status |
|---|---|---|---|---|
| Tail minted so far | 12B × H / (S + H) | derived from tailProgressUsd() | live | live |
| Flat-region minted (F) | totalSupply − tail minted; cross-checked by Σ paper where trackedLpBefore < $2M | eth_call + positions | live | live |
| Curve ceiling (conditional) | F + 100 × S = F + 12B Conditional: F grows again if trackedLp drops below $2M. | derived | live | live |
| Mint cost now | 1 / r(H) | derived | live | live |
| Net house PnL | Σ lpGain − Σ lpLoss per period (gross losses minus wins paid) | positions table | hourly | live |
| Valuation calculator | 12-month staker income = daily volume × take × 365; per PAPER = income × multiple ÷ totalStaked; FDV on the conditional ceiling Model, not a price. Measured defaults are the trailing 24 h. | hourly rollup + eth_call; user inputs | live | live |
Unconfirmed fields and the unnamed event
- PositionOpened: debtFunded name inferred (false on all samples)
- PositionClosed: debtFunded name inferred
- PositionsClosed: marginReturned, newBalance names inferred
- Liquidated: debtFunded name inferred
- Harvested: remaining name inferred
- StakerFeesClaimed: field names inferred
- StakerLpExcessDistributed: field 1 = amount per spec; fields 2,3 names inferred (2 == 1 and 3 == 0 on samples)
- DevFeesClaimed: field names inferred
- MarketOiCapsUpdated: cap names inferred
- Unstaked: found 15 Oct: topic0 0x0f5bb821… on PaperStaking hashes to this signature; not in spec v2
- BatchExecuted: word 4 unnamed
- 0x620c26bf… on PaperTokenomics fires once per close group (one per user per batch, after all of that group’s PositionClosed events). Words: lpLoss, lpGain, trackedLpBefore, trackedLpAfter, tailDelta, paperMinted. PAPER is allocated to the group’s positions in proportion to each position’s loss (−pnlAfterImpact − fee).
- On winning closes, trackedLpBefore equals trackedLpAfter in the event; the win has already been deducted when the event is emitted.
- 0x0bb3f42f… on Exchange: two words, no indexed fields, name not recovered. Not used.
Decisions log
# Decisions Spec items that were ambiguous but did not change the data model. Each was decided here and the build continued (kickoff rule 9). D-001 · ABI source. The companion `papertrade-events.json` was not supplied. `abi/papertrade-events.json` was rebuilt from the signatures in SPEC §3. Every event's keccak topic0 was matched against logs on chain, and every indexed and data word count was checked against a live sample (`scripts/recon/build-abi.mts`, `scripts/recon/idx.mts`). No signature was invented. Field names the spec does not give are marked "inferred" in the file. D-002 · Unstake event. The spec says no unstake event exists. Topic0 `0x0f5bb821…` on PaperStaking hashes to `Unstaked(address,uint256)`, so it is indexed as `unstaked`. D-003 · The close mint event is per group, not per position. The unnamed `0x620c26bf…` event fires once per user per close batch, after that group's PositionClosed events. Its lpGain equals Σ(−pnlAfterImpact − fee) over the group's losing closes, and its lpLoss equals Σ pnlAfterImpact over the group's wins. Each position stores its own lp_gain and lp_loss, computed from PositionClosed. The group's paperMinted and tailDelta are split across positions by loss share. The backfill found 3 groups out of 473,308 where the sums disagree by more than $0.0001, all at launch, and 0 unmatched groups. D-004 · Storage. USD and PAPER amounts are stored as float8 decoded from 1e18 integers, and wallets are interned to int4 ids, to keep inside Neon's free 0.5 GB. Exact integer checks (the PnL formula, supply) run against chain in `scripts/qa.ts`, not against the DB. D-005 · Timestamps. The backfill stores exact timestamps every 300 blocks (`blocks`) and interpolates linearly in between; HyperEVM runs at about 1.015 blocks/s, so the error is a few seconds at most. Live catch-up uses exact block timestamps. D-006 · Topics not indexed on Day 1: CallExecuted, NonceUsed, PaperToken Transfer, PositionsClosed, SweepRequested, StakingRewardCredited, BatchExecuted. None feeds a Day 1 panel. The top strip's relayer count reads BatchExecuted live from chain. The fee split check needs PositionsClosed and is marked pending. D-007 · Snapshot cadence. Every 300 blocks (about 5 minutes) instead of the spec's 500, so the "cap pin ratio" means what §4 says it means (share of 5-minute snapshots). D-008 · Vercel cron. The project is on the Hobby plan, which allows only daily crons, so a one-minute cron is not available. Live ingest has three parts: (a) every API request that reads the DB schedules a catch-up through `after()` when the cursor is more than 8 s old, guarded by a 55 s lease in the `cursor` table; (b) `/api/catchup` protected by `CRON_SECRET`, on a daily Vercel cron and callable from any external minute scheduler; (c) the Alchemy Notify webhook on Day 2. On the Pro plan, set the cron in `vercel.json` to `* * * * *`. D-009 · Bust price. Fitted per side as |bust − entry| / entry = a/lev − b over all liquidations (73,709 at QA): long a = 1.00043, b = 4.785 bps, R² 0.9999993 (43,266 rows); short a = 0.99945, b = 4.782 bps, R² 0.9999972 (30,443 rows). The live fit is recomputed every 10 minutes and shown on the Ladder page. D-010 · Reconciliation deltas against the spec's §1 table. Archive reads at block 48,549,415 reproduce treasury $61.45M, balances $44.98M, locked margin $11.65M, LP $4.82M, tail $154.35M, supply 7.408B and staked 7.352B. Differences: - nextPositionId − 1 = 662,267, against the spec's 662,279. - Accrued fees not yet pushed read staker $81 and dev $73, against the spec's $95.4k and $87.4k. These accumulators are pushed often, so the spec's read was probably taken at a different moment. - Queue: 3 Enqueued events totalling $22.87 at 1e18 scaling, against the spec's "$22.9k". All other amounts on this event family are consistent with 1e18 scaling. - §5.1 "stakers' cumulative sweep $150M+": Σ StakerLpExcessDistributed since launch is $37.9M. The $154M figure is the tail high-water mark (gross losses past $2M), not the sweep. The Loop shows $37.9M. - §1 "Treasury … down from $137.9M pre-launch": treasury() was $0 at the block before the first deposit (47,920,889). The waterfall reconciles Σ Swept − Σ CoreWithdrawal to Δ treasury with a residual of −$101 (0.0002%). D-011 · Loss inflow follows §4: Σ lpGain + Σ liquidated margin. lpGain on closes is already net of the 2% fee while the liquidation term is gross; this is stated on the methodology page. D-012 · OI caps. MarketOiCapsUpdated fires about 90 times per 2,000 blocks, so the caps are dynamic. Their units are not confirmed (raw ÷ 1e18 gives about 2,289 for BTC long), so "OI vs caps" stays pending until the units are matched to open notional. D-013 · Next.js 15 is kept as the spec asks. `npm audit` flags the PostCSS bundled inside Next for build-time CSS stringify and source-map issues. The app only processes its own CSS, so this is not reachable at runtime. Next 16 fixes it and is a later upgrade. D-014 · Local development without DATABASE_URL uses an embedded Postgres (PGlite socket server on port 5433, `.localdb/`). Production uses Neon through the Vercel Marketplace. D-015 · Distributed word order. §4 says "Σ Distributed.amount" without naming the word. On chain, word 2 equals StakerFeesClaimed.amount + StakerLpExcessDistributed.amount in the same tx (checked on tx 0x5c12f925…: 4,772.90 + 145,066.0 = 149,838.9). Word 1 tracks rewardReserve after the push. Word 2 is therefore the USDC amount. Lifetime: $40.89M = $37.90M LP sweep + $2.98M fees. D-016 · Struct layout of Exchange.positions(uint256), confirmed on 100 random ids at a pinned block: [owner, instrumentId, entryPrice, margin 1e18, leverage, openTimestamp, isLong, unknown, isOpen]. Word 7 matches isLong in only 52 of 100, so it is something else; not used. D-017 · Lint. `@typescript-eslint/no-explicit-any` is off. JSON-RPC payloads and decoded logs are untyped at the boundary, and `tsc --strict` still runs on every build. `scripts/` is excluded from the Next type-check and run with tsx. D-018 · Live-edge reconciliation (OPEN ISSUE). Reconciliation is exact (margin Δ $0.00, supply Δ 0.16 PAPER, waterfall $0.00) for any block 200 or more behind the cursor. Within the last ~200 blocks after a catch-up, sums disagree even though every open and close id is present, and the gap heals on later passes. The working hypothesis is a lagging RPC node or partially indexed recent blocks. Mitigation for now: catch-up stays 20 blocks behind head and re-scans the last 300 blocks on every pass. QA should pin at least 200 blocks behind the cursor (QA_LAG=200) until the root cause is found. D-019 · Hourly rollup and insight cache (15 Oct, depth pass). Request handlers never scan raw events: `hourly` (one row per UTC hour, 40 measures) is materialised by `refreshHourly`, called from the catch-up for the hours it touched; `kv` holds the heavy aggregates (concentration, survival, cohorts, fee split, flows) as JSON, refreshed by the catch-up when older than 5 minutes. Cold computation is about 20 s; serving is one row read. D-020 · No `Upgraded` events. None of the five proxies has emitted ERC1967 `Upgraded(address)` since deployment, so the protocol-changes feed shows InstrumentAdded only. Upgrade detection relies on polling the implementation slot and diffing against the launch-block value (parameters panel). D-021 · Time-series charts start at launch. Pre-launch hours (the $137.9M of deposits between 6 and 10 Oct) are excluded from every hourly chart so the axis is not dominated by one bar; lifetime totals that need them (waterfall, net flow since first deposit) read the full `flows` table. D-022 · `Distributed` on PaperStaking: word 2 is the USDC amount (see D-015). Hourly `staker_usdc` sums it; the fee share vs LP sweep split in the staker chart uses `StakerFeesClaimed` and `StakerLpExcessDistributed` from the same hours. D-023 · Liquidation map (15 Oct). The Ladder hero is a time × price map: every open position is a wall at its fitted bust price from the block it opened to now (width and opacity by notional), confirmed liquidations are dots at (close time, liquidation price), the price path is Hyperliquid 1-minute closes joined to the live BBO mid. A depth profile on the same price axis (2 bp buckets, longs left, shorts right) replaces the earlier stand-alone ladder, and the top eight buckets are labelled. Default view: ±1% of mid, 6 h, notional ≥ $100k; the "$10k+" chip is the floor the liquidation feed is capped at (8,000 rows). The §4 bucket scheme (1 bp near mid, 5 bp, 25 bp) is kept in the CSV/table view; on a linear price axis uniform 2 bp buckets draw more honestly. D-024 · 26 Oct, pre-launch pass. The indexer had fallen 690k blocks behind because the request-triggered catch-up moved 6,000 blocks per page view and the Hobby cron runs once a day; it now moves 30,000 blocks per pass (routes that trigger it declare maxDuration 60). The gap was closed with the backfill script. Neon's free project limit was hit at 468 MB; the installation moved to the Launch plan (usage-based, $0.35 per GB-month storage). Two recon-only indexes on `positions` were dropped (open_block, (close_type, close_block)). D-025 · Local Node connects to Neon only with `--no-network-family-autoselection`: Node 24's happy-eyeballs aborts the ~430 ms IPv4 connect. Scripts and the local dev server set NODE_OPTIONS accordingly; Vercel is unaffected. D-026 · Upsert ordering. Concurrent backfill windows deadlocked on `wallets` and `positions`; every chunk is now sorted (addresses, then position ids) so transactions take row locks in one order. Concurrency 2. D-027 · HyperCore preview. Alchemy's docs mark the market-data reads (candles, asset contexts, mids) "documented but not yet callable"; the HyperCore JSON-RPC host returns 401 for this key. Candles and 24h change stay on Hyperliquid's public API, labelled. The `/info` subset on the EVM host (spotClearinghouseState, clearinghouseState) keeps working. D-028 · Revenue page. Adds the narrative layer: staker income per UTC day split into fee share (StakerFeesClaimed) and overflow (StakerLpExcessDistributed), take in bp of volume, the live overflow regime, the top-25 stakers' trading PnL vs staking rewards (live stakedBalance and pendingReward via Multicall3), cost per PAPER by first-trade cohort, OI history by side from the hourly rollup, and a valuation calculator with measured defaults. The reference price ($0.0263, Paragon's 19 Oct settlement) is a manual input and says so. D-029 · Performance after the gap (2.1M positions). `positions` gained `open_ts` and `close_ts` indexes; trailing-window and recent-liquidation queries use them. Lifetime totals read the hourly rollup instead of scanning positions. Launch-block parameter reads are cached in `kv` for a day. The heavy aggregates are split into six `kv` keys (insightsA/B/C, flowsInsights, house, cohortCost) and the catch-up refreshes the stalest one per pass, so no single pass approaches the 60 s function limit. D-030 · 61 close-mint events (150k PAPER in total, blocks 49.19M–49.56M) had no PositionClosed from the same user in the same transaction; they sit in `close_mints_unmatched` and count toward supply reconciliation (residual 99 PAPER, 0.000001%). Not yet investigated; most likely closes executed through a different path than the relayer batch. D-031 · QA at block 49,562,444 (26 Oct): waterfall residual $0.00; Σ mints vs totalSupply 99.31 PAPER; open set Σ margin equals totalLockedMargin to $0.00 over 1,333 positions; 100/100 random positions match `positions(id)`; losses formula exact in wei 525/525; fee 2% 524/525 losses (one rounding), 463/463 wins; ladder next-hour precision 70.5%, recall 100%. D-032 · Cost per PAPER is shown as net trading loss (losses minus wins) ÷ PAPER minted, which is what a wallet actually paid in cash; gross losses ÷ PAPER (what minted) is in the CSV. The net figure reproduces the 22 Oct thread's $0.0064 for the top 10 (dashboard: $0.0065). D-033 · Silent upgrade on 21 Oct. The Exchange and PaperTokenomics implementations changed in block 49,169,385 (21 Oct 22:00:02 UTC), two days after the non-transferability post. No `Upgraded` event was emitted; the implementation-slot poll (parameters panel) caught it and the block was found by bisecting `eth_getStorageAt`. Checked after the upgrade: close fee still 2.000% of loss and of pnlAfterImpact; realised mint rate 9.81 PAPER/$ equals r(H) = 100 × (120M / (120M + 263M))², so the curve parameters and formula are unchanged. Two things did change: (a) 61 close-mint events since block 49,190,341 have no PositionClosed in the same transaction, carry round `lpGain` amounts ($500, $1,000), tailDelta 0 and a trackedLp increase equal to the amount, consistent with a direct "pay USDC, mint PAPER" path (150k PAPER so far; not yet confirmed from traces); (b) the mean pnlAfterImpact / pnlAfterDeadband ratio on winning closes fell from 0.553 to 0.473, which may be a heavier impact haircut or a different mix of moves; shown as observed, not explained. D-034 · Candle source switched to settlement prints (26 Oct). The price path on the Ladder, the 24 h change in the strip and the MAE/MFE approximation now come from Papertrade's own prints: every PositionOpened entry and every PositionClosed / Liquidated exit, which are the exact HyperCore BBO prices the Exchange settled at (indexed from HyperEVM logs via Alchemy). Checked against Hyperliquid's public 1-minute closes: 1,434 of 1,440 minutes covered, mean |diff| 0.28 bp. Hyperliquid's public API is kept only as a fallback when a window has no prints, and the response carries its source. The print queries filter on the open_ts / close_ts indexes. D-035 · QA at block 49,569,232 (26 Oct, after the prints switch): waterfall residual $0.00; Σ mints vs totalSupply 99.31 PAPER; open set equals totalLockedMargin to $0.00 over 1,379 positions; 100/100 positions match `positions(id)`; losses formula exact in wei 542/542; fee 2% 542/542 and 443/443; ladder next-hour precision 71.4%, recall 100%. MAE/MFE from prints on 1,199 sampled positions: wins close at a median MAE of 0 bp and MFE 6.9 bp; losses MAE 4.0 bp; liquidations MAE 6.6 bp with a median MFE of 2.8 bp, i.e. most liquidated positions had a small profitable exit they did not take. D-036 · Rebrand to PAPERNOMICS (27 Oct). paperscope.xyz and papertrail.xyz were both taken by the time of launch; papernomics.xyz was free ($1.99 first year, $13/year after) and fits the Revenue angle. The product, wordmark, page titles, CSV filenames and article brief use the new name; the Vercel project, repo folder and internal identifiers keep `paperscope`. The purchase itself had to be made by the author: Vercel's CLI refuses domain purchases from agents by policy.
Disclosure
Unofficial and unaffiliated with Papertrade. The contracts are unverified and upgradeable, so any upgrade can change the meaning of a field; PAPERNOMICS polls the implementation slots and flags changes. BTC and ETH candles and 24-hour changes are rebuilt from Papertrade's own settlement prints (every open, close and liquidation price, indexed through Alchemy); Hyperliquid's public API is used only as a fallback if that read fails. Price manipulation of the BBO is acknowledged in the protocol's own docs; any suspicious-close panel is a distribution, never an accusation. Nothing here is financial advice.