DEV Community

Khusniddin Qalandarov
Khusniddin Qalandarov

Posted on

AMM Mathematics: Constant Product and Beyond — How Uniswap's x·y=k Formula Powers DeFi

Introduction

Decentralized Finance (DeFi) has transformed how we think about financial primitives. At the heart of this transformation lies a deceptively simple equation: x · y = k. This invariant, introduced by Uniswap V2, underpins billions of dollars in daily trading volume and gave birth to the Automated Market Maker (AMM) paradigm. Yet beneath its simplicity lies a rich mathematical structure — one that governs pricing, liquidity, slippage, and the often-misunderstood phenomenon of impermanent loss.

In this article, we derive the constant-product formula from first principles, analyze its mathematical properties, explore how impermanent loss emerges naturally from the model, and then examine how Uniswap V3's concentrated liquidity model extends and generalizes the original invariant.


1. What Is an Automated Market Maker?

Traditional exchanges use an order book: buyers post bids and sellers post asks, and trades execute when the two sides match. This model requires active market participants and suffers from low liquidity in thin markets.

An AMM replaces the order book with a mathematical pricing function. A smart contract holds reserves of two tokens — say, token X (e.g., ETH) and token Y (e.g., USDC) — and uses a formula to deterministically quote prices based solely on the current reserve balances. No counterparty is needed; the contract itself is always willing to trade at the formula-determined price.

The key insight is that the AMM does not need to know the "true" price. Arbitrageurs will continuously trade against it until the AMM price aligns with the broader market, making the system self-correcting.


2. Deriving the Constant-Product Formula

2.1 The Invariant

Let x denote the reserve of token X and y the reserve of token Y. Uniswap V2 enforces the following invariant after every trade (ignoring fees for now):

x * y = k
Enter fullscreen mode Exit fullscreen mode

where k is a constant. This means the product of the two reserves must remain unchanged after any swap.

2.2 Price Derivation

The marginal price of token X in terms of token Y is the instantaneous rate at which the curve trades one for the other. Taking the total differential of the invariant:

d(x * y) = 0
y dx + x dy = 0
dy/dx = -y/x
Enter fullscreen mode Exit fullscreen mode

The negative sign indicates that as we buy X (x decreases), y must increase. The spot price of X in terms of Y at any point on the curve is:

P = y / x
Enter fullscreen mode Exit fullscreen mode

This is the marginal price. Notice it is not constant — it changes with every trade. This is precisely what creates slippage.

2.3 Executing a Swap

Suppose a trader wants to buy Δx tokens of X by depositing Δy tokens of Y. The new reserves must satisfy:

(x - Δx)(y + Δy) = k = x * y
Enter fullscreen mode Exit fullscreen mode

Expanding and solving for Δx:

x*y - Δx*y + x*Δy - Δx*Δy = x*y
-Δx*y + x*Δy - Δx*Δy = 0
Δx(y + Δy) = x * Δy
Δx = (x * Δy) / (y + Δy)
Enter fullscreen mode Exit fullscreen mode

Alternatively, solving for the input needed to obtain a given output:

Δy = (y * Δx) / (x - Δx)
Enter fullscreen mode Exit fullscreen mode

This closed-form solution means swaps can be computed in O(1) with no order book traversal, which is why AMMs are extremely gas-efficient on-chain.

2.4 Effective Price vs. Spot Price

The effective price paid per unit of X is:

P_eff = Δy / Δx = y / (x - Δx)
Enter fullscreen mode Exit fullscreen mode

Compared to the spot price P_spot = y/x, we see:

P_eff = P_spot * (x / (x - Δx)) > P_spot
Enter fullscreen mode Exit fullscreen mode

The ratio x / (x - Δx) captures price impact — the larger the trade relative to reserves, the worse the execution price.


3. Impermanent Loss: A Mathematical Analysis

Impermanent loss (IL) is the difference in value between holding tokens in an AMM pool versus simply holding them in a wallet. It is one of the most important risks for liquidity providers.

3.1 Setup

Assume a liquidity provider (LP) deposits into a pool when the price of X in terms of Y is P_0 = y_0 / x_0. The invariant gives:

x_0 * y_0 = k
Enter fullscreen mode Exit fullscreen mode

At this point, the LP's portfolio value in terms of Y is:

V_hold = x_0 * P_0 + y_0 = 2 * y_0  (since x_0 * P_0 = y_0)
Enter fullscreen mode Exit fullscreen mode

3.2 After a Price Change

Let the external market price move to P_1. Arbitrageurs will rebalance the pool to match. The new reserves x_1, y_1 satisfy:

x_1 * y_1 = k           ... (invariant)
y_1 / x_1 = P_1         ... (new price)
Enter fullscreen mode Exit fullscreen mode

Solving:

x_1 = sqrt(k / P_1)
y_1 = sqrt(k * P_1)
Enter fullscreen mode Exit fullscreen mode

The LP's pool value in terms of Y is now:

V_pool = x_1 * P_1 + y_1
       = sqrt(k / P_1) * P_1 + sqrt(k * P_1)
       = sqrt(k * P_1) + sqrt(k * P_1)
       = 2 * sqrt(k * P_1)
