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

Users will lose WTokens irreversibly due to non-atomic redeem operations

Summary:

The AaveDIVAWrapper’s non-atomic handling of WToken burns and Aave withdrawals will cause permanent fund loss for users as failed withdrawals irreversibly burn WTokens, leaving users without collateral.

Vulnerability Detail

The _redeemWTokenPrivate() function burns WTokens before withdrawing collateral from Aave V3. If the withdrawal fails (e.g., due to insufficient aToken balance), the WTokens are permanently destroyed, and users receive nothing. This violates atomic transaction principles, as the burn and withdrawal are not rolled back on failure.

Critical Code Flow:

function _redeemWTokenPrivate(...) private returns (uint256) {
...
IWToken(_wToken).burn(_burnFrom, _wTokenAmount); // WTokens burned first
uint256 _amountReturned = IAave(_aaveV3Pool).withdraw(...); // Withdrawal attempt after burn
...
}

Example Scenario:

  1. User redeems 100 WTokens:

    • Protocol burns 100 WTokens (supply reduced).

    • Aave withdrawal fails (e.g., aToken balance = 95 due to negative interest).

  2. Result: User’s 100 WTokens are burned, but they receive 0 collateral.

Impact

High Severity: Users permanently lose WTokens if Aave withdrawals fail post-burn. Validation criteria:

  1. Aave withdrawals can fail (e.g., negative interest, slashing).

  2. WToken burns are irreversible (ERC20 burn() cannot be undone).

Proof of Concept

Steps to Reproduce:

  1. User deposits 100 USDC:

    • aToken = 100, wTokenSupply = 100.

  2. Owner claims yield:

    • claimYield() reduces aToken balance to 100.

  3. Aave imposes 5% negative interest:

    • aToken = 95.

  4. User calls redeemWToken(100):

    • Code burns 100 WTokens (burn()).

    • Aave withdraw(100) fails (balance = 95).

  5. Outcome: User loses 100 WTokens, receives 0 USDC.

Tool used

Manual Review

Recommendation

Reorder operations to ensure atomicity: Withdraw from Aave first, then burn WTokens.

// In AaveDIVAWrapperCore.sol
function _redeemWTokenPrivate(...) private returns (uint256) {
...
- IWToken(_wToken).burn(_burnFrom, _wTokenAmount);
uint256 _amountReturned = IAave(_aaveV3Pool).withdraw(_collateralToken, _wTokenAmount, _recipient);
+ IWToken(_wToken).burn(_burnFrom, _wTokenAmount);
...
}
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.