V3 Concentrated Liquidity

Uniswap V3's most transformative innovation: instead of spreading liquidity across the entire price curve [0, ∞], LPs concentrate their capital into specific price ranges. The result is 50× capital efficiency — but impermanent loss is amplified by the same factor. Understanding this tradeoff is essential for anyone providing liquidity on V3 or competing DEXes.

🎚️ Position Simulator

Configure a V3 ETH/USDC position and see how it performs vs. HODL as price moves.

Position Value (Final)
$11,450
HODL Value
$15,000
IL
-$3,550
Fee Revenue
+$1,200
■ IL   ■ HODL   ■ Position Value   ■ Fees (assumed 30% APY)

🔄 Tick Animation — Price Sweep Through Ranges

Watch how price moves through tick boundaries. When price enters an LP's range, they begin earning fees. When price exits, they stop earning. Each crossing causes the pool to rebalance between the two tokens.

Click play to watch price move through tick ranges
Tick spacing: 50 pips (0.30% tier) Active tick: tick ~6931 Price at active tick: $2,000

📐 Virtual Reserves & the Core Formula

In V3, positions use virtual reserves — the token amounts needed in a hypothetical full-range V2 pool to produce the same swap behavior as the concentrated position. For a position with liquidity √Δ:

sqrtPrice = √(token1 / token0)
virtualAmounts = [liquidity / sqrtPrice, liquidity × sqrtPrice]
// Amount of token0 needed:
amount0 = Δx = (√upper − √price) / (√upper × √price) × L
// Amount of token1 needed:
amount1 = Δy = (√price − √lower) × L

When price is inside the range, the position acts like a constant-product market maker confined to that price segment. When price exits the range, the position provides zero liquidity until rebalanced.

L is constant: Between two ticks, √L is the invariant — it never changes during a swap. When price crosses a tick boundary, the active liquidity set changes and L recalculates for the new active range.

⚡ Range Orders vs. Limit Orders

A V3 range order is a concentrated position with one token only (Δx = 0 or Δy = 0). When the spot price crosses the tick boundary, the position flips from token0 to token1 (or vice versa) — effectively a limit order filled at the crossing price. Market makers use range orders to post bids and asks without active management.

USDC Range Order (buy ETH)
Range: [$1,800 – $1,850]
Deposit: 1,800 USDC
When price ↓ crosses $1,850:
→ receives ETH at $1,850
ETH Range Order (sell ETH)
Range: [$2,050 – $2,100]
Deposit: 0.5 ETH
When price ↑ crosses $2,050:
→ receives USDC at $2,050
💡 JIT attack: Bots sandwich a large swap, add liquidity in the exact tick range just before the swap executes, then remove it immediately after — capturing fees while regular LPs absorb amplified IL. JIT can consume 10–30% of LP fee revenue in busy pools.

📊 IL Amplification: Concentrated vs Full-Range

A position with range width w (fraction of full range) experiences IL amplified by 1/w compared to a full-range position, for the same price ratio. A 2% width position has ~50× IL amplification. This is not a bug — it's the cost of capital efficiency.

Price Move V2 Full-Range IL V3 10% Width IL V3 2% Width IL V3 0.5% Width IL Capital Required

IL amplification = 1/range_width. A 2% width = 50× amplification. But capital deployed is 50× less, so dollar IL may still be comparable to full-range V2 while fee revenue is 50× higher.

🎯 Tick System: How Price Maps to Tick Index

V3 uses discrete ticks instead of continuous price space. Each tick represents a price boundary separated by a tick spacing that varies by fee tier. The formula is:

tick_index = floor(log₁.0001(price)) / tick_spacing × tick_spacing
price_at_tick(i) = 1.0001^i
// Fee tier tick spacings:
0.05% pool → tick_spacing = 10
0.30% pool → tick_spacing = 60
1.00% pool → tick_spacing = 400

