Scaling and ATokens

Previously we explained how deposits were scaled against the liquidity index to reflect every user's unique starting point in the timeseries of interest accumulation.

That brings us to the topic of ATokens and the question of how they are minted - on the basis of the scaled value of deposit or otherwise.

ATokens

Atokens are interest-bearing tokens that represent a user's share in the underlying deposited assets. When users deposit funds into the Aave protocol, they receive Atokens in return, which represent their entitlement to a portion of the pool's reserves.

  • User deposits 100 DAI, receives 100 aDAI in return.

  • ATokens are redeemable 1:1 for their underlying.

A depositor's balance of aTokens will increment over time as interest is accrued.

Example:

  • You deposit 100 DAI and are minted 100 aDAI token.

  • Over time, your aDAI balance will increment beyond 100, reflecting interest accrued.

  • When you look to withdraw in full, you will receive more than 100 DAI.

Therefore, the growth of aToken balance reflects the interest earned on deposits over a period.

You can see your AToken balance increase in real-time directly in your wallet.

Now we run into a contradiction. In the earlier example on scaling positions, we saw that a user who deposited 1000 DAI when the liquidity index was 1.1, had his deposit scaled to 909.

Does this mean that he is minted 909 aDAI? Yes and no:

  • user will see that he has 1000 aDAI in his wallet

  • however, the amount parameter passed into mint will be the scaledbalance of 909

To make more sense of this, let's look at how balanceOf works in the context of aTokens.

AToken: balanceOf

Aave implements a modified version of the ERC-20 standard for its aTokens, such that the balance of aTokens increments without any transactions.

Let's examine the implementation for balanceOf:

Notice the use of override - it serves to override balanceOf functions declared within its inheritance tree, so that the parent functions do not get called.

A user's aToken balance is the multiplication of two components:

  1. super.balanceOf

  2. POOL.getReserveNormalizedIncome()

In a more digestible form, this basically translates to:

super.balanceOf(user) * POOL.getReserveNormalizedIncome(_underlyingAsset)
        scaledBalance * currentLiquidityIndex

Execution flow:

super.BalanceOf

  • Each user has a struct, UserState associated with their address via the mapping _userState

  • The balance element within the UserState stores user's scaled balance

  • super.balanceOf returns _userState[account].balance

super.BalanceOf returns the scaled balance for a user.

POOL.getReserveNormalizedIncome()

You might wonder what calculateLinearInterest does, we will explain this in a later section. For now you can operate on the understanding that getReserveNormalizedIncome returns the latest liquidity index, referred to as currentLiquidityIndex.

So in conclusion,

       super.balanceOf(user) * POOL.getReserveNormalizedIncome(_underlyingAsset)
 _userState[account].balance * currentLiquidityIndex
           userState.balance * currentLiquidityIndex
           "scaledBalance"   * "latest liquidity Index"
  • user deposits 1000 DAI, when Index = 1.1

  • scaledBalance = 909

  • _userState[account].balance = 909

AToken: Incrementation

The scaledBalance of a user is fixed, while the currentLiquidityIndex increments with every state-changing transaction, reflecting accrued interest. Due to this characteristic of the index, users' token balance increases with no action on their part.

You can see your AToken balance increase in real-time directly in your wallet.

AToken: mint

Earlier, we stated that instead of the deposit amount, the scaled amount is passed into the mint function. We will understand why from this section.

Execution flow

AToken::mint -> ScaledBalanceTokenBase::_mintScaled -> MintableIncentivizedERC20::_mint

The abovementioned scaling can be seen from the first line in _mintScaled. Subsequently, amountScaled is passed into _mint, which increments the user's balance which is captured in _userState[account].balance.

Execution flow: Visual Aid

Here is a more complete execution flow chart spanning the relevant portions across different contracts.

Last updated