Model Layer
Location:src/data/models/
The model layer is a lightweight, dependency-free schema layer that gives every feature a shared vocabulary for data shapes, source provenance, and quality metadata. It has zero external dependencies.
Before this layer, data shapes were embedded inline in individual API handlers. Features that build on the same on-chain data (Dune baselines, live wallet events, AI narratives) now share types without re-inventing them.
Model inventory
| File | Models | Used by |
|---|---|---|
source-metadata.js | SourceMetadata, DataQuality | All models |
historical-baseline.js | HistoricalWalletBaseline, HistoricalTokenFlow, HistoricalCounterparty, HistoricalProtocolUsage | Whale Watcher, signal engine, narratives |
live-events.js | LiveWalletEvent | Whale Watcher, signal engine |
signals.js | WalletSignal | Whale Watcher, signal engine, narratives |
narrative.js | NarrativeInput, NarrativeCard | Narrative engine |
holder-wall.js | HolderWallTile | Holder Wall treemap surfaces |
market-radar.js | MarketRadarResult | api/market-radar.js |
quantum-exposure.js | QuantumExposureScore | Quantum Intelligence |
SourceMetadata — the provenance backbone
Every major model carries at least oneSourceMetadata entry. This lets the UI display data-freshness badges and lets consumers decide how much to trust a value.
sourceType values:
dune_scheduled · dune_cached · alchemy · etherscan · coingecko · the_graph · bigquery · ai_narrative · computed · mock
Rules:
- Dune data is scheduled/cached, never live. Use
dune_scheduledfor results from a Vercel Cron or Dune-scheduled run; usedune_cachedwhen served from Redis. bigqueryis a reserved future source type. The MVP avoids a GCP dependency.
DataQuality
Structured quality annotation attached to every model. UsemergeDataQuality() when combining data from multiple sources.
WalletSignal
AWalletSignal is a deterministic, sourced fact about wallet behaviour. It is the atomic unit consumed by the narrative engine and the Whale Watcher workspace.
makeSignalId(walletAddress, signalType, windowStart) produces a stable 8-hex-char ID using djb2 — browser-safe, no crypto dependency.
NarrativeInput / NarrativeCard
NarrativeInput is what you pass to api/analyze.js. NarrativeCard is the structured output you store and render.
makeNarrativeCard enforces: headline ≤ 120 chars, keyPoints ≤ 5 entries, caveats non-empty.
HolderWallTile
HolderWallTile represents one holder in the treemap. It deliberately separates:
historicalSource— always Dune scheduled/cached dataliveSource— optional live delta from supported providers;nullwhen unavailable
HolderWallTile does not contain market-level statistics. Use MarketRadarResult for token/pool market lookup.
MarketRadarResult
Stable Seer data only. No holder analytics. NowalletAddress field. The following fields are intentionally absent: holderCount, topHolders, holderType.
QuantumExposureScore
A 0–100 composite score. Key constraints enforced by the factory:scoreis clamped to [0, 100]riskBandis derived fromscoreviascoreToRiskBand()caveatsdefaults toREQUIRED_CAVEATS(4 entries) — never emptydisclaimerdefaults toSTANDARD_DISCLAIMER
Fixtures
src/data/models/fixtures/ contains six ready-to-use objects for tests, Storybook stories, and API fallbacks:
| File | Scenario |
|---|---|
whale-accumulation.js | High-confidence whale accumulation — baseline + signal + narrative card |
normal-activity.js | Regular DeFi user — medium confidence with estimated prices |
low-confidence.js | Truncated Dune result — low confidence, multiple warnings |
holder-wall-tile.js | ETH whale tile — dual Dune + Alchemy source |
market-radar-result.js | Trending PEPE — rising volume, no holder analytics |
quantum-exposure-score.js | Medium-exposure wallet — full breakdown + caveats |
Provenance UI
Usesrc/components/DataSourceBadge.jsx for compact source footnotes on cards, metric rows, and preview metadata. It accepts either model-style source / dataQuality objects or explicit props:
queryName for user-facing context and only set showQueryId when the ID is intentionally public.
Hard constraints
These are enforced by the test suite:- Dune sources must have
sourceTypeofdune_scheduledordune_cached— never a live type. WalletSignal.caveatsmust be non-empty.NarrativeCard.caveatsmust be non-empty.QuantumExposureScore.caveatsmust be non-empty;disclaimermust be non-empty.MarketRadarResultmust not contain holder analytics fields.HolderWallTile.historicalSourcemust be a Dune source type.QuantumExposureScore.scoreis clamped to [0, 100].- No external dependencies — zero
node_modulesimports.