Baiting MEV Bots: UniV2 Token Trapper
14 min read
So many MEV bots take money from people but why don't people take money from them? I always thought about this when I was in my web3 cybersec assembly arc. I got quite fascinated with reverse engineering them and the contracts they interected with and realised there are some interesting things you can do with the uniswap code, since it has a few assumptions with the tokens you provide to create the pairs. Although not very practical it's definitely an intereting thought experiment that can provoke some further creativity!
Disclaimer
The content and code presented in this article is theoretical and intended solely for educational purposes. The information provided aims to enhance your understanding of blockchain technology and its potential applications and . However, the use of this information, including any associated code, is entirely at your own risk. DeGatchi does not endorse, encourage, or promote any illegal, unethical, or malicious activities. The responsibility for any actions taken based on this material lies solely with the user. DeGatchi shall not be held liable for any damages, losses, or consequences arising from the use or misuse of the information provided herein. Always exercise caution, conduct thorough research, and adhere to legal and ethical standards when engaging with blockchain technologies.
Background
Around a year ago I was developing an exploit generation tool to generate custom obfuscated bytecode when chaining functions together to create an exploit. During this time I thought “Wait, what if I iteratively experiment with contracts and tx contexts to reverse engineer the algorithms of MEV bots”. This was quite an interesting idea, but I don’t think it has happened yet. The idea was simple: look at the most active bots online, see what their scope was for executing a tx, make slightly altered contexts of the ones they were executing in to see the bounds of their algorithms. I did some experiments with [redacted] where we made a contract that forced 3 generalised frontrunners to continuously frontrun each other for 10 iterations.
I thought “Basically everyone is targeting uni pools and the only baiting game is toxic tokens in uni tide pools. The only problem they have is obfuscating their tactics and making it believable”
The Problem
The problem with any bait is that MEV bots run a transaction simulation to see whether they lost money or not using the API call debug_traceCall
which spits out the logs of any events from the simulated transaction. This is a big problem because the operator will be able to decide what action to take based on, the majority of the time, whether they received the correct tokens in the logs relative to their math calculations. And so, the main objective would be to say “Yes squire, you have received your tokens”. But theres a caveat! They’ll check their balances too at the end of the transaction as a safeguard!
“Wat do now?!”
The majority of people tend to build a bot to rug using an automated system to backrun the final buyer after x
threshold of supply has been bought or once t
time has passed. But we don’t want to rely on backrunning and monitoring infrastructure because ya Boi has no monies for AWS. So we need some automatic state transition to wreck the operators. Now there’s an easy assumption to be made: not many people can reverse engineer contracts automatically, let alone custom bytecode. This is perfect for us because we can write a custom contract that has components that aren’t necessarily easy to detect when using something like the debug_traceCall
but would instead need a custom decoder ;)
Laughs in evil
Conditional ERC20 Transfer
Since uniswap pools are nothing but references to 2 underlying tokens we have complete autonomy of our custom ERC20. So let’s look at the uniswap pool contract that the factory contract generates each time a pair is created to find the swap function that everyone uses blindly to buy tokens.
So knowing that the contract prays to have our token sent to the user when swapping using _safeTransfer
our toxic token with
Then this is where we should customise our functionality to do some memeing.
There is one problem with their implementation of that with either burn
, mint
or swap
the _safeTransfer
action comes either first with swap
or last with burn
. So there isn’t a simple standard to implement to check in a conditional. However, there is a solution: record the reserves in our internal state after every swap action. This allows us to always know the reserves beforehand to actually be able to make calculated execution
But again, theres a caveat!
Token1 Requirement
In the swap
function it always transfers token1
last. Interesting, keep this in mind…
And in burn
the same thing…
The mint
function however assumes there is another abstraction contract that transfer the tokens beforehand to mint instead of using transferFrom
This may be problematic but it’s fine for now. This is a thought experiment after all (cop out, ik don’t worry lol).
So lets work with what we got so far. We know that token1
transfer is the final step before they reference the balances of both tokens to then do their calculations and updates. This is important because the WETH will be transferred to the contract or taken our before it reaches our token transfer so we can call the balances of the pair to see the correct token states to dictate our conditional execution. So its clear that we need to make our token contract address be token1
!
How do we do this? First we need to look at the factory contract to understand how they assign the position. So lets look at createPair
from the factory contract (that creates all the uniswap pools/pairs).
Perfect, we found the logic that determines it
Lets plug in the known tokenA
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
and say
This is essentially saying if our input token is larger than the hexadecimal of the WETH address then our token will be assigned token1
in that pool.
“But how can we do this?”
Deterministic Token Address
Using the magic of create2
, woah so spooky!
This allows us to create deterministic addresses, although you may have to brute force a few times to find it.
You can use a Rust implementation of this so you don’t have to brute force onchain
Perfect, now we have an address that’ll always be token1
and we can continue with out memeing.
Implementation
So whenever someone executes a burn
or swap
tx we will always be up to date knowing the reserves after the first tx (which we would probably execute with a mini swap tx). The only caveat now (ffs so many) is that if someone just sends dust it would fuck up our reserve tracking and we would need another swap or burn to happen to readjust.
Anyway, all we have to do now is make 2 conditions to determine what to do with the reserves information. If both reserves decrease then they are clearly burning liquidity so we can add a restriction to see if the reserves decrease after
relative to before
we can throw an error based on whether we’ve hit our threshold liquidity. If both reserves increase it’s clearly adding liquidity. And if one adjusts up and the other down it’s a swapidy swap swap.
So, we can implement monitoring and the corresponding reaction to seeing each condition. I’ll add a tx counter and a time restriction condition too to display the common gimmicks normie uniswap pair creators do to meme on bots. Sometimes they don’t even have any of this and just use private txs to meme and at that point you’re pretty much rekt but this is a cool display of what can be done without bullshit privatised transactions.
Ta’da! Now we’ve theoretically created a sinkhole :) How wonderful. So that was one of my thought experiments back in the day. I cbf taking it out for a joyride because I’m not too interested in fucking around and finding out in cryptoland anymore, im getting old. But I wanted to showcase my thought process at the time and maybe inspire others to do experiment with cool logic stuff similar to this.
There are some other interesting things to mess around with like baiting generalised frontrunners to one-up each other for iterations to drain their ETH or try and get them to auto approve a token to gain some monies — idk how specifically you’d do it but I think transaction baiting is definitely the best way to meme with them. Contract stuff requires a bit too much dependence of making the tx.origin initiate but they’re always going through their own contracts soooo, rekt.
Final
Well, I hoped you like this little thought experiment. I haven’t read anything remotely similar to this apart from the very simple Salmonella contract that takes a quick fee from sandwichers https://github.com/Defi-Cartel/salmonella. But if the sandwichers were checking their balances in their contracts and even with a trace it wouldn’t work. This contract doesn’t work with sandwichers because you trap their swaps and LP tokens conditionally so their backrun tx from the sandwich would fail since the frontrun buy gets trapped. But, im sure some smarty pants could figure something out to make it work. Im simply an old man now and just write articles of my ideas because im too lazy to experiment myself. All-in-all the examples I show should help you understand flaws in systems and help you look out for any malicious intent out there :)
Having said that glhf, anon-kun!
Share this Article
Recent Articles
-
Generating Custom Assembly Smart Contracts
2 years ago I wrote a component that allowed me to generate any custom assembly smart contract on the fly to automatically create exploits without needing to do any manual work. I had a montiroing system that would provide the inputs and the bytecode generator would chug along and spit out an executable program that I could deploy and call on with a bundle of transactions. In this article I'll share the core of that codebase to get you up to speed! Buckle up, anon. There isn't any other article like this revealing these trade secrets!
-
Starting Malware Development
After spending years in MEV and web3 infosec DeGatchi explains his reasoning behind switching to malware development. Although seemingly less money and entering an alreaedy mature field, it's clearly the most powerful long term decision to be made -- especially when combining malware development with custom evolutionary AI algorithms.
-
Understanding Gradient Descent
Machine Learning (ML) and Artificial Intelligence (AI) relies heavily on this very intuitive differentiation-based algorithm called gradient descent. It gets us closer to our desired minima or maxima by starting with a value and adjusting that value based on the change of our gradient. In this article you'll learn to understand what is gradient descent and all the component apart of it. And then explore a few modifications of it from simple to advanced to solidify your understanding!