Front-running on AMMs is a big (and expensive) problem. It causes lost money during large swaps and also raises gas prices unnecessarily due to bidding wars between bots.
I propose a simple method to mitigate AMM front-running by applying zero-knowledge proofs (ZKPs) for updating the swap ratio.
Abstract
Each swap transaction on an AMM can โhideโ the updated pool ratio (and therefore resulting price) by means of a SNARK puzzle, thereby making price-prediction of a transaction in the mempool expensive and uncertain, significantly deterring front-running.
Scenario
Letโs assume that we have a Uniswap-like pool for the ETH/BTC pair. The mechanism is pretty simple.
- A trader executes a swap and updates the pool ratio but hides the details in a SNARK that proves the AMM mathematics remain consistent.
- The trade transaction contains a hint that makes it possible to guess the ratio by
n
times of hash computation (where n
should not be too large to prevent falling into limbo). So anyone can compute the updated pool ratio by solving the SNARK puzzle after n
computations.
- Front-runners will fail to predict the price change easily and will be deterred from making a sandwich attack due to uncertainty.
And here we can add some tokenomics to run the system more efficiently.
- The trader can decide the SNARK puzzle difficulty
n
in the swap transaction.
- The trader should stake
x
amount of tokens, where x
should be proportional to n
.
- After the swap, one of two things can happen:
a. If the trader reveals within 10 minutes, the staked tokens go back to the trader.
b. If the trader does not reveal within 10 minutes, anyone can withdraw the staked tokens by submitting the SNARK puzzle answer.
Difficulty Fee
Since increasing puzzle difficulty (n
) protects the trader while imposing a potential cost on others, we can also implement a โdifficulty feeโ, taken from the staked tokens x
if n
is beyond a certain threshold.
Implementation
With this idea, I designed an anti-front-running AMM protocol โSnarkswapโ based on Uniswap math. You can see the detail protocol design here, and the implementation here.
I need your feedback
Please let me know what you think of this idea, thank you!
4 Likes
Funny seeing two threads at the top trying to tackle the same problem. Hereโs the other thread Iโm referring to: A simple strategy for Uniswap? - #7 by Mister-Meeseeks
I like this approach because itโs a very elegant and novel, since not many people are looking at using ZKPs for this purpose. However, I think there are a few economic issues that still need to be figured out. And also, I am wondering if you have an estimate for how much gas this would take?
Here is the gas reporter result. I expect swapInTheDark
can be reduced roughly to 350K by packing up the input signals. I expect users may use swap
(exactly same as Uniswapโs) in general and use swapInTheDark
only sometimes.
ยท---------------------------------------|---------------------------|----------------|----------------------------ยท
| Solc version: 0.8.1 ยท Optimizer enabled: true ยท Runs: 999999 ยท Block limit: 9500000 gas โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| Methods โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| Contract ยท Method ยท Min ยท Max ยท Avg ยท # calls ยท eur (avg) โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| ERC20Tester ยท approve ยท 44513 ยท 44525 ยท 44525 ยท 86 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| ERC20Tester ยท transfer ยท 36126 ยท 51138 ยท 48831 ยท 111 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| NotePool ยท deposit ยท 186830 ยท 186854 ยท 186850 ยท 45 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| NotePool ยท initialize ยท 65501 ยท 65525 ยท 65522 ยท 55 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| NotePool ยท withdraw ยท 353517 ยท 368577 ยท 358130 ยท 23 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| Sandglass ยท initialize ยท 149448 ยท 149472 ยท 149469 ยท 55 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapFactory ยท createPair ยท 4034723 ยท 4034745 ยท 4034737 ยท 55 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapFactory ยท setFeeTo ยท - ยท - ยท 43458 ยท 2 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapFactory ยท setFeeToSetter ยท - ยท - ยท 28437 ยท 1 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท burn ยท 101526 ยท 171737 ยท 132802 ยท 8 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท mint ยท 150345 ยท 173647 ยท 151482 ยท 51 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท swap ยท 77320 ยท 107344 ยท 103564 ยท 24 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท swapInTheDark ยท 598040 ยท 598136 ยท 598078 ยท 35 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท sync ยท 54211 ยท 84211 ยท 74211 ยท 3 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท transfer ยท 36227 ยท 36239 ยท 36235 ยท 3 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
| SnarkswapPair ยท undarken ยท 182177 ยท 182249 ยท 182201 ยท 14 ยท - โ
ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
1 Like
So itโs basically 598078 gas to swapInTheDark
and then 182201 to undarken
(or reveal
), right?
Thatโs 780k gas on average, which is a lot. But I guess this would mostly be used for larger amounts anyway.
1 Like
An interesting idea. But the transaction needs to not just hide the updated pools and ratios, but also the transaction size itself. It may be possible when applied to fully private versions of the cryptocurrencies/tokens.
The primitive you are looking for is actually not a hash, but a verifiable delay function or โVDFโ. The hash/proof of work puzzle you suggest can be easily parallelized and thus a frontrunner with large resources can still frontrun. Since you want the puzzle to be solvable, it isnโt really possible to take this out of reach of well resourced attackers.
A VDF however has the property that it canโt be parallelized and takes a minimum amount of time to be solved. If the transaction thus gets included before that time has expired, you can be sure that it canโt be frontrun.
1 Like
Thatโs correct. Itโs expected to be useful for large amount swap & maybe on L2.
Firs of all thank you so much for your valuable feedback.
An interesting idea. But the transaction needs to not just hide the updated pools and ratios, but also the transaction size itself. It may be possible when applied to fully private versions of the cryptocurrencies/tokens.
Private pool will be perfect for this. However, hiding the trade is a sell or a buy can be enough to confuse the front-runner.
The primitive you are looking for is actually not a hash, but a verifiable delay function or โVDFโ. The hash/proof of work puzzle you suggest can be easily parallelized and thus a frontrunner with large resources can still frontrun. Since you want the puzzle to be solvable, it isnโt really possible to take this out of reach of well resourced attackers.
For example if the seed of the VDF is a commitment on chain, the front runner can prepare theft transactions behind the mempool everytime. And if a profitable swap is catched on the mempool then they will just release it or abandon. So this cannot protect the trade from front-running.
To be specific,
- Commitment submitted on chain
- A trader Tom creates a swap tx and starts to compute the VDF. Simultaneously, a front-runner Frank creates a sell tx and a buy tx together and starts to compute VDFs for each.
- Tom sends the tx with his VDF to the mempool and Frank catches it and sends the prepared transaction.
By the way, in this snarkswap protocol, undarkening also can be front-run to steal the staking reward after 10 minutes. In this case, I think VDF will be definitely helpful.
proof of work puzzle you suggest can be easily parallelized and thus a frontrunner with large resources can still frontrun
If any front-runner appears, I expect people will increase the difficulty and use higher gas price to be included in the block in a few seconds. But to avoid the difficulty imposes too much cost on other users, governance can adjust the fee structure for it.
Itโs a clever idea, but completely impractical unless Iโm missing something. From skimming the implementation it seems that any individual party can unilaterally shut down trading for 10 minutes, just by โdarkeningโ the pair.
Whatโs to stop someone from DoS-ing everyoneโs liquidity by repeatedly darkening the contract? Why would anybody prefer to add liquidity to a venue where it can be arbitrarily locked up? (Remember front running is not a downside for liquidity providers.) Even without an intentional DoS, a highly active pair like ETH/USDC would pretty much be locked up 24/7.
Predatory bots would wind up abusing this mechanism as a free option. Wait until a volatile period, then buy in the dark. Wait ten minutes. If the price moved in your favor, buy the token at the earlier locked in price. If the price moved against you, just abandon the SNARK.
I think sooner or later someone will come up with a solution to front-running. Or at least a series of improvements that makes it so minor of an issue that hardly anyone cares. But any sort of protocol that relies on shutting down, or even slowing down trading will never catch on in the broader market.
However, hiding the trade is a sell or a buy can be enough to confuse the front-runner.
Probably not for the majority cases. Practically speaking front runners are only interested in front-running buys, since thereโs no easy way to short sell and they donโt want to carry inventory. 95%+ of buys are for more a buyer whoโs currently holding zero tokens. So if I see that Alice sent a transaction for one million tokens, but Iโm not sure if itโs a buy or a sell, I can guess with pretty high accuracy just by checking whether sheโs currently holding a million or more tokens right now.
Thanks for pointing out good points.
-
Trade frequency.
Except ETH/USDT pool, the trade frequency is pretty low for almost pools. ETH/WBTC is the top 5 pool and it took 1.8 minutes per tx during last 15 hours. In addition, the main target of this protocol is a small pool that has a high slippage rate thus many chances exist for front-runners. ETH/RARI Uniswap pair is a good example which trade volume is top 22 today. Its trade frequency was 2.3 minutes per tx during last 20 hours and 13 front-running drained up to 5%. It means that most transactions are safe to use swap
(that does not freeze the pool) and only 13 txs needed to use the swapInTheDark
feature. Therefore, pools will be remained undarkened in general.
-
DoS
Before starting to talk about DoS, let me clarify a little bit about darkening. Darkening does not always lock the pool for 10 minutes. The 10 minutes is just a prioritized period for the darkener of reveal. If anyone reveals the resulting ratio in a few minutes, then it unlocks the pool immediately. But as you pointed out, DoS is still possible. So we can use a fee model just like fee = darkenedPeriod * Difficulty
. Then, the darkener will try to reveal the trade as soon as possible to save the fee, and it may not affect the average trade frequency.
Letโs see the case, You can see the latest sandwich attacks here, and front-runners drained about 2 ETH using 4 txs in this case.
Hereโs the calculation of the expense. Letโs assume that
First, to freeze the pool for an hour, the attacker should pay
- At least 6 darkening tx = 0.84 ETH.
- At least 6 undarkening tx = 0.48 ETH.
- 1 hour of darkening fee = 10.8 ETH.
- ~= 12.1 ETH
In this case, the DoS attacker should pay about 12 ETH to lock the pool for an hour. The attacker will have an incentive when there confidently exist big arbitrage trade opportunities between other exchanges. But it looks pretty unprofitable in ETH/RARIโs case. Otherwise, the victim of this case could save 2 ETH by paying 0.28 ETH for the fee. I think the market will find the equilibrium point between the difficulty fee and the front-running resistance.
By the way, it is a fact that arbitrage opportunities increase the incentive for DoS. Therefore, it will be good to support newly launched tokens, which have low liquidity and high slippage so suffering from front-runnings, to put their main liquidity pool on this protocol like SushiSwapโs Onsen program. Also, we can give liquidity mining rewards like UNI or Sushi since the darkening can be inconvenient for the liquidity providers, although the pool will be remained undarkened as only few tx needs darkening and the difficulty fee accelerates the reveailng.
-
Buy/Sell guess
I can guess with pretty high accuracy just by checking whether sheโs currently holding a million or more tokens right now.
It is a really important point that you are just guessing. I can buy more RARI while holding a bunch of RARI. Or I can sell my whole RARI. How will you do? Only holding a small amount of token can confuse you.
1 Like
1. 10 minutes delay
Interesting, so anyone can undarken
, even if less than 10 minutes? But that person wonโt get the staked amount, right? What will happen to the staked amount?
2. Public tx Info on โdarkโ txs
What is the actual information that the frontrunner gets when a swap is made? I was under the impression that the amounts could be hidden as well (without use of a completely private pool).
3. Frontrun losses and volume
Just curious, but do you have any data about how often large transactions are frontrun? I think it gives us a better idea of the potential size and usage of the proposed AMM.
Interesting, so anyone can undarken
, even if less than 10 minutes? But that person wonโt get the staked amount, right? What will happen to the staked amount?
Right, it goes back to the original staker if itโs revealed within 10 minutes. Otherwise the staked amount goes to the revealer. Please note that it will return the remaining amount after charging the fee. (I need an idea about how to call this fee .) Anyway the 10 minutes of prioritized period is to protect the staker. Itโll be good for the protocol to make pools undarkened as soon as possible. But if thereโs no protection period for the staker, people will front-run the revealing tx to steal the staked amount.
What is the actual information that the frontrunner gets when a swap is made
-
Hashes of 2 input notes and 2 output notes.
Whole information of a note which is just deposited is public. Iโll call this kind of note as a โdeposit noteโ. Except the deposit notes, front-runner cannot know the exact amount of the note and its token address but can guess its minimum amount or possible token addresses. To guess the details, the front-runner may have to label all notes in own database system.
-
A mask
, hReserves
, and hRatio
.
The front runner will get hReserves
. hReserves
are manipulated new resulting reserve values(a.k.a. the swap details) by randomly manipulating the bits which is masked by the given mask
. And for the SNARK puzzle, the darkener gives hRatio
that is a hash of the new reserves and a salt. You can see more details about them in the spec repo.
About hRatio
: GitHub - 0xBeaver/snarkswap-specification
About hReserves
& mask
: GitHub - 0xBeaver/snarkswap-specification
Just curious, but do you have any data about how often large transactions are frontrun?
I am sorry that I donโt have the exact data, but it seems that the front-runners are draining ETH usually in small pools and targeting swaps which amount is over 10 ETH.
1 Like
Interesting idea, i donโt know zksnark very well. What the zero knowledge proof is used for? I mean is it used to check:
Swap parameters of client are the same to that on chain while transaction execute on chain ?