Getting up to speed on Uniswap v1 to v4 in 2025

I promise this only involves simple math & straightforward examples

It’s time for the Ethereum ecosystem to come together and cultivate our community of power users.

This is an attempt to get non-technical people in the community up to speed on Uniswap, a cornerstone DeFi primitive, by taking them through the journey from v1 to v4.

This writeup will be used as pre-reading materials for an upcoming roundtable discussion in Singapore. Feel free to sign up on Luma and join us.

Many thanks to YC from Uniswap Labs for helping to proofread!

TLDR; (1 minute)

1. Simplistic Market Makers:
Simplistic market maker mechanisms with naive automated pools (price = balance ratio) can be easily drained through arbitrage attacks

2. Uniswap v1: The Constant Product AMM
The x * y = k constant product formula prevents pool drainage by making large trades exponentially expensive, enabling permissionless liquidity provision

3. Uniswap v2: Direct token-to-token pairs
Direct token-to-token pairs eliminated constraints of swapping through ETH as the intermediary and added critical DeFi infrastructure (flash swaps, price oracles, routing)

4. Uniswap v3: Concentrated Liquidity
Liquidity providers can specify custom price ranges, achieving up to 4,000x capital efficiency but requiring active management.

5. Uniswap v4: Fully Customizable with Hooks
Platform Transformation: 150+ modular hooks enable unlimited customization (dynamic fees, MEV redistribution, auto-compounding) with massive gas savings

6. How power users use Uniswap & how the math works: Read on to find out 😎

(20 minutes)

Market Makers

Let’s start with some basic concepts.

A market maker is an entity that sells when you buy and buys when you sell. ie. making a market for an asset.

They determine a mid-point price by aggregating information on all buy & sell orders, and then charge some fees to users for facilitating their orders.

Access to large amounts of liquidity is key to being a market maker because you need to first take the opposite position from one user before closing the trade with another.

Simplistic Automated Market Makers

An automated market maker (AMM) does the same thing by automating the price discovery, trade execution, and liquidity provisioning.

It works by allowing any user to deposit 2 assets in a smart contract, forming a “liquidity pool” for the asset pair.

The price of each asset in a pool is determined at all times by the balance of each asset in the pool.

For example, if a liquidity pool contains 1,000,000 USDC and 400 ETH, then:

Price of 1 ETH = 2500 USDC
Price of 1 USDC = 0.0004 ETH

In other words,

Price(ETH) = Balance(USDC) / Balance(ETH)
Price(USDC) = Balance(ETH) / Balance(USDC)

Which generalises to:

P(x) = y/x
P(y) = x/y

When one asset decreases, the other asset increases. When one asset is being bought from the pool, it gets withdrawn, while the other asset gets deposited into the pool.

However, this means that we can drain the pool easily in a few steps:

- Starting pool balance = 1,000,000 USDC, 400 ETH; ETH Price = 2500 USDC
- Deposit 400 ETH in exchange for 1,000,000 USDC 
- Pool balance = 0 USDC, 800 ETH; ETH price = 0 USDC
- Deposit 1 USDC in exchange for 800 ETH 
- Pool balance = 1 USDC, 0 ETH
- Profit = 999,999 USDC + 400 ETH

This is because this simplistic relationship does not account for slippage, which is how price increases as you buy more of an asset and decreases as you sell more—something that happens in the real world!

For example, not everyone who provides ETH in the liquidity pool will want to sell them for 2500 USDC. Some would want to sell for 2600, 2700, 3000 etc.

Similarly, now everyone who provides USDC will want to buy ETH at 2500 USDC. Some might want to buy at 2400, 2300, 2000 etc.

In other words, if you want to sell 400 ETH into the pool as before, you might only get the first 50 ETH that are priced at 2500 USDC, the next 50 at 2400, the subsequent 50 at 2300, and so on.

How do we represent this relationship between the 2 assets?

Uniswap v1: The constant product AMM

Enter a key innovation of Uniswap, the constant product automated market maker.

The relationship between the two assets, x & y, now takes the shape of the famous
x * y = k curve.

