How to Survive in the Ethereum Dark Forest

Avoid a front-running bot from eating you

R
Better Programming

--

Google images

Ethereum is a Dark Forest is a term popularized in crypto by Dan and Georgios from paradigm (if you haven’t read the post, I highly recommend it).

But “The Dark Forest” is actually a science fiction book that brings the concept of a dark forest. This concept basically means that if you are detected a predator will kill you.

Ok, so how does this relate to Ethereum?

To be more precise, this problem applies to almost all chains, but we will focus on Ethereum because it is the chain with the biggest TVL by far.

Following the dark forest analogy, the predators are bots searching for any opportunity there is to make a profit for themselves. Just keep in mind, that a lot of times (not always) the profit they make, is at the expense of the users.

The purpose of this post is to understand on a high level how this predator bots operate, and how to avoid them. In order to truly understand what is going on, we will take a first-principles approach and actually interact with one of this predator on the Ethereum Mainnet.

Prerequisites

You will fully grasp everything if you have the following skills, but you can also understand the overall idea if you don’t:

  1. General understanding of how the EVM works.
  2. Solidity / JS.

Before starting our journey, we need to understand a couple of concepts.

M.E.V

MEV is formerly known as Miner Extractable Value and more recently as Maximal Extractable Value refers to the maximum value that can be extracted from block production in excess of the standard block reward and gas fees by including, excluding, and changing the order of transactions in a block.

Without going into too much detail, what MEV means, is the amount of money that a certain entity (miner, searcher, etc…) can extract by changing something about the transaction ordering.

This concept is going to be completely clear after we interact with the predator.

The Mempool

The Mempool refers to the set of in-memory data structures inside an Ethereum node that stores candidate transactions before they are mined.

What does this mean?

Think about for a second what happens behind the scenes when you send a transaction. What happens when you press send in your wallet?

The short answer is that you are entering the Dark Forest.

When you send a transaction, you are signing a bunch of data, usually an object that looks like this:
* There are more fields than the object shown, this is only to make it simple ..

{
to: "0x123.....,
value: 1000.....,
data: "0x123...,
gasPrice: 100....
}

The moment that you press “send”, you are signing the transaction intent and your wallet provider is forwarding it to a node (usually running go-Ethereum).

The problem with this, is that your transaction is not immediately inside of the blockchain a.k.a “safe zone”, but on the PUBLIC Mempool.

https://www.blocknative.com/blog/mempool-intro

That’s right, everyone can see all the pending transactions*. This has tremendous implications (as we will see).

Just for you to have an idea, at any given time, there are around 180,000 pending transactions on Ethereum (waiting on the Mempool), and a block usually contains around 180 transactions.

*Unless we use a service like FlashBots (as we will).

The Predator

Ok, now that we have a general understanding of what MEV and the Mempool are, let’s see all of this in real action.

CAUTION: You should not do this unless you really know what you are doing !!!

For the sake of research, we will loose some ETH to the predator.

Let’s start!

NOTE: The complete repo with all of the files can be found here: https://github.com/rodrigoherrerai/MEV-EXAMPLE

So the first thing we are going to do is deploying a super simple smart contract:

This contract can do 3 basic things:

  1. Receive ETH.
  2. Transfer the contract’s balance to whoever calls the function.
  3. Emits an event when someone calls the _transfer function.

I will go ahead and deploy the contract. Here is the transaction’s hash, and here is the contract.

Now that we have the contract up and running on Mainnet, we are going to send some ETH to it, here is transaction hash for 0.01 ETH.

To better understand what is going to happen next, just imagine that you are searching for different contracts, and you encounter the contract that we just deployed.

While checking the code on Etherscan, it takes you 2 seconds to realise that the contract is completely vulnerable. You just need to call the _transfer() function and it will send you all the funds right ??

source code on Etherscan

To your surprise, the contract has some ETH!

Well here are the bad news, if you are not well aware of everything we just talked about, you are falling into a trap.

It is true that whoever calls the _transfer() function will receive the contract’s balance. The problem is to make sure that you are the first one to call it. And by that, I do not mean to hurry and just call the function as fast as possible.

So then, what is the problem?

As you remember from our previous explanation, before a transaction gets into the actual block, it goes through the public Mempool.

Are you ready to hear the truth?

Every time a user sends a transaction to the public Mempool, the transaction gets inspected by thousands* of bots to see if they can make a profit out of it. There are different types of attacks, discussing each one of them is out of the scope of this post. For our particular case, we are going to focus on generalized frontrunners.
*It can be more, it can be less, but the number is big.

Generalized frontrunners are basically bots that are observing the mempool, simulating each transaction, copying the potentially profitable transaction’s code, replacing addresses with the frontrunner's address, and running the transaction.

NOTE: The drawing can be a bit misleading, in reality, there is not one mempool, but each node has its own pending transactions. The overall point remains intact.

Ready, Set, Go

Time for reality.

We will try to call the _transfer() function from the smart contract that we deployed. If you have paid attention, you should know by now (at least in theory), that the transaction will be front-run by a bot.

Are you ready?

The script will basically listen for the contract’s “Transferred” event and whenever is called, it will let us know. And just after we trigger the listener, we will call the _transfer() function.

Here is the transaction’ hash.

Funny enough, this is the name of the bot that front-run us:

How did this happen?

Well, pretty simple. The bot simulated our transaction while it was on the mempool, saw that it was profitable, and then execute it before us.

The Solution

Hopefully, by now you understand the severity of this.

The good news is that there is a solution.

The solution is FlashBots. FlashBots has different tools and services, but for our particular use case, we are going to focus on FlashBots Auction.

What FlashBots Auction does, is that it allows us to send private transactions to the miners. This means, that our transaction will not go through the public mempool. Therefore, the predators won’t eat us.

Script:

Here is the transaction’ hash.

The reason why the bot didn’t screw us this time, is because the bot did not know about the existence of our transaction.

Key Takeaways

Currently, base layers have a very adversarial environment. The only way to mitigate this is by developing secure systems and open-source projects like FlashBots.

You need to be very careful as a user to not fall into traps. But even more important, the responsibility really lies on the dapp and system developers.

Good luck out there!

--

--