Enter fullscreen mode Exit fullscreen mode

3.3 The IL Formula

Let r = P_1 / P_0 be the price ratio. Then:

k = x_0 * y_0 = x_0 * (x_0 * P_0) = x_0^2 * P_0
Enter fullscreen mode Exit fullscreen mode

So sqrt(k * P_1) = x_0 * sqrt(P_0 * P_1) = x_0 * P_0 * sqrt(r) = y_0 * sqrt(r)

Therefore:

V_pool = 2 * y_0 * sqrt(r)
V_hold = 2 * y_0
Enter fullscreen mode Exit fullscreen mode

Impermanent loss is defined as:

IL = (V_pool - V_hold) / V_hold
   = (2 * y_0 * sqrt(r) - 2 * y_0) / (2 * y_0)
   = sqrt(r) - 1
Enter fullscreen mode Exit fullscreen mode

More precisely, since the LP must compare pool value against holding the original token amounts at the new price:

V_hold_new = x_0 * P_1 + y_0 = x_0 * r * P_0 + x_0 * P_0 = x_0 * P_0 * (1 + r) = y_0 * (1 + r)

IL = V_pool / V_hold_new - 1
   = (2 * sqrt(r)) / (1 + r) - 1
Enter fullscreen mode Exit fullscreen mode

This is the canonical impermanent loss formula. Let's check key values:

Price Ratio r IL (%)
1.0 (no change) 0%
1.25 (+25%) -0.6%
1.5 (+50%) -2.0%
2.0 (+100%) -5.7%
4.0 (+300%) -20.0%
0.5 (-50%) -5.7%

Notice that IL is symmetric in log-price space: a halving and a doubling produce the same IL. Also, IL is always non-positive — the pool underperforms the holding strategy whenever prices change. However, trading fees can offset this loss.


4. Fees and the Real Invariant

In practice, Uniswap V2 charges a 0.3% fee on every swap. This means only (1 - 0.003) = 0.997 of the input is effectively traded. If a user sends Δy tokens of Y, the effective amount that shifts the invariant is 0.997 * Δy.

The actual swap formula becomes:

Δx = (x * 0.997 * Δy) / (y + 0.997 * Δy)
Enter fullscreen mode Exit fullscreen mode

Fees are collected in the pool, which increases k over time. This is the mechanism by which LPs earn yield. After many trades, the pool's k grows as:

k_new = k_old * (1 + fee_income / pool_value)
Enter fullscreen mode Exit fullscreen mode

LP shares (represented by ERC-20 LP tokens) represent a proportional claim on the pool's growing reserves.


5. Python Implementation

Here is a minimal Python simulation of a Uniswap V2 pool:

class UniswapV2Pool:
    def __init__(self, x: float, y: float, fee: float = 0.003):
        self.x = x
        self.y = y
        self.fee = fee
        self.k = x * y

    def spot_price(self) -> float:
        """Price of X in terms of Y"""
        return self.y / self.x

    def swap_x_for_y(self, dx: float) -> float:
        """Buy Y by selling dx of X. Returns amount of Y received."""
        dx_eff = dx * (1 - self.fee)
        dy = (self.y * dx_eff) / (self.x + dx_eff)
        self.x += dx
        self.y -= dy
        return dy

    def swap_y_for_x(self, dy: float) -> float:
        """Buy X by selling dy of Y. Returns amount of X received."""
        dy_eff = dy * (1 - self.fee)
        dx = (self.x * dy_eff) / (self.y + dy_eff)
        self.y += dy
        self.x -= dx
        return dx

    def impermanent_loss(self, initial_x: float, initial_y: float) -> float:
        """Compute IL relative to holding initial balances at current price."""
        P = self.spot_price()
        v_pool = self.x * P + self.y
        v_hold = initial_x * P + initial_y
        return (v_pool / v_hold) - 1

# Example
pool = UniswapV2Pool(x=100, y=200000)  # 100 ETH, 200k USDC
print(f"Initial price: {pool.spot_price()} USDC/ETH")
print(f"K = {pool.k}")

initial_x, initial_y = pool.x, pool.y

# Simulate a large buy of Y (selling ETH)
dy_received = pool.swap_x_for_y(dx=10)
print(f"Received: {dy_received:.2f} USDC for 10 ETH")
print(f"New price: {pool.spot_price():.2f} USDC/ETH")
print(f"IL: {pool.impermanent_loss(initial_x, initial_y)*100:.2f}%")
Enter fullscreen mode Exit fullscreen mode

6. Uniswap V3: Concentrated Liquidity

Uniswap V3 (released May 2021) introduced a fundamental generalization: concentrated liquidity. Instead of spreading liquidity uniformly across all possible prices from 0 to infinity, LPs can choose a specific price range [P_a, P_b] within which their capital is active.

6.1 The Generalized Invariant

Uniswap V3 transforms the V2 invariant by introducing virtual reserves. If an LP provides liquidity in range [P_a, P_b], the pool behaves as if it has larger reserves x_virtual and y_virtual that include an offset:

(x + x_offset) * (y + y_offset) = L^2
Enter fullscreen mode Exit fullscreen mode

