One row per fungible token movement: a transfer, a mint or a burn, on every chain we decode. amount_raw is the amount in the token’s smallest unit, so divide it by 10^decimals from dimensions.tokens to read whole tokens.
Columns
| Column | Type | Description |
|---|
partition_key | TIMESTAMP | The month the row belongs to, as its first instant. The table is partitioned on it, so bound it alongside block_timestamp. |
block_timestamp | TIMESTAMP | Time of the block containing the movement. |
block_number | INT64 | Block height, or the slot on Solana. |
transaction_hash | STRING | Transaction the movement belongs to. Null on hydradx, where a transfer can be emitted by a block hook rather than by a transaction. |
transaction_index | INT64 | Position of the transaction in its block. Solana only: a decoded Transfer event on the log-shaped chains is the log, and the transaction around it lives in that chain’s own transaction table. |
outer_event_index | INT64 | Enclosing instruction position on Solana. A log has one position and an instruction has two, so this is null on the log-shaped chains, and null on a top-level Solana instruction, which has nothing enclosing it. |
event_index | INT64 | Position within the transaction: the log index, or the instruction index on Solana. |
chain_id | STRING | Chain the movement happened on. |
token_type | STRING | Token standard: erc20, spl or trc20. |
token_id | STRING | Join key to dimensions.tokens and the asset tables, which are laid out on it: {token_address}-{chain_id}. |
token_address | STRING | The token, and the leading cluster key: filter on this with chain_id to read one token, and on this alone to read the address across every chain in one pass. erc20 addresses are stored lowercase and every other standard as the chain writes it, spl and trc20 being base58. Null on the Solana transfers whose token account the upstream decode could not resolve, which leaves token_id null with it. |
event_type | STRING | transfer, mint or burn. Solana’s token program names it; on the log-shaped chains it is read from the EIP-20 zero address, so a burn sent to some other dead address reads as transfer. |
from_address | STRING | Account debited: a wallet on the log-shaped chains, an SPL token account on Solana. Null on a mint. |
to_address | STRING | Account credited: a wallet on the log-shaped chains, an SPL token account on Solana. Null on a burn. |
to_owner | STRING | Holder behind to_address, on Solana transfers, where one wallet can own several token accounts. On the log-shaped chains to_address is already the holder. Null on exactly the rows where token_address is null, since one upstream decode resolves a token account to both its mint and its owner, and null on Solana mints and burns, whose upstream tables hold no owner column. |
authority_address | STRING | Account that authorised the instruction. Solana only. |
transaction_signer | STRING | Signer of the enclosing transaction. Solana only. |
executing_account | STRING | Program that executed the instruction. Solana only. |
amount_raw | STRING | Amount in the token’s smallest unit, as a decimal string, because a uint256 exceeds every BigQuery numeric type. Divide by 10^decimals. |
surrogate_key | BYTES | Row identity: a 128-bit hash of the columns that define the grain, stable across rebuilds. Compare it with from_hex. |
Sample queries
This table is large and split by month. Bound partition_key and filter chain_id on every query, or you read the whole table and the whole table is billed to you.
One token, one day
One token, every chain
Largest movements
One token on Solana
Movements in order
Supply movements
Net flow per account
token_address and chain_id are the cluster keys and partition_key names the month, so the three together read only the blocks this token occupies. Cast amount_raw to BIGNUMERIC and divide by 10^decimals from dimensions.tokens for whole tokens.Leaving chain_id out reads the address on every chain it is deployed at in one pass, which the clustering is built for. partition_key still bounds the months the query reads. amount_raw is a decimal string, so ordering on it directly sorts lexically. Order on the decimal-corrected amount instead, as here.An SPL mint address is base58 and is matched as the chain writes it. from_address and to_address are token accounts here, to_owner is the wallet behind the credited one, and dimensions.accounts names the addresses somebody has attributed. outer_event_index is null where a chain has one nesting level, so nulls first groups those rows together and event_index decides inside the group. The same ordering holds on every chain.A mint fills to_address and a burn fills from_address, so coalesce picks whichever side the row has. Supply read off these rows stays exact even for a rebasing token, whose holder balances accrue between movements. Splitting each movement into its credit and its debit and summing them replays a balance where a balance moves by movement alone. A rebasing token accrues between movements, and an SPL mint configured for confidential transfers moves value the instruction keeps private, so the balance functions inherit the same limit.