Balances Calculation
How we calculate address balances on EVM blockchains.
Concept
Conceptually, the current balance of an account is the cumulative sum of tokens that it has received and sent out from its address.
In our balances schema, we cover the following asset types:
Native token (e.g. ETH / MATIC)
ERC20 (e.g. USDC, LDO. Note: Wrapped ETH and MATIC will fall under ERC20)
ERC721 (e.g. Bored Aped Yacht Club)
ERC1155 tokens (e.g. Opensea Shared Storefront)
To calculate the balance of a particular asset type, we construct a credit-debit table for each asset type, that accounts for both the direction and amount of transfer for each asset.
More on credit-debit tables here.
Identifying assets transfers type
Identifying the various types of transfers for each asset type is the first step toward balance calculation.
These transfers will be used to construct a credit-debit table for cumulative sum calculation.
Native Tokens
For native tokens transfers (i.e. Native ETH, MATIC), the movement of these tokens is mostly identified from traces.
Value transfer: native token transfer that is neither a delegatecall, callcode or staticcall
Gas payment to miner:
receipt_gas_used * (receipt_effective_gas_price - base_fee_per_gas)
Gas burn (EIP-1559):
receipt_gas_used * blocks.base_fee_per_gas
For Polygon, there are events logs to include in this debit-credit table to calculate MATIC balances.
childERC20 event transfers A child chain transfer is a transfer from Ethereum to Polygon
These events surface on Polygon as transactions with to and from addresses equal to the null address
There are no standard transfer traces for those transactions and event logs are used in this case
ERC Tokens
For ERC20, ERC721, ERC1155 tokens. The movement of assets will be accounted for by the transfer event logs emitted by each asset type.
ERC20 Transfer() Deposit() and Withdrawal() for wrapped native assets
ERC721 Transfer()
ERC1155 TransferSingle() and flattened TransferBatch()
Our Approach to Retaining Precision on Snowflake
By default, Snowflake’s precision is 38 and scale is 0 (i.e. NUMBER(38, 0)).
With Snowflake native arithmetic functions and precision for cumulative sum will result in balances getting more inaccurate over time.
To retain precision when calculating balances, we cast our numeric variables into VARCHAR and use Java libraries and Snowflake User-Defined Functions (UDFs) to perform a cumulative sum operation
Last updated