Documentation Index
Fetch the complete documentation index at: https://docs.moralis.com/llms.txt
Use this file to discover all available pages before exploring further.
Question it answers
“Give me every token wallet 0x… holds, with its current non-zero balance.”This is the by-wallet portfolio read. It’s the same ingest as Token Balances by Token, sorted the other way: this recipe keys wallet-first so one wallet’s full token holdings are a contiguous range read, while the sibling keys token-first to list a token’s holders.
What you get
The recipe lands one balance observation per wallet, per transfer leg. Eachtoken_transfer carries absolute post-transfer balances (from_post_balance / to_post_balance), so every transfer becomes two observations — one for the sender, one for the receiver. The latest observation per (wallet, token) is the current balance (“latest-wins”).
| Column | Description |
|---|---|
chain_id | Chain identifier |
wallet_address | The holder — leading sort key |
token_address | The ERC-20 contract |
balance | Absolute post-transfer balance for this wallet, raw uint256 (the latest per (wallet, token) is the current balance) |
leg | from or to — which side of the transfer produced this observation |
block_number, log_index | On-chain ordering tuple — picks the latest observation |
event_ts | Block time |
vendor_event_id | Stable per-observation identity (keeps rows unique) |
0 on a full transfer-out is a real observation you read as the current state — not a missing row.
Source
The transform reads one per-block array —tokenTransfers — and unpivots each transfer into two per-wallet observations: (from_address, from_post_balance) and (to_address, to_post_balance). Because the source supplies absolute post-balances on each transfer, there’s no running-sum reconstruction: the latest observation is the balance.
Destination
| Destination | Table | By-wallet access |
|---|---|---|
| ClickHouse (first-class) | fact_balances_by_wallet | Prefix scan on (chain_id, wallet_address, token_address, …); current balance via argMax over FINAL |
| Postgres | token_balances (materialized view over token_balance_observations) | Partial index (wallet_address, token_address) WHERE balance > 0 |
| MySQL | token_balances (trigger-maintained over token_balance_observations) | PK (wallet_address, token_address) + DELETE … WHERE balance = 0 cleanup |
argMax over FINAL.
Full schema
Below is the complete read table this recipe produces. It’s a starting point — keep the columns you need and drop the rest (see Schema & flexibility). Rawuint256 balances are stored as text (ClickHouse) or NUMERIC(76, 0) (Postgres) so they never overflow.
ClickHouse — fact_balances_by_wallet
ClickHouse — fact_balances_by_wallet
sign column drives reorg collapsing — read with FINAL then argMax, or a sign-aware aggregate, never a bare WHERE sign = 1. A single-node setup can use CollapsingMergeTree(sign) without the replication path.Postgres — token_balances
Postgres — token_balances
REFRESH MATERIALIZED VIEW CONCURRENTLY token_balances;. MySQL is the same shape with a trigger-maintained token_balances table and a DELETE … WHERE balance = 0 cleanup. position is the block-level cursor used during backfill.Example reads
Every token a wallet holds, current non-zero balance only (ClickHouse —argMax over FINAL picks the latest observation per token):
REFRESH MATERIALIZED VIEW CONCURRENTLY token_balances;):
Modes
Shipped defaults: ClickHousehybrid (backfill → realtime), Postgres / MySQL historical (one-shot backfill). For live/reorg-safe ingestion, use ClickHouse — see the overview.
The backfill cursor (
position) is block-level, so realtime/hybrid on Postgres / MySQL is constrained by their single-column UNIQUE requirement. Run realtime/hybrid on ClickHouse; the Postgres / MySQL configs target historical backfill.Multichain
The recipe is chain-parametrized — point it at any supported EVM chain or Solana. On Solana, the per-observation identity already folds(from, to, token, amount) into vendor_event_id so rows stay unique under Solana’s repeated logIndex; the balances it produces are identical in shape.
Fidelity gaps
- Raw balances only.
balanceis the rawuint256post-transfer amount — divide by10^token_decimalsto read human units. Fold in a decimals lookup from a Token Metadata sync if you need it pre-scaled. - No USD value. This recipe lands quantities, not dollar value. Join to a Token Prices sync at read time for portfolio valuation.
- Latest-wins semantics. A
(wallet, token)row reflects the most recent transfer-derived post-balance. Direct mints/burns or rebases that emit a transfer are captured; balance changes with no transfer event are not.
Related
Token Balances by Token
The sibling — same ingest, keyed token-first to list a token’s holders.
Portfolio Tracking
The use case this balance feed powers.

