On the evening of November 8, 2022, as FTX — at that point the world's third-largest cryptocurrency exchange — began its terminal collapse, something remarkable happened. While centralized exchanges froze withdrawals, disabled trading pairs, and...
Learning Objectives
- Derive the constant product formula (x * y = k) from first principles and explain why it maintains a price curve
- Calculate impermanent loss for a liquidity provider given specific price movements, using real numbers
- Explain Uniswap V3's concentrated liquidity and why it represents a fundamental improvement in capital efficiency
- Trace a sandwich attack from detection through front-run to back-run and calculate the attacker's profit
- Compare DEX and CEX on liquidity, price execution, latency, custody, and regulatory exposure
In This Chapter
- The Market That Never Closes
- 22.1 Order Book DEXs vs. Automated Market Makers
- 22.2 Deriving the Constant Product Formula
- 22.3 Uniswap V1 and V2 Architecture
- 22.4 Calculating Impermanent Loss
- 22.5 Uniswap V3: Concentrated Liquidity
- 22.6 MEV and Sandwich Attacks
- 22.7 DEX Aggregators
- 22.8 DEX vs. CEX: The Comprehensive Comparison
- 22.9 Building a Simple AMM
- 22.10 Summary and Bridge to Chapter 23
Chapter 22: Decentralized Exchanges and Automated Market Makers
The Market That Never Closes
On the evening of November 8, 2022, as FTX — at that point the world's third-largest cryptocurrency exchange — began its terminal collapse, something remarkable happened. While centralized exchanges froze withdrawals, disabled trading pairs, and left millions of users staring at locked accounts and evaporating balances, Uniswap kept running. No CEO could halt it. No board of directors could vote to freeze assets. No bankruptcy court could seize user funds. The smart contracts continued executing swaps, liquidity providers continued earning fees, and anyone with an Ethereum wallet could trade, withdraw, or rebalance their portfolio at any time of day or night.
That week, Uniswap processed over $7 billion in trading volume. Not because anyone told it to. Not because a company decided to keep the lights on. Because the code, once deployed, simply could not be stopped.
This is the fundamental proposition of decentralized exchanges: a market that exists as code on a blockchain, operating without intermediaries, without custodians, without the possibility of the kind of catastrophic counterparty failure that erased billions in user funds during the FTX debacle. By the end of 2023, decentralized exchanges had facilitated over $1 trillion in cumulative trading volume. As of early 2025, DEX trading volume regularly constitutes 15-20% of total cryptocurrency spot volume, a share that grows during every centralized exchange crisis.
But a decentralized exchange faces a problem that centralized exchanges solved long ago: how do you match buyers and sellers when there is no central order book, no high-frequency market makers with co-located servers, and every operation costs gas and takes seconds rather than microseconds? The answer — automated market makers — represents one of the most elegant innovations in the history of financial engineering. And to truly understand it, we need to derive it from scratch.
💡 Why This Chapter Matters: DEXs are not just an alternative to centralized exchanges — they are the foundation of all DeFi. Lending protocols, derivatives platforms, yield aggregators, and stablecoins all depend on the liquidity and price discovery that DEXs provide. Understanding AMMs is prerequisite to understanding everything else in the DeFi ecosystem.
22.1 Order Book DEXs vs. Automated Market Makers
How Traditional Markets Work
Every financial market in human history has solved the same core problem: connecting people who want to buy an asset with people who want to sell it. The dominant solution for centuries has been the order book — a ranked list of buy orders (bids) and sell orders (asks), sorted by price.
In a traditional order book:
- Makers post limit orders: "I will buy 1 ETH at $2,000" or "I will sell 1 ETH at $2,010."
- Takers post market orders: "I want to buy 1 ETH at the best available price."
- The exchange's matching engine pairs takers with makers, executing trades at the best available price.
- Professional market makers provide liquidity by continuously posting both buy and sell orders, earning the bid-ask spread as profit.
This model works extraordinarily well on centralized exchanges. The NYSE's matching engine handles millions of orders per second. Binance processes hundreds of thousands of trades per second with sub-millisecond latency. The key to this performance is centralization: all orders flow to a single server that can instantly match buyers and sellers.
Why On-Chain Order Books Are Impractical
Now imagine running an order book on Ethereum. Every limit order — placing it, modifying it, canceling it — is a transaction that costs gas and takes 12 seconds to confirm. A professional market maker on a centralized exchange might place and cancel thousands of orders per second as prices fluctuate. On Ethereum at approximately $5 per transaction, that market maker would spend millions of dollars per day on gas fees alone, just to manage their order book positions.
The fundamental constraint is throughput and cost. Ethereum processes roughly 15-30 transactions per second with finality times of 12 seconds (or 12 minutes for full economic finality). A traditional exchange matching engine processes millions of operations per second with microsecond latency. The mismatch is not a factor of 10 or 100 — it is a factor of roughly one million.
This creates several cascading problems:
- Stale orders. Market makers cannot update their quotes fast enough. By the time a cancel transaction confirms, the price may have moved significantly, leaving the market maker exposed to adverse selection.
- Front-running. Because pending transactions are visible in the mempool before confirmation, attackers can see incoming market orders and place their own orders ahead of them.
- Prohibitive cost. The gas cost of maintaining a competitive order book makes it economically unviable for most market makers.
- Thin books. Without professional market makers, order books are thin, leading to high slippage for traders and a poor user experience.
Some projects have attempted on-chain order books on faster chains (Serum on Solana, dYdX on StarkEx), and these approaches work better when the underlying chain is fast and cheap enough. But on Ethereum — the chain with the deepest DeFi ecosystem — a fundamentally different approach was needed.
The AMM Breakthrough
The automated market maker eliminates the order book entirely. Instead of matching discrete buy and sell orders, an AMM uses a mathematical formula to determine the price of an asset based on the ratio of assets in a liquidity pool.
The insight is deceptively simple: instead of relying on market makers to post orders, anyone can deposit pairs of tokens into a pool. The pool itself becomes the counterparty for every trade. A mathematical function determines the price at which the pool will trade, based on the current ratio of tokens it holds.
No order matching. No bid-ask spread management. No market maker infrastructure. Just a function, a pool of assets, and a smart contract that enforces the rules.
The concept was not invented for crypto. The idea of a constant function market maker was described by economist Robin Hanson in 2003 in the context of prediction markets. Vitalik Buterin discussed the concept in a 2016 blog post. Bancor launched an early implementation in 2017. But it was Hayden Adams's Uniswap, launched in November 2018, that turned the concept into a practical, gas-efficient, composable protocol that would become the cornerstone of DeFi.
📊 By the Numbers: As of early 2025, Uniswap alone has facilitated over $2.2 trillion in cumulative trading volume across Ethereum and Layer 2 networks. Uniswap V3 regularly accounts for 60-70% of all DEX volume on Ethereum. The protocol has generated over $3.8 billion in cumulative fees for liquidity providers.
22.2 Deriving the Constant Product Formula
This is the mathematical heart of the chapter. We are going to derive the constant product formula from first principles — not because it is the only AMM formula (it is not), but because it is the most important one, and understanding its derivation illuminates the logic behind all AMM designs.
The Problem: A Pool Needs a Pricing Function
Suppose we have a liquidity pool containing two tokens: ETH and USDC. The pool currently holds:
- x = 100 ETH
- y = 200,000 USDC
A trader wants to buy some ETH from the pool by depositing USDC. The pool needs a rule — a pricing function — that determines how much ETH the trader receives for a given amount of USDC.
What properties should this pricing function have?
Property 1: The price should reflect supply and demand. If the pool has a lot of ETH and very little USDC, ETH should be cheap (in USDC terms). If the pool has very little ETH and a lot of USDC, ETH should be expensive.
Property 2: The pool should never run out of either token. No matter how large a trade, the pool should always have some of both tokens remaining. Otherwise, the pool ceases to function.
Property 3: The function should be deterministic and simple. It must be computable on-chain with minimal gas. Complex functions with iterative calculations are impractical in the EVM.
Starting from First Principles
Let us define:
- x = quantity of Token A (ETH) in the pool
- y = quantity of Token B (USDC) in the pool
- The marginal price of Token A in terms of Token B is the rate at which you can exchange an infinitesimally small amount of A for B. In a standard market, this would be the spot price.
We want a function f(x, y) = constant that satisfies our three properties.
Consider the simplest approach: a linear function.
f(x, y) = x + y = k
This would mean: 1 ETH always costs 1 USDC, regardless of the pool's composition. That is clearly wrong — it does not reflect supply and demand at all. A trader could drain all the ETH from the pool and the price would never change.
What about f(x, y) = x * y = k?
Let us investigate. If x = 100 (ETH) and y = 200,000 (USDC):
k = 100 * 200,000 = 20,000,000
The marginal price of ETH in USDC is:
P = y / x = 200,000 / 100 = 2,000 USDC per ETH
Now suppose a trader buys 10 ETH from the pool. The pool's ETH decreases from 100 to 90. To maintain the constant product:
90 * y_new = 20,000,000
y_new = 20,000,000 / 90 = 222,222.22 USDC
The trader deposited 222,222.22 - 200,000 = 22,222.22 USDC to receive 10 ETH. That is an average price of 2,222.22 USDC per ETH — higher than the starting price of 2,000 because the trade itself moved the price.
Let us verify that this function satisfies our three properties:
Property 1 (reflects supply and demand): After the trade, the new marginal price is:
P_new = y_new / x_new = 222,222.22 / 90 = 2,469.14 USDC per ETH
The price of ETH went up because there is now less ETH in the pool and more USDC. A subsequent buyer of ETH will pay a higher price. A seller of ETH (buyer of USDC) will receive a better rate. Supply and demand, encoded mathematically.
Property 2 (never runs out): As x approaches 0, y approaches infinity (since x * y = k). The price of buying the last unit of ETH becomes infinite. Similarly, as y approaches 0, x approaches infinity. The function asymptotically approaches both axes but never touches them. The pool can never be fully drained.
Property 3 (simple and deterministic): Multiplication is one of the cheapest operations in the EVM. No iteration, no approximation, no oracle calls.
The Full Swap Calculation
Let us formalize the swap. A trader deposits delta_y of Token B to receive delta_x of Token A.
Before the swap: x * y = k
After the swap: (x - delta_x) * (y + delta_y) = k
Setting these equal:
x * y = (x - delta_x) * (y + delta_y)
Solving for delta_x:
(x - delta_x) = x * y / (y + delta_y)
delta_x = x - [x * y / (y + delta_y)]
delta_x = x * delta_y / (y + delta_y)
This is the core formula. The amount of Token A received is:
delta_x = x * delta_y / (y + delta_y)
Let us verify with our example. The trader deposits delta_y = 22,222.22 USDC:
delta_x = 100 * 22,222.22 / (200,000 + 22,222.22) = 2,222,222 / 222,222.22 = 10 ETH
Correct.
A Table of Successive Swaps
To build intuition, let us trace five successive purchases of ETH from the same pool, each costing 20,000 USDC:
| Trade # | USDC In | ETH Before | USDC Before | k | ETH Out | Avg Price (USDC/ETH) | Marginal Price After |
|---|---|---|---|---|---|---|---|
| 1 | 20,000 | 100.00 | 200,000 | 20M | 9.09 | 2,200.00 | 2,420.00 |
| 2 | 20,000 | 90.91 | 220,000 | 20M | 7.58 | 2,640.00 | 2,880.00 |
| 3 | 20,000 | 83.33 | 240,000 | 20M | 6.41 | 3,120.00 | 3,380.00 |
| 4 | 20,000 | 76.92 | 260,000 | 20M | 5.49 | 3,640.00 | 3,920.00 |
| 5 | 20,000 | 71.43 | 280,000 | 20M | 4.76 | 4,200.00 | 4,480.00 |
Observe several critical properties:
- Each successive trade of the same size receives fewer tokens than the previous one.
- The marginal price increases after each trade — this is how the AMM discovers the price.
- The average execution price is always worse than the starting marginal price — this difference is called price impact (or slippage in informal usage).
- Even after five trades draining significant ETH, the pool still has 66.67 ETH. It can never be fully drained.
Why the Constant Product, Specifically?
The constant product is not the only possible invariant. Here are some alternatives:
Constant sum: x + y = k. This gives zero price impact but allows the pool to be fully drained. Useless for volatile token pairs, but useful insight: a constant sum AMM is equivalent to a fixed exchange rate.
Constant mean: x^w1 * y^w2 = k (where w1 + w2 = 1). This is the generalization used by Balancer. When w1 = w2 = 0.5, it reduces to the constant product. Different weights create pools with different equilibrium ratios — for example, an 80/20 pool rather than 50/50.
StableSwap (Curve): a hybrid between constant sum and constant product. Near the equilibrium price (e.g., 1 DAI = 1 USDC), it behaves like a constant sum (low slippage). Far from equilibrium, it transitions to constant product behavior (preventing drainage). This is optimal for trading between assets that should have similar prices, like stablecoins.
The constant product won the early DEX wars because it is the simplest invariant that satisfies all three properties. It requires no parameters, no governance, and no oracle. A Uniswap V2 pool can be deployed for any pair of ERC-20 tokens with zero configuration.
⚠️ Common Misconception: The constant product formula does not set the "correct" price. It provides a mechanism for the market to discover the price through arbitrage. If the pool price diverges from the true market price, arbitrageurs will trade against the pool until the prices converge. The AMM is a passive price-taker that relies on external arbitrageurs for price accuracy.
22.3 Uniswap V1 and V2 Architecture
Uniswap V1: The Proof of Concept
Uniswap V1, launched on the Ethereum mainnet on November 2, 2018, was stunningly simple. The entire protocol consisted of fewer than 500 lines of Vyper code. Its constraints were severe but clarifying:
- Every pool paired an ERC-20 token against ETH (no direct token-to-token swaps).
- Each token could have only one pool on the protocol.
- No protocol fee — 0.3% of every trade went entirely to liquidity providers.
Despite these limitations, V1 demonstrated that on-chain AMMs were viable. Within months, it had attracted millions of dollars in liquidity and was processing thousands of trades daily.
Uniswap V2: The Production System
Uniswap V2, launched in May 2020, addressed V1's limitations while preserving its core simplicity:
Direct ERC-20 to ERC-20 pairs. Any pair of ERC-20 tokens could form a pool, eliminating the requirement to route through ETH. This halved gas costs for many trades and enabled more efficient pricing for correlated assets.
Price oracles. V2 introduced time-weighted average prices (TWAPs) that other contracts could use as manipulation-resistant price feeds. At the end of each block, the contract accumulated the price * time product, enabling other protocols to compute a time-weighted average over any interval.
Flash swaps. Borrowing from the flash loan concept, V2 allowed traders to receive tokens before paying for them, as long as payment (or return of tokens) happened within the same transaction. This enabled arbitrage without upfront capital.
Protocol fee switch. A governance-controlled parameter that could redirect 1/6 of the 0.3% trading fee (i.e., 0.05%) from LPs to the protocol. This fee switch was initially turned off but represented a future monetization mechanism.
The Anatomy of a Swap
Let us trace a complete swap through Uniswap V2:
Step 1: The trader initiates a swap. Alice wants to swap 1,000 USDC for ETH. She calls the Uniswap Router contract, specifying the input token (USDC), the output token (ETH), the input amount (1,000 USDC), and a minimum output amount (her slippage tolerance).
Step 2: The Router identifies the pool. The Router queries the Factory contract for the USDC-ETH pool address. In V2, each unique token pair has exactly one pool, deterministically addressed using CREATE2.
Step 3: Token transfer and swap. The Router transfers Alice's 1,000 USDC to the pool contract. The pool calculates the output amount using the constant product formula (minus the 0.3% fee):
Input amount after fee: 1,000 * 0.997 = 997 USDC
Output amount: (ETH_reserve * 997) / (USDC_reserve + 997)
Step 4: Output transfer. The pool sends the calculated ETH amount to Alice (or to the next pool, if this is a multi-hop swap).
Step 5: Reserve update. The pool updates its internal reserve balances. The new reserves satisfy x * y >= k (strictly greater than because of accumulated fees).
Liquidity Provider Tokens
When a liquidity provider deposits tokens into a pool, they receive LP tokens proportional to their share of the pool. These LP tokens are themselves ERC-20 tokens that can be transferred, traded, or used in other DeFi protocols.
The math is straightforward. If a pool has 100 ETH and 200,000 USDC with 1,000 LP tokens outstanding, and a new LP deposits 10 ETH and 20,000 USDC (10% of the existing pool), they receive 100 LP tokens (10% of the outstanding supply).
When the LP withdraws, they burn their LP tokens and receive their proportional share of the pool's current reserves. If the pool has grown to 120 ETH and 240,000 USDC (from accumulated fees), the LP burning 100 of 1,100 total LP tokens receives:
- 120 * (100/1,100) = 10.91 ETH
- 240,000 * (100/1,100) = 21,818.18 USDC
The difference between what they deposited and what they withdraw includes their share of accumulated trading fees. But it also reflects any impermanent loss, which we will now calculate in detail.
🔗 Code Connection: See
code/SimpleAMM.solfor a minimal Solidity implementation of a constant product pool with add/remove liquidity and swap functions.
22.4 Calculating Impermanent Loss
Impermanent loss is the most important concept for anyone providing liquidity to an AMM. It is also one of the most frequently misunderstood. We are going to calculate it from scratch with real numbers, derive the general formula, and demonstrate exactly when and why it matters.
The Setup
Alice deposits into a Uniswap V2 ETH/USDC pool:
- 5 ETH at a price of $2,000/ETH = $10,000
- 10,000 USDC = $10,000
- Total deposit: $20,000 (50/50 split as required by the constant product formula)
At this point, the pool has reserves of x = 5 ETH and y = 10,000 USDC (for simplicity, assume Alice is the only LP). The constant product is:
k = 5 * 10,000 = 50,000
The Price Change
Time passes. ETH's price on the broader market rises from $2,000 to $4,000 — a 2x increase. Arbitrageurs trade against the pool to bring its price in line with the market. Remember: the pool does not know the external price. Arbitrageurs enforce price alignment by profiting from any discrepancy.
After arbitrage, the pool price must reflect ETH = $4,000. In the pool, the price of ETH in USDC is:
P = y / x = 4,000
And the constant product must still hold:
x * y = 50,000
We have two equations and two unknowns:
- y / x = 4,000
- x * y = 50,000
From equation 1: y = 4,000x
Substituting into equation 2: x * 4,000x = 50,000
4,000x^2 = 50,000
x^2 = 12.5
x = 3.536 ETH
y = 4,000 * 3.536 = 14,142.14 USDC
Verification: 3.536 * 14,142.14 = 50,000.05 (rounding). Price: 14,142.14 / 3.536 = 4,000.04. Correct.
Calculating Alice's Loss
Pool value (what Alice actually has):
- 3.536 ETH * $4,000 = $14,142.14
- 14,142.14 USDC = $14,142.14
- Total pool value: $28,284.27
HODL value (what Alice would have if she had simply held her original tokens):
- 5 ETH * $4,000 = $20,000
- 10,000 USDC = $10,000
- Total HODL value: $30,000
Impermanent loss:
- Dollar difference: $30,000 - $28,284.27 = $1,715.73
- Percentage: 1 - (28,284.27 / 30,000) = 1 - 0.9428 = 5.72%
Alice's pool position is worth $1,715.73 less than if she had simply held her tokens. This is impermanent loss.
The General Formula
We can generalize this calculation. Let r be the price ratio (new price / old price). In our example, r = 4,000/2,000 = 2.
The impermanent loss formula is:
IL = 2 * sqrt(r) / (1 + r) - 1
Let us verify: IL = 2 * sqrt(2) / (1 + 2) - 1 = 2 * 1.4142 / 3 - 1 = 2.8284 / 3 - 1 = 0.9428 - 1 = -0.0572 = -5.72%
This matches our worked calculation exactly.
Derivation of the General Formula
For those wanting the complete derivation:
Let the initial reserves be x_0 and y_0, with initial price P_0 = y_0 / x_0.
The constant product: k = x_0 * y_0.
After the price changes to P_1 = r * P_0:
New reserves: x_1 = sqrt(k / P_1) = sqrt(k / (r * P_0)) and y_1 = sqrt(k * P_1) = sqrt(k * r * P_0).
Value of pool position: V_pool = x_1 * P_1 + y_1 = 2 * sqrt(k * P_1).
Value of HODL position: V_hodl = x_0 * P_1 + y_0 = x_0 * r * P_0 + y_0.
Since P_0 = y_0 / x_0, we have x_0 * P_0 = y_0, so V_hodl = r * y_0 + y_0 = y_0 * (1 + r).
And V_pool = 2 * sqrt(x_0 * y_0 * r * P_0) = 2 * sqrt(y_0^2 * r) = 2 * y_0 * sqrt(r).
Therefore: IL = V_pool / V_hodl - 1 = 2 * sqrt(r) / (1 + r) - 1.
Impermanent Loss at Various Price Ratios
| Price Change | Price Ratio (r) | Impermanent Loss |
|---|---|---|
| 1.1x (10% up) | 1.1 | -0.11% |
| 1.25x (25% up) | 1.25 | -0.16% |
| 1.5x (50% up) | 1.5 | -0.41% |
| 2x (double) | 2.0 | -5.72% |
| 3x (triple) | 3.0 | -13.40% |
| 4x (quadruple) | 4.0 | -20.00% |
| 5x | 5.0 | -25.46% |
| 10x | 10.0 | -42.50% |
| 0.5x (halves) | 0.5 | -5.72% |
| 0.25x (drops 75%) | 0.25 | -20.00% |
| 0.1x (drops 90%) | 0.1 | -42.50% |
Several crucial observations:
- IL is symmetric: a 2x increase and a 2x decrease (0.5x) produce the same IL (-5.72%).
- IL is always negative (or zero). The pool position is always worth less than or equal to the HODL position.
- IL is nonlinear: a 10x price change produces 42.5% IL, devastating for LPs.
- For small price changes (under 25%), IL is negligible. This is why stablecoin pools (where prices barely move) are popular LP destinations.
When "Impermanent" Becomes Permanent
The term "impermanent" is somewhat misleading. The loss is called impermanent because if the price returns to its original value, the loss disappears — the pool rebalances back to the original composition. But this ignores three realities:
-
Opportunity cost is real. While the price was away from the starting point, Alice's capital was worth less than if she had held. She missed the opportunity to sell at the top or redeploy capital.
-
Withdrawal makes it permanent. If Alice withdraws while the price has moved, the loss crystallizes. It was "impermanent" only in the sense that it was unrealized.
-
Fees must offset IL. For LP profitability, trading fees earned must exceed impermanent loss. A pool with 5.72% IL and 8% annualized fee income is profitable. A pool with 5.72% IL and 2% fee income is not.
⚠️ Key Insight: Providing liquidity to an AMM is economically equivalent to selling a straddle — a type of options position that loses money when the underlying asset moves significantly in either direction. LPs are implicitly short volatility. They profit when prices are stable (fees accumulate, IL is minimal) and lose when prices are volatile (IL exceeds fees). This framing, first articulated by researcher Guillaume Lambert in 2021, fundamentally changed how sophisticated LPs think about their positions.
📊 Code Connection: See
code/impermanent_loss.pyfor a script that calculates and visualizes IL across a range of price ratios.
22.5 Uniswap V3: Concentrated Liquidity
Uniswap V3, launched in May 2021, introduced the single most important innovation in AMM design since the constant product formula itself: concentrated liquidity.
The Capital Efficiency Problem
In Uniswap V2, a liquidity provider's capital is spread across the entire price curve — from zero to infinity. But most trading occurs in a narrow price range. If ETH is trading at $2,000, virtually no trading happens at the $50 or $50,000 price points. Yet a V2 LP's capital is allocated to those price ranges, sitting idle and earning no fees.
How inefficient is this? Consider an ETH/USDC pool where 99% of trading volume occurs between $1,500 and $2,500. A V2 LP with $100,000 deposited has roughly $100,000 * ($2,500 - $1,500) / ($infinity - $0) of that capital actively participating in trades within the relevant range. In practice, the capital efficiency of a V2 position is often below 0.5% — meaning over 99.5% of deposited capital is doing nothing.
The Concentrated Liquidity Solution
Uniswap V3 allows LPs to choose a price range for their liquidity. Instead of providing liquidity from 0 to infinity, an LP can specify: "I want to provide liquidity for ETH/USDC only between $1,800 and $2,200."
Within that range, the LP's capital is effectively magnified. If the range is 1/10th of the full range that their V2 position would cover, their capital is approximately 10x more effective at facilitating trades.
The V3 position, if the price stays within the chosen range, earns roughly the same fees as a V2 position with much more capital. Uniswap's documentation reported capital efficiency improvements of up to 4,000x for tightly concentrated positions in stable pairs.
How Ticks Work
V3 divides the price space into discrete ticks. Each tick represents a 0.01% price change (specifically, each tick is a multiplicative factor of 1.0001). The price at tick i is:
P(i) = 1.0001^i
LPs specify their position as a range [tick_lower, tick_upper]. Their liquidity is active only when the current price is within this range.
Fee tiers determine the minimum tick spacing:
| Fee Tier | Tick Spacing | Intended Use |
|---|---|---|
| 0.01% | 1 | Very stable pairs (USDC/USDT) |
| 0.05% | 10 | Stable pairs (DAI/USDC) |
| 0.30% | 60 | Standard pairs (ETH/USDC) |
| 1.00% | 200 | Exotic/volatile pairs |
The Trade-off: Active Management Required
Concentrated liquidity transforms LPing from a passive activity into an active one:
-
Range selection. LPs must choose a price range. Too narrow, and the price moves out of range frequently, earning zero fees. Too wide, and capital efficiency is low. The optimal range depends on expected volatility — which is itself uncertain.
-
Rebalancing. When the price moves out of an LP's range, they must decide whether to wait (hoping the price returns) or close the position and open a new one in the current range (incurring gas costs and potentially crystallizing losses).
-
Impermanent loss is amplified. Concentrated liquidity magnifies both fee income and impermanent loss. An LP with a $1,900-$2,100 range on ETH experiences the same IL as a V2 LP with approximately 20x more capital. If ETH moves to $2,500, the concentrated LP's position is 100% USDC and 0% ETH — maximum IL for that range.
-
LP tokens are non-fungible. Because each position has a unique range, V3 LP positions are represented as NFTs, not fungible ERC-20 tokens. This makes them harder to use as collateral in other protocols.
LP as an Options-Like Position
The economic structure of a V3 LP position closely resembles selling a covered call and a cash-secured put simultaneously — a "short strangle" in options terminology.
- If the price stays within the range, the LP earns fees (analogous to collecting option premiums).
- If the price moves above the range, the LP ends up holding 100% of the lower-valued token (like having their shares called away in a covered call).
- If the price moves below the range, the LP ends up holding 100% of the higher-valued token (like being put the shares in a cash-secured put).
This insight has spawned an entire sub-ecosystem of active LP management protocols like Gamma Strategies, Arrakis Finance, and Kamino Finance, which automate range management on behalf of LPs, effectively acting as volatility-adjusted market making systems.
A Worked Comparison: V2 vs. V3 Capital Efficiency
To make the capital efficiency improvement concrete, consider two LPs, each with $100,000:
LP-A (Uniswap V2): Deposits $50,000 in ETH and $50,000 in USDC across the full price range (0 to infinity). At the current ETH price of $2,000, this is 25 ETH and $50,000 USDC.
LP-B (Uniswap V3): Deposits $50,000 in ETH and $50,000 in USDC in the range $1,800 to $2,200 only.
The effective liquidity within the $1,800-$2,200 range is dramatically different. LP-B's $100,000, concentrated in a 20% price range, provides the same liquidity depth as approximately $1,100,000 in a V2 position within that range — an 11x capital efficiency improvement.
In a single day where the ETH/USDC pool within this range processes $5 million in trading volume at a 0.3% fee:
- LP-A's fee share: Proportional to their full-range liquidity. If the pool has $50 million TVL, LP-A earns roughly ($100,000 / $50,000,000) * $5,000,000 * 0.003 = $30.
- LP-B's fee share: Their concentrated position captures approximately 11x more fees within the range. LP-B earns roughly $330 — eleven times LP-A's income.
However, if ETH's price moves to $2,500 (outside LP-B's range), LP-B earns zero fees while LP-A continues earning. And LP-B's impermanent loss within the range is amplified by the same 11x factor. This is the fundamental trade-off: concentrated liquidity amplifies everything — fees, impermanent loss, and the consequences of being wrong about the price range.
💡 Practical Insight: Most successful V3 LPs treat their positions like active trading strategies, not passive investments. They monitor price movements, adjust ranges based on volatility expectations, and use tools like Revert Finance to analyze their historical performance. The era of "deposit and forget" ended with V2.
22.6 MEV and Sandwich Attacks
The transparent mempool that makes Ethereum's decentralization possible also creates a predatory trading environment unlike anything in traditional finance. Maximal Extractable Value (MEV) — the profit that block producers (and others) can extract by including, excluding, or reordering transactions within a block — is a fundamental challenge for DEXs.
How Sandwich Attacks Work
A sandwich attack is the most common and intuitive form of MEV extraction on DEXs. Here is how it works, step by step:
Step 1: Detection. A MEV searcher (a bot operator) monitors the Ethereum mempool and detects a pending swap transaction. Alice is attempting to swap 50,000 USDC for ETH on Uniswap, with a 1% slippage tolerance (she will accept up to 1% worse execution than the current price).
Step 2: Front-run. The searcher submits their own transaction to buy ETH with USDC before Alice's transaction, paying a higher gas price to ensure their transaction is included first. This pushes the price of ETH up.
Step 3: Victim execution. Alice's transaction executes at the now-worse price. Because the front-run pushed the price up, Alice receives fewer ETH than she would have without the attack. But she still receives enough to satisfy her 1% slippage tolerance, so her transaction does not revert.
Step 4: Back-run. The searcher immediately sells the ETH they bought in Step 2, at the now-higher price established by Alice's trade. The difference between the buy price (Step 2) and the sell price (Step 4), minus gas costs, is the searcher's profit.
A Worked Example
Pool state: 1,000 ETH and 2,000,000 USDC (k = 2,000,000,000). Price = 2,000 USDC/ETH.
Alice wants to buy ETH with 50,000 USDC. Without the attack:
delta_x = 1,000 * 50,000 / (2,000,000 + 50,000) = 50,000,000 / 2,050,000 = 24.39 ETH at an average price of $2,050.
Now the sandwich attacker front-runs with 100,000 USDC:
Attacker's buy: delta_x = 1,000 * 100,000 / (2,000,000 + 100,000) = 100,000,000 / 2,100,000 = 47.62 ETH
New pool state: 952.38 ETH, 2,100,000 USDC. Price = 2,205.00 USDC/ETH.
Alice's trade now executes against the worse pool state:
Alice's buy: delta_x = 952.38 * 50,000 / (2,100,000 + 50,000) = 47,619,000 / 2,150,000 = 22.15 ETH at an average price of $2,257.
Alice got 22.15 ETH instead of 24.39 ETH — she overpaid by approximately $4,576.
Pool state after Alice: 930.23 ETH, 2,150,000 USDC.
Attacker's back-run (sells 47.62 ETH):
delta_y = 2,150,000 * 47.62 / (930.23 + 47.62) = 102,383,000 / 977.85 = 104,683.47 USDC
Attacker's profit: 104,683.47 - 100,000 = $4,683.47 (before gas and MEV relay costs).
Attacker's net profit after ~$200 in gas/relay costs: approximately **$4,483**.
Alice paid approximately $4,576 more than she would have in a clean execution. The discrepancy between Alice's overpayment and the attacker's profit goes to the pool as fees and to the block producer as priority fees.
The MEV Supply Chain
The MEV ecosystem has evolved into a sophisticated supply chain:
- Searchers identify MEV opportunities (sandwich attacks, arbitrage, liquidations) and construct transaction bundles.
- Builders assemble blocks from submitted bundles, selecting the most profitable combination.
- Relays (like Flashbots' MEV-Boost relay) connect builders to validators, who select the most profitable block to propose.
- Validators earn the block reward plus MEV kickbacks from builders.
Mitigation Strategies
Several approaches aim to reduce MEV extraction:
Flashbots Protect: A private transaction relay that prevents transactions from being visible in the public mempool, making sandwich detection impossible.
MEV-Aware DEX designs: CoW Protocol (Coincidence of Wants) batches trades and uses a solver auction to find the best execution, explicitly protecting against MEV. Osmosis (on Cosmos) uses threshold encryption to hide transaction contents until they are committed.
Slippage management: Setting a lower slippage tolerance (e.g., 0.1% instead of 1%) makes sandwich attacks unprofitable for smaller trades, since the attacker's price impact must stay within the victim's tolerance.
Private order flow: Services like MEV Blocker by Flashbots allow users to route transactions through a system that auctions the right to back-run (but not front-run) the transaction, returning a portion of any extracted value to the user.
Other Forms of DEX-Related MEV
While sandwich attacks are the most visible form of MEV, several other categories are important for DEX participants to understand:
Arbitrage MEV. When an AMM's price diverges from the broader market (due to a large trade, or because the external price moved between blocks), arbitrageurs trade against the pool to capture the discrepancy. Unlike sandwich attacks, arbitrage MEV is generally considered beneficial — it is the mechanism by which AMM prices stay accurate. Without arbitrage MEV, AMMs would display stale prices indefinitely.
Just-in-Time (JIT) Liquidity. In V3 pools, a sophisticated LP can detect a large incoming swap in the mempool, add concentrated liquidity in the exact tick range the swap will traverse, earn fees from the swap, and immediately withdraw the liquidity — all in the same block. This "just-in-time" liquidity provision captures fees that would otherwise go to passive LPs. It is a form of MEV that increases liquidity for the trader (reducing their price impact) but dilutes fee income for long-term LPs.
Multi-block MEV. As of early 2025, there is growing concern about multi-block MEV — strategies that span two or more consecutive blocks. For example, a validator who controls two consecutive blocks can execute a sandwich attack across blocks (front-running in block N, back-running in block N+1), making the attack invisible within any single block. This is particularly concerning under proposer-builder separation, where block builders may gain sufficient market share to control consecutive block production.
📊 Code Connection: See
code/sandwich_attack.pyfor a simulation of a sandwich attack with configurable parameters.
22.7 DEX Aggregators
As the number of DEXs and liquidity pools has proliferated, the problem of finding the best execution across all available venues has spawned a new category of protocols: DEX aggregators.
The Routing Problem
Consider a trader wanting to swap 100,000 USDC for ETH. There might be ETH/USDC liquidity on:
- Uniswap V2 (one pool)
- Uniswap V3 (multiple fee tiers: 0.05%, 0.3%, 1.0%)
- Sushiswap
- Curve (if routing through a stablecoin intermediate)
- Balancer
- PancakeSwap
Each pool has different liquidity depth and therefore different price impact for the trade. The optimal execution might split the trade across multiple pools — perhaps 60% through Uniswap V3's 0.05% pool (deepest liquidity) and 40% through Uniswap V3's 0.3% pool — to minimize total price impact.
Furthermore, the best route might not be a direct swap. It might be cheaper to swap USDC to WBTC on Curve, then WBTC to ETH on Uniswap, even though this involves two hops, because the indirect route has less total price impact.
Major Aggregators
1inch. The largest DEX aggregator by volume. 1inch's Pathfinder algorithm splits trades across multiple DEXs and routes to minimize total slippage. 1inch also operates its own AMM (1inch Limit Order Protocol) that supports gasless limit orders.
Paraswap. Uses a proprietary routing algorithm called "MultiPath" that considers complex multi-hop routes. Paraswap is notable for its integration with institutional trading systems.
CoW Protocol (Coincidence of Wants). A fundamentally different approach. Instead of routing to on-chain DEXs, CoW Protocol batches user orders and attempts to find "coincidences of wants" — cases where one user wants to sell ETH for USDC and another wants to buy ETH with USDC, allowing a direct peer-to-peer match without touching any AMM. Only unmatched order flow goes to on-chain DEXs. This is inherently MEV-resistant because batch auctions eliminate the sequencing exploitation that makes sandwich attacks possible.
Jupiter. Dominant on Solana, Jupiter aggregates across Solana's DEX ecosystem (Raydium, Orca, Lifinity, etc.) and has become the default frontend for most Solana DeFi trading.
Aggregator Economics
Aggregators typically charge a small fee (often 0-0.3%) on top of the underlying DEX fees, or earn revenue through positive slippage capture — if the execution is better than the user's quoted price, the aggregator may keep the difference.
The aggregator business has created an interesting competitive dynamic: since aggregators route to the DEX offering the best price, they reduce the advantage of any single DEX having the deepest liquidity. This has been called the "aggregator-friendly" property of DeFi — pools that offer the best prices get the most routed volume, regardless of which DEX frontend the user is using.
Intent-Based Trading: The Next Evolution
A more recent evolution beyond traditional aggregation is intent-based trading. Instead of the user specifying a swap on a particular DEX, the user signs an "intent" — a statement like "I want to swap 1,000 USDC for at least 0.49 ETH within the next 2 minutes." A network of solvers then competes to fulfill this intent in the best way possible.
The solver might fill the intent from their own inventory (if they already hold ETH), route it through multiple DEXs, match it with an opposing intent from another user, or use a combination of strategies. The user does not care how the intent is fulfilled — only that they receive at least 0.49 ETH.
This intent-based model has several advantages over traditional aggregation:
- Delegation of complexity. The user does not need to understand routing, gas optimization, or MEV protection. They express what they want, and solvers compete to provide it.
- Cross-chain capability. An intent can span multiple chains — "swap my USDC on Ethereum for SOL on Solana" — with the solver handling the cross-chain mechanics.
- MEV internalization. Because solvers compete in an auction, any MEV that could be extracted is captured by the solver competition and returned to the user as better execution, rather than being leaked to block builders.
Protocols implementing intent-based models include UniswapX (Uniswap's own intent system), CoW Protocol, Across Protocol (for cross-chain intents), and 1inch Fusion. As of 2025, intent-based trading represents a growing share of DEX volume, and many analysts expect it to become the dominant trading paradigm within DeFi.
22.8 DEX vs. CEX: The Comprehensive Comparison
Understanding the trade-offs between decentralized and centralized exchanges is essential for any participant in the cryptocurrency ecosystem. The comparison is not a simple "one is better" narrative — each architecture makes fundamentally different trade-offs.
| Dimension | CEX (e.g., Binance) | DEX (e.g., Uniswap) |
|---|---|---|
| Custody | Exchange holds your assets | You hold your assets (self-custody) |
| Counterparty risk | Significant (FTX, Mt. Gox) | Minimal (smart contract risk only) |
| Liquidity depth | Very deep (billions in order books) | Growing but generally thinner |
| Price execution | Excellent (tight spreads, low impact) | Variable (depends on pool depth) |
| Latency | Milliseconds | 12+ seconds (Ethereum L1) |
| Trading fees | Low (0.02-0.1% for makers) | Higher (0.05-0.3% + gas) |
| Asset availability | Curated (exchange decides listings) | Permissionless (any ERC-20 token) |
| Privacy | KYC required (identity on file) | No KYC (pseudonymous by default) |
| Regulatory exposure | Fully regulated, can freeze accounts | Resistant to censorship |
| Uptime | Generally high but not guaranteed | 100% (as long as blockchain runs) |
| MEV exposure | None (internal matching) | Significant (mempool visibility) |
| Fiat on/off ramp | Yes | No (requires separate service) |
| Advanced orders | Yes (limit, stop-loss, etc.) | Limited (some protocols offer limits) |
| Insurance | Some exchanges insure deposits | No insurance (smart contract risk) |
The Convergence Trend
The distinction between CEX and DEX is blurring. Centralized exchanges are adding "proof of reserves" (adopting the transparency ethos of DeFi). DEXs on Layer 2 networks are achieving latency and cost that approaches centralized exchanges. Hybrid models like dYdX (which uses a centralized order book with decentralized settlement) attempt to combine the best of both worlds.
The long-term trajectory appears to be a spectrum rather than a binary: protocols making different trade-offs between performance, decentralization, and regulatory compliance, with users choosing based on their priorities.
When to Use Which
For practical guidance, consider the following decision framework:
Use a CEX when: - You need fiat on/off ramps (converting between dollars/euros and crypto). - You are trading large positions in major pairs (BTC/USD, ETH/USD) where CEX liquidity depth provides clearly better execution. - You need advanced order types (stop-loss, take-profit, trailing stops) that most DEXs do not support. - You are comfortable with the counterparty risk and have verified the exchange's security and regulatory standing.
Use a DEX when: - You want self-custody — you do not trust any third party to hold your assets. - You are trading tokens that are not listed on centralized exchanges (new launches, governance tokens, long-tail assets). - You need censorship resistance (you are in a jurisdiction where centralized exchanges restrict access or freeze accounts). - You are interacting with DeFi protocols (using a DEX swap as part of a larger DeFi transaction like collateral adjustment or yield strategy). - You value privacy and do not want your trading history tied to a KYC identity.
Use a DEX aggregator when: - You are making any trade above approximately $10,000, where the execution improvement from split routing exceeds the aggregator's fee. - You are trading across multiple pools or chains. - You want MEV protection (aggregators like CoW Protocol offer structural protection).
⚠️ Security Note: When using a DEX, verify the contract address of the token you are trading. Unlike CEXs, which curate their listings, DEXs allow anyone to create a token with any name and symbol. Fake tokens with names identical to legitimate projects are a common scam vector. Always verify contract addresses against official project documentation.
22.9 Building a Simple AMM
Having derived the math and studied Uniswap's architecture, let us now examine the implementation of a minimal constant product AMM in Solidity. The full annotated code is in code/SimpleAMM.sol, but we will walk through the critical functions here.
Core State
The contract maintains three state variables: the reserves of each token and the total supply of LP tokens.
uint256 public reserve0; // Balance of token0 in the pool
uint256 public reserve1; // Balance of token1 in the pool
uint256 public totalSupply; // Total LP tokens outstanding
Adding Liquidity
When a provider adds liquidity, the contract must:
- Accept deposits of both tokens in the current ratio (to avoid changing the price).
- Calculate the number of LP tokens to mint.
- Update reserves.
For the first deposit (when the pool is empty), LP tokens minted = sqrt(amount0 * amount1), establishing the initial k. For subsequent deposits, LP tokens are minted proportionally to the smaller of the two deposit ratios, ensuring the price is not changed by the deposit.
Executing a Swap
The swap function is the heart of the AMM:
- Accept an input amount of one token.
- Calculate the output amount using the constant product formula:
amountOut = reserveOut * amountIn / (reserveIn + amountIn). - Deduct a fee (0.3%) from the input before calculation.
- Transfer the output token to the trader.
- Update reserves and verify the constant product invariant holds.
Removing Liquidity
When a provider withdraws:
- They specify how many LP tokens to burn.
- The contract calculates their proportional share:
amount0 = reserve0 * lpAmount / totalSupply. - Both tokens are transferred to the provider.
- LP tokens are burned and reserves updated.
Security Considerations in Production AMMs
Our educational SimpleAMM demonstrates the core logic, but a production AMM must address several additional concerns:
Reentrancy protection. The contract transfers tokens to external addresses. A malicious token contract could re-enter the AMM's functions during a transfer, potentially manipulating state. Production AMMs use reentrancy guards (like OpenZeppelin's ReentrancyGuard) or follow the checks-effects-interactions pattern rigorously.
Minimum liquidity. Uniswap V2 permanently locks the first sqrt(1000) LP tokens (approximately 31.6 tokens) by sending them to the zero address. This prevents a rounding attack where the first LP could manipulate the LP token price by depositing a tiny amount of liquidity, then donating tokens to the pool to inflate the value per LP token, making it too expensive for subsequent LPs to deposit.
Integer overflow and rounding. Solidity 0.8+ provides overflow protection, but rounding errors in division can still accumulate. Production AMMs use careful ordering of operations (multiply before divide) and sometimes use higher-precision intermediate variables.
Oracle manipulation resistance. Uniswap V2's TWAP oracle accumulates price * time at the end of each block. This makes the oracle resistant to single-block manipulation — an attacker would need to sustain an incorrect price across multiple blocks, which is prohibitively expensive. V3 improves on this with a geometric mean TWAP.
Flash loan attacks. An attacker could use a flash loan to temporarily inflate pool reserves, manipulate LP token pricing, and drain value in a single transaction. The minimum liquidity lock and careful invariant checks mitigate this vector.
🔗 Code Connection: See
code/SimpleAMM.solfor the complete implementation with detailed comments explaining each line. Seecode/amm_simulation.pyfor a Python simulation that lets you experiment with adding liquidity, swapping, and calculating price impact without deploying to a blockchain.
22.10 Summary and Bridge to Chapter 23
This chapter established the core mechanism of DeFi's most foundational primitive: the automated market maker. We derived the constant product formula from first principles, showing that x * y = k is the simplest invariant that provides continuous pricing, prevents pool drainage, and can be computed cheaply on-chain. We calculated impermanent loss with real numbers, revealing that an LP who deposits $20,000 into a pool where the price of one asset doubles will have a position worth 5.72% less than if they had simply held — and that this loss grows nonlinearly with price divergence.
Uniswap's evolution from V1 to V3 illustrated the progressive refinement of the AMM concept. V1 proved feasibility. V2 made it production-grade with direct token pairs, TWAPs, and flash swaps. V3's concentrated liquidity transformed LPing from a passive activity into an active capital management challenge, offering up to 4,000x capital efficiency improvements at the cost of requiring active range management.
The dark side of on-chain trading — MEV and sandwich attacks — demonstrated that transparency (the ability to see pending transactions) creates predatory dynamics absent from traditional exchanges. The MEV supply chain (searchers, builders, relays, validators) has become a sophisticated ecosystem extracting billions of dollars annually from DEX traders.
We examined how DEX aggregators solve the routing problem by splitting trades across multiple venues for optimal execution, and how protocols like CoW Swap use batch auctions to achieve inherent MEV resistance.
The DEX vs. CEX comparison revealed that the two architectures make fundamentally different trade-offs. CEXs offer superior performance and liquidity depth. DEXs offer self-custody, censorship resistance, permissionless access, and elimination of counterparty risk. The FTX collapse in 2022 was a vivid demonstration of why these trade-offs matter.
In Chapter 23, we turn to the second pillar of DeFi: lending and borrowing protocols. Where this chapter examined how to exchange tokens, the next chapter examines how to lend them, borrow against them, and — when borrowers fail to maintain their collateral — liquidate them. The lending protocols we will study (Aave, Compound, MakerDAO) are the largest consumers of the liquidity that DEXs provide, and understanding them requires the AMM foundations we have now established.
Key Formulas from This Chapter:
| Formula | Meaning |
|---|---|
| x * y = k | Constant product invariant |
| delta_x = x * delta_y / (y + delta_y) | Output amount for a swap |
| P = y / x | Marginal price of token X in terms of token Y |
| IL = 2*sqrt(r)/(1+r) - 1 | Impermanent loss as a function of price ratio r |
| P(i) = 1.0001^i | Price at tick i (Uniswap V3) |