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

Unsupported Collateral Tokens Lock User Funds

Summary

The redeemWToken function allows users to convert their wTokens back into collateral tokens by withdrawing the underlying assets from Aave V3. However, if the collateral token associated with the wToken is not supported by Aave V3, the function will fail, leaving users unable to retrieve their funds. This vulnerability arises because the contract does not validate whether the collateral token is still supported by Aave V3 before executing the withdrawal. As a result, users who own wTokens may lose access to their collateral tokens, leading to financial losses and reputational damage for the protocol.

Vulnerability Details

Users who hold position tokens (long or short tokens) can interact directly with the DIVA Protocol to redeem their position tokens for wTokens. This process involves the following steps:

  1. The user calls the redeemPositionToken function in the DIVA Protocol, which burns the position tokens and returns the corresponding wTokens to the user.

  2. To convert these wTokens into collateral tokens, the user must call the redeemWToken function in the AaveDIVAWrapper contract.

  3. The redeemWToken function allows users to redeem their wTokens for the underlying collateral tokens by calling the internal _redeemWTokenPrivate function

function _redeemWToken(address _wToken, uint256 _wTokenAmount, address _recipient) internal returns (uint256) {
// Note: wTokens are not transferred to this contract. Instead, they are burnt from the caller's balance by this contract,
// which has the authority to do so as the owner of the wToken. Therefore, no prior approval from the caller is needed.
// Use the user's balance if `_wTokenAmount` equals `type(uint256).max`
uint256 _userBalance = IERC20Metadata(_wToken).balanceOf(msg.sender);
uint256 _wTokenAmountToRedeem = _wTokenAmount;
if (_wTokenAmount == type(uint256).max) {
_wTokenAmountToRedeem = _userBalance;
}
// Withdraw collateral token from Aave, burn wTokens and transfer collateral token to `_recipient`.
// Reverts inside the wToken's burn function if the `_wTokenAmountToRedeem` exceeds the user's wToken balance.
uint256 _amountReturned = _redeemWTokenPrivate(_wToken, _wTokenAmountToRedeem, _recipient, msg.sender);
return _amountReturned;
}
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;
}

This function performs the following steps:

  1. Burns the user's wTokens.

  2. Withdraws the corresponding collateral tokens from Aave V3.

  3. Transfers the collateral tokens to the user.

However, if the collateral token is not supported by Aave V3, the withdraw function call will revert, leaving the user's wTokens burned but without access to the collateral tokens.
The issue is exacerbated by the fact that the wToken burning operation is irreversible. Once the wToken is burned, the user cannot recover it, even if the collateral token withdrawal fails.

Impact

Users who attempt to redeem their wTokens when the collateral token is unsupported will lose access to their funds. The wToken is burned, but the collateral token cannot be withdrawn from Aave V3.

Tools Used

Manual Review

Recommendations

Before burning wTokens and attempting to withdraw collateral tokens, validate that the collateral token is supported by Aave V3. If the token is unsupported, revert the transaction and avoid burning the wToken.

function _redeemWTokenPrivate(
address _wToken,
uint256 _wTokenAmount,
address _recipient,
address _burnFrom
) private returns (uint256) {
if (_recipient == address(0)) revert ZeroAddress();
+ address _collateralToken = _wTokenToCollateralToken[_wToken];
// 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;
}
Updates

Lead Judging Commences

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

Support

FAQs

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