Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Absence of slippage protection in market orders exposes users to significant financial risk through unfavorable execution prices.

Description

Market orders in the perpetual futures protocol lack price slippage controls, unlike limit orders which have price validation. When a market order is executed through fillMarketOrder(), the order is filled at whatever price is returned by getMarkPrice() without any bounds checking.

The issue stems from how market prices are processed and validated in the perpetual futures system. The protocol's architecture routes market order execution through fillMarketOrder() in SettlementBranch.sol, which interfaces with PerpMarket.sol's getMarkPrice() function to determine execution prices. This function calculates prices based on the current market state:

function getMarkPrice(
Data storage self,
SD59x18 skewDelta,
UD60x18 indexPriceX18
) internal view returns (UD60x18 markPrice)

While the protocol implements robust price validation for limit orders through fillOffchainOrders:

ctx.isFillPriceValid = (ctx.isBuyOrder && ctx.offchainOrder.targetPrice >= ctx.fillPriceX18.intoUint256())
|| (!ctx.isBuyOrder && ctx.offchainOrder.targetPrice <= ctx.fillPriceX18.intoUint256());

This critical price validation mechanism is notably absent for market orders. The lack of bounds checking means market orders are executed solely based on getMarkPrice()'s output, without any safety constraints or slippage controls.

Impact

This architectural oversight creates significant vulnerabilities in the trading system. Users executing market orders face exposure to unconstrained price slippage, market skew impacts, potential oracle manipulation, and adverse price movements during the order lifecycle. In volatile market conditions, this could result in severe financial losses through orders executing at unexpected and highly unfavorable prices.

Recommendation

The solution requires adding price bounds validation at both the data structure and execution levels.

First, extend the market order data structure to include slippage controls:

struct Data {
uint128 marketId;
int128 sizeDelta;
uint256 maxSlippage; // Maximum allowed slippage from index price
// ... other existing fields
}

Then implement price validation logic within the order execution flow:

// Calculate max allowed price deviation
UD60x18 maxAllowedPrice = ctx.isBuyOrder ?
ctx.indexPriceX18.mul(ud60x18(1e18 + marketOrder.maxSlippage)) :
ctx.indexPriceX18.mul(ud60x18(1e18 - marketOrder.maxSlippage));
// Validate fill price against slippage bounds
if ((ctx.isBuyOrder && ctx.fillPriceX18 > maxAllowedPrice) ||
(!ctx.isBuyOrder && ctx.fillPriceX18 < maxAllowedPrice)) {
revert Errors.ExcessiveSlippage();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.