Where:

x = balance of asset x
y = balance of asset y

k = a fixed number (constant) that is set when the pool is initially created according to the values of x & y. \

e.g., 400 (ETH) * 1,000,000 (USDC) = 400,000,000

How to interpret:

Indicator

Definition

What it means

A

When one asset decreases, the other asset increases

Need to swap one asset for the other

B

When one asset decreases much more, the other asset increases even more

For larger orders, you will need to swap increasing amounts of one asset for the other

C

The balances of x & y approaches infinity and do not cross their axes

Attempts to drain the pool is typically very costly and unprofitable

How do we determine the average price if we want to swap 400 ETH into the pool as before?

Let’s work backwards from x * y = k to build our intuition.

Step

Workings

Notes

Initial balance

400 (ETH) * 1,000,000 (USDC) = 400,000,000

x * y = k

Swap 400 ETH into pool

[400 + 400] (ETH) * new_y = 400,000,000

Recall that k is a constant

Solve for new_y

new_y = 400,000,000 / 800 (ETH)

new_y = 500,000 (USDC)

Find the new balance of USDC after the swap is executed

Solve for swap price

P(x) = [1,000,000 - 500,000] (USDC) / 400 (ETH)

P(x) = 1250 USDC

How many USDC you withdraw divided by how many ETH you deposited

As you can see, only half of the USDC balance is removed from the pool (vs all) by depositing 400 ETH balance under this new curve.

It is also highly unprofitable to do this because the average price is half of the midpoint price of 2500 USDC.

Overall, a great improvement!

Role of Arbitrageurs

The new pool (A) balance is 500,000 USDC + 800 ETH following the scenario above, implying a mid-point ETH price of 625 USDC.

If the price of ETH in another pool (B) is still at 2500 USDC, the logical thing to do is to deposit USDC into this pool (A) to withdraw ETH, and then swap the ETH for USDC on pool (B).

This effectively allows you to buy ETH for a lower price and sell them for a higher price until the prices of both pools converge.

Arbitrageurs play a crucial role in balancing pools on Uniswap v1 & v2 in this way.

By capitalizing on price discrepancies across different pools, they effectively drive prices of all various pairs towards an equilibrium state.

Liquidity providers, swap fees, and impermanent loss

What are Liquidity Providers?

Anyone can create a liquidity pool on Uniswap and provide liquidity in the pool to earn fees whenever users swap one asset with another in this pool.

These users are called Liquidity Providers (LP)

They will need to deposit the pair assets in the same ratio as the pool balance. e.g., providing liquidity in a pool with 1,000,000 USDC and 400 ETH will require Liquidity Providers to deposit both both USDC & ETH in a 2500:1 ratio.

In return, they will receive ERC-20 LP tokens representing their share of the pool. These tokens are fungible, can be freely transferred, and are composable. e.g., used across DeFi as collateral.

How do Swap Fees work?

On Uniswap v1, Liquidity Providers earn a 0.3% fee per swap on the input asset amount. This fee is deducted from the input amount before the swap calculation is performed.

Using the same example from before, swapping 400 ETH for 500,000 USDC will effectively become a swap of 398.8 ETH for 499,248.87 USDC after applying fees.

However, the swapper will still deposit the entire 400 ETH. The 1.2 ETH difference here gets added to the liquidity pool while 751.13 less USDC gets withdrawn from the pool compared to the initial scenario.

This 1.2 ETH swap fee is then distributed to all Liquidity Providers of the pool according to how much liquidity each of them provided.

More liquidity provided = Higher share of fees.

Because swap fees are added to the liquidity pool, the product of both assets in the pool (k) increases over time. i.e., the constant product formula is actually not that constant!

The math works as follows:

Step

Workings

Notes

Initial balance

400 (ETH) + 1,000,000 (USDC) = 400,000,000

x * y = k

User wants to swap
400 ETH

Swap fees = 0.3% * 400 ETH
Swap fees = 1.2 ETH

Swap amount = 400 - 1.2 ETH = 398.8 ETH

Swap fees are deducted from the input amount before the swap calculation is performed.

