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
“How many transfers has token 0x… had?” Mirrors MoralisEach ERC-20 transfer event contributesGET /erc20/{address}/stats({ transfers: { total } }).
+1 to that token’s counter. The shape is intentionally compact — one counter today — but the pattern is the value: fold any future per-token counter (holder-count delta, daily active addresses, …) onto the same row so a single read returns the full stats block for a token.
What you get
One aggregated row per token, keyed bytoken_address:
| Column | Description |
|---|---|
chain_id | The chain the token lives on |
token_address | The ERC-20 contract address (the counter key) |
transfers_total | Net count of transfer events for the token — transfers.total |
transfers_total counts every row in the source transfer array, including mints (from = 0x0) and burns (to = 0x0) — matching the endpoint’s “transfers of the token” semantics. See Counter semantics to exclude mints/burns.
Source
The transform reads one per-block array and counts it:tokenTransfers
This is by definition the ERC-20 transfer event collection (NFT and native transfers are separate arrays — nftTokenTransfers, nativeTransfers), so no token-standard filter is needed. Each event contributes +1 to transfers_total for its token_address. block_number / block_timestamp come from the block envelope.
Destination
| Destination | Table | Read pattern |
|---|---|---|
| ClickHouse (first-class) | fact_token_stats | ORDER BY (chain_id, token_address); net count via sum(transfers_total) or FINAL |
| Postgres | token_stats (materialized view over token_transfer_events) | Unique index (token_address) |
| MySQL | token_stats (trigger-maintained over token_transfer_events) | Primary key (token_address) |
(chain_id, token_address), so every event for a token shares one key and the engine sums the per-event rows on background merges. The materialized view emits transfers_total = sign per event — +1 for forward inserts, -1 for reorg reverts — so the per-token sum is always the net count and is naturally reorg-safe.
Full schema
Below is the complete read table this recipe produces. It’s deliberately minimal — one counter — and is a starting point for the forward-compatible counter pattern: add more summable columns to land more per-token stats on the same row (see Schema & flexibility).ClickHouse — fact_token_stats
ClickHouse — fact_token_stats
ORDER BY tuple, so adding a new counter is just another Int64 / UInt64 column plus a projection branch in the materialized view — no engine change. Read the net counter with sum(transfers_total) or FINAL (which forces the merge first); never a bare WHERE sign = 1. A single-node setup can use SummingMergeTree() without the replication path.Postgres — token_stats
Postgres — token_stats
REFRESH MATERIALIZED VIEW CONCURRENTLY token_stats;. MySQL keeps the same token_transfer_events table plus a trigger-maintained token_stats state table doing INSERT … ON DUPLICATE KEY UPDATE transfers_total = transfers_total + 1. Add another aggregate column to the view (Postgres) or another trigger column (MySQL) to land more counters.Example reads
Per-token transfer counters on chain 1, most-transferred first —sum() is reorg-safe (ClickHouse):
GET /erc20/{address}/stats:
FINAL (forces the background merge first; identical result):
Counter semantics
transfers_total includes mints and burns, matching the endpoint’s “transfers of the token” definition — every +1 of supply movement is counted, with no from = 0x0 / to = 0x0 filter. The ClickHouse fact table carries only the aggregated counter, so to exclude mints/burns query the Postgres/MySQL event table (which retains per-event rows) — or add from/to columns to the transform and event-table schema if you need that surface in ClickHouse:
Modes
Shipped defaults: ClickHousehybrid (backfill → realtime), Postgres / MySQL historical (one-shot backfill). For live, reorg-corrected counters, use ClickHouse — see the overview.
On Postgres / MySQL the counter only ever increments in
historical mode — there is no reorg-safe row-deletion path on these destinations, and the per-event vendor_event_id uniqueness only guards against double-ingestion of the same canonical event. position is block-level and array-expanded transfer rows share it, which constrains realtime/hybrid here. Run realtime/hybrid on ClickHouse, which corrects reorgs per-block via signed -1 rows.Multichain
The recipe is chain-parametrized via thechain setting — point it at any supported EVM chain or Solana. On Solana, every SPL token transfer contributes +1; the vendor_event_id is widened to stay unique even where a log index repeats within an instruction, so per-token counts round-trip identically in shape.
Related
Token Transfers
The per-event transfer ledger this counter is derived from.
Token Analytics
The use case per-token stats power.

