Curved Inky Ram
Medium
In Aave's protocol, an essential invariant ensures that at any point in time: Total aToken Supply = Reserve Liquidity * Liquidity Index
This relationship is crucial because it guarantees that interest calculations, liquidity metrics, and other protocol mechanisms function correctly. It relies on the assumption that each aToken in circulation is backed by an equivalent amount of the underlying asset in the reserve, adjusted by the liquidity index to account for accrued interest.
The core issue stems from the fact that when repaying with aTokens, the underlying assets corresponding to the burned aTokens remain in the reserve, but the reserve's internal accounting does not reflect the decrease in liabilities (the aToken supply). The reserve effectively shows an inflated liquidity position compared to the outstanding aTokens, disrupting the balance required for accurate interest calculations.
The executeRepay function handles the logic when a user repays their debt. Users have the option to repay their debt using either the underlying asset or their aTokens. When they choose to repay using aTokens (useATokens is true), the protocol burns their aTokens to reduce their debt. However, during this process, the reserve's liquidity is not adjusted accordingly.
When useATokens is true, the user's aTokens are burned:
if (params.useATokens) {
IAToken(reserveCache.aTokenAddress).burn(
msg.sender,
reserveCache.aTokenAddress,
paybackAmount,
reserveCache.nextLiquidityIndex
);
This reduces the total supply of aTokens by paybackAmount.
However, the reserve's liquidity is not decreased correspondingly. In fact, the call to updateInterestRatesAndVirtualBalance passes amountToAdd as 0:
reserveCache.nextScaledVariableDebt = IVariableDebtToken(reserveCache.variableDebtTokenAddress)
.burn(params.onBehalfOf, paybackAmount, reserveCache.nextVariableBorrowIndex);
reserve.updateInterestRatesAndVirtualBalance(
reserveCache,
params.asset,
params.useATokens ? 0 : paybackAmount,
0
);
Since params.useATokens is true, amountToAdd is 0, meaning the reserve's liquidity remains unchanged.
The total aToken supply decreases by paybackAmount due to the burning of aTokens. The reserve's liquidity remains the same because amountToAdd is 0, and there is no adjustment to reflect the repayment.
The invariant expects that the total aToken supply should match the reserve's liquidity (adjusted by the liquidity index). With the aToken supply decreasing and the reserve's liquidity remaining constant, this property is violated.
No response
No response
No response
Interest rates and liquidity indices depend on the accurate tracking of both the total aToken supply and the reserve's liquidity. With the mismatch, interest accruals will be miscalculated, leading to incorrect accruals of interest for both lenders and borrowers.
Honest users will suffer losses due to inaccurate interest charges or unexpected liquidations.
No response
Modify the updateInterestRatesAndVirtualBalance call to reflect the decrease in liquidity:
reserve.updateInterestRatesAndVirtualBalance( reserveCache, params.asset, params.useATokens ? paybackAmount : paybackAmount, 0 ); By setting amountToAdd to paybackAmount even when useATokens is true, we acknowledge that the reserve's liquidity decreases by the repaid amount.