Closed c4-bot-8 closed 4 months ago
Picodes marked the issue as primary issue
RefundAmounts is smaller than delegatedAmounts (in value measured across both tokens) because we subtract the fee from it. This means that an net negative amount of tokens is passed into the respective refund
calls -- transferring net value tokens from the force exercisor to the force exercisee.
Reading the report I think the sponsor is right and values correctly flows from the force exercisor to the exercisee, so I'll invalidate.
Picodes marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/PanopticPool.sol#L1231-L1266 https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/CollateralTracker.sol#L650-L734
Vulnerability details
When liquidating, current tick is checked against 10 minutes TWAP:
This is not done for forceExercise. While both have different tasks, force exercise should pay fees, the farther-the-money, the cheaper it should be to force exercise an option position. Additionally, there's a concept of compensating user for loss in value if chunk has lost money between current and median tick, which can be exploited into user whose position is exercised will pay for the exercise.
Impact
Proof of Concept
When position is exercised, current spot price tick is taken together with 10 minutes TWAP:
In order to proceed, token is validated if it's exercisable, i.e. if at least 1 of the long legs is over tickSpacing apart from strike price:
Following, user whose account is exercised is temporarily delegated virtual shares, to make sure that their position can be settled during burning the position from the user. They will have those shares refunded later:
Next, what's important here is that position exercise cost is calculated. The problem is that the cost is based on
slot0
spot price. This allows to take a flashloan, destabilize position to be highly out of the money and eercise anyone's position for very small amount, because exercise is cheaper, the more OTM the position is:However, fees to pay for force exercise in
CollateralTracker.exerciseCost()
are based oncurrentTick
, which exercisor can manipulate however they wish:However, here the bigger issue pertraits itself:
So, if the spot price is manipulated, it's guaranteed that
currentValue
will be smaller thanoracleValue
, henceexerciseFees
will be substracted by the different between the two.Finally, forceExercise fees are added to the previously substracted value:
So now, the fees can be negative, meaning that ideally the exercisor will be paid to exercise an option, which we'll see next. After this, the protocol calculates how much refund should flow from the exercisee (user whose position is exercised) to the exercisor.
What's important to note is that
delegatedAmounts.add(exerciseFees)
- basically substracts one side if exercise fees, because it was negative. Next,PanopticMath.getRefundAmounts
is called. It's not important to understand this issue - it checks what token0/token1 ratio should be refunded, in case that there is not enough to pay from just one token.Finally, the amound are refunded - exercisor gets difference between
refundAmounts
anddelegatedAmounts
, and exercisee receivesdelegatedAmounts
:Last piece is the
CollateralTracker.refund()
function, which acceptsint
and based on the sign, can invert transfer direction:Now, putting it all together, we add exerciseFees to refundAmounts:
refundAmounts = delegatedAmounts.add(exerciseFees)
, and then use it to repay exercisor:The assumption is that the
refundAmounts - delegatedAmounts
will be negative, so that the exercisor will pay for the exercise. However, becauseexerciseFees
are negative, it is the exercisee that has to pay for the exercose. So, not only they have their position closed, even though it could be profitable (only 1 long leg has to be significantly Out-Of-Money), they also loose their collateral for the exercisor.To summarize, the exercisor is paid for exercising an option, if they are able to flashloan some liquidity. And because positions OTM will be common, because will be used in many strategies, malicious actor will have both incentive and a lot of positions to steal from.
Tools Used
Manual Review
Recommended Mitigation Steps
Introduce TWAP check as with liquidation:
Assessed type
Error