sherlock-audit/2024-04-teller-finance-judging

givn - LenderCommitmentGroup_Smart can calculate wrong price because negative ticks math doesn't round down when it should

Closed this issue · 0 comments

givn

medium

LenderCommitmentGroup_Smart can calculate wrong price because negative ticks math doesn't round down when it should

Summary

LenderCommitmentGroup_Smart uses Uniswap V3 pool as oracle to get TWAP price for collateral.

Vulnerability Detail

getSqrtTwapX96 calculates TWAP sqrtPriceX96.

The problem is that when (tickCumulatives[1] - tickCumulatives[0]) is negative, some additional calculations might be necessary, as it's demonstrated in v3-periphery/OracleLibrary.sol.

Impact

When (tickCumulatives[1] - tickCumulatives[0]) < 0 and (tickCumulatives[1] - tickCumulatives[0]) % int32(twapInterval) != 0, the returned tick is higher than it should be. Thus, in this case the required collateral amount put up will be different from what it should be.

In pools with less liquidity prices across ticks may vary quite a bit.

Code Snippet

getSqrtTwapX96 is responsible for making the TWAP price calculation.

Here are the logs from Uniswap V3 USDT/USDC pool, which demonstrates how price may differ, even in very liquid pools.

[PASS] testShowPricesDiff() (gas: 201802)
Logs:
  blockNumber: 19660300
  twapInterval: 2400
  tickCumulativesDelta: -18852
  tick: -7
  tickRoundedDown: -8
  ----------------------- Tick to price ----------------------
  TWAP priceX96: 79172724977-736354325496673369
  TWAP price: 0-999300
  ------------------- Rounded tick to price ------------------
  TWAP priceX96: 79164808496-886665658930780292
  TWAP price: 0-999200

Gist for validating the calculations

Tool used

Manual Review

Recommendation

Update the getSqrtTwapX96 function in the following way:

int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
int24 tick = int24(tickCumulativesDelta / int32(twapInterval));
if (tickCumulativesDelta < 0 && (tickCumulativesDelta % int32(twapInterval) != 0)) tick--;

// tick(imprecise as it's an integer) to price
sqrtPriceX96 = TickMath.getSqrtRatioAtTick(tick);

Duplicate of #283