OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

MEV Risk in buyOrder Function (Lack of Front-Running Protection → Order Sniping)

MEV Risk in buyOrder Function (Lack of Front-Running Protection → Order Sniping)

Description

The buyOrder(uint256 _orderId) function is publicly accessible and does not include any mechanism to prevent front-running. This allows a malicious actor (e.g., MEV bot) to monitor the mempool and submit a competing transaction with a higher gas fee to buy a desirable order before a legitimate user. Since the contract marks the order as inactive immediately after purchase, the legitimate user's transaction will fail.

// buyOrder(uint256 _orderId)

Risk

Likelihood:

  • Public mempool: Anyone can see pending transactions and replicate them.

  • High-value targets: Valuable orders incentivize bots to snipe.

  • Gas priority: Attackers can easily outbid legitimate users with higher gas.

  • No access restrictions: No checks on who can buy, when, or under what conditions.

Impact:

  • This creates a high risk of opportunistic MEV attacks, where bots snipe high-value orders ahead of real users, leading to:

    Loss of trading opportunities for genuine users.
    Unfair market execution and diminished user trust.
    Potential economic losses or manipulation if bots consistently front-run valuable orders

Proof of Concept

function test_MEV_RiskInBuyOrder() public {
// Setup: Alice creates a sell order for wbtc
vm.startPrank(alice);
wbtc.approve(address(book), 1e8);
uint256 orderId = book.createSellOrder(address(wbtc), 1e8, 100_000e6, 1 hours);
vm.stopPrank();
// Simulate two buyers: dan (legit) and mevBot (front-runner)
address mevBot = makeAddr("mev_bot");
usdc.mint(mevBot, 100_000e6);
usdc.mint(dan, 100_000e6);
// MEV bot front-runs and buys the order first
vm.startPrank(mevBot);
usdc.approve(address(book), 100_000e6);
book.buyOrder(orderId);
vm.stopPrank();
// Dan tries to buy the same order, but it should revert
vm.startPrank(dan);
usdc.approve(address(book), 100_000e6);
vm.expectRevert(OrderBook.OrderNotActive.selector);
book.buyOrder(orderId);
vm.stopPrank();
}

Recommended Mitigation

Introduce front-running protection mechanisms such as:
Commit-reveal pattern: Require users to commit to an order ID hash and reveal it later.
Whitelist authorized buyers: Restrict who can buy during specific windows.
Auction-based matching: Batch settle orders to prevent order-by-order execution sniping.
Time delay buffers: Delay execution after order creation or buy intent declaration.
Use private mempools or Flashbots for submitting transactions privately.
Updates

Lead Judging Commences

yeahchibyke Lead Judge
10 months ago
yeahchibyke Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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

Give us feedback!