HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect Withdrawal Amount in Aave

Summary

https://github.com/Cyfrin/2025-01-diva/blob/23cdc88da7e2a9341f453854e876eee82a18e53e/contracts/src/AaveDIVAWrapperCore.sol#L452C4-L479C6

When redeeming X wTokens, all corresponding aTokens (after interest) must be converted to the collateral token but the code converts only X underlying tokens instead of the full X * exchangeRate, resulting in leftover value, thereby breaking the invariant that all burned wTokens are fully redeemed.

Vulnerability Details

https://github.com/Cyfrin/2025-01-diva/blob/23cdc88da7e2a9341f453854e876eee82a18e53e/contracts/src/AaveDIVAWrapperCore.sol#L452C4-L479C6

function _redeemWTokenPrivate(
address _wToken,
uint256 _wTokenAmount,
address _recipient,
address _burnFrom
) private returns (uint256) {
if (_recipient == address(0)) revert ZeroAddress();
// Burn the specified amount of wTokens. Only this contract has the authority to do so.
// Reverts if `_wTokenAmount` exceeds the user's wToken balance.
IWToken(_wToken).burn(_burnFrom, _wTokenAmount);
address _collateralToken = _wTokenToCollateralToken[_wToken];
// Withdraw the collateral asset from Aave, which burns the equivalent amount of aTokens owned by this contract.
// E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC.
// Collateral token is transferred to `_recipient`.
// Reverts if the collateral token is not a registered wToken (first parameter will be address(0)).
uint256 _amountReturned = IAave(_aaveV3Pool).withdraw(
_collateralToken, // Address of the underlying asset (e.g., USDT), not the aToken.
_wTokenAmount, // Amount to withdraw.
_recipient // Address that will receive the underlying asset.
);
emit WTokenRedeemed(_wToken, _wTokenAmount, _collateralToken, _amountReturned, _recipient);
return _amountReturned;
}

The _redeemWTokenPrivate function burns _wTokenAmount (representing aTokens) and calls IAave.withdraw with _wTokenAmount as the requested underlying amount. However, Aave's withdraw expects the underlying amount, not the aToken amount. Since aTokens accrue interest, burning N aTokens should withdraw N * exchangeRate underlying, not N underlying. Using _wTokenAmount directly results in under-withdrawal, leaving residual aTokens in the contract.

Example: If 1 aToken = 1.1 USDC (due to interest), burning 100 aTokens should withdraw 110 USDC. The current code withdraws 100 USDC, leaving 10 USDC worth of aTokens unclaimed.

Impact

Using _wTokenAmount directly results in under-withdrawal, leaving residual aTokens in the contract. Incorrect conversion of wrapped tokens (wTokens) into the underlying collateral.

Tools Used

Manual Review

Recommendations

Adjust the logic so that burning _wTokenAmount aTokens withdraws the equivalent underlying amount based on the current exchange rate.

Updates

Lead Judging Commences

bube Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.