Solidity Attack Vectors #7 - Front Running

Solidity Attack Vectors #7 - Front Running

Table of contents

Before transactions are added to the block, they are first sent to the transaction pool (mempool). In the mempool, the miners mine the transaction with the highest gas fee and add it to the block before going to the transaction with the lower gas fee. Transactions take some time before they are mined. An attacker can watch the transaction pool and send a transaction, have it included in a block before the original transaction. This mechanism can be abused to re-order transactions to the attacker's advantage.

In the FindThisHash contract below, the player is rewarded 10 ether for guessing correctly the hash in the transaction.

Front Running Illustration

If Alice was able to guess the hash correctly, she will input the hash and call the solve() function. Then Bob that is a malicious player keeps track of Bob's transaction in the mempool, gets the hash, and initiates a new transaction with a higher gas fee.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract FindThisHash {
    bytes32 public constant hash = 0x564ccaf7594d66b1eaaea24fe01f0585bf52ee70852af4eac0cc4b04711cd0e2;

    constructor() payable {}

    function solve(string memory solution) public {
        require(hash == keccak256(abi.encodePacked(solution)), "Incorrect answer");

        (bool sent, ) = msg.sender.call{value: 10 ether}("");
        require(sent, "Failed to send Ether");
    }
}

Since miners look for the transactions with the highest gas fee, Bob's transaction will then be included in a block before Alice's transaction.

Preventive Technique

Use LibSubmarine, which is an open-source smart contract library that makes it easy to protect your contract against front-runners by temporarily hiding transactions on-chain and revealing them at a later stage.