A discrete-bin liquidity market maker for Solana — liquidity priced into a fixed grid of bins instead of a continuous curve, with dynamic fees that respond to real volatility.
Picon DLMM is an automated market maker that replaces a continuous bonding curve with a finite grid of discretely priced bins. Liquidity providers deposit into specific bins instead of along a curve; a swap consumes liquidity bin by bin, in whichever direction the trade moves price, until it's filled. The active bin is the market price — there's no separate oracle or curve formula to invert.
This design gives liquidity providers exact control over the price range they quote at, at the cost of finite liquidity per bin — a large swap can walk through several bins and pick up real price impact, by construction, the same way a real order book does.
Picon's implementation is a from-scratch Anchor program, not a fork: bin traversal is sparse (no bitmap — a swap loads only the bin-array accounts it actually needs), fees combine a fixed base rate with a dynamic surcharge that responds to realized volatility, and positions are Token-2022 NFTs so a bin range can be transferred, listed, or composed with other programs like any other NFT.
A constant-product (x·y=k) pool spreads a liquidity provider's
capital across the entire price range from 0 to ∞, most of which will never be
traded at. Concentrated-liquidity designs (Uniswap v3-style) fix this by letting LPs
pick a price range, but the range is still continuous — capital efficiency and
fee/impact behavior are governed by a curve formula, and volatility-responsive fees
are typically bolted on as a separate mechanism.
A discrete-bin book collapses both problems into one structure: liquidity only exists where someone actually placed it, each bin trades at one fixed price, and because the price ladder is just a lookup rather than a curve, fee mechanics can be layered on cleanly per bin, per swap step.
Every pool fixes a bin step at creation — the fixed percentage price gap between adjacent bins, in basis points, chosen from a fixed table of supported values. A pool's valid range is symmetric around bin 0 and scales inversely with bin step: finer steps cover a huge price range at high density, coarser steps cover a wider range per bin.
Bins are grouped into fixed-size bin arrays (100 bins each) — the unit of account allocation. Bin arrays are created permissionlessly, on demand, and only the arrays a swap actually touches are loaded into the transaction — there is no bitmap scanning the full range up front.
A bin's price is fixed by its id and the pool's bin step — each step away from bin 0 compounds the same fixed ratio:
What a bin actually holds follows directly from that price relative to the pool's current active bin: a bin entirely below the active price has already been fully bought into Y (a resting bid), a bin entirely above holds only X (a resting ask), and the active bin itself is the one place that can hold both — it's mid-trade between the two.
A position is a bounded range of bins (at most 100, i.e. one bin array's width) owned by a Token-2022 NFT. Opening a position mints the NFT; depositing, withdrawing, and claiming fees are all gated to whoever currently holds that NFT — not necessarily the original opener, since selling or transferring the NFT transfers the position along with it.
A deposit is placed across the position's bins by weight — the caller supplies a weight per bin and a total token amount, and the program allocates capital bin by bin according to those weights and each bin's price. What a depositor receives back on withdrawal is a proportional share of a bin's current pooled value, not a guarantee of the same token mix they put in, because swaps move value between the two sides of every bin they cross.
Because the weight is just an array supplied by the caller, a deposit can take any shape across a position's bin range. Three shapes come up often enough to have names:
Equal weight in every bin across the range — capital spread flat, no bin favored over another.
Weight peaks at the active bin and tapers toward the edges — capital concentrated near the current price.
Weight peaks at the two edges of the range and dips at the active bin — capital positioned for price to move away from where it is now.
A swap walks the active bin, and however many further bins the trade needs, consuming each bin's available liquidity on the way, until the requested amount is filled or the pool runs out of liquidity in that direction. Each step is a straightforward fill against a fixed-price bin — no curve integral, no slippage formula beyond how much liquidity sits in the bins being crossed. The pool's active bin is left wherever the swap's last fill landed, which is the new market price.
Every pool has a fixed base fee rate, set at creation, plus a dynamic fee surcharge layered on top. The dynamic fee tracks how many bins recent swaps have crossed within a rolling window:
filter_period don't move the
reference — rapid, contained trading doesn't spike the fee.decay_period of inactivity, the accumulator resets rather than
merely decaying — a genuinely idle pool returns to its base rate.reduction_factor rather than resetting outright — a smooth cool-down,
not a cliff.
The result: a quiet pool trades at its base rate; a pool absorbing a volatility burst
(prices actually moving, real risk to LPs) charges more, automatically, without any
keeper or oracle update — the mechanism is entirely self-contained in swap-triggered
state. Every fee collected is split between liquidity providers and the protocol by a
per-pool, admin-configurable protocol_share.
Pools support both mint types Token-2022 was built for on top of plain SPL Token: transfer fees (netted correctly out of both sides of every transfer) and transfer hooks (arbitrary CPI attached to a mint's transfers, wired through every instruction that moves that mint). Pool creation is admin-gated specifically so transfer-hook mints can be curated rather than accepted from anyone permissionlessly — a hook is program logic the pool doesn't control, so it's treated as the pool's own trust boundary, not the trader's.
Every account relationship is derivation-pinned (Anchor seeds = PDAs): a
bin array's own stored pool/index fields can never diverge
from the address it lives at, and the same holds for vaults, positions, and pool
state. The only privileged actor in the entire program is the admin authority, and its
authority is scoped narrowly — it can create pools, set fee/protocol-share parameters,
and claim protocol fees; it cannot touch a position's principal, move a swap's price,
or freeze funds.
| Instruction | Access | What it does |
|---|---|---|
create_pool |
Admin only | Initializes a pool at a given bin step, base fee, and starting active bin |
create_bin_array |
Permissionless | Allocates a bin array's account, paid for by whoever calls it |
delete_bin_array |
Admin only | Reclaims an empty bin array's account |
open_position / close_position |
Owner | Mints or burns the position NFT |
deposit_by_weight |
Owner | Deposits liquidity into a position's bin range, distributed by weight |
withdraw |
Owner | Removes a proportional share of a position's bins, partial or full by bps |
claim_fee |
Owner | Collects accrued LP fees for a position |
swap |
Permissionless | Exact-in or exact-out swap, walking bins in the trade's direction |
sync_pool |
Permissionless | Advances the active bin across bins already proven empty |
| Admin instructions | Admin only | Fee-rate / protocol-share updates, protocol-fee claims, authority transfer |
The admin authority cannot withdraw, freeze, or redirect a position's principal or accrued LP fees — its powers are limited to pool creation, fee-rate/protocol-share configuration, and protocol-fee claims.
Every stateful account is a PDA whose own stored fields are checked against its address, closing the class of bug where a wrong or substituted account could be accepted in place of the right one.
A bin's share accounting reads only its own stored token amounts — never a live external vault balance — which rules out donation/inflation-style attacks common to naively implemented share vaults.
Transfer-hook CPI risk — logic outside the program's own control — is contained by pool creation being admin-gated, not permissionless.
200+ Rust unit tests cover the core bin/fee/arithmetic math. An adversarial integration suite tries wrong accounts and edge-case inputs and confirms they're rejected. On top of that, an end-to-end test runs many LPs through deposits, swaps, and withdrawals, then checks that once everyone has claimed what they're owed, the pool's vaults are left empty.
The program is feature-complete for v1 (pools, positions, swaps, fees including the dynamic surcharge, governance) and live on Solana mainnet.
pDLMMk3KW3CUSxE1Wgjhx3jSmm2spe6Ry7Mq2HT26rC
A TypeScript SDK (@picon-finance/dlmm-sdk, built on @solana/kit) is published and usable today against mainnet. MIT licensed.
Connect a wallet and try opening a position or providing liquidity on a live pool.