facts.token_balance_changes records how much each accountβs balance moved, and nothing else. Every transfer produces two rows: the amount leaving the sender, written as a negative number, and the same amount arriving at the receiver, written as a positive one. The table is built from Transfers and covers the same ground.
Columns
| Column | Type | Description |
|---|---|---|
block_timestamp | TIMESTAMP | The time when the block containing this change was included. Partition column. |
block_number | INT64 | Number of the block containing this change. |
transaction_hash | STRING | Hash of the transaction that moved the balance. |
log_index | INT64 | Where the Transfer log that caused this change sat within the block. |
transfer_id | INT64 | The facts.token_transfers row this change came from. Both rows of a transfer share it. |
unique_id | INT64 | Row key: fingerprint of the transferβs key plus the account. |
chain_id | STRING | Chain the change happened on. |
token_type | STRING | Token standard, such as erc20. |
token_id | STRING | Token whose balance moved: {token_address}-{chain_id}. |
token_address | STRING | Contract address of the token. |
account_address | STRING | Account whose balance moved. |
balance_change_raw | BIGNUMERIC | How much the balance moved, in the tokenβs raw units. Negative on the sending side. |
Sample queries
- Net receivers
- Both sides of a transfer
Find the largest net receivers of one token on a single day. The number the amounts are divided by is built from
decimals as an exact whole number, so a change that nets to zero reads exactly zero.Notes
Two kinds of transfer are left out entirely. Self-transfers, where an address sends to itself, move no balance at all. And a few transfers carry a value too large forBIGNUMERIC, the widest number BigQuery has, so they cannot be added up. In both cases the leaving row and the arriving row are dropped together, so a balance built from this table still balances exactly.
This table holds individual changes in raw units and nothing else. Adding those raw numbers up would overflow BIGNUMERIC once a tokenβs supply passes roughly 5.79e20 tokens at 18 decimal places: the running total gets too big for the widest number BigQuery has. So the adding up happens on scaled-down amounts instead, inside the balance functions, one token at a time.