Panoptic - lsaudit's results

Effortless options trading on any token, any strike, any size.

General Information

Platform: Code4rena

Start Date: 27/11/2023

Pot Size: $60,500 USDC

Total HM: 7

Participants: 72

Period: 7 days

Judge: Picodes

Total Solo HM: 2

Id: 309

League: ETH

Panoptic

Findings Distribution

Researcher Performance

Rank: 67/72

Findings: 1

Award: $11.32

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Awards

11.3163 USDC - $11.32

Labels

bug
disagree with severity
downgraded by judge
grade-b
QA (Quality Assurance)
sponsor confirmed
Q-30

External Links

Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/f75d07c345fd795f907385868c39bafcd6a56624/contracts/libraries/PanopticMath.sol#L149 https://github.com/code-423n4/2023-11-panoptic/blob/f75d07c345fd795f907385868c39bafcd6a56624/contracts/libraries/PanopticMath.sol#L172

Vulnerability details

Impact

The if/else condition is incorrectly implemented in convert0to1() and convert1to0().

sqrtPriceX96 should be compared against type(uint128).max, while it's compared against 340275971719517849884101479065584693834 value.

Proof of Concept

File: PanopticMath.sol

if (sqrtPriceX96 < 340275971719517849884101479065584693834) {

File: PanopticMath.sol

if (sqrtPriceX96 < 340275971719517849884101479065584693834) {

Given a sqrtPriceX96 and a token amount, convert0to1() and convert1to0() return the amount of token received in exchange.

When we examine those functions closely, we can spot, that there are basically forked from Uniswap getQuoteAtTick():

https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/OracleLibrary.sol#L49-L69 if (sqrtRatioX96 <= type(uint128).max) { uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96; quoteAmount = baseToken < quoteToken ? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192) : FullMath.mulDiv(1 << 192, baseAmount, ratioX192); } else { uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 64); quoteAmount = baseToken < quoteToken ? FullMath.mulDiv(ratioX128, baseAmount, 1 << 128) : FullMath.mulDiv(1 << 128, baseAmount, ratioX128); }

The Uniswap sets the sqrtRatioX96 boundary to sqrtRatioX96 <= type(uint128).max, while the current implementation to sqrtPriceX96 < 340275971719517849884101479065584693834. This discrepancy will lead to a different calculations and may cause a fund loss.

Tools Used

Manual code review

Change if (sqrtPriceX96 < 340275971719517849884101479065584693834) to if (sqrtRatioX96 <= type(uint128).max) {

Assessed type

Math

#0 - c4-sponsor

2023-12-15T20:15:01Z

dyedm1 marked the issue as disagree with severity

#1 - c4-sponsor

2023-12-15T20:15:06Z

dyedm1 (sponsor) confirmed

#2 - dyedm1

2023-12-15T20:29:06Z

I have actually never seen that Quoter function before - i suppose great minds think alike ;) I disagree on the severity - a slight loss of potential precision <1 tick early is not at all harmful to the operation of the protocol and has a negligible effect where it's used. We are not dependent on this price estimate being in parity with the quoter in any way shape or form.

Nevertheless, this can still work as a QA because increasing this value a bit for more precision can't hurt.

#3 - c4-judge

2023-12-23T10:10:08Z

Picodes changed the severity to QA (Quality Assurance)

#4 - Picodes

2023-12-23T10:10:28Z

The described impact is of not of Med severity so downgrading to QA

#5 - c4-judge

2023-12-26T23:12:43Z

Picodes marked the issue as grade-b

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