← Index

xy = k from first principles

Introduction

Uniswap V2 is a protocol that lets you exchange tokens.

Anyone can permissionlessly create a pair of two tokens (TokenX\text{Token}_{X} and TokenY\text{Token}_{Y}).

This pair holds balances of the two tokens, known as reserves (xx and yy). Anyone can permissionlessly add tokens to the reserves, making them available for token swaps.

A token swap involves adding tokens to one reserve (x+Δx)(x + \Delta x), and removing tokens from the other (yΔy)(y - \Delta y).

In the Uniswap V2 protocol, each swap must satisfy the following condition known as the Constant Product Invariant, else the swap transaction is reverted:

(x+Δx)×(yΔy)=x×y(x + \Delta x) \times (y - \Delta y) = x \times y

The same is sometimes formulated more popularly as:

x×y=kx \times y = k

which represents the product of current token reserves, and the state of reserves resulting from a swap having to maintain it:

(x+Δx)×(yΔy)=k(x + \Delta x) \times (y - \Delta y) = k

This simple looking rule creates the intuitive user experience of exchanging tokens at rates that largely match user expectations (e.g. "selling 1ETH1 \hspace{1mm} \text{ETH} for 2500USDC2500 \hspace{1mm} \text{USDC}") based on exchange rates found elsewhere in non-smart-contract systems like centralized exchanges or trading apps.

There are plenty of excellent articles out there that explain how Uniswap V2 works, by taking the x×y=kx \times y = k formula as a given, and then showing e.g. the math for how one can derive the formula for calculating token prices, or the amount of TokenY\text{Token}_{Y} received in exchange for TokenX\text{Token}_{X}, etc.

These articles are valuable, but this is not one of them.

The goal of this article is to explain why the rule "x×y=kx \times y = k" is not an arbitrary design choice, but rather, concretely arises from how we generally, rationally price two assets in terms of each other, whether it be pricing TokenY\text{Token}_{Y} in terms of TokenX\text{Token}_{X}, or apples in terms of oranges.

Pricing tokens in terms of each other

To make two tokens XX and YY tradable and let users exchange token XX for YY and vice-versa, we need supplies of the two tokens that can be traded over.

So, let's start with a pair of tokens XX and YY, with reserves (tradable balances) xx and yy respectively. What should be the exchange rate between the two tokens?

The U.S. dollar is a highly common denomination of monetary value. Going forward, we'll use "monetary value" and "USD value" interchangeably.

When we swap one token for another, we're not trying to increase our wealth. We want to keep our wealth the same while converting the currency it is denominated in.

So, in exchange for adding some USD worth Δx\Delta x in the reserve xx, we should be getting out the same USD worth of Δy\Delta y out of the reserve yy.

Therefore, the reserves xx and yy should be such that:

USD_Value(x)=USD_Value(y)\text{USD\_Value}(x) = \text{USD\_Value}(y)

And so, the ratio yx\frac{y}{x} represents not just "the number of YY tokens per one XX token", but also "the number of YY tokens having the same monetary worth as one XX token".

So, for a given incoming Δx\Delta x, should we calculate the Δy\Delta y to be given out as the following?

Δy=yx×Δx\Delta y = -\frac{y}{x} \times \Delta x

Note, we denominate Δy\Delta y with a minus sign since the change in yy reserves is a decrease.

This fraction yx\frac{y}{x} is also referred to as the spot price of token XX in terms of YY tokens. The converse xy\frac{x}{y} is the spot price of token YY in terms of token XX.


Issues with spot price as the price mechanism

We have the pair of tokens X=USDCX = \text{USDC} and Y=ETHY = \text{ETH} with reserves and x=10,000,000x = 10,000,000 USDC\text{USDC} and y=5,000y = 5,000 ETH\text{ETH}.

A trader wants to swap in 2000USDC2000 \hspace{1mm} \text{USDC} (Δx\Delta x) to purchase ETH\text{ETH} (Δy\Delta y). The trader receives the following in return:

Δy=yx×Δx=500010,000,000×2000=1ETH\Delta y = -\frac{y}{x} \times \Delta x = -\frac{5000}{10,000,000} \times 2000 = -1 \hspace{1mm} \text{ETH}

The new state of the pair's reserves is x=10,002,000x = 10,002,000 and y=4,999y = 4,999.

But notice how much USDC\text{USDC} the trader would receive if they trade this 1ETH1 \hspace{1mm} \text{ETH} back in:

Δx=xy×Δy=10,002,0004,999×1=2000.8USDC\Delta x = -\frac{x}{y} \times \Delta y = -\frac{10,002,000}{4,999} \times 1 = -2000.8 \hspace{1mm} \text{USDC}

