- AMM SDK: request a quote, then execute the swap from a wallet or backend using the published TypeScript SDKs.
- AMM CPI Integration: call
swap_in/swap_outfrom your own on-chain program via cross-program invocation. - AMM Errors: the swap-path error codes, what triggers them, and how to avoid them.
Scope: swaps only. Liquidity actions (deposit, withdraw, borrow, payback) and admin instructions are out of scope for this guide.
How the AMM works
A Lend AMM pool trades exactly one pair of tokens,token0 and token1. Liquidity is packed into a price range around a center price, so trades near the current price get much deeper liquidity than a constant-product pool of the same size.
The tokens backing a pool are Liquidity Layer positions, not tokens the pool custodies. A pool can therefore exist in three shapes:
For swapping you don’t need to care which shape a pool is. The program routes across whatever sides are enabled and returns a single input/output amount. The SDK quote does the same math off-chain.
The two swap instructions
swap0to1picks direction:truetradestoken0 → token1,falsetradestoken1 → token0.amount_out_min/amount_in_maxare your slippage guards, enforced on-chain.swap_inreverts if the output is belowamount_out_min;swap_outreverts if the input exceedsamount_in_max. No funds move on a revert.- Both instructions return the computed counter-amount as a
u64(Anchor return data), so a CPI caller reads the result directly.
Conventions that affect integrators
token0/token1are ordered by public key.token0is the mint whose address sorts lower. This is fixed per pool; computeswap0to1from the mints you hold, not from a fixed slot.- All amounts are native token units (base units of that mint’s decimals) at the API edge. Internally the pool works in a common 9-decimal representation and scales back to native decimals at the boundary. Token decimals above 9 are not supported.
- Rounding always favours the pool. Exact-in floors the output; exact-out ceils the input. Quote, then guard with slippage.
- Pools are addressed by a small integer
dex_id(1..=totalDexes).
Program addresses
PDAs
The AMM’s own PDAs are derived against the Lend AMM program id; the Liquidity Layer accounts a swap touches are derived against the Liquidity Layer program id. Seeds (all strings are ASCII bytes;dex_id is a little-endian u16):
Token vaults are the associated token account of the Liquidity root PDA for each mint (allow-owner-off-curve). The
DexMetadata account stores the pool’s address lookup table (lookup_table), which you use to keep swap transactions under the size limit. The SDK derives all of these for you.
How a pool sits on the Liquidity Layer
An AMM pool holds no token balances of its own. It is registered as a protocol on the Liquidity Layer, and the tokens that back it are Liquidity Layer positions:- The collateral pool is a pair of Liquidity Layer supply positions (one for
token0, one fortoken1). Liquidity providers deposit, and the supplied tokens earn the lending supply rate while also serving swaps. - The debt pool is a pair of Liquidity Layer borrow positions. Borrowers draw debt against the pool, and that outstanding debt is itself the liquidity a swap trades against.
- Pool state lives in one
Dexaccount per pair (seeds["dex", dex_id]), holding the pair identity, live pricing (center_priceand the oracle’s last stored prices), mode switches, range configuration, fees, and share accounting. The optionalcenter_price_addressfield points at an external price source; an all-zero value means the pool prices internally. This distinction matters for the accounts a swap must pass, see external center price. - Liquidity provider stakes are shares, not token balances. Supply shares are a proportional claim on the collateral pool’s two reserves; borrow shares are a proportional obligation against the debt pool’s two reserves. Swappers never touch shares.
- Re-entrancy lock. Every user-facing entry point takes a per-pool
re_entrancylock and releases it at the end. A second entry while locked reverts withDexAlreadyEntered(6017), so you cannot swap the same pool twice inside one instruction. - Pausing. Admins can pause a whole pool (
pause_dex) or only swaps and the rebalance step (pause_swap_and_arbitrage). Paused swaps revert withDexSwapAndArbitragePaused(6050). - Automatic arbitrage. Every operation on a two-sided pool ends with an automatic arbitrage step that re-syncs the collateral and debt prices. It runs inside the swap instruction; you don’t invoke it.
Integration paths
Both paths are the same three steps: quote → guard → execute. The only difference is where the code runs.AMM SDK
Quote with
@jup-ag/lend-read, build and send the swap with @jup-ag/lend/dex. For off-chain integrations.AMM CPI Integration
Call
swap_in / swap_out from your own program via CPI, with the full 25-account context and a raw instruction recipe.