Calculate exchange on swap amount of 398.8 ETH

[398.8 + 400] (ETH) + new_y (USDC) = 400,000,000

For calculation purposes, we exclude swap fees & k is still the initial amount at this step

Solve for new_y

new_y = 400,000,000 / 798.8 (ETH)

new_y = 500,751.13 (USDC)

Slightly higher than the example without fees

Solve for swap price

P(x) = [1,000,000 - 500,751.13] (USDC) / 400 (ETH)

P(x) = 1248.12 USDC

User receives 499,248.87 USDC for their 400 ETH (effective rate of 1,248.12 USDC per ETH)

Solve for new pool balance

x * y = k

[1.2 + 398.8 + 400] (ETH) * 500,751.13 (USDC) = 400,600,904

Once the swap completes, we can add swap fees into back our calculations and k increases as a result

Solve for new ETH price in pool

P(x) = 500,751.13 (USDC) / 800 (ETH)

P(x) = 625.94 USDC

Slightly higher than the example without fees

Summary:

- User deposits: 400 ETH 
- Fee paid: 1.2 ETH (stays in pool) 
- USDC received: 499,248.87 USDC 
- Net exchange rate: ~1,248 USDC per ETH

Impermanent Loss

When the prices of token pairs in a liquidity pool change from what they were when the liquidity was added, it results in a loss of value for the Liquidity Provider versus simply holding both tokens.

These price changes happen when users swap more of one token for the other (e.g., more buying pressure for ETH), causing the balance the token pairs in a pool to change from the time of deposit.

Let’s look at a simple example below (ignoring the effect of swap fees).

Step

Workings

Notes

Initial balance

400 (ETH) * 1,000,000 (USDC) = 400,000,000

x * y = k

Add 100 ETH + 250,000 USDC liquidity to pool

500 (ETH) * 1,250,000 (USDC) = 625,000,000

Share of pool = 20%

Assets are added in the same 1:2500 ratio as the current pool balance

Price of ETH increases to $3000 on other markets

NA

No change to pool yet

Arbitrageurs swap USDC for ETH in pool until ratio is 1:3000

456.44 (ETH) × 1,369,306 (USDC) = 625,000,000

The math for this is not important for now.

new_x = sqrt(k/P_target)
new_y = sqrt(k P_target)

Value of 20% share of pool

Share of pool: 91.287 (ETH) + 273,861 (USDC)

Value of ETH in USDC terms:
91.287 (ETH) × $3000 = 273,861 (USDC)

Total value in USDC terms: 547,722

20% * pool balance

Value if simply hold

100 ETH * $3000 + 250,000 USDC = 550,000 USDC

Liquidity not provided in pool

Impermanent Loss (IL)

IL = Value if HODL - Value if LP

IL = 550,000 - 547,722
IL = 2,278 USDC

IL % = 0.41%

Note: The same effect also applies if the price of ETH decreases

As you can see, some loss is observed when market prices increase compared to simply holding the 2 tokens. The same loss percentage will be observed if prices decrease by the same ratio.

e.g., ETH dropping from $2500 to $2083 would also result in a 0.41% impermanent loss.

However, this loss will be completely reversed if the price of ETH reverts to $2500 on other markets and arbitrageurs bring the pool balance back to the point when the LP deposited the asset pair.

This is why the loss is defined as “impermanent”.

Because LPs also accumulate swap fees over time, they profit if the price of ETH stays the same as or reverts to the point of their deposit.

Some useful data illustrating the impact of impermanent loss from Pintail and the Uniswap docs below.

Mathematical approximation:

Impermanent Loss % = 2√r/(1+r) - 1

Where:
r = ending price / starting price

Example 1: 
If ETH goes from $2500 to $3000
r = $3000/$2500 = 1.2
Impermanent Loss % = 2√1.2/(1+1.2) - 1 = -0.5%

Example 2:
If ETH goes from $2500 to $2083 (same 1.2x ratio in reverse)
r = $2083/$2500 = 0.833
Impermanent Loss % = 2√0.833/(1+0.833) - 1 = -0.5%

