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:
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
ClickHouse uses a SummingMergeTree counter table (not the collapsing pattern most recipes use): the table is keyed by
(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.

