Generalized Ethereum Frontrunners, an Implementation and a Cheat
A Holiday Story About the "Dry Frontrunners" of ETH Against PNK Warrior Lemiscate (Marc Zeller), and the Noble Attempt of Clesaege (Clement Lesaege) to Avenge Him.
Crypto never stops and neither do we. On my way to spend new year’s eve in the Swiss alps, I was pinged on Slack with something quite interesting that was happening with Kleros’ doges on trial dapp. If you are not familiar with it, this awesome explainer by Stuart will help you catch up. Lemiscate, aka Marc Zeller, Kleros community hero and doge connoisseur, was penalizing inactive jurors, more on that later, and noticed that his transactions were getting frontrunned in some sort of distinguishable pattern. He started to dive deep into what was happening and made us learn a few things along the way.
The Penalize Inactive Jurors Action Callback
In Ethereum, smart contracts can’t execute themselves and there are certain actions like penalizing inactive jurors in Kleros, that no party really has an incentive to execute. There are many ways to get around this. We chose to give callers a small reward in ETH, similar to how when you help Crypto Kitties kitties give birth. This is something I’ve heard people refer to as an “action callback”, and is very common across Ethereum. Some of these action callbacks require you to spend some time computing parameters like the addresses of the jurors that are inactive and should be penalized, or the kitties that are ready to give birth. This time/computation can be seen as the cognitive cost you spend to gain the reward of the call.
The Frontrunning
When Marc was penalizing jurors, he noticed that a lot his transactions were getting reverted. A quick check on Etherscan confirmed his suspicions that he was getting frontrunned. Someone had been copying his transactions and their parameters, and upping the gas to win the reward before him. By doing this, they avoid the work of computing the right parameters and/or writing code that does it for them.
The Implications
This doesn’t really affect Kleros. In fact, gas wars in action callbacks will just make the action get executed faster which is a good thing. This also isn’t really a problem if the action callback requires no parameters, but because this one does, if the person who computed them does not win, he/she might feel cheated. We can assume that over time there will be some sort of equilibrium between frontrunners and original callers, because if frontrunners completely decentivize original callers from participating, they’ll have nothing to frontrun. This is a nice parallel to the challenger’s dilemma in law enforcement. In any case, just by coincidence, the new version of Kleros will have a different way of penalizing inactive jurors that will not contribute to this strange side market.
The Dryrunning, a Hint at the Implementation
Marc started to play around a bit with different transactions. He tried tweaking gas prices, seeing if the frontrunner still copied transactions when the amount spent on gas was higher than the reward. He also tried to purposely supply invalid parameters to see if the frontrunner copied those. After a day of testing, we noticed that transactions would only be copied if they would still reap profits, even after upping the gas price. What was happening was pretty obvious at this point, the frontrunner was dryrunning the copied transactions in a local fork and then only sending them to the network if it was profitable to do so. Implementing this is surprisingly simple. Here is some code:
Disclaimer: This was crafted from the Swiss train system and a bar circa new years indulgence. I have not even ran it yet. (You should have seen the bar man’s face when I pulled out my laptop.)
These “dry frontrunners” can be extremely profitable. For example, there are around 37K crypto kitties and giving birth to one pays around $3, that’s $111K just for one action in one dapp.
The Trap
As soon as we figured out how the frontrunner operated, Clement came up with an idea to take advantage of it. If you make an action callback that offers a reward in certain blocks only, say every 10 blocks, there is a probability that frontrunners will see it as profitable and copy it, but the actual transaction gets mined into a later block where it is no longer profitable. You can’t get them to send ETH, so to take advantage of this the best you can do is make the function mint gas tokens, a novel ERC20 that takes advantage of the storage clearing rewards to tokenize gas. Here is some more code, and the view I had from the hotel room:
The Conclusion
All in all, we had a pretty fun investigation into this ingenious approach to frontrunning, how you might implement it, and how you might cheat it. We also learned a bit more about some really interesting research being done by the creators of gas tokens, The Initiative for Cryptocurrencies & Contracts. The surface area of programmable money never ceases to amaze me, this time we created a market as a side effect of an implementation detail of a prototype. Let us know what you think of this and if you have any other ideas on how to implement or cheat these frontrunners. Happy NEwTH Year!
Join Kleros!
Join the community chat on Telegram.