Skip to content

Latest commit

 

History

History
97 lines (62 loc) · 3.23 KB

003.md

File metadata and controls

97 lines (62 loc) · 3.23 KB

Tall Grape Wombat

Medium

Missing Zero-Balance Check in withdrawETH Function May Lead to Gas Wastage and Poor User Experience

Summary

The withdrawETH function in the contract lacks a check for whether the user has a zero balance before proceeding with the withdrawal logic. This oversight can lead to wasted gas and a confusing user experience. Additionally, it may expose the protocol to minor abuse scenarios, such as repeated zero-value transactions or event spamming.

Root Cause

https://github.com/sherlock-audit/2025-01-aave-v3-3/blob/main/aave-v3-origin/src/contracts/helpers/WrappedTokenGatewayV3.sol#L55

function withdrawETH(address, uint256 amount, address to) external override {
    IAToken aWETH = IAToken(POOL.getReserveAToken(address(WETH)));
    uint256 userBalance = aWETH.balanceOf(msg.sender);
    uint256 amountToWithdraw = amount;

    // if amount is equal to uint(-1), the user wants to redeem everything
    if (amount == type(uint256).max) {
        amountToWithdraw = userBalance;
    }

    aWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
    POOL.withdraw(address(WETH), amountToWithdraw, address(this));
    WETH.withdraw(amountToWithdraw);
    _safeTransferETH(to, amountToWithdraw);
}

The function does not explicitly check if the user’s balance is zero before executing subsequent steps.

Internal Pre-conditions

No response

External Pre-conditions

No response

Attack Path

No response

Impact

  • The aWETH.transferFrom function will likely revert if the user attempts to transfer tokens they do not own. However, this happens after other potentially gas-costly operations have already executed, unnecessarily consuming gas.
- Users with zero balance receive no meaningful error message until a later stage, leading to poor user experience.
    
- Repeated calls with zero balance could lead to minor denial-of-service or spamming scenarios.

PoC

No response

Mitigation

Add a check for zero balance at the start of the function to prevent further execution when the user has no funds to withdraw.

Updated Code:

function withdrawETH(address, uint256 amount, address to) external override {
    IAToken aWETH = IAToken(POOL.getReserveAToken(address(WETH)));
    uint256 userBalance = aWETH.balanceOf(msg.sender);

    // Ensure the user has a non-zero balance
    require(userBalance > 0, "Withdraw failed: zero balance");

    uint256 amountToWithdraw = amount;

    // If the user wants to redeem everything
    if (amount == type(uint256).max) {
        amountToWithdraw = userBalance;
    }

    aWETH.transferFrom(msg.sender, address(this), amountToWithdraw);
    POOL.withdraw(address(WETH), amountToWithdraw, address(this));
    WETH.withdraw(amountToWithdraw);
    _safeTransferETH(to, amountToWithdraw);
}

Benefits of the Fix:

  1. Gas Optimization:

    • The function exits early when the balance is zero, avoiding unnecessary operations.
  2. Improved User Experience:

    • Users receive a clear and immediate error message (“Withdraw failed: zero balance”) when they have no funds to withdraw.
  3. Security Hardening:

    • Prevents spamming or minor abuse scenarios.