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

# rwa_multichain.balances

> Daily holder balance snapshots for tokenized real-world assets across all tracked chains, with USD values where NAV coverage exists.

export const PremiumDatasetAccessCard = ({href = "https://dune.com/enterprise#contact-form"}) => <Card title="Premium dataset access" icon="info" href={href}>
    This dataset is part of a premium offering and requires additional access. Contact the Dune enterprise team to request access.
  </Card>;

`rwa_multichain.balances` is the cross-chain holder snapshot table. Grain: one row per holder per token per chain per day, keyed on `(blockchain, day, address, token_id)`. Use it to measure holder counts, concentration, and AUM.

<PremiumDatasetAccessCard />

## Table schema

| Column           | Type        | Description                                                                               |
| ---------------- | ----------- | ----------------------------------------------------------------------------------------- |
| `blockchain`     | `VARCHAR`   | Chain for the native balance source                                                       |
| `day`            | `DATE`      | Balance snapshot date                                                                     |
| `address`        | `VARCHAR`   | Normalized holder address. 0x-hex on EVM, base58 on Solana, native form elsewhere         |
| `token_symbol`   | `VARCHAR`   | RWA token symbol where available                                                          |
| `token_address`  | `VARCHAR`   | Normalized native token identifier as `VARCHAR`. Join key to the NAV tables after casting |
| `token_id`       | `VARCHAR`   | Normalized cross-chain token identifier for joining to `rwa_multichain.tokens`            |
| `token_standard` | `VARCHAR`   | Native token standard or asset namespace                                                  |
| `currency`       | `VARCHAR`   | Token metadata currency where available                                                   |
| `balance_raw`    | `DOUBLE`    | Raw token balance in the source token's native precision                                  |
| `balance`        | `DOUBLE`    | Token balance adjusted for decimals                                                       |
| `balance_usd`    | `DOUBLE`    | USD value of the balance from NAV, where coverage exists                                  |
| `last_updated`   | `TIMESTAMP` | UTC timestamp when the balance last changed                                               |

## USD coverage is partial

`balance_usd` is populated only where the asset has an onchain NAV feed. NAV currently covers 366 assets across 18 chains from 48 issuers, which is roughly 14% of balance rows. Treat `balance_usd IS NULL` as **missing price coverage, not zero value** — summing `balance_usd` without checking coverage will understate AUM.

To see coverage explicitly:

```sql theme={null}
SELECT
  blockchain,
  COUNT(*) AS rows_total,
  COUNT(balance_usd) AS rows_priced,
  ROUND(100.0 * COUNT(balance_usd) / COUNT(*), 1) AS pct_priced
FROM rwa_multichain.balances
WHERE day = current_date - INTERVAL '1' day
GROUP BY 1
ORDER BY 2 DESC
```

If you need a NAV source other than the default, or want to price a day the pipeline has not backfilled, join [`nav_intervals`](/data-catalog/curated/rwa/valuation/nav-intervals) yourself. Note the address type mismatch — `nav_intervals.asset_address` is `VARBINARY` while `token_address` here is `VARCHAR`:

```sql theme={null}
SELECT
  b.day,
  b.token_symbol,
  n.issuer,
  SUM(b.balance * n.usd_nav_price) AS aum_usd
FROM rwa_multichain.balances b
JOIN rwa_multichain.nav_intervals n
  ON n.blockchain = b.blockchain
  AND '0x' || lower(to_hex(n.asset_address)) = b.token_address
  AND b.day >= date(n.valid_from)
  AND (n.valid_to IS NULL OR b.day < date(n.valid_to))
WHERE b.day >= current_date - INTERVAL '30' day
GROUP BY 1, 2, 3
```

## Non-EVM balances are reconstructed

On EVM chains, balances come from balance-update streams. On several non-EVM chains they are reconstructed by accumulating transfers, which means a chain that started tracking mid-history can carry a different starting point than a full-history rebuild would produce. Treat cross-chain holder totals for non-EVM chains as directional rather than exact.

## Zero balances are retained

Rows persist after a holder empties a position, so `balance = 0` rows appear in the snapshot. Filter `balance > 0` when counting holders, or you will count every address that ever held the asset.

## Example query

```sql theme={null}
-- Holder concentration for a single asset
WITH latest AS (
  SELECT address, balance
  FROM rwa_multichain.balances
  WHERE day = current_date - INTERVAL '1' day
    AND token_symbol = 'BUIDL'
    AND balance > 0
)
SELECT
  COUNT(*) AS holders,
  SUM(balance) AS total_balance,
  MAX(balance) / SUM(balance) AS top_holder_share
FROM latest
```

**Top holders across all chains:**

```sql theme={null}
SELECT
  address,
  COUNT(DISTINCT token_id) AS assets_held,
  SUM(balance_usd) AS portfolio_usd
FROM rwa_multichain.balances
WHERE day = current_date - INTERVAL '1' day
  AND balance > 0
  AND balance_usd IS NOT NULL
GROUP BY 1
ORDER BY 3 DESC
LIMIT 50
```
