OrderBook

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

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

Author Revealed upon completion

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
5 days ago
yeahchibyke Lead Judge about 21 hours ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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