The function _fillOrder
is used in settlement of marketOrder
and offchainOrder
. That function _fillOrder
is checking if the marginbalance
of user is greater than requiredMaintenanceMarginBalance
or requiredInitialMarginBalance
depending on whether position is increasing or decreasing. However, due to using wrong _sizeDelta
in markPrice
calculation, markPrice
will be invalid which can lead to liquidations. The function _fillOrder
should calculate full position size in mark price calculation during trade because the position size used in liquidation should be same as position size in which order settlement should be checked.
The function _fillOrder
passes sizeDelta
to the function getAccountMarginRequirementUsdAndUnrealizedPnlUsd
. The function getAccountMarginRequirementUsdAndUnrealizedPnlUsd
calculates required maintenance margin and required initial margin.
The above snippet uses maintenanceMargin
for comparison when position is decreasing
and old position size
is not zero
. So, in below explanation, we will assume that it's the case.
Let's look at the implementation of getAccountMarginRequirementUsdAndUnrealizedPnlUsd
. During the order settlement
, targetMarketId
won't be 0
. It calculates markPrice
based on sizeDelta
instead of considering entire position size. Due to this, markPrice
calculation during this will differ from markPrice
calculation of liquidation. notionalValue
and requiredMaintenanceMargin
is calculated based on markPrice
. Now, if markPrice
calculated during orderSettlement
is less than markPrice
during liquidation, requiredMaintenanceMargin
during orderSettlement
will be less than requiredMaintenanceMargin
during liquidation
. Due to this, trade opened will be subjected to instant liquidation which is unfair to users.
Let's understand above vulnerability with following example:
Assumptions
:
User has only one open position(this is not a restriction but just ease of calculation is this case)
Index price(returned by chainlink) for the user position's asset is $1
(ease of calculation)
Note: The accrued funding and other things won't affect margin balance much when the transactions of order settlement and liquidation are in same block or in adjacent blocks.
Example
:
Position size of user = -10_000(short position)
current skew of perp market = 100_000
skew scale = 1000_000
User wants to open long position of size = 1000 in same perp market. As user has short position opened and user wants to open long position, ctx.isIncreasing
is false
and ctx.oldPositionSizeX18.isZero()
is false
. So, it will use maintenanceMargin
for comparison.
markPrice
calculation being used in orderSettlement
with only sizeDelta
and ignoring old position size:
skew = 100_000
new skew = 100_000 + 1000 = 101000
new position size = -9_000
requiredMaintenanceMarginRate = 5%
markPrice = index_price * (1 + (skew + newSkew) / (2 * skewScale)) = 1 * (1 + (100_000 + 101_000)/ (2 * 1000_000) = 1.1005
requiredMaintenanceMargin = abs(newPositionSize) * markPrice * requiredMaintenanceMarginRate = 9000 * 1.1005 * 0.05 = 495.22500
markPrice
calculation being used in checkLiquidation
with consideration of whole position size after the above trade settlement:
skew = 101_000
position size considered for liquidation = 9_000
new skew due to closing of position size for liquidation = 101000 + 9000 = 110_000
requiredMaintenanceMarginRate = 5%
markPrice = index_price * (1 + (skew + newSkew) / (2 * skewScale)) = 1 * (1 + (101_000 + 110_000)/ (2 * 1000_000) = 1.1055
requiredMaintenanceMargin = abs(newPositionSize) * markPrice * requiredMaintenanceMarginRate = 9000 * 1.1055 * 0.05 = 497.47500
As we can see from the above two instances, requiredMaintenanceMargin
in liquidation is more than requiredMaintenanceMargin
during trade opening. So, the trade can be opened but subjected to liquidation just after settlement of trade.
The trades may succeed requiredMaintenanceMargin
in order settlement which will lead of settlement of order. But it will lead to liquidation as soon as trade is opened.
Manual review
The function _fillOrder
should calculate full position size in mark price calculation during trade because the position size used in liquidation should be same as position size in which order settlement should be checked.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.