Graphical approximation

Graph illustrating the impact of Impermanent Loss from the Uniswap docs

Intuitive approximation:

"Or to put it another way:"
"a 1.25x price change results in a 0.6% loss relative to HODL"

"a 1.50x price change results in a 2.0% loss relative to HODL"

"a 1.75x price change results in a 3.8% loss relative to HODL"

"a 2x price change results in a 5.7% loss relative to HODL"

"a 3x price change results in a 13.4% loss relative to HODL"

"a 4x price change results in a 20.0% loss relative to HODL"

"a 5x price change results in a 25.5% loss relative to HODL"

"N.B. The loss is the same whichever direction the price change occurs in (i.e. a doubling in price results in the same loss as a halving)."

Fun Fact

In Uniswap v1, all liquidity pools were required to be denominated in ETH. e.g., USDC/ETH, DAI/ETH, WBTC/ETH, etc.

This means that swapping from DAI to USDC must route through two pools.

  • Swap DAI to ETH on DAI/ETH pool

  • Swap ETH to USDC on USDC/ETC pool

This was inefficient because it incurred gas costs, swap fees, and slippage twice.

Fortunately, this was greatly improved in Uniswap v2, along with a couple of other cool features!

Uniswap v2: Same math with new and improved features

Direct Token-to-Token Swaps

The most notable improvement in Uniswap v1 was that it allowed liquidity pools to be created with any two ERC-20 tokens.

Benefits:

1) Swappers only need to pay gas, swap fees, and slippage once when swapping between two ERC-20 tokens.

2) Liquidity Providers do not have to maintain exposure to ETH if they do not wish to

As you can imagine, this led to a Cambrian explosion of liquidity pools containing different ERC20 token pairs, and trading volumes on Uniswap followed.

Liquidity Routers

Even if there are no liquidity pools between two ERC20 tokens, they can still be swapped through common tokens across pools.

For example:

1) Swapping through wrapped ETH (WETH) as the common token. Note: To prevent liquidity fragmentation, support for native ETH swaps was removed in Uniswap v2 but later restored in v4.

2) Routing through a custom path across multiple pools

Router contracts are used to find the path with the best price (lowest slippage) for the swapper. e.g., direct vs multi-step swaps.

Illustration from Uniswap v2 Docs

Liquidity Pools as Price Oracles

Because the balance of each token pair in liquidity pools implies the prices of each token, they can be used as price oracles.

However, 2 important upgrades were required to minimise price manipulation before they could be used:

1) Measuring End-of-Block Price: Every token pair measures the market price at the beginning of each block before any trades take place. This price is expensive to manipulate because it was set by the last transaction in a previous block.

2) Updating the Cumulative Price: The end-of-block price is added to a single cumulative-price variable in the core contract, weighted by the amount of time this price existed. e.g., a Time-Weighted Average Price variable

This Cumulative Price variable can then be used by external smart contracts to track accurate time-weighted average prices (TWAPs) of any assets across any time interval.

Flash Swaps

This feature enables anyone to:

1) Execute a swap without having the upfront capital at the start of the transaction,
2) perform additional on-chain actions,
3) and then return the capital, complete the swap, or a mix of both + pay the swap fees at the end of the transaction.

However, Flash Swaps must be repaid in the same transaction or the entire transaction reverts. They are powerful but require careful execution.

Examples where Flash Swaps are useful:

1) Arbitrage between liquidity pools without requiring upfront capital

  • Problem:

If ETH price in 2 different pools is $2400 & $2500:

- If require 1,000,000 USDC to balance the price difference
- Arbitrageurs will have to provide the 1,000,000 USDC in order to capture the full arbitrage opportunity of $40,000
  • Solution:

With Flash Swaps, you can capture this $40,000 arbitrage and then pay cost of using Flash Swaps after.

2) Lever up on a token in one transaction

  • Problem: Levering up on ETH using a DeFi borrowing/lending protocol requires multiple transactions (i.e., multiple gas fees)

