OrderBook

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

🛡️ MEV Bots Can Front-Run Buyer Transactions Preventing Asset Purchase

MEV Bots Can Front-Run Buyer Transactions Preventing Asset Purchase

Description

Normally, a buyer can purchase listed assets by calling the OrderBook::buyOrder function. However, MEV bots can scan the buyOrder transaction from the mempool and front-run it, resulting in:

  • The original buyer’s transaction reverting.

  • The bot successfully buying the asset.

  • The buyer missing out despite having the required funds.

Risk

Likelihood

  • Reason 1: buyOrder can be front-run easily if sent through public RPC or non-private mempool.

  • Reason 2: No commit-reveal or protection from external frontrunning built into OrderBook.

Impact:

  • Impact 1: Buyer is unable to buy the asset even with correct conditions.

  • Impact 2: Critical functionality of the OrderBook is broken — users cannot reliably fulfill orders.

  • Impact 3: Trust in the decentralized marketplace degrades due to frontrunning exploits.

Proof of Concept

The MevBotAttack contract simulates a bot that front-runs legitimate buyers by quickly calling buyOrder on an active order.

Add this test to your TestOrderBook.t.sol file:

//@audit Add MevBotAttack Contract
contract MevBotAttack is Test {
OrderBook public book;
address public usdcHolder;
constructor(OrderBook _book) {
book = _book;
}
function mevBuyOrderInMempool(uint256 orderId) external {
// simulate mempool bot that front-runs amend by buying before it
book.iUSDC().approve(address(book), type(uint256).max);
book.buyOrder(orderId);
}
}

✅ test_MevAttackOnBuyer - Front-running Buyer

function test_MevAttackOnBuyer() public {
// Step 1: Alice creates a sell order
vm.startPrank(alice);
wbtc.approve(address(book), 2e8);
uint256 orderId = book.createSellOrder(
address(wbtc),
2e8,
180_000e6,
2 days
);
vm.stopPrank();
// Step 2: Deploy MEV bot and fund it with USDC
MevBotAttack mevBot = new MevBotAttack(book);
vm.startPrank(dan);
usdc.transfer(address(mevBot), 200_000e6);
vm.stopPrank();
// Step 3: MEV bot front-runs and buys the asset first
mevBot.mevBuyOrderInMempool(orderId);
// Step 4: Actual buyer (dan) tries to buy but fails
vm.startPrank(dan);
usdc.approve(address(book), 200_000e6);
vm.expectRevert(OrderBook.OrderNotActive.selector);
book.buyOrder(orderId);
vm.stopPrank();
// Step 5: Validate bot got asset, dan did not
assert(wbtc.balanceOf(address(mevBot)) == 2e8);
assert(wbtc.balanceOf(dan) == 0);
assert(usdc.balanceOf(alice) == 174_600e6);
assert(book.totalFees() == 5_400e6);
}

Recommended Mitigation

  • Use private RPC providers like Flashbots RPC to protect user intent from public mempool visibility.

  • Consider adding:

    Commit-reveal schemes for critical actions like buyOrder().

    Access control or reservation windows (e.g., "soft-lock" orders for 1 block).

    Slippage protection, where user sets a max token amount or block deadline.

Updates

Lead Judging Commences

yeahchibyke Lead Judge
10 days ago
yeahchibyke Lead Judge 9 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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