While browsing CT, a post by @fifikobayashi caught my eye:
MEV out in the wild!
For someone who has only been living in the protocol and application layer, I saw this as the opportunity for me to start a side project ultilizing MEV (somehow). and get familiar with the infrastructure side of things.
Unfortunately it took me about two days before I managed to get it communicating properly with the flashbot's relayer due to a package version mismatch.
Even for someone who was quite familiar with the tooling, it took me a while before I could get it working. It was at moment that I realize a project with the most asymmetic impact would be one that democratizes this power. And so, began the quest to make flashbots more accessible.
Unfortunately, making flashbots work in the browser wasn't as simple as slapping on a frontend to the existing boilerplate repository. But to know why, we first need to understand how a gasless transaction is constructed.
A gasless transaction is actually comprised of 2 signed transactions from 2 different accounts:
Keep in mind that account 1 will have 0 ETH, whereas account 2 needs some ETH to pay the bribe.
Once both transactions have been signed(!!) by their respective private keys, it'll be submitted repeatedly to the flashbot's relayer. The transaction will only be included in a block if the ETH bribe meets certain conditions.
Another important information to understand is the ETH bribing function:
It basically checks if the a function call (
balanceOf(0x....123)) to an address (
USDC) matches a certain state (
1e10), if so, it'll transfer the amount of ETH sent along with the transaction to the miner of the block.
The bribing code above works because Ethereum is a state machine, where the order of each transaction in each block matters. What that means is that we can trustlessly construct a bribing transaction (transaction 2.) that will only be valid (and broadcasted by the participating miner) if our zero gas transaction (transaction 1.) is successful.
I wanted to make an interface where you could ultilize metamask to pay for the bribe. This is however not possible as metamask (and many other web-based wallet providers) doesn't support the crucial
You could however perform
eth_signTransaction if you had the private key. But I personally didn't liked the idea of prompting people to put in an uncompromised private key into a web browser, and was determined to get this working, somehow.
MEV-Briber is my attempt at making a browser compatible version that works with the current flashbot relayer.
To make it browser compatible, we must solve two problems:
The first problem to overcome is the inability for metamask to perform
eth_signTransaction. Is there any other way for us to verify some arbitrary signature that wallet providers support from a particular user on the contract layer?
Fortunately, ERC-2612 permit does exactly that. It allows us to verify ECDSA signatures on the contract layer, and signing via
eth_signTypedData is supported on most major wallet providers. You might have even seen it before while trying to remove liquidity from UniswapV2:
And luckily for me, openzeppelin already has a draft implementation that I could reference. I added ECDSA signature verification into the contract:
And with that, MEV-Briber can now verify:
Which when combined with our (poor man's) account abstraction, will allow us to make flashbots browser compatible.
Previously, the msg.sender and thereby transaction signer who calls
check32BytesAndSend has to have ETH in their account. However, with
eth_signTypedData msg.sender doesn't need any Eth in their account, provided the transaction signer can transfer ETH to the msg.sender, when the conditional check passes.
Surprise surprise, most ERC-20 compliant tokens already has that behavior:
transferFrom. The only downside is that the user needs to
approve the contract to spend their ERC-20 beforehand.
Therefore, instead of sending ETH to the miner via a conditional transaction, it'll be using wrapped ether, ETH that is ERC-20 compliant.
Since the (W)ETH used to bribed will be provided via a ECDSA signature, we can now use a randomly generated wallet as
msg.sender as we don't need any ETH in it. This is perfect as
eth_signTransaction can be performed as long as you have the private key.
By using ECDSA signatures and WETH, we can call
eth_signTypedData on metamask, and
eth_signTransaction on a randomly generated wallet. That way users don't have to enter their (uncompromised) private key into the browser.
The process to bribe a miner with ETH on the browser is now:
In solidity land, the
check32BytesAndSend function now looks like so:
And with that, we're able to bribe miners purely through most browser wallet providers.
This turned out to be more challenging than anticipated. Excited to dive deeper into the MEV world!
Example transaction in the wild