The 1.0001 factor means each tick is ~0.01% above the previous (log₁.0001(1.0001) = 1). For a 0.30% fee tier with tick spacing 60, the minimum price step between active ticks is 60 × 0.01% ≈ 0.6%. Stablecoin pairs use 0.05% with tight 10-pip spacing to enable very narrow range orders.

0.05% — Stablecoin Pairs
  • USDC/USDT,DAI/USDC
  • Tick spacing: 10 pips
  • Extremely narrow ranges viable
  • Fee revenue: 0.05%/trade
  • Capital efficiency: highest
0.30% — General AMM
  • ETH/USDC, BTC/ETH
  • Tick spacing: 60 pips
  • Medium-width ranges typical
  • Fee revenue: 0.30%/trade
  • Most popular tier overall
1.00% — Exotic Pairs
  • Meme coins, long-tail assets
  • Tick spacing: 400 pips
  • Wider ranges compensate for volatility
  • Fee revenue: 1.00%/trade
  • Higher IL risk, higher fees

🏗️ Position Management: Adding, Removing, Splitting

V3 positions are NFTs, meaning each position is unique and non-fungible. You can hold multiple positions in the same pool at different price ranges, each as a separate NFT. This enables sophisticated LP strategies.

Adding Liquidity

  1. Select the pool (token pair + fee tier)
  2. Set your price range [lower, upper]
  3. Deposit token0 and/or token1 amounts
  4. Receive an ERC-721 NFT representing the position
  5. Position starts earning fees immediately if price is in range

Removing / Closing

  1. Transfer the position NFT to the V3 router
  2. Call decreaseLiquidity for partial removal
  3. Call collect to withdraw earned fees + principal
  4. Or call multicall to atomically remove all and claim
  5. NFT is burned; tokens go to your wallet
Multiple positions per pool: A sophisticated LP might run 3 positions simultaneously — a tight range around current price (high fees, high IL risk), a wide range as a "safety net" (lower fees, lower IL), and a range order for a directional bet. Each position is managed independently and earns fees proportionally to liquidity amount × time in range × fee tier.

⚖️ V2 vs V3 vs Curve: Which AMM Wins?

Feature Uniswap V2 Uniswap V3 Curve ( stableswap)
Capital EfficiencyLow (full-range only)High (concentrated)Very High (stablecoins)
IL AmplificationStandardAmplified (tight ranges)Minimal (correlated)
Slippage (stablecoins)HighMediumVery Low
Slippage (volatile)MediumLow (in range)Not designed for volatile
Position TypeFungible LP tokensNFT (non-fungible)Fungible LP tokens
Range OrdersNoYes (native)No
Impermanent Loss ProtectionNoneIL amplification riskBuilt-in (stableswap)
Fee TiersSingle fixed0.05/0.30/1.00%Dynamic (governance)
Composable (as token)Yes (ERC-20)Partial (needs wrapper)Yes (ERC-20)
When to use V2: Simple long-term LP positions where you don't want to manage ranges. Better for illiquid pairs where tight ranges would never be in range. V2 still has significant TVL on smaller chains.
When to use V3: Active LP management on high-volume pairs. When you want range orders for directional positions. When capital efficiency matters more than simplicity. Best for ETH/USDC, BTC/USDC type pairs.

🖼️ Non-Fungible Positions: Why V3 Uses NFTs

In V2, your LP share is a fungible ERC-20 token — anyone who holds the same amount has an identical position. In V3, each position has unique parameters: lower bound, upper bound, liquidity amount, fee tier, and token composition. This makes every position non-fungible, represented as an ERC-721 NFT.

🔀
Not Swappable
Each position has different parameters — you can't directly swap one position for another
📦
Transferable
NFT can be transferred, sold on NFT marketplaces, or used as collateral in NFT lending
📊
Composable (limited)
Cannot be used as ERC-20 in DeFi composables — needs position wrapper contracts for DeFi integration
💰
Multi-Position
Same wallet can hold unlimited positions in the same pool — each managed independently

How V3 concentrated liquidity works

