Noncompetitive orders can be replaced with smaller orders
Description
The _removeNonCompetitiveOrder()
function allows the removal of orders when the order book is at its limit. The removal is only supposed to be triggered if the incoming order is worth more. However, it only validates that the newOrder.price > minBidPrice
or newOrder.price < maxAskPrice
respectfully, depending on whether the order is a bid limit or ask limit.
However, competitive potential of an order should be calculated by volume * price
. Otherwise, this will allow a malicious user to cancel all orders in the furthest tick boundaries from the current price, replacing them with slightly better prices but much smaller volumes.
This could lead to the book having concentrated liquidity only within a few price ticks from the current price, leading to unnecessary volatility in pricing.
Impact
Valid, superior orders are canceled, leading to volatile pricing.
Recommendations
Validate that replaced orders are worth more both by volume and price.
Remediation
This issue has been acknowledged by Liquid Labs, Inc.
Liquid Labs, Inc. provided the following response to this finding:
Removing non competitive orders is a failsafe so that a book with over 2 billion orders doesn’t stall. We use
minLimitOrderAmount
to ensure this does not occur. Making the removal of the farthest orders conditional on new order having more value adds too much additional logic.