AToken
Inheritance
Firstly, it is important to note the inheritance chain of the AToken contract:
contract AToken is VersionedInitializable, ScaledBalanceTokenBase, EIP712Base, IATokenAToken inherits VersionedInitializable, ScaledBalanceTokenBase, EIP712Base and IAToken.
VersionedInitializable
Abstract helper contract to implement initializer functions.
Inspired by the OpenZeppelin Initializable contract.
VersionedInitializable.sol
abstract contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized.
*/
uint256 private lastInitializedRevision = 0;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
uint256 revision = getRevision();
require(
initializing || isConstructor() || revision > lastInitializedRevision,
'Contract instance has already been initialized'
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
lastInitializedRevision = revision;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
/**
* @notice Returns the revision number of the contract
* @dev Needs to be defined in the inherited class as a constant.
* @return The revision number
*/
function getRevision() internal pure virtual returns (uint256);
/**
* @notice Returns true if and only if the function is running in the constructor
* @return True if the function is running in the constructor
*/
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
//solium-disable-next-line
assembly {
cs := extcodesize(address())
}
return cs == 0;
}
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
This contract is used to assist with initialization. It is modified from the Initializable contract of OpenZeppelin, and the revision version number is introduced. When the version number becomes larger, it can be initialized again.


The revision number is defined on AToken.sol, which is obtained via getRevision. However, when the modifier initializer executes, it calls getRevision as defined in AToken.sol, due to override.
Both revision values and getRevision are defined on contracts inheriting VersionedInitializable; this keeps VersionedInitializable modular as it does not need to be altered for each inheritance.
IncentivizedERC20
ScaledBalanceTokenBase inherits MintableIncentivizedERC20, which in turn inherits IncentivizedERC20.
IncentivizedERC20 is similar to the standard ERC-20, with two differences.
balanceOf is modified with struct
UserState:
balance saved in UserState is the actual balance, and additionalData is the liquidity index.
_transfer will apply incentives via IAaveIncentivesController

It is also interesting to note that transferFrom incorporates both approve and transfer.

Mintable Incentivized ERC20
Abstract contract MintableIncentivizedERC20 inherits IncentivizedERC20, and implements only two functions:
_mint
_burn
These two functions will update the balance in _totalSupply and UserState, and then call IAaveIncentivesController.
ScaledBalanceTokenBase
Abstract contract ScaledBalanceTokenBase inherits MintableIncentivizedERC20 and implements three functions:
_mintScaled
_burnScaled
_transfer
Visual Aid
EIP712Base
WIP
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:
override(IncentivizedERC20, IERC20) serves to override balanceOf functions declared within its inheritance tree, so that the parent functions do not get called.
On multiple inheritance

In short, we need to specify the contracts if we are overriding from more than one contract. Otherwise, you just need to use the override keyword.
Read more: https://solidity-by-example.org/inheritance/
A user's aToken balance is the multiplication of two components:
super.balanceOfPOOL.getReserveNormalizedIncome()
In a more digestible form, this basically translates to:
Execution flow:

super.BalanceOf
super.BalanceOf This calls balanceOf as declared in IncentivizedERC20.sol.
Each user has a struct,
UserStateassociated with their address via the mapping_userStateThe
balanceelement within theUserStatestores user's scaled balancesuper.balanceOfreturns_userState[account].balance
super.BalanceOf returns the scaled balance of a user.
getReserveNormalizedIncome
getReserveNormalizedIncome
getReserveNormalizedIncome returns the latest liquidity index, as currentLiquidityIndex.
Putting them together
Example:
user deposits 1000 DAI, when Index = 1.1
scaledBalance = 909
_userState[account].balance= 909
Visual Aid
mint
Execution flow
AToken::mint -> ScaledBalanceTokenBase::_mintScaled -> MintableIncentivizedERC20::_mint

amountScaled, the amount to mint is scaled against the liquidity index in_mintScaled._mintincrements the user's balance byamountScaled.user's balance held 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
