Panoptic - Vancelot's results

Permissionless, perpetual options trading on any token, any strike, any size.

General Information

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

Panoptic

Findings Distribution

Researcher Performance

Rank: 32/55

Findings: 1

Award: $153.80

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: DadeKuma

Also found by: Bauchibred, Dup1337, Vancelot, jesjupyter, sammy

Labels

bug
2 (Med Risk)
downgraded by judge
partial-25
:robot:_30_group
duplicate-537

Awards

153.7983 USDC - $153.80

External Links

Lines of code

https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/PanopticPool.sol#L333-L344 https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/PanopticFactory.sol#L328-L411

Vulnerability details

Impact

The returned parameter currentSqrtPriceX96 from slot0 can be easily manipulated with a flashloan, resulting in a loss of funds.

Proof of Concept

The first function that calls slot0 and uses the returned price is assertPriceWithinBounds in PanopticPool.sol:

function assertPriceWithinBounds(uint160 sqrtLowerBound, uint160 sqrtUpperBound) external view { (uint160 currentSqrtPriceX96,,,,,,) = s_univ3pool.slot0(); if (currentSqrtPriceX96 <= sqrtLowerBound || currentSqrtPriceX96 >= sqrtUpperBound) { revert Errors.PriceBoundFail(); } }

One of the comments for this function states that it can be used in a multicall, as a slippage check, for a force exercise or liquidation. If a malicious user were to front-run the call to this function with a flashloan, they could bump up the price so that their options aren't exercised or their account isn't liquidated.

The second function that utilizes slot0 is _mintFullRange in PanopticFactory.sol:

function _mintFullRange(IUniswapV3Pool v3Pool, address token0, address token1, uint24 fee) internal returns (uint256, uint256) { (uint160 currentSqrtPriceX96,,,,,,) = v3Pool.slot0(); uint128 fullRangeLiquidity; unchecked { // Since we know one of the tokens is WETH, we simply add 0.1 ETH + worth in tokens if (token0 == WETH) { fullRangeLiquidity = uint128(Math.mulDiv96RoundingUp(FULL_RANGE_LIQUIDITY_AMOUNT_WETH, currentSqrtPriceX96)); } else if (token1 == WETH) { fullRangeLiquidity = uint128( Math.mulDivRoundingUp(FULL_RANGE_LIQUIDITY_AMOUNT_WETH, Constants.FP96, currentSqrtPriceX96) .....

A malicious user could manipulate the price so that the newly created SFPM is deployed with more liquidity than intended.

Tools Used

Manual Review

I suggest refactoring the functions, in order for them to use Uniswap's TWAP, as it's the safer choice.

Assessed type

Oracle

#0 - c4-judge

2024-04-23T11:55:24Z

Picodes marked the issue as duplicate of #537

#1 - Picodes

2024-04-23T11:55:48Z

For assertPriceWithinBounds as it's a query function and there is no real scenario described here I consider it to be of low severity

#2 - c4-judge

2024-05-01T10:49:13Z

Picodes changed the severity to 2 (Med Risk)

#3 - c4-judge

2024-05-01T10:51:26Z

Picodes marked the issue as satisfactory

#4 - c4-judge

2024-05-01T10:51:42Z

Picodes marked the issue as partial-25

#5 - Picodes

2024-05-01T10:51:56Z

Giving partial credit for the lack of PoC.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter