Tick Bitmap
A sparse bitmap indexed by word that records which ticks in a concentrated-liquidity pool are initialized, letting the swap loop find the next relevant tick with a single storage read.
The tick bitmap is the data structure that makes a Uniswap V3 swap affordable. A pool spans roughly 1.7 million usable ticks. Most are empty. A swap needs to know where the next non-empty one is, and it cannot scan.
The bitmap is a mapping(int16 => uint256): each key is a word index, each value packs 256 tick flags. A tick is decomposed by dividing its compressed index by 256 — the quotient selects the word, the remainder selects the bit. Both are computed with arithmetic that must round toward negative infinity, which is why the implementations use a shift rather than a division for the word index and a mask rather than a modulo for the bit.
Flipping, not setting
The bitmap exposes one mutation, flipTick, which XORs a single bit. It never sets or clears explicitly.
This is correct because the pool only calls it at the moment a tick transitions between initialized and uninitialized — when the first position using it as a boundary is created, or the last one is removed. XOR makes the operation self-inverse and removes the need to read the current state first. It also makes a double-flip a no-op rather than a corruption, which matters because the alternative encoding would let an off-by-one in the caller silently clear an unrelated tick.
Finding the next tick
nextInitializedTickWithinOneWord is the search, and its name states its limitation precisely: it looks inside one word only. It builds a mask covering the bits on the relevant side of the current position, ANDs it against the word, and returns the highest or lowest set bit — searching downward for a swap that lowers the price, upward for one that raises it.
If the masked word is empty, the function does not recurse. It returns the boundary of the word and reports the tick as uninitialized. The swap loop then steps to that boundary, does no crossing work, and calls the function again on the next word. Bounding the search to one word bounds the gas of a single iteration; the loop handles the rest.
The consequence, which surprises people reading the loop for the first time, is that a swap through a long stretch of empty price range performs several iterations that cross nothing. They are cheap — one warm storage read each — and they are what keeps the worst case linear in words rather than in ticks.
Where reviews should focus
The masks are the sharp edge. Off-by-one errors in mask construction are easy to write and hard to see: an inclusive bound where an exclusive one belongs causes the loop to stop at the tick it is already standing on and spin, or to skip a tick and apply the wrong liquidity net. Both produce mispriced swaps rather than reverts.
The second thing to check is that the compression by tick spacing is applied consistently on both write and read. The bitmap stores compressed indices; a caller that flips an uncompressed tick and searches with a compressed one will find nothing, and the pool will quietly ignore every position boundary it should have stopped at.
Related Terms
Tick
A discrete price point in concentrated liquidity AMMs where each tick maps to a small step in the pool price curve.
Tick Spacing
The fixed interval that constrains which ticks a concentrated-liquidity position may use as its boundaries, set per fee tier at pool creation and immutable thereafter.
Liquidity Net
The signed amount of liquidity a concentrated-liquidity pool adds to its active total when the price crosses a given tick moving upward, and subtracts when moving downward.
Concentrated Liquidity
A liquidity provision model where LPs can specify custom price ranges for their capital.
Need expert guidance on Tick Bitmap?
Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.
Get a Quote