Ethereum is currently the most well established blockchain where users swap tokens, trade NFTs, and form DAOs among a plethora of other on-chain activities. A lot of the innovations we’ve seen in decentralized finance and the NFT space have originated from this protocol’s extensive network effect of users and world-class developers. Despite its massive success as a protocol, many users are not aware of the fact that anytime a transaction is made it might be in the crosshairs of a hyper-optimized sniper bot. These sophisticated bots are fine-tuned around the core technological architecture of Ethereum to hunt for profitable opportunities. Earlier this year it was not uncommon to see these bots make more than $250k in a single trade. Many stories have already been documented on the dangers of these bots such as Dan Robinson’s journey into the Dark Forest and samczun’s escape from the Dark Forest. Fortunately, recent innovations within the Ethereum eco-system have been developed to help reduce the negative externalities of these snipers.
This research piece will be structured into the following sections:
- Part 1: Overview of Ethereum transactions and Maximal Extractable Value (MEV)
- Part 2: Overview of Flashbots
- Part 3: Case Study – Rescuing an NFT with Flashbots
- Part 4: Case Study – Exploiting a Smart Contract with Flashbots
1. Overview of Ethereum Transactions and MEV
Whenever a transaction is made on the Ethereum network there’s a variety of steps which need to take place for the transaction to be confirmed in the blockchain. Before we dive into some examples below are a few key definitions which will be useful to keep in mind (adapted from ethereum.org).
- Transaction: anytime a user wishes to change the state of the Ethereum blockchain this will involve a transaction. Whether it be buying an NFT on OpenSea, yield-farming across multiple protocols, or simply transferring ETH to another account, all of these activities are examples of state changes to the Ethereum blockchain which need to be verified by miners to be considered final. To prevent spamming the network users are required to pay a fee for every transaction which is paid out to miners.
- Block: this can be thought of as a container which stores new transactions from users across the network. There is a limit to how many transactions can fit in a block, therefore, miners will prioritize transactions with the highest fees first.
- Miner: these parties are responsible for creating new blocks. As mentioned above, there’s a limit to how many transactions can be included in a block so miners need to be selective of which transactions get included. As a result, miners will bundle pending transactions into blocks and prioritize transactions with higher gas fees. Miners will then race against other miners to solve a complicated function in the hopes of arriving at the first solution. The miner who solves the problem and submits their block to the network first wins all of the transaction fees in that particular block. Once the winning miner’s block is mined into the blockchain, all of the transactions within that block are considered to be permanent (there are some exceptions but we won’t discuss these cases here). One critical point to realize is miners have the ability to arbitrarily order transactions in a block. As will be discussed below, this has significant consequences on the overall user experience.
- Node: a device that is running an implementation of the Ethereum software which verifies all transactions in each block. Nodes have an important role in ensuring the network is secure and data is accurate. Whenever a user wishes to make a transaction it must be initially broadcasted from a node to the rest of the network. The vast majority of nodes run GETH which is the Go implementation of Ethereum. These GETH nodes interact with the Ethereum blockchain through remote procedure calls (RPC). For example, calling the RPC `eth_blockNumber` endpoint will retrieve the current block number in the network.
- Gas: is the unit of measurement required to submit transactions on the Ethereum blockchain. Transactions with more complexity will demand higher gas fees. For example, a simple transfer of 1 ETH from address A to address B will cost 21,000 units of gas, however, buying the latest NFT on OpenSea could cost over 300,000 units of gas. Although a simple ETH transfer will always require 21,000 units of gas, the price of gas itself fluctuates based on the current activity in the network, thereby making the total transaction fee variable. Users who wish to fine-tune their transaction fees will likely have to optimize the various components of the gas fees which includes the following:
Gas Limit: the maximum amount of gas which can be spent by the transaction
Gas Price: the maximum price per unit of gas the user is willing to pay
Base Fee: the units of gas required to run the transaction (algorithmically determined by the Ethereum network - ie: in the case of a simple ETH transfer, this amount will always be 21,000 units of gas)
Priority Fee: an optional tip which is paid to miners - this can incentivize miners to include the transaction in a block
- Mempool: before a transaction is verified in the blockchain it sits in a pool of other pending transactions known as the mempool. A transaction in the mempool is unconfirmed until it is selected by a miner to be included in a block. If a transaction sits in the mempool for a long period of time this likely means the user did not specify a high enough gas fee to entice miners to include the transaction in the block.
Let’s consider a simple ETH transfer.
Suppose Alice wants to send 1 ETH to Bob from her Ledger hardware wallet. In this case the transaction would be routed through Ledger’s Ethereum node which will propagate the transaction to a pool of other pending transactions in the mempool.
It is the responsibility of miners to group these transactions into blocks. Transactions with higher gas fees have a higher chance of being included because miners thereby receive more fees. If Alice was in a rush to send the 1 ETH to Bob she would be better off raising her transaction gas limit. This would result in her transaction having higher priority than existing transactions in the mempool.
From this example we can see miners are the parties responsible for recording any state changes to the Ethereum network – they have a very important role in maintaining the functionality of the blockchain. In return for their service, miners are rewarded with fees from the transactions in the block and the newly issued Ethereum (ie: coinbase rewards).
With this background we now have the sufficient context to appreciate the potential dangers of submitting transactions on a public blockchain. Let’s consider a real-world scenario to reflect on the risk of submitting sensitive transaction data to the public mempool. It’s important to note that anyone can look at the unconfirmed transactions in the public mempool — including sniper bots.
Suppose XYZ token is trading for $100 on Uniswap but $120 on Sushiswap. A simple arbitrage strategy would be to buy XYZ token for $100 on Uniswap and sell the same token on Sushiswap at $120, resulting in an arbitrage of $20. An arbitrageur would submit both trades at the same time to ensure the position is opened and closed in the same transaction which ensures a relatively risk-free profit. In this case let’s suppose the arbitrageur sends over this transaction with a gas transaction fee worth $5, leaving him with a net profit of $15.
When the arbitrageur submits this transaction to the network, he’s unaware that sniper bots are sniffing through the mempool looking for any exploitable opportunities. Given this user’s trade is publicly available for anyone to see before it becomes finalized in the blockchain, a sophisticated sniper bot could front-run this user by simply bribing the miner with higher gas fees. In this case the sniper bot would simply copy the exact same trade as the arbitrageur but offer a slightly higher gas fee of $10, leaving the sniper bot with a net profit of $10. Ironically, this bot may get sniped by another bot willing to pay a higher gas fee bribe to the miner. This new sniper bot may be willing to pay $15 worth of transaction fees to collect a net arbitrage profit of $5. This competitive nature of sniper bots trying to out bid each other results in higher transaction fees across the Ethereum network while stealing the original trade from the user. It’s important to note that only one bot can capture the trading opportunity as all other bots will have their trades fail. These failed transactions take up space in the block and crowd out other users which is how bots can push up gas prices for everyone else. This can be frustrating for the original arbitrageur who spent the time and effort to detect the trade but only to get front-runned by bots competing against each other.
This puts users and snipers in an interesting game-theory problem. On one hand users want to minimize fees but at the same time they are highly incentivized to increase their transaction fees to ensure their transaction is selected by miners. Overall, it’s the miners who mostly benefit from these sniper bots as this activity causes a surge in transaction fees across the network. “Maximal Extractable Value” or MEV is a popular term used to describe the additional profit a miner makes from the re-ordering of transactions in the blockchain at the detriment of users. Given MEV arises from miners having the ability to re-order transactions in a block, this means nearly every blockchain has some degree of MEV risk, including Bitcoin. For Ethereum specifically, since the beginning of 2020, nearly $750M USD worth of MEV has been extracted from users!
As a whole, the presence of MEV is one of the most pressing issues facing the Ethereum ecosystem. MEV is also one of the key reasons why gas prices for transaction fees are volatile as bots competitively bid up gas prices to battle for opportunities. This issue is not just for arbitrage trades – as will be seen below, any sensitive trade which may tip off sniper bots can lead to the transaction being exploited and the user losing money. With this understanding, we can now appreciate a potential solution to the MEV crisis and how this technology can be used to protect everyday users.
2. An Overview of Flashbots
As we discussed above, the main issue with sending public transactions directly on the Ethereum network is that all of our pending transactions in the mempool are visible to the rest of the network. This means a sniper can search through any exploitable trade and attack it accordingly.
With the introduction of Flashbots users are no longer at the mercy of these hyper-optimized sniper bots. Instead of using the public mempool, Flashbots allows users to send transactions as a bundle through the Flashbots relayer which directly delivers transactions to miners. From there miners can choose to accept the Flashbots bundle transactions as if they were just like normal Ethereum transactions. On a technical note, miners who want to receive Flashbots bundles must run a special node called MEV-GETH. Similar to GETH, this node implementation simply includes two new RPC endpoints called `sendBundle` and `callBundle` which are used to interact with transactions from the Flashbots relayer.
A few important things to note:
One of the main benefits of using Flashbots is users are able to keep their pre-transaction data private from sniper bots. The transaction data is only published after it is fully mined into the blockchain. In case a transaction is not included by a miner in the current block (ie: other transactions may offer higher gas fees), developers using the Flashbots Protect API will have to continuously re-submit their bundle in each block until it is accepted by a miner. More importantly, if a transaction doesn’t get included in the block by a miner immediately, that’s ok because the transaction is not publicly broadcasted to the network, therefore, no sniper bots can front-run the trade. This is a huge step forward towards preserving pre-transaction privacy for users. At the same time this brings forth a healthier and more robust market for gas prices instead of sniper bots competitively out-bidding each other. Another key benefit of Flashbots is it allows for a more efficient auction mechanism for MEV. As discussed above, failed bids are kept off-chain which frees up the block space for everyone else, hence keeping gas costs lower.
Let’s revisit the DEX arbitrage transaction from earlier. Recall the arbitrageur’s goal is to execute the arbitrage transaction without being front-runned by sniper bots. In the original example, the main issue was the arbitrage transaction was submitted through the public mempool for everyone to see. However, if the arbitrageur routed this transaction through the Flashbots relaying service, he would bypass the public mempool and directly submit the transaction to miners. If for some reason the transaction was not included in the current block (ie: block might be full or other transactions might have higher priority given higher gas fees), the arbitrageur could try again for the next block. The most important thing to note is that the arbitrageur’s transaction is not sitting idly in the public mempool waiting to get sniped by bots, rather it remains hidden. Only after the transaction is mined does it become public for everyone to see which would make it too late for a sniper bot to front-run the trade.
Although users can greatly benefit from Flashbots, sniping bots themselves can also use the Flashbots relayer for executing trades. If a bot detected a potential arbitrage opportunity, it would be foolish to submit the transaction to the public mempool. Every other sniper bot will be listening to the pending transactions and aggressively bid up the transaction gas price until the arbitrage opportunity no longer remains profitable. Instead, the sniper bot which detected the arbitrage opportunity would be best suited to route the transaction through the Flashbots relayer where it can avoid having to reveal its transaction before it is confirmed. This way the sniper bot can ensure the transaction will only be known until after it is mined into the blockchain.
3. Case Study — Rescuing A Stranded NFT
In this example, suppose a developer is working on a blockchain project and accidentally pushes his Ethereum private key to Github. If the repo is public, it’s likely his funds will be gone within several minutes as there are bots scanning through Github and StackOverflow for exposed private keys. Once a bot detects the exposed private key, it would immediately transfer the entire ETH balance to a separate address it controls. Although all of the ETH would be drained from the developer’s wallet, it would be much harder for the bot to detect any NFTs or ERC-20 tokens stored to this address.
Suppose the developer had a valuable NFT stored in this exploited address. Here’s the problem – in order to transfer the NFT to a new safe address, there needs to be ETH in the exploited address to pay for the gas fees to transfer the NFT. The moment any ETH is sent to the exploited address, bots will detect the incoming transfer and immediately withdraw the funds to a separate address. This leaves the NFT stuck in the exploited address as the developer is not able to fund the address with enough ETH to pay for the gas fees to rescue his NFT. Furthermore, even if he was successful in funding the exploited address, when the developer tries to transfer the NFT to a new address, there’s a risk this activity may alert bots and cause them to front-run the transaction, leading them to steal the NFT as well.
Thankfully the developer can use Flashbots to save his NFT. One of the cool features of Flashbots is that users can group multiple transactions into the same bundle provided they are atomic. This means the transaction has to be all or none – every transaction in the bundle needs to execute for it to be successfully sent through the Flashbots relayer. This presents an interesting concept of sponsor transactions where a user can make a transaction from account X but pay for the transaction’s gas fees from account Y. This sounds exactly like what we need in our case!
In the diagram below we’ll combine two transactions into a bundle and submit this through the Flashbots relayer.
- Transaction 1: The sponsor address will transfer a small portion of ETH to the exploited address to pay for the gas fees to transfer the NFT to a safe address
- Transaction 2: Transfer the NFT from the exploited address to the safe address
Let’s review some of the high level aspects of how we will execute this transaction. For those interested in the detailed JS code implementation check out the Github repository for this research project here. Instead of testing out our code on main-net and risk losing thousands of dollars we’ll use the Goerli testnet to simulate these transactions with the help of Paradigm’s awesome testnet faucet.
As can be seen below, the NFT in this example is trapped in the exploited address. Currently there’s no ETH in the exploited address and if anyone were to send ETH to this address it would immediately be swept up by sniper bots.
At the same time the user has a sponsor address which will be used to pay for the transaction gas fees to rescue the NFT and move it to the sponsor’s address.
The developer will have to compile these two transactions into a bundle. The first transaction will involve sending some ETH to the exploited address from the sponsor address to pay for the gas fees to transfer the NFT. The second transaction will involve transferring the NFT itself to the sponsor address. This bundle of transactions called `signedTxBundle` will be sent to the Flashbots relayer. Note: given all of this is done at once (ie: atomically) there’s no feasible way for a sniper to front-run and beat us to this transaction. From here the Flashbots relayer will directly connect the user’s transaction to miners. If miners choose to include this bundle into the block then the developer has successfully rescued his NFT. In the case the miner doesn’t include this transaction in the current block, nobody will know about this transaction given it did not touch the public mempool. When this happens the developer will have to re-submit his transaction until the miner finally includes it in the block (ie: the developer could increase the gas fee to incentivize the miner to include it in the block faster).
Using this JS code the developer was able to successfully transfer the NFT from the exploited address. Notice how the sponsor address now has the NFT which was previously stuck in the exploited address.
At the same time we can see the exploited address no longer has the NFT in its account, however, there is some ETH remaining from the sponsor's transaction (note: we can be more accurate in terms of estimating the gas fees - in this case we just used an arbitrary 0.01 ETH as the estimated gas fee). This excess ETH would be sniped away immediately once it hits the exploited address.
4. Case Study – Exploiting a Smart-Contract
In this case we’re the sniper exploiting opportunities on the blockchain - plot twist!
Suppose a developer released a flawed contract which allows any user to withdraw all of the funds from the contract. Below is an example of such a contract – it can receive ETH from anyone but at the same time any user can also withdraw the contract’s entire ETH balance. This is clearly a huge flaw in the contract because if the balance stored in the smart-contract is enough to cover gas fees, then it is an obvious trade to withdraw all of the funds ASAP. This contract can be viewed on Goerli Etherscan here and originally had a balance of 0.20 ETH.
A naive sniper bot might immediately call the `withdraw` function on the smart-contract and relay this transaction through the public mempool. Even though this sniper bot may have paid a higher gas fee to expedite the transaction, ironically this transaction will be front-runned by more sophisticated sniper-bots.
Why is this so? Anytime a transaction is made with a smart-contract on Ethereum, there will be associated call data encoded which is available for anyone to see when it hits the mempool. For example, if the exploiter wanted to call the `withdraw` function on this smart-contract he would have to sign a transaction with the following hex call-data:`0x3ccfd60b` as shown in the animation below. This data is visible to all sniper bots scanning the mempool.
This data field is in hex and is not decipherable to humans, however, sophisticated sniper bots can take this data and simulate what the transaction would look like if they ran this transaction themselves. Therefore, if this transaction is left in the public mempool, then these sniper bots can still front-run by bidding up higher gas transaction fees. It might get to a point where the sniper bots are paying 0.199 ETH worth of gas fees and receiving 0.2 ETH, hence only resulting in 0.001 ETH of profit.
From this example we can see how these sniper bots can aggressively bid up the price of gas fees for the entire network due to the competitive gas auctions. Therefore, we must prevent this transaction from being detected by other sniper bots before it is mined into the blockchain in order to successfully exploit this contract. We'd be better off relaying this transaction through Flashbots as shown in the diagram below. This will ensure the transaction will not be revealed until after it is mined into the blockchain.
Conclusion and Future Thoughts
As we see millions of new participants come to Ethereum, tools like Flashbots will be critical to ensure a positive user experience and efficient eco-system. There will always be some degree of MEV in any given blockchain, however, tools like Flashbots can help reduce the negative externalities of these sniper bots and potentially encourage a more efficient market-place for on-chain transactions.
While most of this analysis has been in favour of Flashbots, one key risk to mention is that all transactions have to go through a centralized Flashbots relayer which is maintained by the core team. Despite this centralization risk, I believe this is the best approach as decentralizing too early can greatly limit the project’s overall growth and speed of innovation. The team currently has plans in place to decentralize the entire Flashbots project, however, this is a multi-year process.
Furthermore, although this piece has been critical of sniper bots, I think these participants play an important role in maintaining the efficiency for on-chain DEX markets. For example, arbitrage opportunities across DEX exchanges are now extremely competitive given hundreds of bots are constantly scanning for price inefficiencies. Collectively, this makes prices more liquid and accurate which benefits the market as a whole.
Overall, I believe projects focused on protecting their users from sniper bot exploits will be well received by the community. At the same time we’ve seen an increase in demand for MEV resistant trading solutions such as Cowswap, MistX, or simply using Flashbots protection in MetaMask. It’s undeniable that snipers will get more sophisticated, however, smart teams will continue to innovate and constantly focus on optimizing for the best possible user experience.
Acknowledgements: goofyballer (anonymous developer in the Flashbots Discord group) for helping me understand how to submit Flashbot bundles with sufficient gas fees. Ishan Verma for spending hours guiding me through the mechanics of MEV and proof-reading this piece with useful suggestions for several technical definitions. And lastly, Robert Miller for also proof-reading and providing his valuable feedback on several topics pertaining to the core Flashbots architecture.
Disclaimer: Nothing mentioned in this article constitutes as financial advice. Opinions expressed are solely my own and do not express the views or opinions of LedgerPrime.