Panoptic - ptsanev'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: 27/72

Findings: 2

Award: $219.65

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: hash

Also found by: 0xCiphky, Neon2835, Topmark, Udsen, critical-or-high, lanrebayode77, ptsanev

Labels

bug
2 (Med Risk)
downgraded by judge
partial-50
duplicate-516

Awards

208.3324 USDC - $208.33

External Links

Lines of code

https://github.com/code-423n4/2023-11-panoptic/blob/f75d07c345fd795f907385868c39bafcd6a56624/contracts/SemiFungiblePositionManager.sol#L961-L980

Vulnerability details

Impact

The _createLegInAMM() function is used to create AMM positions using the legs of a specific tokenId. The function uses an unchecked block to save on gas by manually checking for over/underflows, but there's a scenario where the removedLiquidity could underflow.

Proof of Concept

The block of code we are looking at is:

if (_isBurn) { removedLiquidity -= chunkLiquidity; }

Upon burning a position with a isLong=0, this means we are closing a long position, so we should remove short liquidity. Of course, we can only burn liquidity if we have provided it first, which happens when we mint a isLong=1 position where removedLiquidity += chunkLiquidity. The problem is in the value of chunkLiquidity. As stated by the LiquidityChunk library: "A liquidity chunk is an amount of liquidity (an amount of WETH, e.g.) deployed between two ticks: tickLower and tickUpper into a concentrated liquidity AMM". The value of chunkLiquidity between calls can easily fluctuate, since it tracks total liquidity between ticks for a specific leg of a tokenId, but since any user can use any tokenId, some users are bound to use the same tokenId and move the liquidityChunk's liquidity inbetween calls. A simple scenario on the top of my head is a user1 mints, his removedLiquidty = x. Then another user2 mints and his removedLiquidity = y, but the liquidity in the chunk would have increased, meaning if user1 tries to burn his long position removedLiquidity would underflow, breaking user accounting.

Tools Used

Manual Review

Remove the unchecked field or manually check if the chunkLiquidity does not exceed the removedLiquidity, just like it is done in if (startingLiquidity < chunkLiquidity) revert Errors.NotEnoughLiquidity();

Assessed type

Under/Overflow

#0 - c4-judge

2023-12-14T14:39:25Z

Picodes marked the issue as duplicate of #332

#1 - c4-judge

2023-12-26T21:53:43Z

Picodes changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-12-26T21:59:29Z

Picodes marked the issue as satisfactory

#3 - c4-judge

2023-12-26T22:00:51Z

Picodes marked the issue as partial-50

#4 - Picodes

2023-12-26T22:01:44Z

No medium-severity impact (and in particular no loss of funds scenario although this report was initially submitted as high) is described in this report so I'll give only partial-50

Awards

11.3163 USDC - $11.32

Labels

bug
grade-b
QA (Quality Assurance)
edited-by-warden
Q-15

External Links

[L-01] - usage of slot0 to get spot data of Univ3 pool is prone to manipulation:

(, newTick, , , , , ) = univ3pool.slot0(); if ((newTick >= tickLimitHigh) || (newTick <= tickLimitLow)) revert Errors.PriceBoundFail();

Use observe() instead

[L-02] - rebasing tokens would work against the users in events of negative rebases, as stated by the uniswap docs. This detail was probably missed, but due to not being mentioned in the README - Low

[L-03] - the ERC1155Minimal does not implement a balanceOf(), only a balanceOfBatch() function, possibly tampering with potential external integrations that would use it's balanceOf(). Incompliance to ERC1155

[L-04] - tokens with blacklists would not allow users to burn their already opened positions, consider creating a mechanism for removing such users' liquidity, compensating the protocol with their fees.

[L-05] - Slippage tolerance values should be inclusive. Consider rewriting if ((newTick >= tickLimitHigh) || (newTick <= tickLimitLow)) to -> if ((newTick > tickLimitHigh) || (newTick < tickLimitLow)) in order to allow the edge-cases to be accepted.

#0 - c4-judge

2023-12-14T17:04:33Z

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