Skip to content

zenith-dlmm — Liquidity Book (bins)

zenith-dlmm is a discrete liquidity-book DEX. Instead of a continuous curve, liquidity lives in fixed price bins. Within a bin the price is constant, so a swap fills at a single price until the bin is exhausted, then moves to the next bin. This gives zero-slippage trades inside a bin and precise control over where liquidity sits.

Program ID (devnet): 7pxn8tEm44gXjfPH9YXsLywuYpAbgbxq9nPwG1XQczsz

Core ideas

Bins and bin step

Each bin id maps to a price via the bin step (in basis points): adjacent bins differ by a fixed ratio 1 + bin_step/10_000. A bin holds reserves of both tokens; the pair tracks an active bin — the one the current price sits in. Bins below the active bin hold the quote token, bins above hold the base token, and the active bin holds a blend. Bins are stored in fixed-size bin array accounts, allocated as needed and passed to swaps as remaining accounts so a trade can cross several bins in one transaction.

Swaps fill bin by bin

A swap consumes the active bin's opposing reserve at that bin's price, then crosses to the next initialized bin and repeats, accumulating output and fees per bin. Crossing shifts the active bin id. Because each bin has a constant price, the per-bin fill is exact.

Dynamic fee + oracle

The fee has a constant base component plus a volatility-driven component: a volatility accumulator grows with price moves and decays over idle slots, so fees rise during turbulence and relax when quiet. A TWAP oracle account records a rolling price history for downstream consumers. Fees split into an LP share (tracked per bin as fee growth) and a protocol share.

State

AccountHolds
LbPairActive bin, bin step, base fee, volatility accumulator, protocol fee, references to the oracle.
BinArrayA contiguous run of bins (reserves + per-bin fee growth).
PositionOwner, the bin range it covers, and per-bin liquidity + fee checkpoints.
OracleRolling price observations for the TWAP.

Instructions

InstructionPurpose
initialize_lb_pairOpen a pair at a starting active bin, bin step, and fees.
initialize_bin_arrayAllocate a bin array covering a range of bin ids.
initialize_oracleAllocate the pair's TWAP oracle.
initialize_positionOpen a position over a bin range.
add_liquidityDeposit across bins using a strategy — Spot, Curve, or BidAsk — that shapes how liquidity is distributed.
remove_liquidityWithdraw from a position's bins.
swapTrade across bins, crossing arrays as needed.
claim_feeClaim a position's accrued per-bin LP fees.
claim_protocol_feeWithdraw the protocol fee share.
close_positionClose an empty position.

Liquidity strategies

add_liquidity accepts a shape for how the deposit spreads across the chosen bin range:

  • Spot — even across the range (uniform depth).
  • Curve — concentrated toward the middle (deeper near the current price).
  • BidAsk — weighted toward the edges (for range orders / directional views).

What proves it works

  • Host unit + vector tests in the program and math crate.
  • On-chain lifecycle tests, and devnet e2e checks in sdk/scripts that assert the realized on-chain output equals the SDK quote exactly, that an LP round-trip conserves value, and that a seeded position's fee claim matches the replayed fee growth.

Built on Solana devnet. Integer-exact math, no floats.