_updateSettlementPostBurn() may not correctly reduce s_grossPremiumLast[chunkKey] #462
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
M-06
satisfactory
satisfies C4 submission criteria; eligible for awards
selected for report
This submission will be included/highlighted in the audit report
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Lines of code
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1862
Vulnerability details
Vulnerability details
s_grossPremiumLast[]
definitions are as follows:a critical rule: if there is a change in
totalLiquidity
, we must recalculate this value.when
Pool.mintOptions()
,s_grossPremiumLast[chunkKey]
will increase.step:
mintOptions()
->_mintInSFPMAndUpdateCollateral()
->_updateSettlementPostMint()
when
Pool.burnOptions()
,s_grossPremiumLast[chunkKey]
will decreaseburnOptions()
->_burnAndHandleExercise()
->_updateSettlementPostBurn()
The issue lies within
_updateSettlementPostBurn()
, where it adds a condition thatif (LeftRightSigned.unwrap(legPremia) != 0)
must be met fors_grossPremiumLast[chunkKey]
to decrease.This results in not recalculating
s_grossPremiumLast[chunkKey]
even whentotalLiquidity
changes.For example, in the same block, if a user executes
mintOptions()
,s_grossPremiumLast[chunkKey]
increases by 50. Immediately after, executingburnOptions()
doesn't decreases_grossPremiumLast[chunkKey]
by 50 becauselegPremia == 0
.Proof of Concept
The following code demonstrates this scenario, where
s_grossPremiumLast[chunkKey]
keeps increasing,solast gross accumulated
keeps decreasing.Misc.t.sol
PanopticPool.sol
function _updateSettlementPostMint( TokenId tokenId, LeftRightUnsigned[4] memory collectedByLeg, uint128 positionSize ) internal { ... unchecked { // L LeftRightUnsigned grossPremiumLast = s_grossPremiumLast[chunkKey]; // R uint256 positionLiquidity = liquidityChunk.liquidity(); // T (totalLiquidity is (T + R) after minting) uint256 totalLiquidityBefore = totalLiquidity - positionLiquidity; //console.log("s_grossPremiumLast[chunkKey].rightSlot() from:",s_grossPremiumLast[chunkKey].rightSlot()); s_grossPremiumLast[chunkKey] = LeftRightUnsigned .wrap(0) .toRightSlot( uint128( (grossCurrent[0] * positionLiquidity + grossPremiumLast.rightSlot() * totalLiquidityBefore) / (totalLiquidity) ) ) .toLeftSlot( uint128( (grossCurrent[1] * positionLiquidity + grossPremiumLast.leftSlot() * totalLiquidityBefore) / (totalLiquidity) ) ); + console.log("last accumulated : ",(grossCurrent[0] - s_grossPremiumLast[chunkKey].rightSlot()) * totalLiquidity); } } } }
Impact
Due to the incorrect accounting of
s_grossPremiumLast[chunkKey]
, the calculation in_getAvailablePremium()
is also incorrect. This results in inaccuracies in the amount of premium received by the seller when closing their position.Recommended Mitigation
Regardless of the value of
legPremia
, it should recalculates_grossPremiumLast[chunkKey]
whenlong == 0
.Assessed type
Context
The text was updated successfully, but these errors were encountered: