Skip to content

Latest commit

 

History

History
61 lines (46 loc) · 2.87 KB

035.md

File metadata and controls

61 lines (46 loc) · 2.87 KB

Strong Gauze Hawk

Medium

withdrawPartial() function lacks slippage controls for amount0Out and amount1Out

Summary

Strategy:withdrawPartial() function removes partial liquidity from the main and secondary positions by calling the _removeFromPosition function.

function withdrawPartial(uint256 shares, uint256 totalSupply)
        external
        onlyVault
        returns (uint256 amount0Out, uint256 amount1Out)
    {
        (uint256 bal0, uint256 bal1) = idleBalances(); // before withdrawing any liquidity, but after collecting fees.

        uint256 liqToRemove = mainPosition.liquidity * shares / totalSupply;
        (uint256 m0, uint256 m1) =
            _removeFromPosition(uint128(liqToRemove), mainPosition.tickLower, mainPosition.tickUpper);
        mainPosition.liquidity -= uint128(liqToRemove);

        liqToRemove = secondaryPosition.liquidity * shares / totalSupply;
        (uint256 s0, uint256 s1) =
            _removeFromPosition(uint128(liqToRemove), secondaryPosition.tickLower, secondaryPosition.tickUpper);
        secondaryPosition.liquidity -= uint128(liqToRemove);

        amount0Out = m0 + s0 + (bal0 * shares / totalSupply);
        amount1Out = m1 + s1 + (bal1 * shares / totalSupply);

        return (amount0Out, amount1Out);
    }

Because the _removeFromPosition() function does not have slippage controls for bal0 and bal1 returned by the IUniswapV3Pool.burn() function call, the withdrawPartial() function call can suffer from price manipulation on the associated Uniswap V3 pool.

 function _removeFromPosition(uint128 liquidity, int24 tickLower, int24 tickUpper)
        internal
        returns (uint256 bal0, uint256 bal1)
    {
        if (liquidity != 0) {
            (bal0, bal1) = IUniswapV3Pool(pool).burn(tickLower, tickUpper, liquidity);
            IUniswapV3Pool(pool).collect(address(this), tickLower, tickUpper, type(uint128).max, type(uint128).max);
            return (bal0, bal1);
        }
    }

If a price manipulation frontruns the withdrawPartial() transaction, the withdrawn token amounts (amount0Out and amount1Out) can be much less than what they should be.

Impact

Without slippage controls, an attacker can manipulate the Uniswap V3 pool price just before a withdrawal, causing the IUniswapV3Pool.burn() call to return significantly fewer tokens than expected. This means that when a user withdraws liquidity via withdrawPartial(), they may end up receiving much less than their rightful share

Recommendation

The withdrawPartial() function can be updated to include slippage controls for amount0Out and amount1Out returned by the IUniswapV3Pool().burn function call

Code Snippet

https://github.com/sherlock-audit/2025-02-yieldoor/blob/main/yieldoor/src/Strategy.sol#L134-L155 https://github.com/sherlock-audit/2025-02-yieldoor/blob/main/yieldoor/src/Strategy.sol#L486-L495