4 min read

Detect Ethereum front-runners with honey pot contract

In this post, I'll show you how to see Ethereum front-runners in action. To do this, I've developed the special "honey pot" contract, which allows anyone to withdraw some ethers, if they are fast enough. We will let the front-runners to do this and then research their behavior in details.
Detect Ethereum front-runners with honey pot contract

In this post, I'll show you how to see Ethereum front-runners in action. To do this, I've developed the special "honey pot" contract, which allows anyone to withdraw some ethers if they are fast enough. We will let the front-runners do this and then research their behavior in detail.

Probably, this method is not the best, because you should allow someone to steal your real ETH. The best thing to do is to monitor the memory pool and try to identify the Priority Gas Auctions (PGAs). But it's not an easy task and requires much more development, so let's begin with simple research.

Honey pot contract

For demonstration purposes, I've written a neat but powerful smart contract. You can interact with it in only two ways - lock you ethers and unlock (withdraw) your ethers. The process is simple:

  • Imagine some strong hard-to-guess password.
  • Calculate the hash of the password (let's say sha256)
  • Lock your ethers by providing the password's hash
  • Unlock your ethers by providing the raw password. The contract will calculate the hash itself and compare it to the specified on step 2. If the hash matches - the contract will send you locked ethers back. Easy to see - only you can withdraw the ethers since no one else knows the original password. Really?
pragma solidity ^0.6.0;

contract TryToGetYourMoney {
    mapping(bytes32 => uint) passwordHashToBalance;
    
    function lockEthersWithPassword(
        bytes32 passwordHash
    ) public payable {
        passwordHashToBalance[passwordHash] += msg.value;
    }
    
    function getHash(string memory raw) public view returns(bytes32) {
        return keccak256(abi.encodePacked(raw));
    }
    
    function unlockEthersWithPassword(
        string memory password
    ) public {
        bytes32 passwordHash = getHash(password);

        require(
            passwordHashToBalance[passwordHash] > 0,
            "No Ethers locked with specified password"
        );
        
        msg.sender.transfer(passwordHashToBalance[passwordHash]);

        passwordHashToBalance[passwordHash] = 0;
    }
}
Solidity source code.

Well, probably not. Any front-runner can see the transaction while it's in the pending status, extract the raw password, and send his own unlock transaction with the higher gas price. Since the higher gas price means faster confirmation, the front-runner's transaction probably will be mined first and he will receive your ethers.

Experiment

I've deployed the contract above in the Ethereum Main network ( 0x9478abe9244872274808d324b968c30f29e1a442). I've tried twice to lock ethers and unlock them after - both unlock transactions have been front-runned!

Two locks - 0.1 ETH and 0.05 ETH. Two failed transaction is the unlock transactions. They failed because someone have already stolen the locked ETH!

Let's see why the transactions have failed. You can see, that the reasons are the same: "No ethers locked with specified password". But how is it possible? To answer this, let's see the Internal txns section on the Etherscan:

With these transactions, the front-runner has stolen my ETH. Let's compare my transaction 0xa88.. and 0x3fa.... Both of them are trying to unlock 0.1 Ether.

My transaction is on the left, front-runner transaction is on the right.

See how the gas price affects the confirmation time. My transaction has 50 Gwei gas price and it was confirmed in ~3 minutes. Front runner has specified the 58 Gwei - this gave him confirmation within 30 seconds! Even though I sent the unlock transaction first, his transaction has been confirmed 11 blocks earlier than mine.

How they do that?

There's no technical struggle to make your front-runner bot. First of all, you need to monitor all new Ethereum transactions. Since you want to be the first to know about new transactions, probably you'll need multiple transaction listeners in all parts of the world.

After you've been notified about the new transaction, you need to simulate the same call but from your address. If it's not reverted and you earn more than you spend - send it to the Main net! Also, don't forget to set up a higher gas price to overtake the original transaction. That's it.

Try to bait front-runner on your own

You can also try to bait the front runner! To do this, just use the provided smart contract.

  • Imagine some strong password. Let's say - nooneeverguess123
  • Calculate the hash of the password. Use the getHash method on the etherscan "Read contract" page, press Query, and copy the long 0x prefixed string.
  • Go to the "Write contract" section, Connect to Web3, and find the lockEthersWithPassword method. In the payableAmount field specify the amount Ethers you want to use as bait (I think 0.01 would be enough). In the passwordHash filed specify the password hash you've received on step 2. Click write, confirm the transaction, and wait till it's mined.
  • Now the interesting part begins! Try to get back your Ethers with unlockEthersWithPassword method. Specify the raw password in the password field (in my case it's nooneeverguess123). Click write, click confirm, and wait.

In the pop-up you can try to customize gas price (Details - Gas fee - Edit), to manipulate the probability of successful front-run. The more gas price you specify, the faster transaction will be confirmed, the fewer chances that it would be front-runned.

Leave default options if you want to get front-runned.

Most likely, your transaction will fail! See the internal calls section to find out the sender of the front-run transaction.