If you’ve ever opened a Uniswap V3 or V4 position and seen a chart full of little vertical bars, price ranges, and a mysterious number called a “tick,” you’ve probably felt a small wave of panic. Don’t worry, ticks are one of those ideas that sound intimidating but turn out to be pretty simple once you see the problem they were built to solve.
The Real Problem: Liquidity Stopped Being Constant
In Uniswap V2, liquidity is a constant. Every pool holds a fixed reserve curve (x * y = k), and that liquidity is spread evenly across every possible price, from zero to infinity. That sounds generous, but it’s wasteful. If ETH is trading around $3,000, there’s basically no chance it trades at $0.01 or at $10 million anytime soon, yet V2 forces your capital to sit idle across that entire range, earning fees only from the tiny sliver of trades that happen near the current price.
Uniswap V3 changed the fundamental model: instead of liquidity being a single constant number across the entire price curve, liquidity providers can choose which segment of the price curve they want their capital to sit in. You might deposit only between $2,800 and $3,200, someone else might deposit between $2,000 and $5,000, and someone else might go extremely narrow, $2,990–$3,010.
The consequence is that liquidity is no longer a single constant L; it becomes a function of price, L(P), that steps up and down depending on how many LPs have active positions covering that particular price. This is what “concentrated liquidity” really means: not just “more liquidity near the current price,” but liquidity as a variable, piecewise quantity across the curve instead of a flat one.
That creates a new engineering problem: how do you track a liquidity function that changes shape every time someone opens or closes a position, without making every swap prohibitively expensive to compute? You can’t just re-integrate some continuous curve on every trade; that would be a gas nightmare. You need a way to represent “liquidity changes here” as a small number of cheap, discrete events. That’s exactly what ticks are for.
Price Has Two Sides: P and 1/P
Before ticks even enter the picture, it’s worth being precise about what “price” means inside a pool, because it’s easy to get backwards.
A pool holds two tokens, call them X and Y, with reserves x and y. The price of X, denominated in Y, is defined as the ratio:
P = y / x
This tells you how much Y you get per unit of X. If P = 10, that means 1 unit of X is worth 10 units of Y.
But every price has a flip side, the price of Y, denominated in X, and that’s just the reciprocal:
P_y = x / y = 1 / P
So if P = 10, then P_y = 1 / 10 = 0.1. That is, 1 unit of Y is worth 0.1 units of X. Same pool, same reserves, just looked at from the other token’s point of view.
This matters for ticks because Uniswap has to pick one consistent direction to define “the” price of a pool (by convention, token1 per token0), and every tick, every range boundary, and every “in range / out of range” check is implicitly expressed in that direction. If you ever flip a chart or a UI from showing X/Y to Y/X, you’re just looking at P versus 1/P, and since 1.0001^(-tick) = 1 / 1.0001^tick, that flip corresponds exactly to negating the tick.
So What Is a Tick, Exactly?
Think of the entire possible price spectrum for a trading pair as a number line. Uniswap chops that number line into discrete steps like marks on a ruler. Each mark is called a tick.
Formally, each tick corresponds to a specific price using this formula:
price = 1.0001^tick
Why 1.0001? Because each tick represents a 0.01% (1 basis point) price movement from the previous one. That’s a small enough step to give fine-grained pricing, while still being a fixed, predictable increment that smart contracts can compute cheaply.
So:
- Tick 0 → price = 1.0001^0 = 1
- Tick 1 → price = 1.0001^1 ≈ 1.0001
- Tick -1 → price = 1.0001^-1 ≈ 0.9999
- Tick 100 → price ≈ 1.0100
As the number of ticks increases, the price increases. As it goes down, the price goes down. It’s essentially a logarithmic index for price — instead of storing raw prices (which involve messy decimals and rounding issues), Uniswap stores integers, and integers are cheap and precise for a blockchain to work with.
How Ticks Make Variable Liquidity Cheap to Track
Here’s the part that actually answers “why ticks”: Uniswap V3 doesn’t store liquidity as a smooth curve. It stores liquidity as piecewise constant flat within a segment between two ticks, and only changes at a tick.
Every tick that has at least one position starting or ending on it is called an “initialized tick,” and it stores a single important number: liquidityNet, how much total liquidity gets added (or removed) the moment the price crosses that tick.
When a swap happens and price moves through the pool:
- As long as the price stays within the current segment, the contract uses the same L value for every calculation. No recomputation needed.
- The moment price crosses an initialized tick, the contract just adds that tick’s liquidityNet to the running total and keeps going.
That’s the entire trick. Instead of continuously modeling every LP’s individual range on every single trade, the contract only has to do work at the handful of tick boundaries a swap actually crosses. Most of a swap’s execution is just “keep using this same flat number” cheap arithmetic with occasional O(1) jumps at crossings. This is what makes concentrated liquidity computationally practical on a blockchain where every operation costs gas.
Tick Spacing: Not Every Tick Is Usable
Here’s a wrinkle beginners often miss: pools don’t let you set a position at every single tick. Each pool has a tick spacing parameter, and LP positions can only start or end on ticks that are multiples of that spacing.
- Low-fee pools (like stablecoin pairs, 0.01% or 0.05% fee tier) tend to have small tick spacing, because prices barely move, and you want precision.
- Higher-fee, more volatile pools (like 1% fee exotic pairs) use larger tick spacing, because fine-grained precision isn’t as useful when price swings are big anyway.
This is a gas-vs-precision tradeoff: fewer usable ticks means fewer possible positions to check during a swap, which keeps transactions cheaper.
Slot0: Where the Pool Keeps Its “Right Now”
Every idea above the current price, the current tick, and tick spacing has to actually live somewhere in the contract’s storage. That place is a single storage variable called slot0.
Storage on Ethereum is expensive: every distinct storage slot you read or write costs gas. So instead of storing the pool’s current price, current tick, and a handful of other frequently-read values as separate variables (which would mean separate expensive storage reads every time), Uniswap V3 packs them all into one 256-bit slot. Reading “the state of the pool right now” becomes one cheap storage read instead of five or six.
slot0 bundles together things like:
- sqrtPriceX96 — the current price, but stored as its square root, fixed-point encoded (multiplied by 2^96). Uniswap works with the square root of price internally because it makes the swap math (which involves multiplying and dividing by liquidity) much simpler and avoids precision loss — squaring and unsquaring is cheaper and safer than working with raw price ratios throughout.
- tick — the current tick corresponding to that price, cached so contracts (and the front end) don’t need to recompute it from sqrtPriceX96 on every read.
- observationIndex and observationCardinality pointers into the pool’s price/liquidity oracle history, used for time-weighted average price (TWAP) calculations.
- feeProtocol and an unlocked flag protocol fee settings, and a reentrancy lock.
You don’t need to memorize every field, but the concept is worth internalizing: slot0 is effectively the pool’s “dashboard”, the current price (as a square root), the current tick, and a few bookkeeping values, all packed together so that checking “where is the market right now” is as gas-cheap as a single read. It’s the same design philosophy as ticks themselves: concentrated liquidity only works economically on-chain because Uniswap is relentless about turning expensive continuous math into cheap discrete lookups.
How Ticks Relate to Your LP Position
When you provide liquidity on Uniswap V3, you’re literally choosing a segment of the curve: a lower tick and an upper tick. Under the hood, opening that position adds your liquidity amount to liquidityNet at your lower tick, and subtracts it at your upper tick. That’s how the contract knows to “turn your capital on” when price enters your segment and “turn it off” when price leaves it.
- If the current market price is inside your range, your liquidity is active and contributes to the pool’s L for that segment, earning fees on every trade that happens within it.
- If the price moves outside your range, your liquidity goes “out of range.” It stops earning fees and effectively converts entirely into one of the two tokens, sitting there until the price comes back.
Every other LP is doing the same thing on their own chosen segments, which is exactly why total liquidity varies across the price curve instead of being one flat number like in V2.
This is why LPs talk about “narrow ranges” vs “wide ranges.” A narrow range around the current price earns more fees per dollar of capital (because it’s more concentrated) — but it’s riskier, since price is more likely to drift outside a tight range, leaving you exposed to just one asset and out of the fee-earning game until you rebalance.
Why This Matters for You
Even if you never plan to write a smart contract, understanding ticks helps you:
-
Read LP dashboards intelligently. When a Uniswap interface shows your position as “in range” or “out of range,” it’s really telling you where the current tick sits relative to your chosen tick boundaries.
-
Understand impermanent loss dynamics better. Concentrated positions amplify impermanent loss compared to V2-style full-range positions, because your capital is doing more “work” in a smaller price window.
-
Make smarter range choices. Wider ranges = more passive, lower fee density, more forgiving. Narrower ranges = active management, higher fee density, higher risk of going out of range.
-
Follow protocol design conversations. Ticks are foundational to how newer AMMs (including Uniswap V4 hooks) build custom logic around liquidity concentration, dynamic fees, and range orders.
The Short Version
- Concentrated liquidity means liquidity is no longer constant across price; it’s piecewise, because each LP chooses its own segment of the curve.
- Ticks are the discrete markers (price = 1.0001^tick) that let the contract represent that piecewise function as a small set of integers instead of a continuous curve.
- Each initialized tick stores a liquidityNet value, the amount of liquidity to add or remove the moment price crosses it, which is what makes swaps cheap: no recomputation, just occasional O(1) jumps at crossings.
- slot0 packs the current price (as sqrtPriceX96), the current tick, and oracle bookkeeping into a single storage slot, so checking the pool’s current state costs one cheap read instead of several.
- Tick spacing limits which ticks can serve as position boundaries, depending on the pool’s fee tier.
- Your LP position is defined by a lower and upper tick, and you only earn fees while the current price tick falls between them.
Once you see ticks as just “steps on a price ruler” rather than some exotic DeFi math, the rest of Uniswap V3/V4’s mechanics, range orders, active liquidity, and fee concentration start to click into place much faster.
Disclaimer: This article is for educational purposes only and does not constitute financial or investment advice. DeFi protocols carry smart contract, market, and liquidity risks always do your own research before providing liquidity.
Leave a comment