Editor's Note: This article comes fromBabbitt Information (ID: bitcoin8btc)Editor's Note: This article comes from
, by Dan Robinson and Georgios Konstantopoulos, translated by Free and Easy, published with permission.
challenge
This is a scary and true story.
secondary title
challenge
Like any normal person, I spend a lot of time lurking in the Uniswap Discord support channel (disclosure: Uniswap is a Paradigm portfolio company).On Wednesday afternoon, someone asked if it was possible to recover Uniswap liquidity tokens that were accidentally sent to the pairing contract.My initial thought was that the tokens would be locked forever, but late that night it dawned on me that if the tokens were still there, anyone could go and recover them.
When anyone calls the burn function on the Uniswap core contract, the contract measures its own liquidity token balance and burns it, providing the withdrawn tokens to the address specified by the caller. This is a core part of Uniswap v2's intended behavior (the basic mechanics are in
Uniswap v2 white paper
described in Section 3.2 of the ).
I found the contract, and the liquidity tokens are still there, and they're worth about $12,000.
I can put on my white hat and try to help the owner get back his tokens. It's very simple. I just need to call the pool's burn function and pass it my own address.
dark forest
It's just... I know it's not easy.
secondary titleDark Forestdark forest
It’s no secret that the Ethereum blockchain is a highly hostile environment. If a smart contract can be exploited for profit, it will eventually be exploited. The frequent occurrence of hacks shows that some very smart people spend a lot of time checking for loopholes in contracts. But this unforgiving environment pales in comparison to the Mempool, a collection of pending, unconfirmed transactions. If the blockchain itself is a battlefield, the mempool is something even worse: a dark forest.Flash Boys 2.0The Dark Forest, my favorite science fiction novel, introduces the concept of a "dark forest", an environment where detection means the death of certain advanced predators. In this environment, publicly identifying someone's location is as good as destroying them outright. (This concept is also on the Ethereum testnet
The source of inspiration for the game. )
In Ethereum Mempool, these top predators would take the form of "arbitrage bots". Arbitrage bots monitor pending trades and try to exploit them to create profitable opportunities. No white hat knows more about these bots than Phil Daian, who co-authored with his colleagues "
Phil once told me about a cosmic horror he called a "generalized snap-runner." Arbitrage bots typically look for specific types of trades in the Mempool (such as DEX trades or oracle updates) and try to front-run trades according to a predetermined algorithm. Generic frontrunners look for any transactions that make frontrunners profitable by copying and replacing addresses with their own.
That's why this rescue operation won't be easy. Anyone can call the burn function, and if I submit a transaction that calls the burn function, it's like a blinking "free money" sign pointing directly to this profitable opportunity. If these monsters are really in the mempool, they will see, copy and then mutate, and preempt my transaction before it is accepted.
Note that this environment is more brutal than the state of the Ethereum blockchain itself. These free funds have been sitting on the blockchain for about 8 hours, undiscovered, waiting to be withdrawn from the pool by anyone calling the burn function. But any attempt to pick it up was immediately thwarted during the flight.
secondary title
rescue operation
In order to withdraw funds without notifying the bot, I needed to obfuscate the transaction so the bot couldn't detect its call to the Uniswap pair, which would involve writing and deploying a custom contract. Although I am a professional DeFi thought leader, I have never deployed a contract on Ethereum before.
I needed help and it was past midnight. Fortunately, some of the best smart contract engineers I know live in European time zones. My colleague Georgios Konstantopoulos at Paradigm agreed to help deploy the contract and submit the transaction. Alberto Cuesta Cañada, lead engineer at Yield, another of our portfolio companies, voluntarily executed the contract.
Deploy a Getter contract that, when called by the owner, will only issue a burn call when activated, otherwise it will resume;
Deploy a Setter contract that will activate the Getter contract when called by the owner;
image description
Figure: Code of our custom smart contract
If the attacker only tries to execute a get transaction, it will recover without calling the set transaction. We want our transaction to be included in the block before the attacker executes the two transactions in sequence.
image description
Figure: Our rescue script
And this became a fatal mistake!
Our get transaction is indeed included, but there is a UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED error, which means that the liquidity token is gone. The result is that within seconds of our get transaction entering the mempool, someone executes the call and sweeps away the funds.
Monsters devour us.
secondary title
lesson
Lesson 1: Monsters are real! Although intellectually, we know that these front-running bots are prevalent, there is a good chance you are underestimating them until you actually see them in action.
We took a chance and made rescue an internal call through the authorization contract, which we thought would protect us, but it didn't.
If you find yourself in this situation, we recommend contacting Scott Bigelow, a security researcher who has been working on this topic, and he has a better prototype implementation of obfuscation.
Lesson 2: Don't be hasty We should stick to our original plan even when time is tight. If we spend more time on the script, tweak the contract (maybe change the Getter contract to do nothing instead of resuming the call before activation), or even sync our own nodes to avoid using Infura, we might be able to convert Two transactions are put into the same block. Lesson 3: Don't rely on generic infrastructure The weirder things you make, the harder it will be for you to get past existing infrastructure like Infura. In our case, we were trying to submit a transaction that looked like it would fail based on the current state of the blockchain, and Infura had reasonable safeguards in place for this. Using our own nodes avoids this problem.
Or, if you happen to know a big miner (we don't), you can have them include the transaction you're committing directly in a block, skipping the mempool and monsters entirely.
Lesson 4: The future will only get scarier
This is just one example of a front-running event that has happened to us, and similar things happen many times a day. Today, front-running traders are just bots, and tomorrow, they may be miners.
Today, miners are not taking these opportunities and leaving the money where it is, but there is no guarantee that they will reorder and submit their own transactions in the future to serve their own interests. Worse, they may reconstruct blocks mined by other miners in an attempt to steal MEV they did not claim, leading to blockchain instability.
