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
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
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
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
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)
Alternatively, solving for the input needed to obtain a given output:
Δy = (y * Δx) / (x - Δx)
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)
Compared to the spot price P_spot = y/x, we see:
P_eff = P_spot * (x / (x - Δx)) > P_spot
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
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)
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)
Solving:
x_1 = sqrt(k / P_1)
y_1 = sqrt(k * P_1)
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)
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
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
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
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
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)
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)
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}%")
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
where L is called liquidity and the offsets are:
x_offset = L / sqrt(P_b)
y_offset = L * sqrt(P_a)
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)
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
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
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
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)
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');
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) - 1that 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
Adams, H., Zinsmeister, N., Salem, M., Keefer, R., & Robinson, D. (2021). Uniswap v3 Core. Uniswap Labs. https://uniswap.org/whitepaper-v3.pdf
Adams, H., Zinsmeister, N., & Robinson, D. (2020). Uniswap v2 Core. Uniswap Labs. https://uniswap.org/whitepaper.pdf
Angeris, G., Kao, H. T., Chiang, R., Noyes, C., & Chitra, T. (2019). An analysis of Uniswap markets. arXiv:1911.03380.
Pintail. (2019). Understanding Uniswap Returns. Medium. https://medium.com/@pintail/understanding-uniswap-returns-cc593f3499ef
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)