Skip to content

Latest commit

 

History

History
73 lines (51 loc) · 2.33 KB

094.md

File metadata and controls

73 lines (51 loc) · 2.33 KB

Prehistoric Cobalt Aphid

High

Strategy main ticks are not symmetric when the tick spacing is one due to incorrect isLowerSided inequality

Summary

Strategy main position ticks are set according to:

function _setMainTicks(int24 tick) internal {
    int24 halfWidth = int24(positionWidth / 2);
    int24 modulo = tick % tickSpacing;
    if (modulo < 0) modulo += tickSpacing; // if tick is negative, modulo is also negative
    bool isLowerSided = modulo < (tickSpacing / 2);

    int24 tickBorder = tick - modulo;
    if (!isLowerSided) tickBorder += tickSpacing;
    mainPosition.tickLower = tickBorder - halfWidth;
    mainPosition.tickUpper = tickBorder + halfWidth;

    emit NewMainTicks(tickBorder - halfWidth, tickBorder + halfWidth);
}

As can be seen, when the tick spacing is 1, the tick will be deemed lower sided, which adds a tick spacing (1) to the tick border. So, if the current tick is -1769, the ticks will be -1770 to -1766, which is not symmetric and will miss out on fees.

Root Cause

In Strategy:236, is lower sided check is incorrect.

Internal Pre-conditions

None.

External Pre-conditions

None.

Attack Path

  1. Protocol rebalances but main ticks are not symmetric and will miss out on fees when the price moves to the side that has less liquidity allocated.

Impact

Loss of fees.

PoC

    // in setup
    IUniswapV3Pool pool = IUniswapV3Pool(0x20E068D76f9E90b90604500B84c7e19dCB923e7e);
    IERC20 wbtc = IERC20(0x4200000000000000000000000000000000000006); // token0
    IERC20 usdc = IERC20(0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452); // token1
    address uniRouter = address(0x2626664c2603336E57B271c5C0b26F421741e481);
    vm.createSelectFork(vm.envString("RPC_URL_BASE"), 26874136);

function test_POC_WrongTicks_DueToIsLowerSide() public {
    skip(10 minutes);
    vm.startPrank(rebalancer);
    IStrategy(strategy).rebalance();

    IStrategy.Position memory mainPos = IStrategy(strategy).getMainPosition();
    (, int24 tick,,,,,) = pool.slot0();
    //@audit position is not symmetric, harming long term fees
    assertEq(tick, -1769);
    assertEq(mainPos.tickLower, -1770);
    assertEq(mainPos.tickUpper, -1766);
}

Mitigation

bool isLowerSided = modulo <= (tickSpacing / 2);