Running the canyon upgrade.
In order to update the balances of every account as ETH yield comes in, Blast represents ETH balances in terms of shares. The desired yield mode is stored in Flags
, and the Fixed
, Shares
, and Remainder
fields store the necessary data to support each mode.
// upstream // blast
type StateAccount struct { type StateAccount struct {
Nonce uint64 Nonce uint64
Root common.Hash Root common.Hash
CodeHash []byte CodeHash []byte
- Balance *big.Int + Flags uint8
+ Fixed *big.Int
+ Shares *big.Int
+ Remainder *big.Int
} }
Modifying the type of the state trie is a significant change that affects test cases, chain genesis, and balance merkle proofs. However, from the perspective of a single transaction, there’s no difference. The balance opcode behaves identically, and smart contracts never need to consider their account’s shares.
In order to remain EVM compatible, Blast’s share system is designed to maintain wei-level precision. Accounts can transfer a precise amount of wei, even if their balances are rebasing and the recipient’s balance is/is not rebasing. Other share-based rebasing implementations do not necessarily have this property, which is essential for maintaining EVM compatibility.
Instead of adding new opcodes to handle transactions that require modifying these new fields (e.g. changing an account’s yield mode), we instead place that logic in a precompile. This is to avoid complicating the development toolchain since there’s no compiler modifications needed to use new precompiles.
In this mode, balances increase automatically as yield gets reported to the L2. The formula is:
balance = account.shares * sharePrice + account.remainder
Generally, in this mode, account.remainder
will be a small dusty value to enable wei-level precision. It should adhere to account.remainder < sharePrice
because otherwise, account.shares
would be higher.
If the yield mode is claimable, then the balance is just:
balance = account.fixed
claimable = account.shares * sharePrice + account.remainder - account.fixed
The claimable
value refers to yield that this account can claim that accumulates separately from the account’s balance
.
If the yield mode is disabled, then the balance is static and there’s no claimable yield.
balance = account.fixed
claimable = 0