Fall 2022
Introduction
Manifold Trading, a quantitative investment firm, hosted an algorithmic trading challenge titled “Manifold MEV Bounty.” The goal is to use a high-frequency trading (HFT) strategy known as MEV to capitalize on inefficiencies within the simulated markets. MEV stands for “Maximal Extractable Value” and refers to the maximum value that can be extracted from including, excluding, or changing the order of transactions in a block on the blockchain. The Ethereum blockchain has a robust ecosystem of decentralized financial platforms such as exchanges where users can trade assets. Like the traditional markets, inefficiencies occur in decentralized markets, which create opportunities for risk-free profit. In traditional markets, informed traders need to execute these trades before their competitors, thus developing HFT. On the blockchain, a similar trading paradigm has proliferated where informed traders must have their trades execute before their competitors’. However, blocks— batches of confirmed and executed transactions added to the ledger— are added to the blockchain every ~12 seconds on average. The realm of MEV (essentially on-chain HFT) has become very complex, so for the purpose of this competition, we can assume that transaction order in a block is purely based on the fee that a transaction pays. Transactions are executed in descending fee order, meaning a transaction that pays a high transaction fee will be executed before a transaction that pays a low fee. Transactions that are yet to be included in a block are stored in the “mempool”, which is publicly visible. Pending transactions are subject to attacks, such as front running, as other traders can pay a higher or lower fee relative to a targeted transaction. As you may imagine, MEV is highly competitive and requires great engineering effort on both the financial and technical sides of things in order to run profitable trading algorithms.
Competition Setup
Manifold, the host of the competition, set up a replica blockchain that operates the same way as Ethereum. On this blockchain existed three tokens: WETH, WBTC, and MANI; three liquidity pools (markets): WETH/WBTC, WETH/MANI, and WBTC/MANI; and two technical/utility smart contracts: Router and Multicall. Participants were given connection details to an Ethereum node, to which HTTP requests and WebSocket messages can be sent. This is the full extent of information that was provided to participants. Part of the challenge was for participants to figure out where the profit opportunities lie.
Our Work
Once given the connection details to the node, we wrote up a script to start monitoring activity on the blockchain. Our tech stack was the ethers.js library in Node.js and TypeScript.
Once establishing a WebSocket connection to the node, we quickly noticed a constant stream of transactions. Upon closer inspection, these transactions were a mix of transfers between the bots (simulated traders) and trades on the markets. These trades that these bots sent were random noise trades, and these noise trades created the inefficiencies that we were to correct and profit from.
The next task was to examine the smart contracts that we would be interacting with. We used an EVM bytecode compiler to inspect the given smart contracts. The functions in the Router contract matched up with the Uniswap V2 Router contract, so we were determined that the DEX system we were dealing with was Uniswap V2. Decompiling the liquidity pool contracts and finding the Factory contract further confirmed this.
After an examination of the given contracts (and the one Factory contract we found from on-chain analysis), we took a look at the pairs. The astute trader should quickly realize that this presents an opportunity for triangular arbitrage, and that is exactly what we realized. When simulated trades execute, the prices are often left out of line, which is an inefficiency that can be corrected with arbitrage. Upon further assessment of the blockchain, we found that this DEX activity is the only activity where MEV could be found, so the goal of this competition was to create a bot that could extract as much value as possible from these arbitrage opportunities.
As this is a competition, we wanted to see how our competitors are doing. We set up a monitor that would alert us whenever a new smart contract is deployed— a sign that a competitor is ready to execute trades on-chain.
After this point, we had both gotten too busy with other obligations that we had to take a break from making progress on the competition. Unfortunately during this time, many contracts had been deployed, meaning our competitors were working hard on their bots, updating their code and perfecting their trade execution.
On the last weekend before the end of the competition, we found some time to try to get a bot going. We first figured out the algorithm for deciding what route to take through the trading pairs to come out with a profit. We first decided to take the “product of rates”:
$$ P=\frac{MANI}{WETH}\frac{WBTC}{MANI}\frac{WETH}{WBTC} $$
If the value of $P$ is not equal to 1, then there is an arbitrage. Because ETH is the native currency of the chain, we wanted to be able to put in ETH (more specifically WETH) and get more ETH out. However, we found that you could not just start the arbitrage by picking an ETH pair at random. We found that if $P>1$ we had to start by swapping WETH to WBTC, and if $P<1$ we had to start by swapping WETH to MANI.
Now that we had figured out the algorithm for “routing” through the pairs, we decided it would be a good idea to actually watch what our competitors are doing in real time to see how they are executing their trades and if there is any way to beat them. Unfortunately, we were blown away by what we were seeing. After the submission of each “noise trade” (simulated trade), a backrunning arbitrage trade was instantaneously submitted. There seemed to be one bot that seemed to be winning the latency race, 0x3812. There was another bot that seemed to win occasionally, 0xb4F8. However, 0xb4F8’s behavior was a bit strange as it would often not emit any event logs. After the competition, we found out from the bot’s developer that this was due to the bot’s smart contract canceling the arbitrage if the transaction was too slow (which it often was), thus not performing any trade and not emitting any events. Bot 0x3812 seemed to have super low latency to the private chain node as its backrunning transaction would show up at the same moment that its corresponding noise trade came in, so we determined that we had no edge and could not compete against this bot.
Conclusion