Skip to main content
Every stateful account in the program is a PDA whose own stored fields are checked against the address it lives at — a bin array’s stored pool/index, for example, can never diverge from the address it’s actually loaded from. This closes off an entire class of bug where a wrong or substituted account could be accepted in place of the right one.

Pool

Seeds: [b"pool", token_mint_x, token_mint_y, bin_step.to_le_bytes(), fee_rate.to_le_bytes()] One Pool account exists per (mint_x, mint_y, bin_step, fee_rate) combination — the same token pair can have multiple pools at different bin steps or fee tiers, each independently addressable.

BinArray

Seeds: [b"bin_array", pool, bin_array_index.to_le_bytes()] 100 consecutive bins for one pool. Fixed-size, always fully allocated — no bitmap, no variable-length packing, every bin addressable in O(1) by local index.

Position

Seeds: [b"position", position_mint] A depositor’s claim over a contiguous bin range, represented by an owned Token-2022 NFT (position_mint). Holds one FeeState slot per bin in range, indexed by local position (bin_id - lower_bin_id), not the pool’s own bin-array indexing.

AdminConfig

Seeds: [b"admin_config"] — a fixed-seed singleton; at most one AdminConfig can ever exist program-wide.
See Governance for the transfer/bootstrap flow this account gates.

Coordinate system reference

div_euclid/rem_euclid, not plain //%, are required — truncating division misclassifies negative bin ids.