The function Position.isIncreasing()
has issues handling some edge cases, causing it to incorrectly return false
for orders that that cross from long to short (or short to long), even if the resulting position is actually larger than the initial one. This allows increasing orders to be placed in disabled markets or when settlements are disabled, and these orders are subject to smaller margin requirements.
Orders that reduce the size of an existing position are treated differently during settlements. They have lower margin requirements and can be settled even when markets are disabled. However, the Position.isIncreasing()
check is flawed, incorrectly identifying some orders as decreasing orders.
The code snippet below from the Position.isIncreasing()
function shows that it returns false
whenever the sign of the current position (self.size
) and sizeDelta
are opposite. However, it does not account for cases where the signs are opposite but abs(sizeDelta + self.size) > abs(self.size)
i.e the resulting position after order settlement is actually larger than the initial one. Consequently, the true position will increase while the isIncreasing()
function incorrectly returns false
.
This flaw can lead to two possible exploits:
Increase position in disabled markets/settlements: If a user has a long position of size minTradeSize
in a disabled market, they should only be able to reduce or close the position. However, if they send a market order with sizeDelta = -3 * minTradeSize
, they can create a larger short position even though the market is disabled. (See the POC below. Apply the diff to test/integration/perpetuals/settlement-branch/fillMarketOrder/fillMarketOrder.t.sol
and run forge build && forge test –match-test testIsIncreasingPOC
).
Reduced Margin Requirements: Malicious users can exploit this to place orders with the maintenanceMargin
instead of the InitialMargin
. For example, a user wanting to place a short position of size B
can first create a minimum trade size long position of size A
, and then place another order with sizeDelta = -(B + A)
. After settlement, they will have a short position of size B
. However, due to the flawed isIncreasing()
method, this will be treated as a decreasing order, requiring only the maintenanceMargin
instead of the initialMargin
for order settlement.
POC
Orders that cross from long to short (or vice versa) will be incorrectly identified as decreasing orders, even if the resulting position is actually larger than the initial one. This allows them to be subject to smaller margin requirements and be settled in disabled markets.
Manual Review.
Consider modifying Position.isIncreasing()
function to deal better with these edge cases.
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.