where L is called liquidity and the offsets are:

x_offset = L / sqrt(P_b)
y_offset = L * sqrt(P_a)
Enter fullscreen mode Exit fullscreen mode

This ensures the curve "runs out" of one token at each end of the price range.

6.2 Liquidity as a Geometric Quantity

The parameter L measures the depth of the market at the current price. It is defined as:

L = sqrt(x * y)   (for the full-range V2 case)
Enter fullscreen mode Exit fullscreen mode

In V3, a position with liquidity L in range [P_a, P_b] requires the following capital:

Δx = L * (1/sqrt(P_current) - 1/sqrt(P_b))   if P_current < P_b
Δy = L * (sqrt(P_current) - sqrt(P_a))        if P_current > P_a
Enter fullscreen mode Exit fullscreen mode

This means the capital required for a given liquidity depth scales with the square root of the price, not linearly.

6.3 Capital Efficiency Comparison

The key innovation of V3 is capital efficiency. Consider a pool with price at P = 2000 USDC/ETH and an LP who wants to provide liquidity only in the narrow range [1900, 2100] (a ~10% band).

In V2, the LP's capital is spread across [0, infinity), so only a tiny fraction is ever used for trades near the current price.

In V3, all of the LP's capital is concentrated in that narrow range, providing much deeper liquidity per dollar deployed. The capital efficiency gain is approximately:

Efficiency Gain = sqrt(P_b / P_a) / (sqrt(P_b / P_a) - 1)

For [1900, 2100]: sqrt(2100/1900) / (sqrt(2100/1900) - 1)
                = sqrt(1.105) / (sqrt(1.105) - 1)
                = 1.0513 / 0.0513
                ~ 20.5x
Enter fullscreen mode Exit fullscreen mode

A V3 LP in this narrow range achieves roughly 20x better capital efficiency than a V2 LP with the same amount of capital.

6.4 Tick Architecture

V3 discretizes the price range into ticks. Each tick corresponds to a price:

P(i) = 1.0001^i
Enter fullscreen mode Exit fullscreen mode

This gives approximately 1 basis point (0.01%) spacing between adjacent ticks. Liquidity positions are defined between integer tick boundaries, and the contract tracks aggregate liquidity per tick using a tick bitmap for efficient O(1) updates.

When a swap moves the price across a tick boundary, the contract initializes or exits LP positions at that boundary, updating the active liquidity accordingly.

6.5 V2 vs V3: Key Differences

Feature Uniswap V2 Uniswap V3
Price Range [0, infinity) [P_a, P_b] custom
Capital Efficiency Low Up to 4000x higher
LP Complexity Simple Requires active management
Fee Tiers Fixed 0.3% 0.05%, 0.3%, 1%
LP Token Fungible ERC-20 Non-fungible ERC-721 (NFT)
IL Exposure Moderate Higher within range

7. Slippage Tolerance in Practice

Real-world AMM integrations must handle slippage — the difference between the expected price and the execution price. Most DEX aggregators let users set a slippage tolerance (e.g., 0.5%).

The maximum output a user can receive is bounded by the constant-product formula. For a trade of Δy input:

Minimum output Δx_min = Δx_expected * (1 - slippage_tolerance)
Enter fullscreen mode Exit fullscreen mode

If the pool state changes between transaction submission and execution (due to front-running or sandwich attacks), and the output falls below Δx_min, the transaction reverts. This is enforced by Uniswap's smart contract via:

require(amountOut >= amountOutMinimum, 'Too little received');
Enter fullscreen mode Exit fullscreen mode

8. Conclusion

The constant-product formula x * y = k is one of the most elegant and impactful mathematical primitives in modern finance. From it, we can derive:

  • A closed-form pricing function that requires no order book
  • An impermanent loss formula IL = 2*sqrt(r)/(1+r) - 1 that precisely quantifies LP risk
  • A generalization in Uniswap V3 that concentrates liquidity to dramatically improve capital efficiency

The brilliance of the design is that a single mathematical invariant — just three tokens and a multiplication — creates a self-contained, trustless exchange that operates entirely on-chain. Understanding the mathematics behind AMMs is essential for anyone building in DeFi, whether as a developer, LP, or protocol designer.


References

  1. Adams, H., Zinsmeister, N., Salem, M., Keefer, R., & Robinson, D. (2021). Uniswap v3 Core. Uniswap Labs. https://uniswap.org/whitepaper-v3.pdf

  2. Adams, H., Zinsmeister, N., & Robinson, D. (2020). Uniswap v2 Core. Uniswap Labs. https://uniswap.org/whitepaper.pdf

  3. Angeris, G., Kao, H. T., Chiang, R., Noyes, C., & Chitra, T. (2019). An analysis of Uniswap markets. arXiv:1911.03380.

  4. Pintail. (2019). Understanding Uniswap Returns. Medium. https://medium.com/@pintail/understanding-uniswap-returns-cc593f3499ef

  5. Buterin, V. (2021). Improving front running resistance of x*y=k market makers. Ethereum Research. https://ethresear.ch/t/improving-front-running-resistance-of-x-y-k-market-makers/1281

Top comments (0)