Why calculating Uniswapv3 prices is so hard for MEV and how to fix it

Tim Truyens
Coinmonks
4 min read3 days ago

--

UniswapV3 has brought a lot of positive changes for traders, most prominent are the ability to concentrate liquidity and variable trading fees. For MEV searchers however, it has posed a challenge to overcome.

You see, most MEV developers are used to the pricing mechanism of UniswapV2. Here, one would simply fetch the reserves of a pair and calculate the price off-chain. Being able to fetch reserves has a lot of advantages over simply fetching the price via the Router contract. For one, if you simply fetch the price, say 1 ETH = 3000 USDT, you would need to recalculate and refetch the price for every other input (2 ETH, 3 ETH, …) you would want to know. This is because the constant formula that Uniswap uses is not linear:

https://medium.com/@kinaumov/back-to-the-basics-uniswap-balancer-curve-e930c3ad9046

Because the formula is not linear in nature, one can not simply say that 2 ETH would be equal to 6000 USDT in this case. In reality, it will be a number close to 6000, but not quite. It’s these small differences that matter a lot in MEV and arbitrage.

On the other hand, if you use the reserves of a pool, you only need to fetch the reserves once (and on every update) and can simply calculate the output/price off-chain. This eliminates a lot of latency and ultimately results in a faster MEV bot 🤖. For those interested, see my other article for more tips to improve your MEV bot:

Now that we’re up-to-date as to why we want to fetch the reserves of a pool instead of simply fetching the price, let’s take a look at UniswapV3. Upon closer inspection, we’ll see that the liquidity of UniswapV3 pools is actually divided into multiple ticks:

https://www.paradigm.xyz/2021/06/uniswap-v3-the-universal-amm

This model allows for more capital efficiency on top of other benefits (such as easy integration for limit orders). Alas, for MEV developers it means that our job has become a little more difficult. Now, if we want to calculate prices using the reserves of this pool, we’ll have to fetch multiple ticks.

Although a little harder than UniswapV2, fetching reserves for V3 is not impossible. In fact, this is one of the ways that the UnsiwapV3 SDK was designed to work. One can simply fetch the ticks of a pool and use the SDK to calculate the amount of tokens you would get for a given input (https://github.com/Uniswap/sdks/blob/main/sdks/v3-sdk/src/utils/v3swap.ts#L19).

The catch here is that the SDK expects all ticks to be pre-fetched (otherwise it throws an error). For a lot of bots, this is simply too much data to fetch. Even when using a batch contract, you would still need to make many RPC calls just to fetch the ticks for a pool.

This is why I’ve made a custom fork of the SDK that allows you to fetch a subset of ticks and still work.

Patched V3 SDK Fork

The fork is more flexible and allows the dev to choose how many ticks to fetch. Note that this does however create a trade-off. If you do not fetch enough ticks (especially for large trade sizes on low-liquidity pools), the results will not be 100% accurate. Although, in most cases, a few ticks (~5) fetched around the current tick will suffice and give you 100% accurate results. For my personal bot, this is exactly the trade-off that I need and have accepted to make. It allows me to work with many pools without being hindered by latency and excessive memory usage.

Thanks for reading this far. Feel free to use the fork in case you find yourself in a similar situation. Happy MEV hunting!

--

--

Tim Truyens
Coinmonks

Believer in discipline and creating value. Interested in Blockchain technology, cyber security and low level code.