Uniswap v3: The Universal AMM

6.7.2021 | Dan Robinson

Introduction

Uniswap v3 (paper) allows liquidity providers to provide custom amounts of liquidity in selected price ranges. This unlocks tremendous capital efficiency gains for liquidity providers who can manually adjust their exposure.

But this feature also greatly expands the design space for automated liquidity provision. Any static AMM can be approximated by a custom liquidity provision strategy involving multiple positions on Uniswap v3.

We can visualize the liquidity provided by any AMM as a curve in “tick space.” Applying this method to existing AMMs like Curve, Balancer, and the logarithmic market scoring rule (LMSR) shows how those AMMs concentrate their liquidity across different prices, revealing the unique “liquidity fingerprint” corresponding to each of those AMMs.

Follow-up work will explore how strategies like this can be efficiently and accurately approximated in practice on Uniswap v3.

Automated market makers

This paper assumes you are familiar with automated market makers between two assets X and Y that are defined as a trading function (see paper), meaning a relationship between its reserves x and y. We will only consider two-asset pools.

For ease of comparison, let’s define the constants in each of these formulas in terms of s, where s is the quantity of x when x = y. You can loosely think of s as the number of “shares” that liquidity providers have in that pool. For example, the constant product formula used by Uniswap v2 (ignoring fees) can be described with the formula x \cdot y = s^2, with s roughly corresponding to the total supply of liquidity tokens.

We will use P to refer to the price of asset X in terms of asset Y. P is equivalent to the negated derivative of the reserves curve, -\frac{dy}{dx}. (For more background on thinking about AMMs in terms of derivatives, see the YieldSpace paper).

Uniswap v3

In Uniswap v3, anyone can create a position to provide some amount of liquidity—L—within a price range between two ticks. Tick indexes (t_i) are logarithmic in price, and specify the lower and upper prices at which that position provides liquidity.

As shown in the Uniswap v3 whitepaper, this is the trading function that describes the relationship between the reserves of a single Uniswap v3 position while its liquidity is in range:

    \[(x + x_{offset})\cdot (y + y_{offset}) = L^2\]

    \[x_{offset} = \frac{L}{\sqrt{p_{upper}}}\]

    \[y_{offset} = L \cdot \sqrt{p_{lower}}\]

If a strategy involves providing liquidity in multiple positions, these definitions defined in terms of total reserves will no longer apply.

It would therefore be helpful to find a local definition for liquidity, that describes liquidity in its conventional sense: the pool’s resistance to price impact when someone is trading with it.

As shown in Appendix A, it turns out that L can also be defined as the rate of change of y (the reserves of the Y token) for a given change in \sqrt{P} (the square root of the price of the X token in terms of the Y token):

    \[L = \frac{dy}{d\sqrt{P}}\]

Simulating other curves

How can liquidity providers use Uniswap v3 to simulate a custom curve? One intuitive way to do so is to create many different positions, with a custom amount of liquidity in each:

The more narrow these “slices” are, the more accurately this will simulate the target curve. For this post, we will treat tick space as infinitely divisible, and imagine that a liquidity provider is allowed to provide any arbitrary function L(t_i) to provide that amount of liquidity at any tick.

Graphing the L(t_i) function shows us the “liquidity fingerprint” of these other AMMs. (For convenience in defining functions of ticks, we will define t_i as \ln(P), as if our tick size was e.) Appendix B shows the steps to derive this L(t_i) function from a given invariant.

Uniswap v2

The behavior of the reserves in Uniswap v2 can be described with the following equation:

    \[x \cdot y = s^2\]

The liquidity fingerprint of this curve is a flat line:

    \[L = s\]

To simulate this curve in Uniswap v3, we can simply create a single position with liquidity s, and set our tick boundaries to t_{min} and t_{max}.

Curve (with constant chi)

The formula used by Curve is described in the StableSwap whitepaper. That paper first describes its invariant in terms of a constant amplification factor, \chi. Their formula can be written as:

    \[2 \chi s (x + y) + xy = 4 \chi s^2 + s^2\]

This reserves curve (with Uniswap v2 shown for comparison) looks like:

It turns out that with a constant \chi, the liquidity provided by this formula is exactly equivalent to a single Uniswap v3 position, if we set L = s \cdot (2\chi + 1), and set the upper and lower prices to {\left(\frac{2\chi + 1}{2\chi}\right)}^2 and {\left(\frac{2\chi}{2\chi + 1}\right)}^2. This means that we can simulate this formula with a single position in Uniswap v3:

Curve in fact uses a non-constant \chi, which is defined (using our terminology) as \frac{Axy}{s^2}, where A is a constant amplification factor. This leads to a more complicated equation that is harder to represent with a closed-form liquidity function. In follow-up work, I’ll show how to approximate this and other curves numerically.

Balancer

The reserves in a two-asset Balancer pool can be described by this invariant, where w_x is the weight of the X asset and w_y is the weight of the Y asset (or 1 - w_x):

    \[x^{w_x} \cdot y^{w_y} = s\]

In liquidity space, this corresponds to an exponential function:

    \[L(t_i) = s \cdot (2 {w_x}^{w_y} {w_y}^{w_x}) \cdot e^{(w_x - \frac{1}{2}) t_i}\]

Intuitively, when asset X is weighted less heavily, more of the pool’s liquidity is reserved for lower prices of asset X. This makes sense, because at any given time, liquidity reserved for lower prices is effectively buy orders for asset X, so it is currently held in asset Y.

Logarithmic market scoring rule