- Deposit collateral (ETH)
- Mint USDC
- Swap for more collateral asset (ETH)
- Mint more USDC
- Loop until desired leverage is achieved
  • Solution: Using Flash Swaps for leverage

- Flash borrow ETH from Uniswap (without paying upfront) 
- Deposit all ETH (owned + borrowed) as collateral in lending protocol 
- Borrow USDC against the larger collateral position 
- Use borrowed USDC to complete the Uniswap swap (repay the flash loan)
- Result: Higher leverage position in one transaction

3) Executing liquidations: If there are collateral positions on borrowing/lending protocols that can be liquidated

- Withdraw the borrowed asset (first half of a swap)
- Pay off the liquidation amount
- Unlock deposited collateral on borrowing/lending protocol + claim liquidation bounty
- Deposit collateral in the Uniswap pool to complete the swap
- Profit = Liquidation bounty 

4) Preventing self-liquidations: Similar to (3), you can pay off your borrowed amount before you get liquidated and complete the swap using the unlocked collateral

- Cost saving = Liquidation bounty paid

Uniswap v3: Concentrated Liquidity

Concentrated Liquidity

In Uniswap v2, liquidity deposited by LPs is distributed across the entire price range of each token. e.g., from 0 to ∞.

While this covers the maximum possible trading prices of the token pair, it is highly inefficient as swaps occur within a narrower price range most of the time. e.g., ETH has been trading between $2000 and $3000 in recent months.

In other words, the liquidity provided in an ETH/USDC pool below $2000 and above $3000 is underutilised and does not earn swap fees.

Concentrated Liquidity in Uniswap v3 addresses this capital inefficiency by allowing LPs to define the price ranges for their liquidity provided. The v3 positions of each LP for a given token pair are aggregated into a single pool, forming a combined curve for users to trade against.

The current spot price and active liquidity range are determined by “ticks”, which are discreet price points at every 0.01% interval.

Three benefits of v3:

1) LPs can earn the same amount of swap fees using way less capital if prices stay within the LP’s defined range

Illustration of v3’s capital efficiency from Uniswap Docs

2) A concentrated liquidity position also reduces LP’s risk exposure relative to a v2 liquidity position with similar expected APR. e.g., if ETH goes to $0, LPs lose a smaller portion of their capital

Illustration of v3’s stop-loss use case from Uniswap Docs

3) Providing more liquidity depth to a narrower range can increase the absolute profit from swap fees vs deploying the same amount of liquidity in a v2 pool. However, this greatly increases impermanent loss to LPs as well

v3 Trade-offs:

The key consideration of using v3 is that the LP’s liquidity becomes inactive if prices move beyond their defined range, resulting in:

1) No swap fees earned outside of the defined range
2) Greater risk and impact of impermanent loss
3) LP’s liquidity composing entirely of the less valuable of the two assets in the pool

Although all three negative effects are reversed when prices move back into the LP’s defined range, the risks are materialised if prices deviate permanently.

How do power users use Uniswap v3 in practice?

1) Range orders: Limit orders, Dollar-Cost Average (DCA), Take-profit, Primary issuance

- LPs deposit a single token in a custom price range above or below current price

- Swap one asset for the other from start to end price points if market price moves into the LP’s specified range

- Range orders below current price = DCA

- Range orders above current price = Take-profit orders, Primary Issuance

- Primary Issuance: Deposit liquidity in a single asset and specify range of prices to sell their tokens

- Note: Stop-loss or Stop-buy orders don't work because when prices move against you, you end up holding more of the losing token, not less. However, this is made possible in v4.  

2) Periodically rebalancing concentrated liquidity positions

- Rebalance liquidity back to 50:50 when market price moves out of range, causing the LP’s liquidity to consist solely of the less valuable of the token pair

- Realise the impermanent loss but continue earning swap fees

- Usually only makes sense for pools with high swap volumes (i.e., high swap fees APR)

3) Hedging out-of-range downside on centralised exchanges (CEX)
Some sophisticated LPs use external derivatives or CEX positions to hedge their concentrated liquidity risk.

  • Problem: If ETH drops below your range, you're stuck with ETH (the losing asset). If ETH price rises above your range, you move entirely into USDC and miss out on further ETH gains.

