I started a small but interesting journey of building a bot for some MEV arbitrages in Ethereum. Through my project under Teal Finance on a DeFi options price aggregator, Rainbow, I explore and interact with various DeFi protocols. This is how I stumble upon 0x78e111f6, this mysterious function signature that is present in a lot of intriguing MEV transactions. This is my story of trying to uncover part of that mystery.

Function signatures

When you interact with a smart contract in Ethereum, you provide in your transaction tx the function you want to call and the parameters, if any. It tells the Virtual Machine, EVM, which part of the code should be running. This function signature or selector is encoded as follow:

import 	"github.com/ethereum/go-ethereum/crypto"

func convert(s string) []byte {
	return crypto.Keccak256([]byte(s))[:4]
}

where sis the name of the function with the parameter types but not the names. Let’s take a look at the transfer function in the ERC20 token standard:

function transfer(address to, uint256 amount)
==>transfer(address,uint256)
==>0xa9059cbb

For an explorer like Etherscan, a user or a developper, we can translate 0xa9059cbb to what it means in “English”, making understanding what is going on in the tx easier. Since Keccak/SHA3 is a cryptographic hash function, either you know the function name and parameter types, either you have to bruteforce them. Here are the main ressources to reverse those signatures:

MEV

MEV originally standed for Miner Extractable Value, but now the definition has evolved to mean Maximum Extractable Value. It emphasizes on the role block producers, being miners or validators, have when they build the blockchain history. Indeed, they decide in which order the transactions are included and as such are incentivized to choose the order that will procure them the most extra income, ontop of block rewards.

One of the oldest and famous occurences of MEV were during the ICO boom in 2017 with the project status.im. This was a very popular ICO at that time and I remember myself trying to participate while I was at work. The network got really congested and I was rushing home (of course there was a lot of traffic 😓🤣) to have a chance to make my transactions go through. We were many that lost ETH in failed transactions that day. Then we heard that F2POOL made sure their transactions were included in priority. You can read about it here (Chap.5) SoK: Transparent Dishonesty: Front-Running Attacks on Blockchain.

Nowadays there are more conversations about MEV and Flashbots did change the landscape in Ethereum (for the best 🤷‍♂️). MEV searchers spend a lot of time trying to spot those opportunities, with good or bad or who the F knows MEV, and hopefully can harvest those for a long time. But as we know, Ethereum is a Dark Forest, there is no privacy and their alpha has to be hidden in plain sight.

Obviously an MEV bot will not share its competitive advantage and provide the code source of its strategies to everyone. In subsequent articles, we’ll explore those different obfuscation methods. But for today, we can focus on what this lack of transparency means for us: there are functions whose names are unknown, even after reverse engineering the parameters. I cannot recommend enough this series of articles on a fascinating MEV bot. This is where I enter the scene. Can I reverse 0x78e111f6?

The Challenge

To tackle this question, with have the following hints.

From Solidity guide, we got:

Functions should use mixedCase. Examples: getBalance, transfer, verifyOwner, addMember, changeOwner.

This will make things more fun on Etherescan.

From the MEV bot, we have:

It also means that at least as far as we can tell, 0x78e111f6’s args are (address,bytes), which would mean that it is not named execute, since we’ve already got an execute(bytes,bytes). I did try a number of variants using Cast, like execute0, execute_, and x, but to no avail.

My plan was then to try to find:

execute@@@@@(address,bytes) ==>0x78e111f6
@ a char in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"

Note_1: I didn’t know before that I could use $ in function naming.

Note_2: 4 bytes for signatures gives you a random collision with a set of 2^16, per the Birthday paradox. You also expect Keccak to give you one hit if you go through 4 bytes = 2^32 candidates.

I set to hack this together quickly. The plan was for the cracker to run while I was doing other things on the side. So no cronjobs to start and enough logs to know what that things are working but not slowing down the brute force. The POC was quick to make because I have done something similar before. I also use Go as my go-to language(pun intended) so that I can use goroutines and go-ethereum code without having to overthink it.

Results

It took some hours before I got an answer:

0x78e111f6 :: executeFFsYo(address,bytes)

It was late in the night when I saw I had a candidate and thought it meant Execute For F**C Sake Yo but that is most likely random.

Anyway, I decided to propagate that answer before the Twitter discussion. I submitted the answer to those signature databases. But to also prove that I got an answer first, I made a verified contract on Etherscan. This means that anyone using that function now will see my bad signature. Sorry MEV Bot 0xa57.

The unforseen consequence is that you can tag a function of a competitor in a funny way. See below what @MevRefund did. Notice how Etherscan breaks the mixedCase. Hopefully this won’t escalate into spamming Etherscan but I am a bit curious about their policy if some names are, let’s say, unethical.


This was my small contribution to the MEV world. I have no plan to polish and publish that code but I will do if anyone is asking, since it could also be useful to find an address starting with 0x000.... In any case, that’s it for me.

Jean Yves Z.