Aave V3 Tokenization Contracts
Reference for AToken, Rwa, Stata and Variable.
AToken
aTokens are tokens minted and burned upon supply and withdraw of assets to an Aave market. aTokens denote the amount of crypto assets supplied to the protocol and the yield earned on those assets. The aTokens’ value is pegged to the value of the corresponding supplied asset at a 1:1 ratio and can be safely stored, transferred or traded. All yield collected by the aTokens' reserves are distributed to aToken holders directly by continuously increasing their wallet balance.
This contract is the implementation of the interest bearing token for the Aave Protocol. It inherits the ScaledBalanceTokenBase and EIP712Base token contracts.
All standard ERC-20 methods are implemented for aTokens, such as balance, transfer, transfer, approve, total etc.
balance will always return the most up to date balance of the user, which includes their principal balance and the yield generated by the principal balance.
The source code is available on GitHub.
Write Methods
initialize
function initialize(
IPool initializingPool,
address underlyingAsset,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) public virtual
Called when aToken instance is initialized. The treasury and incentives controller are immutable and set in the constructor.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| initializingPool | IPool | The address of the associated pool |
| underlyingAsset | address | The address of the underlying asset |
| aTokenDecimals | uint8 | The decimals of the underlying asset |
| aTokenName | string | The name of the aToken |
| aTokenSymbol | string | The symbol of the aToken |
| params | bytes | A set of encoded parameters for additional initialization |
mint
function mint(
address caller,
address onBehalfOf,
uint256 scaledAmount,
uint256 index
) external virtual override onlyPool returns (bool)
Mints aTokens to on.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| caller | address | The address performing the mint |
| onBehalfOf | address | The address of the user that will receive the minted aTokens |
| scaledAmount | uint256 | The scaled amount of tokens getting minted |
| index | uint256 | The next liquidity index of the reserve |
Return Values:
| Type | Description |
|---|---|
bool | true if the previous balance of the user was 0 |
burn
function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 scaledAmount,
uint256 index
) external virtual override onlyPool returns (bool)
Burns aTokens from from and sends the equivalent amount of underlying to receiver.
In some instances, the mint event could be emitted from a burn transaction if the amount to burn is less than the interest that the user accrued.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| from | address | The address from which the aTokens will be burned |
| receiverOfUnderlying | address | The address that will receive the underlying asset |
| amount | uint256 | The amount of underlying to be burned (non-scaled) |
| scaledAmount | uint256 | The scaled amount of aTokens to be burned |
| index | uint256 | The next liquidity index of the reserve |
Return Values:
| Type | Description |
|---|---|
bool | true if the new balance of the user is 0 |
mintToTreasury
function mintToTreasury(uint256 scaledAmount, uint256 index) external virtual override onlyPool
Mints aTokens to the reserve treasury.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| scaledAmount | uint256 | The scaled amount of tokens getting minted |
| index | uint256 | The next liquidity index of the reserve |
transferOnLiquidation
function transferOnLiquidation(
address from,
address to,
uint256 amount,
uint256 scaledAmount,
uint256 index
) external virtual override onlyPool
Transfers aTokens in the event of a borrow being liquidated, in case the liquidator reclaims the aToken.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| from | address | The address getting liquidated, current owner of the aTokens |
| to | address | The recipient of aTokens |
| amount | uint256 | The amount of tokens getting transferred |
| scaledAmount | uint256 | The scaled amount of tokens getting transferred |
| index | uint256 | The next liquidity index of the reserve |
transferUnderlyingTo
function transferUnderlyingTo(address target, uint256 amount) external virtual override onlyPool
Transfers the underlying asset to target.
Used by the Pool to transfer assets in borrow(), withdraw() and flash.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| target | address | The recipient of the underlying |
| amount | uint256 | The amount getting transferred |
permit
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override
Allows a user to permit another account (or contract) to use their funds using a signed message. This enables gas-less transactions and single approval/transfer transactions. Allow passing a signed message to approve spending.
Implements the permit function as for EIP-2612.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| owner | address | The owner of the funds |
| spender | address | The spender of the funds |
| value | uint256 | The amount the spender is permitted to spend |
| deadline | uint256 | The deadline timestamp, use type(uint256). for max/no deadline |
| v | uint8 | The V signature parameter |
| r | bytes32 | The R signature parameter |
| s | bytes32 | The S signature parameter |
Example of signing and utilizing permit:
import { Contract, Signature, Wallet, getDefaultProvider } from "ethers";
const signer = new Wallet(process.env.PRIVATE_KEY!, getDefaultProvider());
const aTokenAddress = "ATOKEN_ADDRESS";
const aToken = new Contract(
aTokenAddress,
[
"function name() view returns (string)",
"function nonces(address owner) view returns (uint256)",
"function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
],
signer
);
const owner = await signer.getAddress();
const spender = "SPENDER_ADDRESS";
const value = 100n;
const nonce = await aToken.nonces(owner);
const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600);
const signature = await signer.signTypedData(
{
name: await aToken.name(),
version: "1",
chainId: 1,
verifyingContract: aTokenAddress,
},
{
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
],
},
{ owner, spender, value, nonce, deadline }
);
const { v, r, s } = Signature.from(signature);
await aToken.permit(owner, spender, value, deadline, v, r, s);
rescueTokens
function rescueTokens(
address token,
address to,
uint256 amount
) external override onlyPoolAdmin
Rescue and transfer tokens locked in this contract. Only callable by POOL_.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| token | address | The address of the token |
| to | address | The address of the recipient |
| amount | uint256 | The amount of token to transfer |
View Methods
balanceOf
function balanceOf(address user)
public
view
virtual
override(IncentivizedERC20, IERC20)
returns (uint256)
Returns the amount of tokens owned by user.
Overrides the base function.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| user | address | The address of the user |
Return Values:
| Type | Description |
|---|---|
uint256 | The amount of tokens owned by user |
totalSupply
function totalSupply() public view virtual override(IncentivizedERC20, IERC20) returns (uint256)
Returns the amount of tokens in existence.
Overrides the base function.
Return Values:
| Type | Description |
|---|---|
uint256 | The amount of tokens in existence |
RESERVE_TREASURY_ADDRESS
function RESERVE_TREASURY_ADDRESS() external view override returns (address)
Returns the address of the Aave treasury, controlled by governance, receiving the fees on this aToken.
Return Values:
| Type | Description |
|---|---|
address | The address of the Aave treasury |
UNDERLYING_ASSET_ADDRESS
function UNDERLYING_ASSET_ADDRESS() external view override returns (address)
Returns the address of the underlying reserve asset of this aToken (E.g. WETH for aWETH).
Return Values:
| Type | Description |
|---|---|
address | The address of the underlying asset |
DOMAIN_SEPARATOR
function DOMAIN_SEPARATOR() public view override(IAToken, EIP712Base) returns (bytes32)
Get the domain separator for the token at the current chain.
Return cached value if chainId matches cache, otherwise recomputes separator.
Overrides the base function to fully implement IAToken.
Return Values:
| Type | Description |
|---|---|
bytes32 | The domain separator of the token at current chain |
nonces
function nonces(address owner) public view override(IAToken, EIP712Base) returns (uint256)
Returns the nonce value for address specified as parameter. This is the nonce used when calling permit().
Overrides the base function to fully implement IAToken.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| owner | address | The address of the owner |
Return Values:
| Type | Description |
|---|---|
uint256 | The nonce of the owner |
Example:
const token = new Contract(aTokenAddress, aToken.abi, provider);
await token.nonces(user);
RwaAToken
Rwa is a specialized version of the AToken contract designed for Real-World Assets (RWAs). It represents a user’s supplied collateral in the Aave Horizon market. To comply with regulatory requirements, Rwa instances are non-transferable by default for end-users.
Key functionalities such as transfer, approve, and permit are disabled to prevent peer-to-peer movement of these tokens. Aave Horizon introduces an ATOKEN_, which can be granted to RWA issuers or their designated managers to manage functions such as wallet recovery or position migration. An address holding this role can execute authorized transfers on behalf of users, as detailed below.
Write Methods
authorizedTransfer
function authorizedTransfer(address from, address to, uint256 amount) external returns (bool)
Transfers an amount of aTokens between two users. This function can only be called by the Rwa address holding the ATOKEN_ to granularly manage aToken-specific transfers. It is intended for administrative actions, such as migrating a user’s position to a new wallet. The transfer is still subject to the protocol’s health factor checks.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| from | address | The address to transfer from |
| to | address | The address to transfer to |
| amount | uint256 | The amount of tokens to transfer |
Return Values:
| Type | Description |
|---|---|
bool | true if the transfer was successful |
mint
function mint(
address caller,
address onBehalfOf,
uint256 amount,
uint256 index
) public virtual returns (bool)
Mints amount aTokens to a user. This function overrides the standard mint to enforce that the caller of the transaction must be the same as the on address. This effectively disables the supply functionality for RWAs.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| caller | address | The address performing the mint |
| onBehalfOf | address | The address of the user that will receive the minted aTokens |
| amount | uint256 | The amount of tokens getting minted |
| index | uint256 | The next liquidity index of the reserve |
Return Values:
| Type | Description |
|---|---|
bool | true if the previous balance of the user was 0 |
Pure Methods
ATOKEN_ADMIN_ROLE
function ATOKEN_ADMIN_ROLE() external pure returns (bytes32)
Returns the bytes32 identifier for the ATOKEN_. This role grants permission to call authorized.
Return Values:
| Type | Description |
|---|---|
bytes32 | The identifier of the ATokenAdmin role |
Unsupported Operations
To enforce the non-transferable and compliant nature of RWA collateral, most standard ERC-20 interactions are disabled for Rwa. Calling any of the following functions will revert with an OPERATION_ error:
permitapproveincreaseAllowance decreaseAllowance transfertransferFrom mintTo Treasury transferOn Liquidation transferUnderlying To
StataTokenFactory
The Stata is a factory and registry contract that manages all deployed Stata instances for a specified Aave pool. It allows deploying new Stata instances on demand and validates that there is only one Stata instance per underlying asset. This contract maintains a mapping between underlying assets and their corresponding Stata addresses.
Stata are ERC-4626 compliant tokens that wrap Aave’s a to provide a non-rebasing yield accrual mechanism.
The source code is available on GitHub.
Write Methods
initialize
function initialize() external initializer
Initializes the Stata contract. This function is part of the Initializable pattern and is required to initialize the contract after deployment. In this implementation, it does not perform any actions.
createStataTokens
function createStataTokens(address[] memory underlyings) external returns (address[] memory)
Creates new Stata instances for the given underlying assets if they do not already exist. For each provided underlying asset, the function checks if a Stata already exists. If it does, the existing Stata address is returned. If not, it deploys a new Stata for that underlying asset, registers it, and returns the new address.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| underlyings | address[] | An array of underlying asset addresses |
Return Values:
| Type | Description |
|---|---|
| address[] | An array of Stata addresses corresponding to the provided underlying assets |
Emits:
Stataevent for each newToken Created(address indexed stata Token, address indexed underlying) Statacreated.Token
Reverts:
Notif the underlying asset is not listed in the Aave pool.Listed Underlying(address underlying)
View Methods
getStataTokens
function getStataTokens() external view returns (address[] memory)
Returns all Stata instances deployed via this factory.
Return Values:
| Type | Description |
|---|---|
| address[] | An array of all Stata contract addresses |
getStataToken
function getStataToken(address underlying) external view returns (address)
Returns the Stata address for a given underlying asset.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| underlying | address | The address of the underlying asset |
Return Values:
| Type | Description |
|---|---|
| address | The address of the corresponding Stata; returns address(0) if not found |
POOL
function POOL() external view returns (IPool)
Returns the address of the Aave pool associated with this factory.
Return Values:
| Type | Description |
|---|---|
| IPool | The address of the associated Aave pool |
INITIAL_OWNER
function INITIAL_OWNER() external view returns (address)
Returns the initial owner of the Stata proxies created by this factory.
Return Values:
| Type | Description |
|---|---|
| address | The address of the initial owner |
TRANSPARENT_PROXY_FACTORY
function TRANSPARENT_PROXY_FACTORY() external view returns (ITransparentProxyFactory)
Returns the address of the transparent proxy factory used for creating new Stata proxies.
Return Values:
| Type | Description |
|---|---|
| ITransparentProxyFactory | The address of the transparent proxy factory |
STATA_TOKEN_IMPL
function STATA_TOKEN_IMPL() external view returns (address)
Returns the address of the Stata implementation used when deploying new Stata instances.
Return Values:
| Type | Description |
|---|---|
| address | The address of the Stata implementation |
VariableDebtToken
Implements a variable debt token to track the borrowing positions of users at variable rate mode.
transfer and approve functionalities are disabled as variable debt tokens are non-transferable.
The vToken value is pegged 1:1 to the value of underlying borrowed asset and represents the current total amount owed to the protocol i.e. principal debt + interest accrued.
The VariableDebtToken contract inherits the Debt and Scaled token contracts.
The source code is available on GitHub.
Write Methods
initialize
function initialize(
IPool initializingPool,
address underlyingAsset,
uint8 debtTokenDecimals,
string memory debtTokenName,
string memory debtTokenSymbol,
bytes calldata params
) external virtual
Called when variableDebtToken instance is initialized.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| initializingPool | IPool | The pool contract that is initializing this contract |
| underlyingAsset | address | The address of the underlying asset of this variable debt token (e.g. WETH for variableDebtWETH) |
| debtTokenDecimals | uint8 | The decimals of the variableDebtToken, same as the underlying asset’s |
| debtTokenName | string | The name of the variable debt token |
| debtTokenSymbol | string | The symbol of the variable debt token |
| params | bytes | A set of encoded parameters for additional initialization |
mint
function mint(
address user,
address onBehalfOf,
uint256 amount,
uint256 scaledAmount,
uint256 index
) external virtual override onlyPool returns (uint256)
Mints the variable debt token to the on address.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| user | address | The address receiving the borrowed underlying, being the delegatee in case of credit delegate, or same as on otherwise |
| onBehalfOf | address | The address receiving the variable debt tokens |
| amount | uint256 | The unscaled amount of debt, used for the borrow allowance |
| scaledAmount | uint256 | The scaled amount of variable debt tokens to mint |
| index | uint256 | The variable debt index of the reserve |
Return Values:
| Type | Description |
|---|---|
uint256 | The scaled total debt of the reserve |
burn
function burn(
address from,
uint256 scaledAmount,
uint256 index
) external virtual override onlyPool returns (bool, uint256)
Burns user variable debt.
In some instances, a burn transaction will emit a mint event if the amount to burn is less than the interest that the user accrued.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| from | address | The address from which the debt will be burned |
| scaledAmount | uint256 | The scaled amount of debt getting burned |
| index | uint256 | The variable debt index of the reserve |
Return Values:
| Type | Description |
|---|---|
bool | true if the new balance is zero |
uint256 | The scaled total debt of the reserve |
View Methods
UNDERLYING_ASSET_ADDRESS
function UNDERLYING_ASSET_ADDRESS() external view override returns (address)
Returns the address of the underlying asset of this variableDebtToken (e.g. WETH for variableDebtWETH)
Return Values:
| Type | Description |
|---|---|
address | The address of the underlying asset |
balanceOf
function balanceOf(address account) public view virtual override returns (uint256)
Returns the amount of tokens owned by account - the most up to date accumulated debt (principal + interest) of the user.
Standard ERC-20 function.
Input Parameters:
| Name | Type | Description |
|---|---|---|
| account | address | The balance of this address |
Return Values:
| Type | Description |
|---|---|
uint256 | The amount of tokens owned by account |
totalSupply
function totalSupply() public view virtual override returns (uint256)
Returns the amount of tokens in existence - the most up to date total debt accrued by all protocol users for that specific variable rate of debt token.
Standard ERC-20 function.
Return Values:
| Type | Description |
|---|---|
uint256 | The amount of tokens in existence |
Unsupported Operations
Being non-transferable, the variable debt token does not implement any of the standard ERC-20 functions for transfer and allowance.
The following functions revert with Operation: transfer, allowance, approve, transfer, renounce, increase, decrease.