DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: high
Invalid

Market orders cannot be cancelled before the marketOrderMinLifetime, leading to potential unintended executions

Lines of code

https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/branches/OrderBranch.sol#L396

Impact

If a user creates a market order and realizes it was incorrect, they cannot cancel it before the marketOrderMinLifetime of 10 seconds has passed but the markedOrder can be executed during this cool down period. The inability to cancel an incorrect order promptly can lead to unintended order executions, potentially causing financial losses for the user.

Proof of Concept

The OrderBranch contract includes a function cancelMarketOrder that allows users to cancel their market orders. However, this function includes a check marketOrder.checkPendingOrder() which enforces that a market order cannot be cancelled before it has existed for the minimum order lifetime of 10 seconds.

function cancelMarketOrder(uint128 tradingAccountId) external {
// load existing trading account; reverts for non-existent account
// enforces msg.sender == owner so only account owner can cancel
// pending orders
TradingAccount.loadExistingAccountAndVerifySender(tradingAccountId);
// load trader's pending order; reverts if no pending order
MarketOrder.Data storage marketOrder = MarketOrder.loadExisting(tradingAccountId);
// reverts if a trader has a pending order and that pending order hasn't
// existed for the minimum order lifetime; pending orders can't be cancelled
// until they have existed for the minimum order lifetime
marketOrder.checkPendingOrder(); <== @audit: check prevents immediate cancelation
// reset pending order details
marketOrder.clear();
emit LogCancelMarketOrder(msg.sender, tradingAccountId);
}

According to the team, during this 10 second, the order can be executed which can lead to unintended order filling.

Example:

  1. A user creates a market order.

  2. The user realizes the order was incorrect and attempts to cancel it immediately.

  3. The cancelMarketOrder function reverts due to the marketOrder.checkPendingOrder() check.

  4. The market order remains active and is executed within the 10-second window, even though it could have been cancelled.

  5. The filling of the order leads to unintended financial consequences for the user.

Recommended Mitigation Steps

Remove the marketOrder.checkPendingOrder() check from the cancelMarketOrder function to allow users to cancel their market orders immediately, regardless of the minimum order lifetime.

function cancelMarketOrder(uint128 tradingAccountId) external {
// load existing trading account; reverts for non-existent account
// enforces msg.sender == owner so only account owner can cancel
// pending orders
TradingAccount.loadExistingAccountAndVerifySender(tradingAccountId);
// load trader's pending order; reverts if no pending order
MarketOrder.Data storage marketOrder = MarketOrder.loadExisting(tradingAccountId);
- // reverts if a trader has a pending order and that pending order hasn't
- // existed for the minimum order lifetime; pending orders can't be cancelled
- // until they have existed for the minimum order lifetime
- marketOrder.checkPendingOrder();
// reset pending order details
marketOrder.clear();
emit LogCancelMarketOrder(msg.sender, tradingAccountId);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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