- Deposit liquidity and define a narrow price range. e.g., ETH/USDC between $2400 and $2600

- Simultaneously open a stop-sell order on Binance for ETH at $2400 and a stop-buy order at $2600

- If market price falls below $2400, CEX profits offset LP losses, as if LP sold ETH at $2400

- If market price rises above $2600, value of LP’s position rises along, as if LP bought ETH at $2600 with USDC

Note: This requires advanced risk management so only use this if you fully understand how it works.

Custom Fee Tiers

LPs can tailor their required swap fees according to the volatility of the token pair in a pool, allowing them to be better compensated by taking on more risk or vice versa.

Fee Tier

Typical Use Case

0.05%

For stable token pairs such as USDC/DAI. Lowest risk.

0.30%

For non-stable token pairs that are less volatile, such as ETH/USDC. Medium risk.

1.00%

For exotic token pairs. Higher risk.

Non-Fungible Liquidity

Because each LP defines its own price range, LP tokens are no longer fungible in Uniswap v3.

They are now represented by non-fungible tokens (NFTs) instead of ERC20 tokens, and the LP’s swap fees no longer reinvest automatically into the pool.

However, common LP positions can still be made fungible (ERC20) via peripheral contracts or partner (external) protocols.

As more LP positions are made fungible over time, increasingly sophisticated strategies can also be tokenised—e.g., multi-range positions, auto-rebalancing positions, fee reinvestment, lending, and more.

Advanced Price Oracles

This feature is more relevant to DeFi developers, so I will only cover it briefly. Compared to Uniswap v2, v3’s price oracles are:

1) Cheaper to create and use
2) More advanced (beyond just TWAP)—e.g., simple-moving averages, exponential-moving averages, outlier filtering

Uniswap v4: Fully-Customisable Liquidity Pools with Hooks

Uniswap v4 inherits all of the capital efficiency gains of Uniswap v3, but provides flexibility via hooks and gas optimisations across the entire lifecycle.

Hooks

Hooks are smart contracts that can be deployed by anyone to attach custom logic to liquidity pools across their entire lifecycle.

This logic can be executed before or after major operations such as:
1) Pool creation
2) Adding/Removing liquidity
3) Swapping
4) Donations (e.g., Fee rebates for LPs)

To enable Hooks, liquidity pool owners and LPs must allow their selected Hooks to interact with their pools.

Some obvious use cases of Hooks include:

  • Limit orders for DCA or take-profit

  • Stop-loss & stop-buy orders (previously impossible with v3)

  • Auto-compounding of LP fees

  • Automated liquidity management for LPs

  • Custom price curves beyond x*y=k or concentrated liquidity

  • Custom fees: Dynamic pool fees, Fee rebates for LPs, Fees for using Hooks

  • MEV fee redistribution to users

  • Channeling inactive liquidity onto lending platforms for yield maximisation

  • For Solo Stakers: Finding optimal periods to channel staking rewards into liquidity pools with high volume, fees, & incentives

Overall, Hooks encourages developers to build on top of Uniswap rather than forking and building competing protocols.

Curated list of deployed Hooks

Category

Number (Percentage)

Description

Projects

5 (4.0%)

Full stand-alone products leveraging Uniswap v4

By Uniswap

6 (4.8%)

Official foundational hooks providing core functionality

By Community

43 (34.1%)

Strong community participation

From Hackathons

72 (52.1%)

Experimental use cases

Total

126

Lower gas costs for everyone

Uniswap v4 brings 4 key gas-saving improvements.

1) Flash Accounting: Swapping, adding/removing liquidity, and donations within a single transaction are netted against one another. Users only pay to settle the final balance change
2) Singleton Architecture: Creating a pool is now a state update instead of the deployment of a new contract (vs v1-v3). Swapping through multiple pools no longer requires transferring tokens for intermediate pools.
3) Bringing back Native ETH swaps: No need to wrap ETH into WETH before swapping

Sources

Uniswap v1

Uniswap v2

Uniswap v3

Uniswap v4