Platform: Code4rena
Start Date: 01/04/2024
Pot Size: $120,000 USDC
Total HM: 11
Participants: 55
Period: 21 days
Judge: Picodes
Total Solo HM: 6
Id: 354
League: ETH
Rank: 28/55
Findings: 1
Award: $212.89
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: DadeKuma
Also found by: 0xStalin, 0xhacksmithh, 99Crits, Aymen0909, Bauchibred, CodeWasp, Dup1337, IllIllI, John_Femi, K42, KupiaSec, Naresh, Rhaydden, Rolezn, Sathish9098, Topmark, ZanyBonzy, albahaca, bareli, blockchainbuttonmasher, cheatc0d3, codeslide, crc32, d3e4, favelanky, grearlake, hihen, jasonxiale, jesjupyter, lanrebayode77, lirezArAzAvi, lsaudit, mining_mario, oualidpro, pfapostol, radin100, rbserver, sammy, satoshispeedrunner, slvDev, twcctop, zabihullahazadzoi
212.8863 USDC - $212.89
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/libraries/PanopticMath.sol#L241-L268 https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1450-L1452 https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1017-L1171
Available possibility for loss of funds, due to unexpected liquidation DoS
At the end of PanopticMath::twapFilter
, the tick at sortedTicks[10]
is returned, which isn't at the median of sortedTicks
with 19 length, which leads to permanent returning of higher tick than actual.
There are 2 main scenarios which could occur due to bad indexation:
PanopticPool::liquidate
, the function could revert unexpectedly due to (Math.abs(currentTick - twapTick) > MAX_TWAP_DELTA_LIQUIDATION)
won't pass, because of currentTick - twapTick
is going to be higher than it is supposed to be (if actualTwapTick > currentTick).PanopticPool::liquidate
, PanopticPool::_getSolvencyBalances
is called to compute the balanceCross
and thresholdCross
.function _getSolvencyBalances( LeftRightUnsigned tokenData0, LeftRightUnsigned tokenData1, uint160 sqrtPriceX96 ) internal pure returns (uint256 balanceCross, uint256 thresholdCross){ unchecked { // the cross-collateral balance, computed in terms of liquidity X*√P + Y/√P // We use mulDiv to compute Y/√P + X*√P while correctly handling overflows, round down balanceCross = Math.mulDiv(uint256(tokenData1.rightSlot()), 2 ** 96, sqrtPriceX96) + Math.mulDiv96(tokenData0.rightSlot(), sqrtPriceX96); // the amount of cross-collateral balance needed for the account to be solvent, computed in terms of liquidity // overstimate by rounding up thresholdCross = Math.mulDivRoundingUp(uint256(tokenData1.leftSlot()), 2 ** 96, sqrtPriceX96) + Math.mulDiv96RoundingUp(tokenData0.leftSlot(), sqrtPriceX96); } }
The third parameter from the input is the sqrtPrice at the twapTick. Due to the logic error the sqrtPrice is permanently going to be higher than actual, because of this the chases of (balanceCross >= thresholdCross)
check to revert are permanently increased (if tokenData0.rightSlot() > tokenData0.leftSlot()).
Rewrite the end of the function to get the median value from 9th index instead of 10th
function twapFilter(IUniswapV3Pool univ3pool, uint32 twapWindow) external view returns (int24) { ... ... ... // Get the median value +++ return int24(sortedTicks[9]); --- return int24(sortedTicks[10]); } }
Other
#0 - c4-judge
2024-04-26T18:57:34Z
Picodes marked the issue as duplicate of #239
#1 - c4-judge
2024-04-26T18:59:32Z
Picodes marked the issue as not a duplicate
#2 - c4-judge
2024-04-26T18:59:49Z
Picodes marked the issue as duplicate of #421
#3 - c4-judge
2024-04-29T21:47:32Z
Picodes changed the severity to QA (Quality Assurance)
#4 - c4-judge
2024-04-29T21:47:48Z
Picodes marked the issue as grade-a