Hot on the heels of the previous bot project, this lesson will cover how to implement the recently-developed bundle executor to implement atomic functionality for the gOHM-wsOHM swapping.
Why Bother?
I take an iterative approach to my bot building. When I’m testing a proof of concept, I’ll start with code that gives me very narrow utility. It often relies on assumptions regarding the nature of the MEV strategy.
Using the Snowsight CRA-WAVAX bot as an example, I began with a very narrow scope: connect to Snowsight, keep my account paid, watch the CRA-WAVAX pair, then execute any profitable arbs that arose. It had a lot of specific items baked in: a handful of token addresses, a narrow selection of compatible mempool transaction types, a simple mempool prediction strategy, and a fixed set of hand-coded arb paths. Good enough for learning purposes, but it was not robust enough to handle mempool transactions of different token types and lengths.
I later extended the functionality to predict the effect of mempool transactions, which added several layers of complexity. At the end, I had a more generic bot that could duplicate the behavior of the initial CRA-WAVAX bot, but with the ability to do any two-token pair.
I have since extended this another time to support multi-token swaps and simulation of more than one future pool state (I will post about that right after this).
This takes a lot of effort, extensive bug testing, and revisiting many old assumptions. The result is a bot that grows more generic and extensible with each new feature.
The bundle executor takes a similar approach on the smart contract side. Instead of deploying single-use smart contracts, I can deploy a generic executor contract. Then I need to wrap my head around taking the familiar uniswapV2-style functions and translating them into generic payloads.
The end goal is a smart contract that does whatever I want in a generic way, and a bot that takes my human-readable strategies, convert them into generic payloads, then feeds them to my smart contract.
Strategy
One advantage of moving to a generic payload strategy: I can choose to use either the router or the pair contract.
The traditional bot uses the router because it has to. But not us! Using the pair contract directly provides some gas savings, and it’s more applicable to our grand atomic arbitrage strategy.
Here are the code sections we need to operate this bot:
Monitor the gOHM-wsOHM pair (already done)
Determine when to execute a swap of either token, or migrate some quantity (already done)
Generate a payload for a direct token swap at the contract
Generate a payload for a token migration
Submit the payloads to the bundle executor
The execution logic is implemented already, so most of our work is figuring out how to build payloads for familiar functions.
Generating Payloads with Brownie
Let’s fire up a Brownie console and load the Olympus contract for a simple example: