We continue our series of instructive articles with some special recommendations for developers using Aave V3 DeFi integration!
In this article, we present tips that we have acquired over the years of auditing such integrations.
You will also find a list of tools and research for self-study, and we strongly recommend that you read it separately for better understanding!
Make sure to read the rest of the series:
Have audit firms actually gotten worse at what they do?
This, in our opinion, is not the case; yet, the topic is rather tricky because, in certain ways, you can reduce the risks to yourself and your project! By the way, we are working on such a solution within the team and hope to deliver it shortly:
We believe there is no one who doubts that the basis of any secure integration is a special approach to writing code. Consequently, this article will be focused only on those aspects that can be really useful for making your code safe and secure.
Therefore, below you will see not a typical article but a systematization of knowledge (SoK), in which I will rely on authors that I myself trust in this matter and, of course, our pessimistic.io auditors!
This is what we’ll cover in this post about using Aave V3 in your project!
Due to its decentralized nature, Aave makes loans available to users who would otherwise be ineligible for them. As stated, Aave is used to create non-custodial liquidity markets to earn interest on supplying and borrowing assets with a variable or stable interest rate.
The protocol is designed for easy integration into your products and services!
Additionally, Aave specifically uses the idea of over-collateralisation, which states that users are only allowed to borrow up to the value of the collateral they provide.
Given the unpredictability of cryptocurrency prices and Aave’s singular focus on collateral value when issuing loans, this design decision makes sense!
Aave works by allowing pool-to-peer lending, where depositors put their assets in liquidity pools (LP), and then borrowers can borrow from these pools.
When depositing funds into an LP, you receive “aTokens” in return, with which the user will receive a portion of the interest gained from the LP and flash loans and which can be redeemed for your collateral at any time.
In short, V3 Market offers greater capital efficiencies, increased security, and cross-chain functionality while facilitating increased decentralization across the protocol. Aave V3 brings new features as well!
In V2, LPs consisted of many different underlying tokens compared to in V3, where “E-Mode” maximizes efficiency by grouping assets correlated in price and where “Isolation Mode” will allow Aave risk admins to add new assets without exposing the general LPs to the risk of the asset.
The loan-to-value ratio, liquidity threshold, and health factor are the three main values that determine risk on Aave.
The difference between the LTV and the liquidation threshold serves as a safety buffer for borrowers and is used to calculate the user’s health factor.
If a user’s health factor drops below 1, a liquidator can repay up to 50% (100% in V3) of the borrowed amount and receive a liquidation bonus.
It is important to mention that the Aave protocol uses Chainlink Aggregator as the default price oracle to get the price feed and allows customization to set the other price oracle as a fallback oracle.
Users can also use flash loans, which allow them to borrow without putting up any collateral as long as the original amount plus an additional 0.09% fee is returned at the end of the transaction (or block).
The Aave protocol competes in the overcolatorized Defi lending market on the Ethereum blockchain, as well as other EVM-compatible chains such as Avalanche, Polygon, Arbitrum, Fantom, Harmony, and Optimism.
Let’s get started with our own tips! We hope you find today’s article informative and helpful!
Following the tips below can significantly improve the security of your project’s integration!
1. Depending on the user’s health factor, you could liquidate up to 50% of your debt in Aave V2 but up to 100% of your debt in V3:
if HF <= 0.95, you can liquidate up to 100%.
if HF > 0.95, only up to 50% of the debt.
2. To get the user’s health factor data, use Pool.getUserAccountData(address user)
3. Liquidation interface: Pool.liquidationCall() in case of Ethereum and L2Pool.liquidationCall() in case of Optimism, Polygon, etc. The debtToCover parameter defines the number of tokens (debtAsset) that the liquidator wants to cover. You can pass uint(-1) to liquidate all the available debt.
When the prices of collateral and borrowed assets are correlated, the E-mode feature maximizes capital efficiency.
For example, DAI, USDC, and USDT are all stablecoins pegged to the USD. These stablecoins are all within the same E-mode category. As a result, a user who supplies DAI in E-mode will have higher collateralization power when borrowing assets such as USDC or USDT.
The tips below can help you significantly improve the security of your project’s integration:
1. The category with id=0 is the default category and it indicates that e-mode is disabled!
2. Pool.setUserEMode(uint8 _id) — is used to set the user’s efficiency mode to the category with id=_id. When one of the following occurs, the function is reverted:
The user owes one of the tokens that is not listed in the category.
Changing e-mode will shift the user’s health factor to the liquidation zone (i.e. HF < 1)
This feature allows assets with potentially manipulatable oracles (for example, illiquid Uni V3 pairs) to be listed on Aave as a single borrow asset, which means that if a user borrows a siloed asset, they cannot borrow any other asset. This helps mitigate the risk associated with such assets without impacting the overall solvency of the protocol.
The suggestions provided below can significantly improve the security of your project’s integration:
1. AaveProtocolDataProvider.getSiloedBorrowing(address asset) — is used to find out if the asset is in siloed borrowing mode or not.
1. Pool.supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) — is used to supply an asset. Also keep in mind that:
The a-tokens are minted to the onBehalfOf address.
In referralCode you must enter 0, since the referral code feature is currently inactive.
At the moment of call, Pool contract must have an approve on amount of tokens from msg.sender.
2. Pool.supplyWithPermit(asset, amount, onBehalfOf, referralCode, deadline, V, R, S) — you have to remember to do supply, having erc-2612 permit signature.
3. To set an asset as collateral, call Pool.setUserUseReserveAsCollateral(asset, true).
4. Pool.withdraw(asset, amount, to) is used to withdraw the user’s underlying asset in such an amount that its health factor does not drop below 1 (maximum — amount). It also returns the number of tokens actually withdrawn (<= amount).
1. You can get the borrow rate for the required asset through AaveProtocolDataProvider.getReserveData(asset). The call will return the tuple, where indexes 7 and 8 will contain variable and stable borrow rates respectively. (scaled to 10²⁷)
2. Pool.borrow() — you must send msg.sender to onBehalfOf if there is no need to make a credit delegation.
3. To repay the loan in amount of the required number of debt tokens, call Pool.repay(asset, amount, rateMode, onBehalfOf), where asset is the underlying asset address, rateMode equals 1 for stable rate and 2 for variable rate. The onBehalfOf address has debt tokens burned, msg.sender pays the debt at its own cost. You must pass onBehalfOf=msg.sender if you pay your own debt (do not ever send a null/zero address!).
4. AaveProtocolDataProvider.getReserveTokensAddresses(asset) outputs a-token, stable-debt-token and variable-debt-token addresses. Debt-token addresses can be useful for credit delegation!
Credit delegation enables a depositor to deposit funds in the protocol in order to earn interest and to delegate borrowing power (i.e., their credit) to other users.
The depositor and borrower agree on the loan’s terms, which can be done off-chain through legal agreements or on-chain through smart contracts.
Keep in mind:
1. To approve the user’s loan, call .approveDelegation(address delegatee, uint amount) from the corresponding debt token. Then delegatee can delegate the loan of amount with Pool.borrow().
Isolation mode allows Aave Governance to list new assets as isolated assets, which have a specific debt ceiling. Only certain assets can be borrowed in isolation mode — specifically, approved stablecoins.
Assets are approved for borrowing after being voted on by AAVE token holders via the Aave Governance Forum. The debt ceiling for an isolated asset is represented as the maximum amount in USD that can be borrowed with two decimal places against the user’s collateral.
Follow these guidelines to make sure your project’s DeFi integration with Aave V3 is as safe as possible:
1. Although there is no external method available to know if the asset is in isolation mode, you can take the value which Pool.getConfiguration(asset) returns — which is uint256 — and then read bits 212–251 from it, which store the debt ceiling for an isolation mode. Keep in mind that if it is greater than zero, the asset is in isolation mode.
Users may not know, but you can use Uni-V2 stable coin pairs with huge liquidity as a flash loan source just by passing additional 4th argument (byte array for call).
We hope that this article was informative and useful for you! Thank you for reading!
Support is very important to me, with it I can do what I love — educating users!
If you want to support my work, you can send me a donation to the address:
4AhpUrDtfVSWZMJcRMJkZoPwDSdVG6puYBE3ajQABQo6T533cVvx5vJRc5fX7sktJe67mXu1CcDmr7orn1CrGrqsT3ptfds — Monero XMR