Early rate$2,400 of senior audit time for $500. Early members keep the rate as it climbs.$2,400 of senior audit time for $500See how

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.

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