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 ERC-20 transfer — all transfers of token 0x…, or every transfer wallet 0x… sent or received.”One flat event log of token transfers, served two ways from a single sync: by-token (every movement of a given token) and by-wallet (every transfer a wallet was on either side of). Each row is one transfer carrying exactly one token and one amount — there’s no USD enrichment, because a transfer event carries no price.
What you get
One row per transfer, from Moralis-indexed, normalized per-block onchain data:| Column | Description |
|---|---|
token_address | The transferred token’s contract |
from_address, to_address | Sender and recipient |
amount | Raw uint256 token units (not decimal-adjusted) |
transfer_type | Transfer kind as emitted (erc20, …) |
initiated_by | Address that initiated the transfer |
block_number, log_index, transaction_index | On-chain ordering tuple |
tx_hash | Transaction that produced the transfer |
block_timestamp / event_ts | Block time |
Source
The transform reads a single per-block array —tokenTransfers — and lands one row per transfer. Fields map straight from the source struct (tokenAddress → token_address, fromAddress → from_address, toAddress → to_address, amount → amount, type → transfer_type, initiatedBy → initiated_by).
There’s no price join: transfers are unpriced, so there is no amount_usd column. The per-transfer vendor_event_id is widened beyond (tx_hash, log_index) so the id stays unique on Solana, where logIndex is not row-unique within an instruction (see Multichain).
Destination
| Destination | Table | Read pattern |
|---|---|---|
| ClickHouse (first-class) | fact_token_transfers | Prefix scan on (chain_id, token_address, block_number) for by-token; bloom_filter skip-indexes on from_address / to_address for by-wallet; read with FINAL or sum(sign) |
| Postgres | token_transfers | Index on (token_address, block_number DESC); plus (from_address, …) and (to_address, …) |
| MySQL | token_transfers | Index on (token_address, block_number); plus (from_address, …) and (to_address, …) |
+1/−1 reorg pair for a row shares an identical key and collapses on merge. The fact table’s sort key is token-first, so all transfers of a token are a contiguous range read; by-wallet reads are accelerated by data-skipping bloom filters rather than a second sort key.
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).amount is stored raw (uint256 token units) because the transfer event carries no decimals; scale by 10^token_decimals at read time.
ClickHouse — fact_token_transfers
ClickHouse — fact_token_transfers
sign column drives reorg collapsing — read with FINAL or sum(sign), never a bare WHERE sign = 1. A single-node setup can use CollapsingMergeTree(sign) without the replication path.Postgres — token_transfers
Postgres — token_transfers
amount uses NUMERIC(76, 0) so large raw uint256 values don’t overflow; position is the block-level cursor used during backfill.Example reads
All transfers of a token, newest first (ClickHouse):FINAL):
Modes
Shipped defaults: ClickHousehybrid (backfill → realtime), Postgres / MySQL historical (one-shot backfill). For live/reorg-safe ingestion, use ClickHouse — see the overview.
The realtime reorg path needs a single-column
UNIQUE on the position column, but position is block-level (many transfers share one block), so array-expanded transfer rows can only carry a composite unique. Run realtime/hybrid on ClickHouse, where the collapsing log table corrects reorgs per-block. The Postgres / MySQL configs are intended for historical backfill.Multichain
The recipe is chain-parametrized via thechain setting — point it at any supported EVM chain or Solana. On Solana, multiple events in one instruction can share a logIndex, so the vendor_event_id is widened with (from_address, to_address, token_address, amount) to keep rows distinct; the transfer log it produces is identical in shape.
Fidelity gaps
The recipe lands exactly what thetokenTransfers array carries. Fields a transfers endpoint might surface that have no onchain source in this array are omitted:
- USD value — a transfer carries no price. Pricing requires joining the same-block price data; that’s out of scope for a plain transfer log (see Token Prices for the price-join pattern).
- Token metadata (
symbol,name,decimals, logo, verified/spam flags) — these come from a separate token-metadata sync, not the transfer event.amountis therefore stored raw, not decimal-adjusted. - Pre/post balances — the balance surface lives in the balances recipes (Token Balances by Token / by Wallet); this transfer log stays a flat event stream.
Related
Token Holders
The balance roll-up these transfers feed — all non-zero holders of a token.
Accounting & Tax
Per-asset transfer ledgers for reconciliation, valued via Token Prices.

