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 DEX trade that touched token 0x…, newest first — with the amount on each side, the USD notional, the protocol, and whether it was a buy or a sell.”A single read returns what the public Moralis Swaps endpoints serve by token, stored pre-shaped and indexed by token in your own database. Both direct pool fills and aggregator-routed trades are captured, so you see every fill of the token once.
What you get
The recipe lands one row per (trade, token side) — each trade is unpivoted so it appears under both of its tokens, and a by-token lookup is a prefix scan. Key columns of the fact table:| Column | Description |
|---|---|
token_address | This side’s token (the leg you’re querying by) |
counter_token_address | The other token in the trade |
leg | token0 or token1 — which side of the underlying trade this row is |
side | buy or sell — derived from the base token’s pool-balance delta |
side_amount | Raw amount of token_address (uint256, as text) |
counter_amount | Raw amount of counter_token_address |
notional_usd | Trade notional in USD (bought-leg amount × in-block price) |
price_usd | Bought-leg (token1) USD price used for the notional |
source_kind | pool_fill (direct pool) or aggregator (aggregator-routed) |
protocol | DEX/protocol label |
fee_amount, fee_token, fee_usd | Trade fee (pool fills only) |
trader_address, pool_address | Trader and pool/aggregator address |
block_number, event_ts, tx_hash | On-chain ordering and time |
Source
The transform reads two per-block trade arrays and unions them into the trade feed:tokenSwaps (direct pool fills) · aggregateTokenSwaps (aggregator-routed trades)
The two branches are disjoint by construction — pool fills are keyed off the pair address, aggregator routes off the aggregator address — so together they give every fill exactly once. USD values are computed inline from the same block’s tokenPriceUpdates (the chronologically-last update wins on duplicate keys), so no separate price join is needed at read time.
Destination
| Destination | Table | Read pattern |
|---|---|---|
| ClickHouse (first-class) | fact_swaps_by_token | Prefix scan on (chain_id, token_address, event_ts); read with FINAL or sum(sign) |
| Postgres | swaps | Indexes on token0_address and token1_address, each (…, block_number DESC) |
| MySQL | swaps | Indexes on token0_address and token1_address |
swaps table and reach a token via either side’s index.
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 amounts and fees are stored as text in ClickHouse and as NUMERIC(76, 0) in Postgres (explicit precision so large raw balances never overflow); USD columns are nullable wide decimals.
ClickHouse — fact_swaps_by_token
ClickHouse — fact_swaps_by_token
leg = 'token0' and 'token1') so it’s found under both tokens. leg is part of the ORDER BY so the two sides never collapse into each other, while the +1/−1 reorg pair for one side shares an identical key and collapses cleanly. 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 — swaps
Postgres — swaps
DECIMAL(38,18) for the USD columns. The Postgres/MySQL table is one row per trade (not unpivoted), so a by-token read filters either token0_address or token1_address. position is the block-level cursor used during backfill.Example reads
All trades touching 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 cursor, but
position is block-level (many trades per block), so the array-expanded trade 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 — point it at any supported EVM chain or Solana. On Solana, multiple events in one instruction can share alogIndex, so the pool-fill event identity is widened (with the token addresses and amount) to keep rows distinct; the by-token feed it produces is identical in shape.
USD valuation and fidelity gaps
notional_usdis the bought-leg (token1) amount scaled by its decimals × the in-block price (token1Amount / 10^token1Decimals × price), so it’s a true dollar value when the token had an in-block price update.price_usd,notional_usd,fee_usdareNULLwhen the bought token had no in-block price update — there’s no off-block price backfill at write time. Join the Token Prices sync for fuller coverage.fee_*is populated for pool fills only; bps-style fees (V3/V4/CL) are converted to an absolute amount, and already-absolute fees pass through. Aggregator-routed rows leave feesNULL.side(buy/sell) is derived from the lower-priority (base) token’s pool-balance delta on the trade.
Related
Swaps by Pair
The sibling — every trade keyed by pool/pair address.
Token Analytics
The use case this by-token trade feed powers.

