> ## Documentation Index
> Fetch the complete documentation index at: https://docs.walletwall.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Wallet Evidence Model

> How WalletWall normalizes existing provider outputs into source-aware claims — the wallet scan lifecycle and the evidence schema behind the /api/wallet response.

# Wallet Evidence Model

<Warning>
  The Wallet Evidence Model adds **no new provider**, **no Dune execution**, **no write
  action**, and **no wallet connection**. It is a pure, synchronous transform over data
  the existing `/api/wallet` providers already compute — it fetches nothing on its own.
</Warning>

`walletEvidence` is a provenance-aware layer on the `/api/wallet` response. It normalizes
Etherscan transaction/transfer/balance data, Alchemy token balances, DeFiLlama contract
pricing, CoinGecko ETH pricing, and cache-only Dune DEX-trade enrichment into **source-aware
claims**: what is claimed, which source(s) back it, what its status is, what scope it
covers, what was excluded, what fallback was used, and how confident the UI should be.

Its central job is distinguishing **zero data from unavailable or degraded data** — for
example, a wallet that genuinely holds no ERC-20 tokens must never look identical to a
wallet whose token balances simply failed to load. See
[Data Quality and Observability](/architecture/data-quality) for the underlying
`observability` / `dataQuality` fields this model builds on, and the
[Model Layer](/architecture/model-layer) for the shared schema conventions it follows.

***

## Wallet scan lifecycle

Every step below is **read-only**. There is no wallet connection, no signature request,
and no transaction is ever executed on this path.

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': {'actorBkg': '#B84923', 'actorBorder': '#6B2412', 'actorTextColor': '#FFF7E8', 'actorLineColor': '#8A5A1F', 'signalColor': '#2B2118', 'signalTextColor': '#2B2118', 'labelBoxBkgColor': '#A7B0B5', 'labelBoxBorderColor': '#59646A', 'labelTextColor': '#172014', 'loopTextColor': '#2B2118', 'noteBkgColor': '#D6A85A', 'noteBorderColor': '#8A5A1F', 'noteTextColor': '#2B2118', 'activationBkgColor': '#FAFAF0', 'activationBorderColor': '#B87333', 'sequenceNumberColor': '#FFF7E8'}}}%%
sequenceDiagram
    autonumber
    actor User
    participant UI as WalletWall UI
    participant API as /api/wallet
    participant Providers as Etherscan/Alchemy/DeFiLlama/CoinGecko/Dune cache
    participant Evidence as Wallet Evidence Model

    User->>UI: Enter wallet address or ENS
    UI->>API: GET /api/wallet?address=...
    Note over UI,API: Read-only request. No wallet connection, no signature request.
    API->>Providers: Fetch balances, transfers, prices (read-only)
    Providers-->>API: Provider responses (fresh, partial, or unavailable)
    API->>Evidence: buildWalletEvidence(ctx)
    Evidence-->>API: claims + sourceHealth + warnings
    API-->>UI: Normalized response including walletEvidence
    Note over API,UI: No transaction is ever executed in this path.
    UI-->>User: Source-aware claims with confidence and caveats
