Wallet Risk Report Model
WalletRiskReport.v1 is the canonical per-wallet risk assessment for a single public
Ethereum address. It composes four existing dimensions — quantum exposure readiness,
stablecoin/concentration exposure, dormancy/activity, and deterministic behavioral signals
— into one object with an overall canonical readiness tier, without inventing any new
score, tier, or driver vocabulary.
Source: src/lib/wallet-risk-report/
(schema.js, build-wallet-risk-report.js) and
api/wallet-risk-report.js.
Three report-shaped objects — do not confuse them
This is the third distinct report/packet object in the codebase. Each has a different scope and a different purpose:| Object | Scope | Purpose | Signed? |
|---|---|---|---|
Vault Readiness Packet (buildVaultReadinessPacket.js) | Per-wallet, vault-specific | A bounded, shareable “proof packet” for the Vault Candidate surface | Yes, via api/readiness-packet.js (ECDSA P-256) |
Exposure Report Edition (exposure-report/buildExposureReportEdition.js) | Cohort (many wallets aggregated) | A citable, dated snapshot of Holder Wall cohort exposure stats | No |
| Wallet Risk Report (this page) | Per-wallet, general-purpose | The canonical cross-dimension risk assessment for one wallet | No (v1) |
Schema shape
What each dimension actually is
Quantum
Reuses
api/quantum-readiness.js’s already-composed Quantum Vault Readiness pipeline
(score/band/exposureLevel, higher = better-prepared) plus its freshness-aware evidence
diagnostics. The separate, higher-is-worse “Quantum Exposure Score” pipeline
(src/lib/quantum-exposure.js) is intentionally not composed in v1 — see
“Deferred work” below.Concentration
Reuses
getStablecoinVaultReadiness() (stablecoin balance / portfolio share / dormancy
/ signature exposure), which implements the OR-of-four-facts null-gate: score/tier stay
null only when none of the four primary facts were observed.Dormancy / activity
Built directly from the Dune-sourced
dormancy facts (daysDormant, dormancyBucket,
lastActiveAt) already fetched for the Quantum dimension — no separate query.Behavior
Reuses
deriveWhaleWatcherSignals() — the same deterministic WalletSignal[] engine
Whale Watcher itself uses. An empty signal array is a valid, meaningful “no notable
behavior” result, distinct from “no evidence” (status: 'unknown'), which is set only
when neither a Dune 12-week baseline nor live transaction events existed to evaluate.The overall readiness tier
Theoverall.riskTier is derived by calling buildStablecoinVaultReadiness() — the same
composition point existing Vault Readiness surfaces already use — not a new tier-derivation
rule. That function resolves the strongest categorical signal across whichever dimension
inputs are available and bridges the result to risk-tiers.js’s canonical 5-tier vocabulary
(monitor → review → prepare → migrate → vaultPrototype / “Vault Candidate”) via
getCanonicalRiskTier().
There is no separate composite risk score. overall.compositeScoreNote says so
explicitly on every report — each dimension carries its own score/label on its own scale;
they are never averaged or blended into one number (see “What’s deterministic, inferred, or
unavailable” below for why: the dimensions genuinely use different scales and null-gate
rules, and collapsing them would erase real distinctions the underlying models were built
to preserve).
Deterministic vs. inferred vs. unavailable
| Category | Meaning | Example |
|---|---|---|
| Deterministic (observed) | Read directly from a source, or a pure deterministic function of observed facts | dimensions.quantum.value.vaultReadinessScore when Dune facts exist |
| Deterministic (inferred) | A pure, deterministic derivation with no invented data | overall.riskTier, derived from dimension outputs via the existing composition rules |
Unavailable (status: 'unknown') | No evidence source existed | dimensions.behavior when neither a Dune 12-week baseline nor live wallet transactions were available |
AI narrative generation is optional and strictly downstream — never computed by this module. narrative is always null in v1. A future PR may add an opt-in narrative step
that reads a finished WalletRiskReport and produces plain-English copy; it must never be
required to interpret the report, and it must never write back into the deterministic
fields above.
Honesty rules (enforced by tests)
- Unknown is never zero. A dimension with no evidence reports
status: 'unknown', not a fabricated'monitor'/0/false. - Stale/conflicting evidence lowers confidence, not necessarily severity. A stale Dune
dormancy fact downgrades
dimensions.dormancyActivity.confidence, but does not by itself changeoverall.riskTier. - If nothing can be honestly assessed, the report says so structurally —
status: 'insufficient_evidence',overall.riskTier: null,overall.recommendation: 'unsupported'— never a fabricated tier. - The client cannot inject any computed field. The read-only API
(
GET /api/wallet-risk-report?address=0x…) never reads a request body, and the only client-controlled input is the wallet address itself. - Dune data is never described as live.
dataSources[].typedistinguishesdune_scheduledfromlive_provider; the app-wide Dune spend-path rules (docs/operations/dune-spend-path-controls.md) apply unchanged — this endpoint only reads Dune’s cache, never executes or reads live results. - Mock/demo data is never served as a real report. Unlike
/api/wallet, this endpoint does not fall back tomockWalletProviderwhen no live provider key is configured — the concentration and behavior dimensions honestly degrade tounknowninstead.
Deferred work (intentional v1 scope)
Not built in this PR — listed here so a follow-up doesn’t need to rediscover the reasoning:- Report page / UI. This PR ships the model, API, tests, and docs only.
- Quantum Exposure Score pipeline (
deriveWalletSignatureExposure→deriveQuantumExposureScore). That pipeline has never been server-composed anywhere in this codebase; wiring it here would mean writing new composition logic rather than reusing an existing one. v1 composes the already fully server-composed Quantum Vault Readiness pipeline instead. - Dune 12-week Whale Watcher cohort baseline. The behavior dimension currently relies only on live wallet transactions (when a provider key is configured) for its baseline; most report subjects are outside the curated 12-week active-wallet cohort anyway.
- ENS resolution. The endpoint requires a raw
0xaddress; resolve via/api/resolve-walletfirst. - Report persistence, sharing, signing, or a database. Every call recomputes the report fresh from current cache/live state.
- Portfolio / multi-wallet batching.
- Reconciling Vault’s two disagreeing threshold sets (legacy 30/60 vs. canonical 25/50/75) — a pre-existing, separate gap this PR does not touch.
Related
Wallet Evidence Model
The provenance-aware
/api/wallet layer this report’s concentration dimension reads
balances from.Model Layer
The shared
SourceMetadata / DataQuality / WalletSignal conventions this report’s
behavior dimension builds on.
