In-depth analysis of the mathematical principles of Uniswap V3 liquidity provision
Written by: Mellow Protocol
Compiled by: Blake
Hello everyone, let's skip the pleasantries and dive into the mathematical logic of Uniswap V3!
We will explore how liquidity provision works in Uniswap V3 and how to adjust the portfolio of two tokens to maximize your LP position while minimizing IL. There will be many formulas and numbers ahead.
Uniswap V2 Review: Trader's Perspective
Uniswap V2 is an automated market maker that allows:
- Traders to swap one asset for another;
- Liquidity providers (LPs) to provide liquidity and earn trading fees.
Each pool has two tokens: X and Y. If there are X~p~ tokens of X and Y~p~ tokens of Y in the pool (also known as pool reserves), the pool liquidity L is defined as:
The ratio of tokens in the current pool defines the current exchange price p:
If a trader wants to swap y units of Y tokens, they will deposit y tokens into the pool and receive x tokens of X. The value of x is determined by the pool using the following equation:
Here, ϕ is the pool fee. For Uni V2, its value is 0.3%.
Now, let's assume that when ϕ = 0, we look at what happens if the current price p = 1, pool reserves X~p~ = 1, Y~p~ = 1, and the trader wants to swap y = 1 unit of Y tokens.
Figure 1: Trader's Perspective on Uniswap V2
The trader will receive x = 0.5 tokens of X. The pool reserves and price will update to X~p~ = 0.5, Y~p~ = 2, p = 4.
We expected x = 1 when the current price p = 1, but the actual amount of x will incur a loss, which we call slippage (sl = 0.5):
The good news is that sl → 0 as pool liquidity L increases or the swap amount decreases, meaning for sufficiently small swap amounts, the cost of swapping at price p is lower.
Uniswap V2 Review: Liquidity Provider's Perspective
Now let's see what happens if p = 4, pool reserves X~p~ = 0.5, Y~p~ = 2, L = 1, and the liquidity provider wants to deposit x = 0.25 tokens of X and y = 1 token of Y.
Figure 2: Liquidity Provider's Perspective on Uniswap V2
In this case, the new reserves of the pool will be X~p~ = 0.75, Y~p~ = 3, and L² = X~p~·Y~p~ = 2.25, thus L = 1.5, and the liquidity provider receives ΔL = 0.5 in the form of Uni V2 lp tokens. Now, for each trade, the liquidity provider will receive ΔL/L = 1/3 share of the fees.
In this example, we intentionally used x = 0.25 and y = 1 as the liquidity provider's investment, so y / x = 4 = p.
What happens if y / x ≠ p? In this case, a portion of tokens Δx or Δy will be returned to the liquidity provider, making the remaining ratio (y - Δy) / x = p or y / (x - Δx) = p. If the liquidity provider wants to fully utilize their tokens and achieve maximum liquidity, they must first trade their tokens so that y / x = p and then deposit them into the pool.
For Uni V2, adjusting your token portfolio for maximum liquidity is quite simple. What about Uni V3? It turns out to be increasingly complex.
Uniswap V3: Single Position
In May 2021, the Uniswap team launched V3. On Uni V3, you can place liquidity in any price range [pᵃ, pᵇ]. As long as the price is within the range [pᵃ, pᵇ], you have liquidity L and earn fees. When the price goes out of range, you do not earn any fees until the price returns to the range.
Let's see how it works. First, let's consider a mining pool with only one position and a price range of [pᵃ, pᵇ] = [0.25, 4]. The current pool reserves are X~p~ = Y~p~ = 0.5, and the price is p = 1. In this case, as swaps occur and the price fluctuates, we observe the following pool behavior:
Figure 3: Uniswap V3 Single Position
Here, the green curve represents the actual token reserves used for swaps (real liquidity curve), while the red curve represents the virtual liquidity curve, simulating user swaps on Uni V2.
As long as the price is within [0.25, 4], the pool behaves exactly like a UniV2 pool with the red liquidity curve. When the price breaches the range, the virtual liquidity drops to zero, and the actual liquidity concentrates in either X or Y tokens, not used for swaps.
Uniswap V3: Multiple Positions
Now let's see what happens if there are two liquidity investments x₁, y₁ in [pᵃ₁, pᵇ₁] and x₂, y₂ in [pᵃ₂, pᵇ₂]. Each of these investments implies (as we will see in later sections) virtual liquidity L₁ and L₂.
Figure 4: Uniswap V3 Two Positions
It can be seen that when both ranges cover the price, both actual reserves are used, and the pool's virtual liquidity equals the total liquidity. When only one range covers the price, only its liquidity is used. When the price is outside both ranges, the pool liquidity is zero (or you do not earn any fees).
This gives Uni V3 a unique feature—piecewise liquidity function. As the price moves along the virtual curve, the liquidity value changes at certain price points (i.e., the boundaries of the liquidity positions) by some ΔL. You can see this jump occurring at prices pᵃ₁ and pᵇ₁ in Figure 3.
Ticks and Tick Spacing
The reality of Uniswap V3 is a bit more complicated than shown in the above figures. In true Uni V3, you cannot place liquidity in any arbitrary price range. Instead, the so-called ticks form a discrete grid within the price range. Ticks are defined by the formula (i is an integer):
For each pool, there is also the concept of tick spacing. Tick spacing is another grid above the ticks that limits the ticks at which you can place liquidity. For example, for a 0.3%-fee pool, the tick spacing is 60, so you can only place liquidity at every 60 ticks, such as 0, -60, 60, 120, -120, … The following figure shows the tick spacing ticks (orange) and the ticks (black).
Figure 5: Ticks and Tick Spacing
Because the boundaries of your liquidity price range can only be tick spacing ticks, any liquidity within a tick spacing is constant and will only change when the price crosses the tick spacing tick.
Thus, we have a piecewise liquidity function where jumps may occur at tick spacing ticks (similar to Figure 2).
Liquidity Value of Positions
Let's see how liquidity L is calculated, given initial tokens x and y, price range [pᵃ, pᵇ], and current price p.
From these equations, it can be seen that if the ratio of x and y tokens is incorrect (Lx ≠ Ly), some tokens will be returned to the liquidity provider. This is similar to the behavior we observed in Uni V2.
However, for Uni V3, it is more complex because we have a piecewise liquidity function with jumps at tick spacing ticks. In the next chapter, we will show how to place tokens on Uni V3 in the most efficient way.
Effective Liquidity Provision
If we have a portfolio consisting of x tokens of X and y tokens of Y, and we want to provide liquidity for the price range [pᵃ, pᵇ], how many tokens X or Y should we swap to achieve maximum liquidity?
To answer this question, let's denote R = y / x—the ratio of tokens in our portfolio—and rᵃᵇ(p)—the optimal token ratio that makes Lx = Ly. From the formulas for Lx and Ly, we can derive:
So our goal is to make R = rᵃᵇ.
However, this task is slightly more complex than merely aligning x and y to the specified ratio rᵃᵇ. As we start swapping x for y or vice versa, the pool price p begins to change, and so does rᵃᵇ. This behavior is illustrated in the following figure:
Figure 6: Aligning R to rᵃᵇ
Another layer of complexity is that as the price p changes, the pool liquidity L also changes across tick spacing! To tackle this issue, let's first understand how the ratio R evolves when we swap token X for token Y while keeping liquidity L constant.
From the equations L² = xy and p = y / x, it is easy to derive:
Thus, if we swap Y for X, subtracting fees from Y, the post-swap price settles at p₁ (p₁ > p₀):
If we swap X for Y, then p₁ < p₀, we have:
The next question is:
At what ratio will R cross the tick spacing and cause a change in liquidity?
If we denote R+ as the ratio crossing the upper tick, R- as the ratio crossing the lower tick, p₀ as the initial price, and p- and p+ as the corresponding prices at each tick, with L being the current liquidity of the tick spacing, we then obtain:
Finally, we are ready to solve the problem.
First, we need to answer two questions:
- Is R > rᵃᵇ(p₀)? If so, we need to swap Y for X; otherwise, we swap X for Y.
- When we swap—does the pool price cross a tick spacing? If not—we can solve the problem immediately. If so—we need to adjust our values as if we were swapping all the way to the tick spacing, then repeat our algorithm on the new liquidity.
The answers to these questions lead us to four different cases:
- Swapping Y for X within a tick spacing: R > rᵃᵇ(p₀), R+ ≤ rᵃᵇ(p+)
- Swapping X for Y within a tick spacing: R < rᵃᵇ(p₀), R- ≥ rᵃᵇ(p-)
- Swapping Y for X across different tick spacings: R > rᵃᵇ(p₀), R+ > rᵃᵇ(p+)
- Swapping X for Y across different tick spacings: R < rᵃᵇ(p₀), R- < rᵃᵇ(p-)
Case 1: Swapping Y for X within a tick spacing: R > rᵃᵇ(p₀), R+ ≤ rᵃᵇ(p+)
Figure 7: Swapping Y for X within a tick spacing. When we swap from Y to X, the price increases to p₃, R decreases to R+, and rᵃᵇ increases to rᵃᵇ+. Since initially R > rᵃᵇ and R+ ≤ rᵃᵇ+, it guarantees R = r within the tick spacing.
If we swap y for x and the post-swap price stabilizes at p₁, we just need to ensure Ryx(p₁) = rᵃᵇ(p₁):
Assuming z = √p₁ and rearranging the terms of the equation, we will obtain a quadratic equation:
Thus, we can solve it and find p₁:
The amount of token Y to swap is:
Case 2: Swapping X for Y within a tick spacing: R < rᵃᵇ(p₀), R- ≥ rᵃᵇ(p-)
Figure 8: Swapping X for Y within a tick spacing. When we swap from X to Y, the price drops to p₂, R increases to R-, and rᵃᵇ decreases to rᵃᵇ-. Since initially R < rᵃᵇ and R- ≥ rᵃᵇ-, it guarantees R = r within the tick spacing.
This case is very similar to Case 1, except we are swapping X for Y, so we need to ensure Rxy(p₁) = rᵃᵇ(p₁):
Similar to Case 1, we can derive:
The amount of token X to swap is:
Case 3: Swapping Y for X across different tick spacings: R > rᵃᵇ(p₀), R+ > rᵃᵇ(p+)
Figure 9: Swapping Y for X across different tick spacings. When we swap from Y to X, the price increases to p₂ and then to p₃, R decreases to R+, and rᵃᵇ increases to rᵃᵇ+. Since initially R > rᵃᵇ and R+ > rᵃᵇ+, it guarantees that when we swap to R = rᵃᵇ, the price will cross the tick spacing.
In this case, we will swap Y for X until R = R+ and p = p+, and we are in a new tick spacing with new liquidity. We remember how many Y tokens we swapped to add them to the final count later. Then we restart the algorithm and repeat until we encounter Case 1. Then we redefine:
Case 4: Swapping X for Y across different tick spacings: R < rᵃᵇ(p₀), R- < rᵃᵇ(p-)
Figure 10: Swapping X for Y across different tick spacings. When we swap from X to Y, the price drops to p₃ and then to p₂, R increases to R-, and rᵃᵇ decreases to rᵃᵇ-. Since initially R < rᵃᵇ and R- < rᵃᵇ-, it guarantees that when we swap to R = rᵃᵇ, the price will cross the tick spacing.
This is very similar to Case 3, except we are swapping X for Y until R = R- and repeat until we encounter Case 2. We redefine:
Conclusion
Providing liquidity in the correct ratio in Uni V3 is a very complex task. You need to consider many factors, such as different liquidity values within tick spacings. The algorithm above describes how to use pool data to calculate the number of tokens to swap for maximum liquidity.
Digital charts can be found here:
https://www.desmos.com/calculator/rqbrnapxbj
https://www.desmos.com/calculator/ys7kcfgjxe
https://www.desmos.com/calculator/ehdwkbtu7z
https://www.desmos.com/calculator/huzzwffze9
https://www.desmos.com/calculator/t9u9x8xgcy
In future articles, we plan to discuss other interesting aspects of Uni V3, such as impermanent loss, multi-asset portfolios, strategy risks, and more.
Mellow Protocol is exploring the liquidity provision and market-making space of AMMs. You can also check our preliminary research paper here. Mellow aims to build a robust ecosystem of tools to eliminate market inefficiencies and create outcomes for users.
We see it not only as a product but also as an evolution that complex mathematics can bring to the DeFi space. Similar to how Uniswap and Curve innovate user trading experiences, we believe LP optimization is also driving possibilities in tradfi.
In the upcoming articles, we will discuss more ideas on how to implement appropriate rebalancing strategies and continue to explore broader topics in DeFi.