```

*The Wallet Evidence Model never calls a provider itself — it transforms data the route
handler already fetched. If a provider is not configured or fails for this request, the
affected claim reports a non-`fresh` status and an explicit caveat instead of silently
reading as "no data."*

***

## Evidence schema

```mermaid theme={null}
erDiagram
    WALLET_EVIDENCE ||--|| WALLET : describes
    WALLET_EVIDENCE ||--o{ CLAIM : contains
    WALLET_EVIDENCE ||--o{ SOURCE_HEALTH : reports
    WALLET_EVIDENCE ||--o{ WARNING : aggregates
    CLAIM }o--|| PROVIDER : "sourced from"
    CLAIM ||--o{ EXCLUSION : excludes
    CLAIM ||--o{ FALLBACK : "falls back via"
    SOURCE_HEALTH }o--|| PROVIDER : "status of"

    WALLET_EVIDENCE {
        int schemaVersion
        string generatedAt
    }
    WALLET {
        string address
        string chain
        boolean isContract
        string ensNames
    }
    CLAIM {
        string status
        string source
        string scope
        string confidence
        string updatedAt
    }
    SOURCE_HEALTH {
        string provider
        string status
    }
    PROVIDER {
        string name
        string capability
    }
    EXCLUSION {
        string reason
    }
    FALLBACK {
        string reason
    }
    WARNING {
        string message
    }

    class WALLET_EVIDENCE process
    class WALLET input
    class CLAIM decision
    class SOURCE_HEALTH,PROVIDER datastore
    class EXCLUSION,FALLBACK,WARNING risk

    classDef input fill:#FAFAF0,stroke:#B87333,color:#2B2118;
    classDef process fill:#B84923,stroke:#6B2412,color:#FFF7E8;
    classDef decision fill:#D6A85A,stroke:#8A5A1F,color:#2B2118;
    classDef risk fill:#8F2F1D,stroke:#5E1D12,color:#FFF7E8;
    classDef datastore fill:#6F7068,stroke:#3C3D38,color:#FFF7E8;
```

*`WALLET_EVIDENCE` carries exactly five `CLAIM`s today — `pricedPortfolioValue`,
`tokenHoldings`, `activity`, `protocolAffinity`, and `movements` — plus one
`SOURCE_HEALTH` entry per provider (Etherscan, Alchemy, DeFiLlama, CoinGecko, Dune). A
`CLAIM` may name zero or more `EXCLUSION`s (what it deliberately leaves out) and
`FALLBACK`s (what degraded path it used); every excluded or fallback reason also rolls
up into the top-level `warnings` list.*

### Status vocabulary

Every claim and every `sourceHealth` entry uses one shared status vocabulary, so
"throttled" or "fresh" means the same thing everywhere in the object:

| Status           | Meaning                                                               |
| ---------------- | --------------------------------------------------------------------- |
| `fresh`          | The source answered normally for this request.                        |
| `partial`        | Some of the claim's data loaded; part of it is sampled or incomplete. |
| `degraded`       | The source responded but produced no usable result for this wallet.   |
| `throttled`      | The source rate-limited this request — a temporary gap, not a fact.   |
| `unavailable`    | The source failed for this request.                                   |
| `not_configured` | No API key/credential is configured for this source.                  |
| `not_used`       | The source was not needed for this claim (not a failure).             |

### Claims

| Claim                  | Answers                                                                                                 |
| ---------------------- | ------------------------------------------------------------------------------------------------------- |
| `pricedPortfolioValue` | What is the wallet's priced USD value, and which legs (ETH, tokens) contributed?                        |
| `tokenHoldings`        | Which ERC-20 holdings were priced, and what was excluded (unpriced, invalid, or beyond the top-25 cap)? |
| `activity`             | How many observed transactions and token transfers, and is the sample complete?                         |
| `protocolAffinity`     | Which known routers/contracts does observed activity touch — not full protocol exposure.                |
| `movements`            | The largest priced-movement candidates, and how each was priced (transfer-time vs. current rate).       |

<Note>
  Not built for the mock/demo provider — synthetic data has no real provenance to
  report, so `walletEvidence` is simply absent there. Every consumer treats it as
  optional and falls back to the legacy fields it extends.
</Note>

***

## Related

<CardGroup cols={2}>
  <Card title="Data Quality and Observability" icon="chart-line" href="/architecture/data-quality">
    The underlying observability and data-quality fields this model builds on.
  </Card>

  <Card title="Model Layer" icon="cubes" href="/architecture/model-layer">
    The shared schema layer for source provenance and quality metadata across features.
  </Card>

  <Card title="Wallet Graph Contract" icon="diagram-project" href="/architecture/wallet-graph-contract">
    The full `/api/wallet` response contract that `walletEvidence` extends.
  </Card>
</CardGroup>
