Skip to main content

Wallet Risk Report Model

WalletRiskReport.v1 adds no new scoring, no new provider, no Dune execution, and no wallet connection or signing. It is a read-only composition layer over EXISTING canonical scorers — Quantum Vault Readiness, Stablecoin Vault Readiness, Migration Readiness, and Whale Watcher behavioral signals. The report is reachable via a live route (/wallet-risk-report/:chain/:address, with entry points from Whale Watcher, Quantum, and Wallet Profile) and a share-snapshot route (/wallet-risk-report#<fragment>) using client-side content-hash integrity only — not cryptographically signed, unlike the Vault Readiness Packet.
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: The Wallet Risk Report is the only one of the three that spans quantum + concentration + dormancy + behavior in a single object with an overall readiness tier. It never aggregates across wallets (that’s the Exposure Report’s job) and it is not a vault-specific artifact (that’s the Readiness Packet’s job).

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

The overall.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 (monitorreviewpreparemigratevaultPrototype / “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

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 change overall.riskTier.
  • If nothing can be honestly assessed, the report says so structurallystatus: '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[].type distinguishes dune_scheduled from live_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 to mockWalletProvider when no live provider key is configured — the concentration and behavior dimensions honestly degrade to unknown instead.
  • The report can never read more confident than the canonical Whale Watcher page for the same wallet snapshot. dimensions.behavior.confidence is capped by the SAME evaluateWhaleInvariants/resolveWhaleConfidence composition WhaleWatcher.jsx’s buildLedgerProps applies — a cross-domain invariant failure (an internally contradictory priced-movement sample) marks status: 'partial' and surfaces INVARIANT_FAILED in reasonCodes, the same way it would show a data-quality warning on the live page (see AUDIT-WALLET-RISK-WHALE-BYPASS in data-foundation-audit.md). This is enforced for every consumer built on top of the report — CSV/JSON export, Portfolio Assessment, and the /api/analyze narrative payload (which withholds transferVolumeUsd/netFlowUsd rather than sending an invariant-tainted figure to the AI provider as if it were trustworthy).

Deferred work (intentional v1 scope)

Not built yet — listed here so a follow-up doesn’t need to rediscover the reasoning:
  • Quantum Exposure Score pipeline (deriveWalletSignatureExposurederiveQuantumExposureScore). 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 0x address; resolve via /api/resolve-wallet first.
  • Report persistence, cryptographic signing, or a database. Every call still recomputes the report fresh from current cache/live state. A client-only, unsigned content-hash share/export lane exists (src/lib/wallet-risk-report-share.js) — it is integrity-only (detects tampering with the shared payload), not authenticity/signed, mirroring how the UI’s own integrity badge and share controls describe it. This is distinct from the Readiness Packet’s cryptographically signed sharing.
  • Portfolio / multi-wallet batching.

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.