Skip to content

Tick arrays and full range

Allocate only useful boundaries, discover pages by bitmap, and build full-range positions.

Paginated tick storage, introduced in Pool version 3 and retained in the current Pool version 6, replaces the 32-boundary tick book with pages covering the supported tick domain. Hook policies remain external programs. Pagination changes storage and transaction construction, while preserving concentrated-liquidity accounting.

How pages work

Each page represents 64 aligned tick slots. Compute its signed index with floor division:

array_index = floor(tick / (64 * tick_spacing))

Use array_index in the Rust library; truncating division gives the wrong page for negative ticks. The pool's TickDirectory has a two-level bitmap, so swaps skip empty pages and uninitialized slots. Boundaries with zero net liquidity but positive gross liquidity remain initialized and must still update fee checkpoints when crossed.

flowchart LR
Pool[Pool: price and active liquidity] --> Directory[TickDirectory: nonempty pages]
Directory --> Lower[Lower endpoint page]
Directory --> Upper[Upper endpoint page]
Lower --> RecordA[Initialized slot and fee growth]
Upper --> RecordB[Initialized slot and fee growth]

Choose a page format

FormatBytes per pageAllocation
Fixed4152All 64 record slots reserved
Compact56 + 64 × capacityPacked initialized records; capacity from 0 to 64

A compact page with capacity two occupies 184 bytes. The 1816-byte directory is shared by every position in the pool. Capacity grows through reserve_tick_array, funded by a signer before adding liquidity. Removing a boundary clears its slot and reuses capacity; it does not shrink the account or refund rent. Page addresses are shared, so the first initialization selects the format for that page.

Add full-range liquidity

  1. Read the pool's immutable spacing and call full_range_ticks(spacing).
  2. Derive the two endpoint page PDAs. Initialize missing pages or reserve enough compact capacity for new endpoints.
  3. Call open_position with those ticks.
  4. Call modify_liquidity with positive liquidity, token maximums, endpoint pages in ascending signed index order, and any declared hook extras afterward.
  5. Collect fees, remove liquidity, and close the empty position through the ordinary LP lifecycle.

For spacing 64, the widest valid range is [-443584, 443584]. Full range creates only two boundary records; the interior contains no position-specific tick records. Other positions may share the same boundaries.

With the current price inside the range, adding full-range liquidity normally requires both assets. One-sided positions use a range outside the current price. A zap can swap part of a single-asset budget and then deposit both assets atomically. The caller chooses the swap amount and protects the result with a minimum liquidity limit. Wide coverage also spreads capital over more prices, so it does not imply the same fee return per unit of capital as a narrow range.

Before the tickL = Lₐ
Initialized tickApply signed ΔL
After the tickL = Lₐ + ΔL
Moving to a higher tick applies its signed liquidity net. Crossing downward applies the opposite change. Price continues with the new active liquidity.

Transaction and router budgets

Swaps accept at most 16 page accounts, independently of the hook account limit. This is a ceiling, not a promise that every combination fits the transaction packet or CU budget. The Metis adapter caches up to 16 nonempty pages per direction, refreshes newly discovered addresses, and builds execution metas from the pages actually visited by the quote. A missing initialized page rejects; it never silently changes liquidity.

The traversal can conservatively require the next initialized page beyond the requested price limit. Extra hook state and Merkle proofs consume the same transaction envelope. Every proof sibling adds 32 bytes, so measure the complete account and payload plan. A proof format’s maximum depth does not guarantee that every transaction carrying it fits.

Plan account and compute budgets

Measure the exact position ranges, page format, hook composition, proof depth, and transaction format used by your application. Setup costs and steady-state liquidity changes are different workloads. Reserve sufficient budget for the largest supported traversal.