- Quote the swap off-chain with
@jup-ag/lend-read. - Derive a slippage guard from the quote (
amountOutMin/amountInMax). - Build and send the swap instruction with
@jup-ag/lend/dex.
Install
The
/dex entry point ships from @jup-ag/lend v0.2.0. If the latest tag is still older, install the beta tag: npm install @jup-ag/lend@beta.1. Request a quote
estimateSwapIn / estimateSwapOut return a SwapResult:
You normally only need
amountIn / amountOut. The col* / debt* legs are the per-side routing split (they sum to the total) and are exposed for analytics.
The quote is pure math on a fresh snapshot and mirrors the on-chain formulas, so it can throw before you build a transaction if the swap would be rejected on-chain, for example when the trade exceeds 50% of the input reserves, falls below the dust floor, or the pool’s swaps are paused. Treat a thrown quote as “not executable right now”.
Exact-out quoting
2. Derive the slippage guard
The quote is a point-in-time estimate; the pool can move before your transaction lands. Turn the quote into a hard bound the program enforces.DexNotEnoughAmountOut (6024) for swap_in or DexExceedsAmountInMax (6051) for swap_out. No funds move.
3. Build and send the swap
getSwapInIx / getSwapOutIx resolve every account for the pool (mints, token programs, reserves, vaults, the four liquidity positions), auto-attach the external center-price accounts when the pool needs them, and load the pool’s address lookup table. They return the instruction(s) plus the loaded ALT. You sign and send.
getSwapOutIx takes amountOut + amountInMax.
Return shape
Both builders return:
Because the builders return raw instructions, you can compose a swap with your own instructions (wrap/unwrap SOL, create an ATA, etc.) in the same transaction. Include all of them and pass
addressLookupTableAccounts when compiling.
Sending output to a different recipient
Passrecipient (a PublicKey) to deliver the output elsewhere; the builder derives that owner’s ATAs for both mints. The recipient’s associated token account for the output mint must already exist (or be created in the same transaction).
Full example: quote to swap (exact-in)
Why a versioned transaction and lookup table
A swap touches ~25 fixed accounts, plus the oracle and its price sources for external-center-price pools. A legacy transaction can exceed the 1232-byte limit, so always send a versioned (v0) transaction and pass the pool’s ALT (returned by the builders asaddressLookupTableAccounts). This is not optional for external-center-price pools and is good practice for all of them.
Exact on-chain quoting via simulation (optional)
estimateSwapIn / estimateSwapOut are kept in lockstep with the program and are enough for production. If you want the pool’s exact on-chain result (for example, to cross-check), build a swap whose recipient is the all-zero pubkey (PublicKey.default, the ADDRESS_DEAD sentinel) and simulate it. The instruction runs the full pricing path and deliberately reverts, logging:
simulateTransaction. This never moves funds.
Error handling
Anchor throws anAnchorError; read err.error.errorCode.number and map it. The full table is in Errors; the ones you’ll hit most:
