Closed c4-bot-6 closed 4 months ago
Picodes marked the issue as primary issue
TickCumulatives are populated in reverse order of time (we increase the secondsAgos for each index in the input array), so this order is actually correct.
Picodes marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/libraries/PanopticMath.sol#L257-L259
Vulnerability details
Impact
The
PanopticMath.twapFilter
function is used to compute thetwap
of a Uniswap V3 pool using data from its oracle. Thetwap
value in this case computed by taking the theaverage price
over aseries of time intervals
and then taking themedian
of those averages.The computation of the
average price
over aseries of time intervals
is performed as shown below:The
tickCumulatives
value above represents thecumulative sum
of theactive tick
at thetime of the observation
. This tick accumulator value increases monotonically and grows by the value of the current tick - per second (As per the Uniswap Docs).Hence it is clear there is an error in the above depicted code snippet since the delta of the two observations (tickCumulatives) is taken in the reverse order
tickCumulatives[i] - tickCumulatives[i + 1]
where as this should be taken astickCumulatives[i + 1] - tickCumulatives[i]
since thetickCumulatives
values increase monotonically.Since the order of
tickCumulatives
used to compute thetwap
is erroneous this will result in wrong value fortwap
. (Eg: if correcttwap
value is positive thetwapFilter
function will return the negative value of it and vice versa).The
PanopticMath.twapFilter
function is called by thePanopticPool.getUniV3TWAP
function. ThePanopticPool.liquidate
andPanopticPool.forceExercise
functions call thegetUniV3TWAP
function in their transaction execution flows.In the case of
PanopticPool.liquidate
function execution the following issues may occur due to above explained vulnerability.The
liquidate
function performs the following check to ensure the maximum allowed delta between thecurrentTick
and theUniswap TWAP tick
during a liquidation is not exceeded (if it exceeds then the transaction will revert).Issue here is since the returned
twapTick
is of opposit sign value the above condition will result intrue
and transaction will revert even if it should have resulted infalse
. Because if the correcttwapTick
is positive thecurrentTick - twapTick
value will be less. But since the returnedtwapTick
by thePanopticMath.twapFilter
is negative this will result incurrentTick - (-twapTick) => currentTick + twapTick
thus increasing on the total which could be> MAX_TWAP_DELTA_LIQUIDATION
thus reverting the transaction. Hence this will revert a validliquidation
thus putting the protocol into broken state and a state of insolvency.Further to the above the
liquidate
function uses thetwapTick
value when calling theCollateralTracker.getAccountMarginDetails
function. This function is used to calculate the tokenRequirement of theliquidatee
to remain healthy in his position. In the execution flow of thegetAccountMarginDetails
function the_getRequiredCollateralSingleLegNoPartner
and_getRequiredCollateralSingleLegPartner
functions are called. These functions compute therequired amount collateral needed for a specific leg 'index' of the position
. And thisrequired
amount calculation is dependent on thetwapTick
value as shown below:Hence as a result the
erroneous twapTick
value provided to theCollateralTracker.getAccountMarginDetails
function could result in wrongrequired collateral amount
returned. Hence this could lead to positions which areunhealthy
not being able to beliquidated
(if the returnedrequired
collateral amount is erroneously larger) and positions which arehealthy
beingliquidated
. Hence this leads thePanoptic protocol
into a broken state and could make the protocol insolvent sinceliquidation
process is broken.Similarly the
liquidate
function uses thetwapTick
(errorneous value) when calling the_getSolvencyBalances
,PanopticMath.getLiquidationBonus
functions, which could put the protocol into broken states.Similarly the
twapTick
value is used in thePanopticPool.forceExcercise
function execution as well which could further prompt the protocol into broken states and undesirable behavior.Proof of Concept
https://github.com/code-423n4/2024-04-panoptic/blob/main/contracts/libraries/PanopticMath.sol#L257-L259
Tools Used
Manual Review and VSCode
Recommended Mitigation Steps
Hence it is recommended to correct the logic of the
PanopticMath.twapFilter
function such that thedelta
of the two adjacenttickCumulatives
values are taken in the correct order. The modified code snippet in thePanopticMath.twapFilter
should look as follows after the correction.Assessed type
Other