Indexing Account Balances
Overview
If you’re building a product that indexes ETH balances on Blast, it’s important that you understand how Blast’s account model differs from other EVM chains.
Instead of representing ETH balances as integer values, Blast represents them in terms of shares. Each account has some number of shares associated with it and that number is multiplied by a global share price to determine its ETH balance. In this way, Blast account balances are capable of automatically rebasing as new yield is reported and the global share price increases.
For the most accurate indexing of account balances, we recommend saving individual account shares along with the global share price instead of saving account balances directly. At read time an account’s balance can then be derived by multiplying its shares with the global share price.
The rest of this document describes how to accurately index every account’s ETH balance on Blast using this method.
Yield Modes
Blast accounts support three different yield modes, giving the user / builder control over how they want to handle rebasing when new yield is reported:
Yield Mode | Description |
---|---|
AUTOMATIC | ETH balance automatically rebases (increasing only) |
VOID | ETH balance never changes in response to yield; no yield is earned |
CLAIMABLE | Yield accumulates separately and can be claimed to any recipient address |
Defaults
By default, all accounts on Blast are set to AUTOMATIC
yield mode, which means their ETH balances will rebase automatically.
However, when a smart contract is deployed to an address, the account is switched to VOID
mode. In practice, this means that smart contract accounts default to VOID
mode and EOAs default to AUTOMATIC
mode.
Both smart contracts and EOAs can change their yield modes (e.g. a smart contract opting in or an EOA opting out) using the Blast yield predeploy at address 0x4300000000000000000000000000000000000002
.
See our article on Receiving and claiming ETH Yield for details.
Blast’s Account Model
Blast uses a modified version of op-geth
(blast-geth
) to represent balances in terms of shares and enable all accounts to update as yield is reported. More specifically, blast-geth
modifies the underlying StateAccount
struct that represents account state to accomplish this:
op-geth (Upstream)
blast-geth
The desired yield mode is stored in the Flags
field and the Fixed
, Shares
, and Remainder
fields store the data required to calculate account balances in each of the three yield modes as follows:
In AUTOMATIC
mode, balances increase automatically as yield is reported to the L2:
In this mode, account.remainder
will be a dusty value to enable wei-level precision.
account.remainder < sharePrice
(otherwise, account.shares
would just be higher).While modifying the type of the state trie is a significant change, there is no difference from the perspective of a single transaction; Blast’s BALANCE
opcode behaves the same as it normally does, so smart contracts don’t need to consider their account’s shares.
To remain EVM compatible, Blast’s share system guarantees wei-level precision, allowing accounts with rebasing balances to transfer precise amounts of wei to accounts with non-rebasing balances and vice versa.
Global Share Price
The global share price that determines how much ETH each share is worth is stored in the SharesBase predeploy at address 0x4300000000000000000000000000000000000000
.
This contract tracks the share price, the total number of shares, and the total amount of ETH that has yet to be reflected in the share price. You can read the current ETH share price by calling SharesBase::price()
as demonstrated below using cast call
or the eth_call
RPC:
awk
and jq
for styling purposes to show the units of the return value.You can also index the NewPrice(uint256 price)
event emitted by this contract to get the new global share price whenever an update occurs. Generally, this update happens every day at midnight UTC, but this schedule is not guaranteed in code and may be subject to change.
Indexing Account Shares
As mentioned above, for the most accurate results it is recommended that you index account shares instead of account balances directly.
For the most part, this works the same way as indexing balances on ETH mainnet: we first identify which accounts were touched in the transactions within a given block and then re-fetch the balances of those accounts on that block.
Usually, these ETH balances are re-fetched using the eth_getBalance
RPC method, but on Blast we need to be able to read and save the account’s shares
value instead. Blast nodes expose a new RPC method, eth_getBalanceValues
, to support indexing the flags
, shares
, remainder
, and fixed
fields for accounts.
eth_getBalanceValues
This RPC method exposes the Blast-specific fields of the StateAccount
struct.
Request
Same as eth_getBalance
Same as eth_getBalance
; hex or “latest”
, “pending”
, etc
Unique request identifier
Request Example
Response
String representing RPC version number
Object containing fixed
, flags
, remainder
, and shares
Hex number string, e.g. "0x1"
Hex number string representing one of three yield modes:
"0x0"
: AUTOMATIC"0x1"
: VOID"0x2"
: CLAIMABLE
Hex number string, e.g. "0x1"
Hex number string, e.g. "0x1"
Unique request identifier
Response Example
Edge Cases
On Ethereum mainnet, selfdestruct
allows ETH to be sent to a beneficiary address without triggering any code at that address. As a result, the beneficiary account’s balance changes without there being any call
made. Indexers must handle this edge case to ensure perfect accounting.
Blast introduces a similar edge case that indexers should be aware of. Accounts set to CLAIMABLE
yield mode can claim accumulated yield to an arbitrary beneficiary address. This claim operation works the same as selfdestruct
in that it can increase an arbitrary account’s balance without a call
.
While this edge case is exceptionally rare and not particularly important to handle, we include it here for completeness.