Skip to content
Request an audit

‹ All findings

Vault::withdraw() withdraws too much liquidity leading to idle capital and loss of fees

MediumYieldoor·Sherlock · CLMM · 24th February 2025CodebaseM-7

Summary

Vault::withdraw() withdraws from the lp position whenever the idle capital is not enough. However, it withdraws too much as it does not take into account that some of the idle capital is already available.

Root Cause

In Vault:98, it withdraws too many shares.

Internal Pre-conditions

None.

External Pre-conditions

None.

Attack Path

  1. User withdraws 1000 shares, worth 1000 tokens. There already are 500 tokens idle, but the code will still withdraw all 1000 tokens, keeping 500 tokens idle.

Impact

Loss of fees as the liquidity stays idle.

PoC

solidity
function withdraw(uint256 shares, uint256 minAmount0, uint256 minAmount1)
    public
    returns (uint256 withdrawAmount0, uint256 withdrawAmount1)
{
    IStrategy(strategy).collectFees();

    (uint256 totalBalance0, uint256 totalBalance1) = IStrategy(strategy).balances();

    uint256 totalSupply = totalSupply();
    _burn(msg.sender, shares);

    withdrawAmount0 = totalBalance0 * shares / totalSupply;
    withdrawAmount1 = totalBalance1 * shares / totalSupply;

    (uint256 idle0, uint256 idle1) = IStrategy(strategy).idleBalances();

    if (idle0 < withdrawAmount0 || idle1 < withdrawAmount1) {
        // When withdrawing partial, there might be a few wei difference.
        (withdrawAmount0, withdrawAmount1) = IStrategy(strategy).withdrawPartial(shares, totalSupply);
    }

Mitigation

Reduce the shares to withdraw from the strategy by the liquidity already available (idle).