Start now →

I reread Uniswap V3 and realized the hardest part is not the math, but the mental model

By BWV 1062 · Published April 28, 2026 · 7 min read · Source: Ethereum Tag
DeFiMarket Analysis
I reread Uniswap V3 and realized the hardest part is not the math, but the mental model

I reread Uniswap V3 and realized the hardest part is not the math, but the mental model

BWV 1062BWV 10626 min read·Just now

--

Press enter or click to view image in full size

If you start from Uniswap V2, you usually begin with a very familiar model:

x * y = k

Two assets. One pool. One curve. Price changes simply mean the state point moves along that curve.

That model is elegant, and it works well for V2.

But if you try to use the same mental model to understand Uniswap V3, you will quickly get confused. V3 is not just “V2 with better formulas.” What it really does is break one global AMM curve into many locally active price ranges.

That is the key idea behind concentrated liquidity.

This is also why I think the hardest part of Uniswap V3 is not the formula itself, but the mental model you use at the beginning.

I put together a full set of architecture notes here:

https://uniswap-v3-architecture-notes.vercel.app/

1. The problem with V2: the money is in the pool, but not all of it is working

In Uniswap V2, liquidity is spread evenly across the entire price range (0, ∞).

That sounds simple, but it creates a capital efficiency problem.

A swap usually moves price only a small distance along the curve. In practice, only the liquidity near the current price is actually used. The rest just sits there, technically available, but not participating in the trade.

So the real problem is:

Most capital is idle most of the time.

That leads to a natural question:

If swaps only happen around the current price, why should LPs provide liquidity everywhere?

That is exactly the idea Uniswap V3 introduces: concentrated liquidity.

2. The essence of V3: not “market making across the whole curve,” but “market making inside a range”

In V3, an LP does not spread liquidity across the entire price space.

Instead, the LP chooses a limited range:

[p_lower, p_upper]

So a position is no longer just “I deposit money into the pool.”

It becomes:

“I provide liquidity only inside this price range.”

That single change makes the whole protocol much more powerful, but also much harder to reason about.

Because now you have to answer questions like:

All of those questions come from the same root cause:

Your liquidity is only active inside the range.

3. A position is not always working

This is the most important mental model shift in V3.

Whether a position participates in a swap depends only on whether the current price is inside its range:

tickLower <= currentTick < tickUpper

When this condition is true:

When price leaves the range, the position becomes inactive.

There are three cases:

Case 1: price is below the range

currentTick < tickLower

In this case, the position does not participate in swaps.

The asset is effectively all token0.

You can think of it as: price has not yet entered your market-making range.

Case 2: price is inside the range

tickLower <= currentTick < tickUpper

In this case, the position is active.

It holds both token0 and token1, and the proportions change as price moves.

This is the part that many people misunderstand at first. V3 positions are not static. They continuously transform from token0 into token1, or from token1 into token0, as price moves through the range.

Case 3: price is above the range

currentTick >= tickUpper

In this case, the position is also inactive.

The asset is effectively all token1.

So the position is not “always on.” It is only active while price stays inside the chosen interval.

4. Why virtual liquidity matters

If V3 only allowed range-based liquidity, it would still have a problem:

How do you keep a continuous AMM price curve if liquidity only exists locally?

The answer is virtual liquidity.

The idea is simple:

The protocol does not treat the local curve as isolated. Instead, it embeds the real reserves into a larger constant-product system by introducing virtual reserves.

That gives us a complete curve again:

(x_R + x_V)(y_R + y_V) = L²

Where:

This is a very elegant design.

It allows LPs to provide local liquidity, while the protocol still behaves as if it is operating on a full AMM curve.

So V3 does not throw away x * y = k.

It localizes it.

5. Why V3 uses ticks instead of continuous prices

Once you understand range-based liquidity, the next question is: why does V3 use ticks?

The answer is efficiency.

In V2, price can be thought of as a simple reserve ratio:

P = y / x

But in V3, price must be discretized, because the protocol needs to answer questions like:

That is why V3 uses:

P = 1.0001^tick

So tick is basically the integer index of price in logarithmic space.

This gives V3 several advantages:

That is also why V3 has both tick and sqrtPriceX96.

6. Swap is not one formula. It is a state machine.

A lot of people think a swap is just:

That is not how V3 works.

In V3, a swap is a continuous price movement under current liquidity, and whenever price reaches an initialized tick, liquidity changes discretely.

That means one swap is broken into many local steps.

Each step asks one question:

Given the current price, current liquidity, target price, and remaining input/output, how far can price move in this step?

That is what computeSwapStep does.

If the step does not reach a tick boundary, price stops inside the current range.

If the step reaches a boundary, the protocol crosses the tick, reads liquidityNet, updates the current liquidity, and continues.

So the entire swap engine looks like this:

That is why I say V3 swap is not just a calculation.

It is a state machine.

7. Fees are not paid out immediately

V2 fee distribution is simple because all liquidity is global.

Fees go into the pool, and LPs receive them through their share of the pool.

V3 is different.

Because liquidity is spread across ranges, only active liquidity participates in a swap. That means different LPs participate at different times and in different ranges.

So V3 cannot just split fees globally.

If it tried to do that by scanning every position on every swap, gas costs would explode.

So V3 uses a different idea:

The core concept is feeGrowth.

You can think of feeGrowth as:

“how much fee has been earned per unit of liquidity so far.”

When a position is settled, the protocol looks at:

feeGrowthInsideNow — feeGrowthInsideLast

Then multiplies by the position’s liquidity.

That is how the protocol computes the amount owed:

tokensOwed += liquidity * (feeGrowthInsideNow — feeGrowthInsideLast)

This is one of the most elegant parts of the V3 design.

It avoids per-swap distribution and avoids iterating over all LPs.

8. Where V3 becomes hard

If you only look at the concept, V3 can be summarized in one sentence:

Concentrated liquidity.

But once you read the code, you realize the hard part is how all the pieces fit together:

Each piece is understandable on its own.

What makes V3 hard is that all of them work together around the same core problem:

How does price move through range-based liquidity?

That is the real architecture question.

This article was originally published on Ethereum Tag and is republished here under RSS syndication for informational purposes. All rights and intellectual property remain with the original author. If you are the author and wish to have this article removed, please contact us at [email protected].

NexaPay — Accept Card Payments, Receive Crypto

No KYC · Instant Settlement · Visa, Mastercard, Apple Pay, Google Pay

Get Started →