The logarithmic market scoring rule (LMSR) is one of the first and most widely studied automated market makers. The two-asset case is best known for its application to a binary prediction market (i.e., between YES and NO shares), where the price of the two assets (in cash) adds up to 1.

Typically, LMSR is described in terms of the rule for market-making between each asset (YES and NO) and cash. We could instead describe it in terms of the rule for market-making between one asset and the other. If we do that, then as explained here, the reserves can be described by this invariant:

    \[2^{-\frac{x}{s}} + 2^{-\frac{y}{s}} = 1\]

The reserves curve for this formula looks like:

When transformed into tick space, the liquidity fingerprint of this curve is shaped like—you guessed it—the hyperbolic secant function:

    \[L(t_i) = \frac{s}{\ln(2)} \cdot \operatorname{sech}{\left(\frac{t_i}{2}\right)}\]

As you can see, LMSR concentrates more of its liquidity closer to tick 0 (the price of 1). In prediction markets, when YES and NO shares are equal, that implies a probability of 50\%. So LMSR concentrates more liquidity to support probabilities around 50\% than to support more extreme probabilities.

Appendix B shows how this liquidity fingerprint can be computed.

Future work

This paper showed how several popular AMMs could be simulated using Uniswap v3, and showed how graphing curves in liquidity space provides insight into their unique “liquidity fingerprints”. However, there are several limitations that need to be overcome before Uniswap v3 can be used to simulate most of these AMMs:

  • Ticks are not infinitely divisible, and liquidity providers have to approximate this curve using the granular ticks available.
  • The gas cost of minting and burning is proportional to the number of ticks updated, so providing liquidity at custom levels across all of tick space would be insurmountably inefficient.
  • Finally, not every useful AMM can be easily represented as a function in liquidity space.

Future work will demonstrate some techniques for getting around these problems using numerical approximation, as well as some smart contract tricks to make custom liquidity provision much more gas-efficient.

Appendices

Appendix A: Definition of liquidity

We can show that in Uniswap v3, the derivative \frac{dy}{d\sqrt{P}} is equal to L.

We start with the trading function (while the position is in range):

    \[(x + x_{offset})\cdot (y + y_{offset}) = L^2\]

Solving for x (to use later):

    \[x = \frac{L^2}{y + y_{offset}} - x_{offset}\]

Solving for y:

    \[y = \frac{L^2}{x + x_{offset}} - y_{offset}\]

Finding P as a function of x by taking -\frac{dy}{dx}:

    \[P = \frac{L^2}{\left(x + x_{offset}\right)^2}\]

Solving for \sqrt{P} instead:

    \[\sqrt{P} = \frac{L}{x + x_{offset}}\]

Substituting for x and simplifying:

    \[\sqrt{P} = \frac{y + y_{offset}}{L}\]

Solving for y:

    \[y = L * \sqrt{P} - y_{offset}\]

Taking the derivative:

    \[\frac{dy}{d\sqrt{P}} = L\]

Appendix B: Example derivation

This appendix shows how to go from an AMM formula defined as a trading function to a liquidity curve in tick space. We’ll use LMSR as an example.

As shown in Appendix A, liquidity can be defined as the rate of change of y with respect to \sqrt{P}. Since P is simply -1 times the derivative of y with respect to x, we know that liquidity can be computed as:

    \[L = \frac{dy}{d\sqrt{-\frac{dy}{dx}}}\]

We start with the AMM defined as an invariant:

    \[2^{-\frac{x}{s}} + 2^{-\frac{y}{s}} = 1\]

Solving for y:

    \[y = -s \log_2{(1-2^{-\frac{x}{s}})}\]

Taking the derivative and negating it to get the price (of asset X in terms of asset Y) as a function of x:

    \[P_x(x) = -\frac{dy}{dx} = \frac{1}{2^{\frac{x}{s}}-1}\]

We then need to find the formula for that same price, but as a function of y rather than x. Since this curve (like the others described in this post) is symmetrical between x and y, we can easily get the price as a function of y by replacing x with y and taking the reciprocal:

    \[P_y(y) = 2^{\frac{y}{s}} - 1\]

Next, we invert this to find y as a function of P, and then rewrite it as a function of \sqrt{P}.

    \[y_{\sqrt{P}}(\sqrt{P}) = s \log_2{(\sqrt{P}^2+1)}\]

Then we take the derivative with respect to \sqrt{P}:

    \[L(\sqrt{P}) = \frac{dy}{d\sqrt{P}} = \frac{2s}{\ln(2)} \cdot \frac{1}{\sqrt{P}+\frac{1}{\sqrt{P}}}\]

Finally, we convert to tick space by rewriting this as a function of tick index t_i (ln(P)):

    \[L(t_i) = \frac{1}{\ln(2)} \cdot \frac{2}{e^{\frac{t_i}{2}}+e^{-\frac{t_i}{2}}} = \frac{s}{\ln(2)} \cdot \operatorname{sech}{\left(\frac{t_i}{2}\right)}\]

Written by:

Dan Robinson

Dan Robinson is a Research Partner and the Head of Research at Paradigm, focused on crypto investments and research into open-source protocols. Previously, Dan was a protocol researcher at Interstellar. [→]

Disclaimer: This post is for general information purposes only. It does not constitute investment advice or a recommendation or solicitation to buy or sell any investment and should not be used in the evaluation of the merits of making any investment decision. It should not be relied upon for accounting, legal or tax advice or investment recommendations. This post reflects the current opinions of the authors and is not made on behalf of Paradigm or its affiliates and does not necessarily reflect the opinions of Paradigm, its affiliates or individuals associated with Paradigm. The opinions reflected herein are subject 
to change without being updated.