Reconcile an Aave v3 aToken balance with its scaled principal

An aToken balance can grow between two blocks without a transfer from another holder. In the reference v3 implementation the visible balance combines a scaled balance with the reserve’s normalized income.

Read both factors at one block

Resolve the reserve’s aToken and pool. Read scaledBalanceOf for the account and getReserveNormalizedIncome for the underlying at the same block. Apply the implementation’s ray multiplication and rounding, where one ray is 10^27.

scaled balance = 1000000
normalized income = 1.05 × 10^27
nominal balance = 1050000 underlying base units

In the fixture one million scaled units become 1,050,000 nominal units. A ledger that simply sums ERC-20 transfer amounts may miss index-driven growth. Compare the reconstructed result with balanceOf on the actual deployed token.

Keep snapshots and deployment versions together

A reserve’s stored liquidityIndex and its current normalized income need not be equal between updates. Use the block’s applicable normalized value. Newer v3 implementations can change rounding details, so verify behavior against the deployed aToken code. github.com AToken.sol