Interesting! The trader decides to trade their newly gained 11 ETH\text{ETH} back for 2000.82000.8 USDC\text{USDC}. The new reserves are x=9,999,999.2x = 9,999,999.2 and y=5000y = 5000

The trader has effectively drained the pair's reserves for 0.80.8 USDC\text{USDC}, which is unacceptable.


So, what's going wrong? Let's make the problem clearer.

In the initial state, swapping in Δx=1\Delta x = 1 USDC\text{USDC} gets out:

Δy=yx×Δx=500010,000,000×1=0.0005ETH\Delta y = -\frac{y}{x} \times \Delta x = -\frac{5000}{10,000,000} \times 1 = -0.0005 \hspace{2mm} \text{ETH}

The updated reserves are:

xnew=10,000,001USDCynew=4999.9995ETHx_{new} = 10,000,001 \hspace{2mm} \text{USDC} \hspace{4mm} y_{new} = 4999.9995 \hspace{2mm} \text{ETH}

Now, swapping in Δx=1\Delta x = 1 USDC\text{USDC} again gets out:

Δy=yx×Δx=4999.999510,000,001×1=0.00049999995ETH\Delta y = -\frac{y}{x} \times \Delta x = -\frac{4999.9995}{10,000,001} \times 1 = -0.00049999995 \hspace{2mm} \text{ETH}

Notice how swapping in the first 1USDC1 \hspace{1mm} \text{USDC} yielded more ETH\text{ETH} compared to the next 1USDC1 \hspace{1mm} \text{USDC}. This trend continues as we swap successive 1USDC1 \hspace{1mm} \text{USDC}.

Let's now see what would happen if we'd have swapped Δx=2USDC\Delta x = 2 \hspace{1mm} \text{USDC} at once:

Δy=yx×Δx=500010,000,000×2=0.001ETH\Delta y = -\frac{y}{x} \times \Delta x = -\frac{5000}{10,000,000} \times 2 = -0.001 \hspace{2mm} \text{ETH}

We got out more ETH\text{ETH} by simply swapping in 2USDC2 \hspace{1mm} \text{USDC} at once instead of two successive 1USDC1 \hspace{1mm} \text{USDC} swaps.

Each swap in of the smallest possible Δx\Delta x in exchange for getting out the corresponding Δy\Delta y changes the reserves; it increases xx and decreases yy, which makes yx\frac{y}{x} smaller.

Therefore, each successive trade of the smallest possible Δx\Delta x should be evaluated at the reserve ratio yx\frac{y}{x} based on the changed reserves resulting from the prior trade. As we've seen, the reserve ratio continues to decrease on each successive trade. You get out successively less Δy\Delta y for every marginal Δx\Delta x swapped in for it.

And so, in our example of swapping in 2000USDC2000 \hspace{1mm} \text{USDC}, we end up giving out more ETH\text{ETH} than we should have because we calculate Δy\Delta y for the entire Δx=2000\Delta x = 2000 amount using the ratio of the reserves right at the start of the trade, where the ratio is at its highest!

The right calculation for Δy\Delta y would, instead, evaluate the formula

Δy=yx×Δx\Delta y = -\frac{y}{x} \times \Delta x

at infinitely many tiny steps. Each step takes in an infinitely tiny amount of Δx\Delta x and calculates Δy\Delta y at the current reserve ratio. After each step, both reserves are updated. The next Δy\Delta y is calculated using the updated reserves. The total Δy\Delta y to give out is the sum of these infinitely many Δy\Delta y outputs.

Deriving the Constant Product Invariant

The reserves xx and yy are not independent values. The whole point of the reserves being tradable is that adding some Δx\Delta x into the xx reserve yields some Δy\Delta y out of the yy reserve.

Therefore, yy is a function of xx:

y=f(x)y = f(x)

Specifically, we care about a function ff that relates the xx and yy reserves in the way that the previous section just established: the change in yy from a given change in xx should be based on a continuously adjusting reserve ratio.

We don't know what this ff looks like, exactly. In fact, our goal is to find ff so that, given an increase Δx\Delta x in the xx reserve, we can calculate the correct corresponding Δy\Delta y to give out from the yy reserve:

Δy=f(x+Δx)f(x)\Delta y = f(x + \Delta x) - f(x)

Note that for an arbitrarily small Δx\Delta x, the calculation f(x+Δx)f(x)f(x + \Delta x) - f(x) simply corresponds to Δf\Delta f i.e. the change in ff resulting from an arbitrarily small change in xx.

So, for a given set of current reserves of xx and yy, the formula:

Δf=Δy=yx×Δx\Delta f = \Delta y = -\frac{y}{x} \times \Delta x

gives us the change in ff for an arbitrarily small change in xx.

Therefore, though we don't know what the function ff looks like, we do know what the derivative of ff i.e. the function ff' ("f prime") looks like!

