Introduction
AAVE V2 is the leader in the rapid development of the decentralized finance (DeFi) ecosystem One of the decentralized lending agreements is always at the forefront of the industry in providing innovative lending and liquidity management solutions. Its unique trustless mechanism and efficient capital utilization have attracted the participation of a large number of users and institutions. However, with the popularity of its application and the scale of funds involved gradually expanding, the importance of security audits and risk control measures is becoming increasingly prominent. This manual will provide an in-depth discussion of the core design, key functions and related audit points of the AAVE V2 protocol.
Project background overviewAAVE V2 is an open lending platform built on the Ethereum blockchain, allowing users to deposit and deposit various ERC-20 tokens from them Earn interest, while also allowing to borrow tokens from the market in the form of paying interest. By introducing the concept of "interest rate market", AAVE V2 has realized decentralized fund pool management and an automated interest rate adjustment mechanism. In addition, AAVE V2 also provides advanced features such as flash loans, mortgage loans and token exchanges to meet the diverse needs of users, further consolidating its leading position in the DeFi field.
Project architecture analysisThe overall architecture design of AAVE V2 focuses on users, capital flow management, and mortgage Key functions such as mechanisms, clearing processes and interest rate strategies are developed to provide efficient and secure decentralized lending services. The following is a comprehensive analysis:
User operation processUser: Users can deposit, borrow, repay, withdraw, lending interest rate model exchange, lightning loan, and entrusted credit, etc. type of operation. When a user interacts with the agreement, he will automatically mint or destroy the corresponding aTokens according to his or her operations, representing his or her deposit interest in the agreement and obtaining profits based on the interest rate strategy.
Trust Credit: Users can delegate their own credit limit to other users, expanding the flexibility of the agreement and usage scenarios.
Core ComponentsLendingPool: As the core module, it is responsible for handling all user operation requests, including deposits, borrowing, repayment, lending interest rate model exchange, lightning loan and liquidation, and Update interest rates and status.
Collateral Mager: manage collateral assets to ensure that users’ borrowing behavior is safe and controllable. When mortgage assets are insufficient, a liquidation process will be triggered to protect the overall liquidity of the system.
Libraries: encapsulate savings logic, verification logic, general functional logic, such as calculations of liquidation and lending operations, to support LendingPool.
GenericLogic calculates and verifys user status, including asset appraisal, collateral value calculation, health coefficient and other operations.
ReserveLogic is used to manage reserve pools, track and update the amount of deposits, borrowings, and current interest rate status of each asset.
ValidationLogic is responsible for verifying whether the user's operations comply with the agreement rules, and conducting deposits, borrowing, repayment, liquidation, flash loans, When switching debt mode and other operations, strictly check collateral and liabilities.
Debt and TokenizationDebt Tokens: used to track users' borrowing liabilities and the amount of loaned funds is 1:1. Debt tokens have fixed interest rate and variable interest rate options (such as DebtDAI Stable, DebtDAI Variable, etc.), and the debt tokens are not transferable.
aTokens: When a user deposits assets, a 1:1 aTokens will be generated to anchor the underlying assets. These aTokens will continue to increase in value to reflect the interest earned by the deposit. This introduces a ratio along with the principal balance, which is called scaled balance (ScB).
The formula is as follows:
Price and interest rateOracles Proxy: Rely on external oracles (Chainlink) to provide asset market price data, which is used to evaluate the value of users' collateral assets, and ensure the pricing accuracy of lending behavior and the stability of the system.
Lending Rate Oracle: Provide dynamic lending and lending rates based on the system's status and market conditions, and optimizeCapital utilization and liquidity.
Configurator: Used to configure system parameters, such as risk parameters and borrowing limits for different assets, and manage various operations of reserve funds, including activation and borrowing , mortgage, freeze, update parameters and enable or disable features in emergencies. Ensure that the agreement can be adjusted dynamically according to market changes. Other key functionsLiquidation Manager: When the value of user collateral falls below the liquidation threshold, manage liquidation operations to protect the security of the system's funds. The liquidator can obtain rewards through liquidation operations.
Reserves Balances: Stores the system's reserve fund data for calculating and adjusting interest rate strategies. Interest Rate Strategy: Dynamically adjust interest rates according to market and user needs to achieve optimal capital allocation, while taking liquidity risks into account to ensure the system is in different markets Flexibility and stability under conditions.
Although there are two interest rate models (stable and floating), their model calculations are similar to a turning point model. Slope1 under the optimal utilization rate of the inflection point and slope2 exceeding the optimal utilization rate are calculated in segments, and under this condition, they are also divided into fixed interest rate model and variable interest rate model.
The formula is as follows:
Processing deposits left;">The user deposits by calling the deposit function of the LendingPool contract. This function accepts four parameters: asset address, deposit amount, receiver address and recommendation code. First verify that the contract is not enabled, then verify that the deposit amount must be greater than 0 through ValidationLogic.validateDeposit, and confirm that the reserve is active and has not been frozen. Then the system will update the reserve status and call reserve.updateState() to update the liquidity cumulative index and variable borrowing index., and calculate the interest generated during the time period, part of which will be minted and transferred to the agreement treasury.The formula is as follows:
Then dynamically adjust liquidity rates, stable borrowing rates and variable borrowing rates through reserve.updateInterestRates according to the latest supply and demand relationship (all are updated by the DefaultReserveInterestRateStrategy.calculateInterestRates function). In the asset transfer process, the system transfers the user's underlying assets into the aToken contract, and at the same time mints an equal amount of aToken to the onBehalfOf address submitted by the user. Among them, aToken uses a scaled balance to process interest accumulation. If it is the user's first deposit, the system will automatically mark the asset as the user's collateral.
Compound, the deposit process of AAVE V2 has the following main features:
Support Specifies the receiver address (onBehalfOf).
Disclaimer verification through ValidationLogic contract.
Update the liquidity cumulative index and variable borrowing index to calculate and allocate the agreement treasury interest.
At the same time adjust the three interest rates: liquidity, stable borrowing and variable borrowing.
Use aToken's scaled balance to process interest.
First deposits are automatically marked as collateral.
WithdrawThe user withdraws by calling the withdraw function. First, take the reserve data of the specified asset, including the corresponding aToken address, and check the balance of this user in the aToken. Next, call the ValidationLogic.validateWithdraw function to verify the withdrawal request, including checking whether the withdrawal amount is valid and the user balance isWhether it is sufficient, whether the reserves are active, etc. The user's health coefficient and whether withdrawal affects collateral are checked through GenericLogic.balanceDecreaseAllowed, which is similar to the role of the getHypotheticalAccountLiquidityInternal function in compound. In the balanceDecreaseAllowed function, the calculateUserAccountData and calculateHealthFactorFromBalances functions calculate the liquidation threshold after withdrawing funds and check the user's total mortgage, total borrowing amount, and the user's current health coefficient to determine whether the user's health coefficient is in the safe state of the liquidity threshold.
HF calculation formula is as follows:
Then update the status of the reserve and update the interest rate, passing the withdrawal amount to the function. If the amount of cash withdrawal requested by the user is equal to its current balance, the user configuration is updated and the reserve is marked as no longer used as collateral. Finally, destroy the user's aToken and transfer the withdrawal assets to the specified address.
Compound, the withdrawal process of AAVE V2 has the following main features:
Usage aToken represents the user's deposit in the agreement, and withdrawal is actually destroying aToken.
allows users to withdraw cash to a specified address (through the to parameter), adding flexibility.
The options for partial withdrawal and full withdrawal are provided.
In withdrawal verification, AAVE uses a more complex balanceDecreaseAllowed function to check the impact of withdrawal on the user's overall collateral status.
AAVE's withdrawal process directly updates the interest rate, rather than updates through the accrueInterest function like Compound.
LendUser borrows and lends through the borrow function,Bank borrowing will first obtain the current price of the asset from the price oracle and convert the borrowing amount into an ETH equivalent. Then check the ValidationLogic.validateBorrow and whether the GenericLogic.calculateUserAccountData user loan is legal, and calculate the total mortgage assets, total debt, current loan value ratio (LTV), liquidation threshold and health factor, and market stability, etc. (similar to Compound getHypotheticalAccountLiquidityInternal), whether there are sufficient mortgage assets to borrow. reserve.updateState Updates reserve status such as interest rates and borrowing index (this step is similar to accrueInterest in Compound) to calculate and update interest.
Then generate debts based on the interestRateMode (stable or floating interest rate) selected by the user, and select token contracts with different interest rate models to mint tokens. At the same time, checks are also performed when minting tokens. If the onBehalfOf address is not the caller, its loan authorization to the caller will be subtracted in the token contract. If it is the user's first loan, it will be configured as an active borrower. After DebtToken is minted to the user, the agreement will update the loan interest rate through updateInterestRates, reflecting the changes in the new interest rate and reserve pool after the loan. If the user requests to release the underlying assets of the loan, the agreement transfers the assets directly to the user.
Compound, the lending process of AAVE V2 has the following main features:
Support Stable and variable interest rate modes.
Use a separate verification logic contract for lending verification.
Use debt tokens (DebtTokens) to represent users' loans.
Supports credit entrustment and allows users to borrow on behalf of other addresses.
RepaymentThe user repays the user through the repay function, and first obtains the user's current debt (including stable debt stableDebt and floating debt variableDebt). According toThe interest rate mode (stable or floating) selected by the user is verified by ValidationLogic.validateRepay, including whether the user's debt balance is sufficient for repayment. Determine the specific debt type (stable interest rate or floating interest rate) of the repayment based on the interest rate model selected by the user. If the amount the user wants to repay is less than the current debt balance, the system will use the repayment amount provided by the user to make partial repayments; otherwise, all debts will be repaid. Update Status of Reserves UpdateState, used to calculate and update the interest, borrowing volume and borrowing index in the agreement. The corresponding stable debt tokens are then burned and the borrowing rate is updated through updateInterestRates. At this time, if all the user's debts (including stable and floating debts) are zero after repayment, the user's borrowing status will be marked as false, indicating that the user will no longer borrow. Finally, the user transfers the repayment amount from his account to the aToken contract address of the agreement.
Compound, the repayment process of AAVE V2 has the following main characteristics:
Supports repayment in both stable and floating interest rate modes.
Use DebtToken to represent and manage debts, burn corresponding debt tokens when repaying.
Supports partial repayments and full repayments, and handles stable and floating debts respectively.
Support users to repay loans to other addresses through credit delegation.
SettlementThe user cleanses through the liquidationCall function of lendingpool. The function calls the liquidationCall function of LendingPoolCollateralManager through proxy mode to ensure the successful execution of the function. First, GenericLogic.calculateUserAccountData obtains the reserve data of collateral assets and debt assets and user configuration information, calculates the user's health factor, and obtains the user's current stable and variable liabilities through getUserCurrentDebt.
ValidationLogic.validateLiquidationCall function verifys the legitimacy of the liquidation call, including checking the user's health reasons.Sub, debt status and collateral allocation. If the health factor is less than the threshold, it has been used as collateral and neither debt is 0, then it is verified. Then calculate the maximum liquidable debt of the user and determine the actual amount of debts that need to be liquidated. If the liquidated debt exceeds the available collateral of the user, the liquidation amount will be adjusted.
If the liquidator chooses to receive the underlying assets mortgaged by the liquidator, it is necessary to ensure that there is sufficient liquidity in the mortgaged reserve. Update the status of the debt reserve and burn the corresponding number of variable and stable debt tokens based on whether the liquidator receives aToken. Update the interest rate of debt to reflect the liquidated market conditions. Liquidator Reward If you choose to receive aToken, the liquidator will receive the corresponding number of aTokens. If aToken is not accepted, the mortgage status and interest rate of the collateral are updated, the corresponding number of aTokens are burned from the user account, and the underlying assets are transferred to the liquidator. Finally, the debt assets required for liquidation are transferred from the liquidator to the corresponding reserve aToken to complete the liquidation process.
Compound, the liquidation process of AAVE V2 has the following main features:
Support A combination of collateral liquidation of multiple collateral and debt assets.
Allows liquidators to choose to receive aToken or underlying assets.
The clearing process is more modular, separating verification logic, calculation logic, etc. into different functions.
Supports the liquidation of two types of debt, stable interest rate and variable interest rate.
Flash LoanUsers perform flash loans through the flashLoan function of lendingpool. As a loan agreement, the flash loan can allow the current flash loan to be repaid immediately or subsequently as a debt, which is determined by the different incoming modes parameters. 0 is the immediate repayment, 1 is the stable debt, and 2 is the floating debt.
function first checks the input parameter matching through ValidationLogic.validateFlashloan, calculates the premium cost required for Lightning Loan, and directly transfers the required aToken to the recipient address. Call the receiver's executeOperation operation to implement the preset flash loan. AAVE implementationLightning loan operations have included redemption, redemption settlement, and redemption repayment operations. After the above operation is completed by executeOperation, record the amount of the flash loan to be repaid and the corresponding expenses. If the user chooses to return funds in a non-debt mode: the system updates the reserve status, accumulates reserve liquidity, and updates the liquidity index. Finally, the funds and expenses are transferred from the requester to the reserve pool. If the user chooses to handle it in debt mode, call _executeBorrow to open the corresponding debt position.
Convert debt modeIn AAVE V2, users can switch between stable interest rate mode and floating interest rate mode through the swapBorrowRateMode function. First, the user's current stable interest rate debt and floating interest rate debt on the target asset are obtained through the getUserCurrentDebt function to determine the user's debt status. Then call the ValidationLogic.validateSwapRateMode function to verify whether the switch operation is legal. It checks whether the user has sufficient stable or floating debt to support mode switching to ensure that the switching target mode is in line with the asset configuration and the user's debt situation. Call reserve.updateState to update the status of asset reserves to ensure that the reserve data is up to date. Then there is the mutual conversion of the two debt tokens, burning stable debt tokens to mint floating debt tokens or burning floating debt tokens to minting stable debt tokens. After the conversion is completed, reserve.updateInterestRates updates the target asset interest rate to ensure changes in current market status and user debts are reflected.
Security vulnerability Checklist rounding vulnerability caused by empty marketIn both AAVE and Compound, there are vulnerabilities caused by accuracy loss in the empty market. If in an empty market situation (i.e. no user borrows or lends in the market), since the value of liquidityIndex in the cumulateToLiquidityIndex function depends on the number of underlying asset tokens corresponding to the contract, the attacker can deposit a large amount of money into the contract through lightning loans. The underlying asset token is used to manipulate the price of aToken.
Similar to the first time that the Compound fork project Hundred Finance was hacked, in the HopeLend incident, the attacker first manipulated the liquidityIndex to control the value of hETHWBTC to WBTC to 1 :1. Improve liquid by redeeming underlying assets and borrowingThe value of natureIndex. The _handleFlashLoanRepayment function is then continuously called through the looped flash loan.
In the cumulateToLiquidityIndex function, the accuracy loss of rayDiv will amplify the reserve.liquidityIndex value again, and finally the WBTC that can be redeemed is enlarged. (Attack transaction: https://etherscan.io/tx/0x1a7ee0a7efc70ed7429edef069a1dd001fbff378748d91f17ab1876dc6d10392)
Audit key points: during auditing, you need to pay attention to whether the calculation method of the redemption rate is easily Whether the control and rounding method is appropriate, it can also be recommended that the project team cast aToken immediately after the new market is created to prevent the market from being controlled in vain.
ERC677 / ERC777 tokens caused by reentry vulnerabilityThe same as the second time that the Compound fork project Hundred Finance was hacked, in the Agave attack, the attacker was The liquidateCall function is called without any liabilities to liquidate itself. The cleared token is the ERC-677 standard token used on the Gnosis Chain chain. This type of token will call the function of the receiving address externally when transferring money, so the clearing contract calls the attack contract, and the attack contract is deposited in the process 2728 WETH obtained through Lightning Loans were minted, and 2728 aWETH was used as collateral to lend out all available assets in the Agave project. After the external call is completed, the liquidationCall function directly clears the 2728 aWETH deposited by the attacker and transfers it to the liquidator.
(Reference source: https://x.com/danielvf/status/1503756428212936710 ;Attack transaction: https://gnosis.blockscout.com/tx/0xa262141abcf7c127b88b4042aee8bf601f4f3372c9471dbd75cb54e76524f18e)
Audit key points: in audit, you need to pay attention to whether the relevant code of the lending function complies with the CEI (Checks-Effects-Interactions) specification or whether there is a preventive reentry lock, and the impact of tokens with callback functionality needs to be considered.
Price manipulation risks caused by inappropriate oracle mechanismIn the Blizz Finance project hacked, the price of Chainlink used by the agreement continued to plummet at that time due to the continued plunge of LUNA's price at that time The information becomes inaccurate, resulting in the borrowing of funds with expensive LUNA collateral. At the same time, the project does not have an existing fail-safe mechanism. Although it seems that the alarm has been issued in advance, no preventive measures have been established in time to prevent losses. When the price falls below that level, it allows anyone to buy a large amount of LUNA at the market price (well below $0.10) and borrow funds from the platform as collateral (valued at $0.10).
(Reference source: https://x.com/BlizzFinance/status/1524911400992243761)
Audit key points: During auditing, you need to pay attention to whether the oracle price feeding mechanism used to calculate the value of the collateral is easily manipulated by external control. It can be recommended that the project party use a variety of price sources for comprehensive evaluation to avoid the risks caused by a single price source. . At the same time, it is also necessary to pay attention to whether there is a reasonable suspension mechanism for the project to prevent such emergencies.
Unexpected issues introduced by external calls to peripheral contractsIn the interaction between the AAVE protocol and the Para Swap protocol, there are multiple _buyOnParaSwap functions of the Aave Collateral Repay Adapter V3 contract. Safety hazards. This function sets the limit of assetToSwapFrom on tokenTransferProxy to maxAmountToSwap by calling the safeApprove method, but does not consider the situation of not redeeming or partial redemption, resulting in the remaining limit remaining if the limit is not fully used. In addition, the function relies on external contract calls (augustus.call(buyCalldata)) Perform redemption and fail to fully verify and restrict the paraswapData parameter, allowing the attacker to manipulate the decoded buyCalldata and augustus contract addresses through the maliciously constructed paraswapData to bypass the expected redemption logic or avoid redemption completely. Since the function does not reduce or check the token limit of assetToSwapFrom after redemption, even if the redemption fails or is bypassed, the attacker can still use the unchanged high limit to withdraw tokens from the contract, thereby achieving unauthorized transfer of funds . The lack of verification of input data and exchange results, and the failure to effectively manage token limits, led to the attacker's use of the contract.
(Attack transaction: https://etherscan.io/tx/0xc27c3ec61c61309c9af35af062a834e0d6914f9352113617400577c0f2b0e9de)< /p>
Audit key points: During auditing, special attention should be paid to the interactive code with external third-party agreements. Focus on evaluating whether the input and output of external contracts have been strictly restricted, whether the interaction logic has potential impact on the security of the core model of the protocol or funds, and whether the input data has been cleaned and verified to prevent malicious data from causing security problems. By strictly reviewing the code logic of external interactions and data verification mechanisms, the risk of such vulnerabilities can be effectively reduced.
Token compatibility issues with interest rate strategiesIn the Polygon chain, during the AAVE deployment, the function abnormal caused by the incompatibility of InterestRateStrategy settings, and the WETH was set incorrectly Incompatible interest rate strategies.
The interface in the InterestRateStrategy contract that is set incorrectly is as follows:
The code of the LendingPool implementation of AAVE V2 is as follows:
(Reference source: https://x.com/mookim_eth /status/1659589328727859205)
Due to incompatibility of the interface, the new InterestRateStrategy cannot be called normally by LendingPool, which directly causes the WETH pool function of AAVE V2 to be interrupted, and the user cannot store or extract ETH.
Audit key points: During auditing, you need to ensure that the interfaces of key components in the code (or fork) are fully compatible. At the same time, although the above problems are not caused by the multi-chain feature, you still need to pay attention to different things during auditing. Will unexpected results be caused under the characteristics of the chain?
Dust Token ProblemAAVE's deposits and withdrawals will be implemented by setting the usingAsCollateral function to flexibly Manage collateral policies. When an external agreement or contract borrows funds for the first time through the AAVE lending function, the lending function sets usingAsCollateral to true. When an external agreement or contract fully withdraws funds from AAVE, the usingAsCollateral status of the protocol handler in AAVE will be Set to false. But in fact, when AAVE calculates the number of aTokens that need to be burned out for withdrawal, at this time, if there are arithmetic accuracy errors, there may be very few aTokens left in the protocol handler. Therefore, when the protocol handler next time When depositing to AAVE, usingAsCollateral will not change and will still be set to true. Since there is no interface called the setUserUseReserveAsCollateral function in the protocol handler contract, this may cause the protocol handler to no longer perform the borrowing operation.
Audit key points: During auditing, you need to have sufficient familiarity with the called protocol and fully understand its characteristics, and judge whether there is a certain compatibility problem for its interaction with external protocols. Such as token compatibility, call implementation logical compatibility, etc.
Write at the end
This manual explores the core design, key features and related audit points of the AAVE V2 protocol in depth. We hope that this manual can better help developers and security researchers identify potential risks and ensure the safe operation of the protocol. Due to space limitations, this article is omitted. Some codes and pictures are available. Readers can click the original text at the end of the article to jump to GitHub to read the full version (https://github.com/slowmist/AAVE-V2-Security-Audit-Checklist).