In Uniswap V2, every LP provides liquidity across the entire price spectrum. If ETH is $2,000, most of the $10,000 deposited in an ETH/USDC pool is sitting idle at prices the market will never visit — only the $2,000 of USDC that sits at the current price actively earns fees. V3 fixes this by letting LPs define a price range [Pa, Pb] and concentrating their capital there.

The position is represented by a liquidity amount √Δ and the two price boundaries. The swap math inside the range is identical to a constant-product AMM but with virtual reserves — a position that would need $10,000 of full-range capital to produce the same depth can be opened with $200 if the range is 2% wide. This is the capital efficiency multiplier: 1 / (range width as a fraction of full range).

The tradeoff is IL amplification. When ETH moves from $2,000 to $3,000, a V2 LP is left holding 33% more USDC than they started with (in USD terms, the portfolio is +8.2%). A V3 LP with a $1,800–$2,200 range had their position crossed twice, rebalancing the token ratio more aggressively. The IL curve is the same shape but compressed into the smaller price window, so a tight-range LP experiences what looks like much deeper IL per unit of price move.

V3's tick spacing is set by fee tier: 0.05% pools use 10-pip spacing (enabling near-1:1 stablecoin swaps), 0.30% pools use 60-pip spacing (general ETH/USDC type pairs), and 1.00% pools use 400-pip spacing (exotic/volatile pairs). When the spot price crosses from tick i−1 to tick i, the pool records the cumulative fee growth per liquidity at that tick — this allows fee calculations without iterating the entire transaction history.

Key concepts

Active tick
The current price boundary that separates the two tokens in a V3 pool. Swaps only cross one tick at a time; when the price crosses from below tick i to above tick i, the pool records the cumulative per-liquidity metrics at that tick so fee accrual can be computed exactly without iterating the entire history.
Virtual reserves
Before V3, a pool with $1M of liquidity had exactly $1M of actual token reserves. In V3, the real reserves of a concentrated position can be lower than the virtual reserves that determine swap pricing. The swap formula x·y=k uses virtual reserves; real reserves are what is actually in the contract. Crossing a tick updates the active liquidity tracking, which moves real vs virtual in lockstep.
Just-in-time (JIT) liquidity
A MEV attack specific to V3. A bot watches the mempool for large swaps, estimates the exact tick range those swaps will cross, then adds liquidity just before the swap executes (capturing the fee tier) and removes it immediately after (before the price can leave the range and cause IL). The regular LP earns nothing while JIT attackers extract the fee spread. Compounded across thousands of daily swaps, JIT can consume 10–30% of LP fee revenue in busy pools.
Range orders
A V3 position with zero amount of one token (Δx = 0 or Δy = 0). When the spot price crosses the range boundary, the position flips its token composition atomically — effectively a limit order that fills at the crossing price. Market makers use range orders to post bids and asks without active management.
Cross-chain V3
V3 is deployed on Ethereum mainnet, Optimism, Arbitrum, Base, Polygon, Celo, BNB Chain, and Avalanche. Each deployment has its own pools and liquidity; there is no shared state between chains. Uniswap Labs' Fee Renderer aggregates routing across all chains in the frontend. Each chain uses the same V3 contract code but with different chain-specific parameters.

The N = L / √P formula

V3 introduces the concept of virtual liquidity L. The key identity is: x = L / √P (token0 held for price √P) y = L × √P (token1 held for price √P)

This means at price √P, the ratio y/x = P — exactly the spot price. As price moves, the token amounts held by the position change continuously according to the constant-product formula within the range. The liquidity L is constant between tick crossings; only the active liquidity set changes at tick boundaries.

For a position providing √Δ of liquidity within [Pa, Pb], the two token amounts are: Δx = √Δ × (√Pb − √P) / (√Pb × √P) for token0 Δy = √Δ × (√P − √Pa) for token1 When P = √Pa, Δy = 0 (position is all token0). When P = √Pb, Δx = 0 (position is all token1). This is what enables range orders — the position smoothly flips composition as price traverses the range.