f(x)=yxf'(x) = -\frac{y}{x}

This derivative f(x)f'(x) tells us the rate at which f(x)f(x) changes in a given current state of reserves xx and yy (which itself is a function of xx), and an arbitrarily small change Δx\Delta x in the xx reserve.

We can now recover ff from ff' via integration, and then we'll have a concrete way of calculating the right Δy\Delta y amount that should be taken out from the yy reserve for a given Δx\Delta x increase in the xx reserve.

Given y=f(x)y = f(x), we have:

f(x)=ddxf(x)=dydx=yxf'(x) = \frac{d}{dx} f(x) = \frac{dy}{dx} = -\frac{y}{x}

since dydx\frac{dy}{dx} refers to the rate at which yy changes for an arbitrarily small change in xx.

1y×dydx=1x\frac{1}{y} \times \frac{dy}{dx} = -\frac{1}{x}

Now, integrate both sides with respect to xx 1ydydxdx=1xdx\int \frac{1}{y} \cdot \frac{dy}{dx} \hspace{1mm} dx= \int \frac{-1}{x} \hspace{1mm} dx

The right hand side evaluates as

1xdx=ln(x)+C\int \frac{-1}{x} \hspace{1mm} dx = -\ln(x) + C

For the left hand side, note 1ydydx\frac{1}{y} \cdot \frac{dy}{dx} is the derivative of ln(y)\ln(y) when yy is a function of xx. Therefore:

1ydydxdx=ddxln(y)dx=ln(y)\int \frac{1}{y} \cdot \frac{dy}{dx} \hspace{1mm} dx = \int \frac{d}{dx} \ln(y) \hspace{1mm} dx = \ln(y)

Putting both sides together:

ln(y)=ln(x)+C\ln(y) = -\ln(x) + C

ln(y)+ln(x)=C\ln(y) + \ln(x) = C

ln(x×y)=C\ln(x \times y) = C

x×y=kf(x)=y=kxx \times y = k \hspace{4mm} \equiv \hspace{4mm} f(x) = y = \frac{k}{x}

That looks familiar! We've derived the famous Constant Product Invariant. Now, what does it mean?

We've been trying to find a way to calculate the "right" Δy\Delta y to give out of the yy reserve in exchange for an increase Δx\Delta x in the xx reserve.

We established earlier that the "right" Δy\Delta y means that for an incoming Δx\Delta x, we calculate the corresponding Δy\Delta y as the sum of the outputs of infinitely many runs of the following:

Δyn=yx×Δxn\Delta y_n = -\frac{y}{x} \times \Delta x_n

where each run nn takes in an infinitely tiny amount of Δx\Delta x and calculates the corresponding Δy\Delta y output at the reserve ratio resulting from the previous run n1n-1, at reserve values xn1x_{n-1} and yn1y_{n-1}.

However, performing this operation is not straightforward, since the Δxn\Delta x_n in each run of the formula is arbitrarily small and does not have a definite numerical value. And so, we can't put a definite numerical value to corresponding Δyn\Delta y_n output, and just sum up all the infinite Δy\Delta y outputs.

But then, we established that the yy reserve is a function of the xx reserve, and therefore, upon finding ff such that y=f(x)y = f(x), we can calculate the "right" Δy\Delta y to give out in exchange for an incoming Δx\Delta x as follows:

Δy=f(x+Δx)f(x)\Delta y = f(x + \Delta x) - f(x)

We then concretely derived the function ff as a direct consequence of our initial understanding of how Δy\Delta y for an incoming Δx\Delta x should be calculated with a constantly adjusting reserve ratio in mind.

The function ff we found that dictates what the yy reserves should be for any given xx reserve is:

f(x)=y=kxf(x) = y = \frac{k}{x}

where kk can be thought of as the product of the two reserves. This product is first established when a liquidity provider seeds a UniswapV2 pair with balances of token XX and YY, and this kk changes every time a liquidity provider adds to or removes liquidity (i.e. their share of the reserves) from the pair.

Therefore, when no liquidity provider is adding or removing liquidity from the pair, the function f(x)=y=kxf(x) = y = \frac{k}{x} describes all the values that the xx and yy reserves are allowed to take.

That is, xx and yy are allowed to change in all the ways that keeps kk the same i.e. constant. And apart from adding and removing liquidity by liquidity providers, xx and yy change during swaps. This is why swaps are considered valid only if:

(x+Δx)×(yΔy)=x×y=k(x + \Delta x) \times (y - \Delta y) = x \times y = k

As long as swaps obey this invariant, we know that the swap is taking out the right amount of Δy\Delta y in exchange for an incoming Δx\Delta x, and the trade is happening, intuitively, near the spot prices of the two tokens XX and YY, comparable with non-smart-contract systems like centralized exchanges or trading apps.