Chi Li

Blockchain / Frontend Engineer

Uniswap Logo
Uniswap

Comparison with v2

In v2, the formula:

xy=kx \cdot y = k

is used to calculate the pool's liquidity, reserves, and price via the ratio of x and y. Liquidity is provided globally, meaning it covers the entire price range. No matter the market price, there's always liquidity available, avoiding token depletion.

In v3, users can concentrate liquidity within specific price ranges to improve capital efficiency. This requires major changes in liquidity calculation, as a single global k constant no longer applies.

Figure1

Providing Liquidity in a Specific Range

In v3, liquidity can be provided within specified ranges, called positions — stored as NFTs. As long as the market price is within the range, LPs collect fees.

Figure2

When price moves out of range, the position becomes inactive and can't collect fees. If liquidity is withdrawn, it will be in a single token.

When price reaches a boundary (e.g. P2), the position's token B is exhausted — it can't provide market making beyond this point.

Figure3

Price & Liquidity Calculations

v3 only stores:

  • P\sqrt P — square root of price (y/x\sqrt{y/x})
  • LL — liquidity, xy=k=L2x \cdot y = k = L^2

From xy=kx \cdot y = k:

  • x=1PLx = \frac{1}{\sqrt{P}} L
  • y=PLy = \sqrt{P} L

Prices are expressed in ticks:

  • p(i)=1.0001ip(i) = 1.0001^i
  • p(i)=1.0001i/2\sqrt{p(i)} = 1.0001^{i/2}
  • log1.0001(p)=i\log_{1.0001}{(p)} = i

Liquidity

In v2, liquidity depends on reserves with a 50/50 value ratio.

In v3:

  • Each position has price bounds.
  • The pool’s total liquidity is a collection of these positions.

Figure4

LP Use Case

From Figure 3:

  • Δy=ΔPL\Delta y = \Delta \sqrt{P} L (f1)
  • Δx=Δ1PL\Delta x = \Delta \frac{1}{\sqrt{P}} L (f2)

Further:

  • Δy=(PP2)L\Delta y = (\sqrt{P} - \sqrt{P2}) L
  • Δx=(1P1P1)L\Delta x = (\frac{1}{\sqrt{P}} - \frac{1}{\sqrt{P1}}) L

Finally:

ΔyΔx=(PP2)×PP1P1P\frac{\Delta y}{\Delta x} = (\sqrt{P} - \sqrt{P2}) \times \frac{\sqrt{P} \cdot \sqrt{P1}}{\sqrt{P1} - \sqrt{P}}

Example:

  • p=2645p = 2645
  • p1=2998p1 = 2998
  • p2=1000p2 = 1000

Result: ΔyΔx16779\frac{\Delta y}{\Delta x} \approx 16779 — providing 1 y requires 16779 x.

Note: Solidity uses ticks and Q64.96 fixed-point (sqrtPriceX96). On-chain results may differ.

Price

Swap flow without crossing ticks:

  1. Specify input or output amount
  2. Use pool’s LL and token amount to compute ΔP\Delta P
  3. Compute corresponding token change

From (f1) and (f2):

  • ΔP=ΔyL\Delta \sqrt{P} = \frac{\Delta y}{L} (f4)
  • Δ1P=ΔxL\Delta \frac{1}{\sqrt{P}} = \frac{\Delta x}{L} (f5)

Example: Adding 10 y in a L=100L=100 pool:

  • ΔP=0.1\Delta \sqrt{P} = 0.1
  • Pt=Pc+0.1\sqrt{P_t} = \sqrt{P_c} + 0.1

Then:

Δx=(1Pt1Pc)L\Delta x = (\frac{1}{\sqrt{P_t}} - \frac{1}{\sqrt{P_c}}) L

Result: Δx0.236\Delta x \approx 0.236

UI Example

Figure 5: USDT/ETH pool UI

Figure5

Current price: 3632, range: 2195~6620. Fixing 1 ETH requires 3188 USDT.

Adjusting price range (Figure 6) increases required USDT as range widens.

Figure6

Contract Architecture

Uniswap Overview

Universal Router manages both v2 and v3 swaps.

Uniswap Universal Router

Universal Router

Acts like a multicall, bundling operations via bytes-encoded instructions. The frontend picks optimal paths and parameters.

V3 Core

Minimal contract architecture (production uses Universal Router).

V3 Core

PoolFactory

Creates pools and assigns ownership.

Pool

Handles:

  • mint — add a position, mint NFT
  • burn — remove liquidity, burn NFT
  • swap — execute token swaps
  • collect — collect earned fees

Periphery

Helper contracts.

SwapRouter

Handles swap logic with exactInput / exactOutput.

NFTManager

ERC-721 implementation for position NFTs with functions like collect, increaseLiquidity, decreaseLiquidity.

References