solana swap-instruction lib for direct DEX integrations.
swaps tells you which accounts to read and builds a
stack-backed instruction view from those account bytes.
the instruction output is stack-backed and allocation-free.
use swaps::{InstructionBuf, SwapRequest};
use swaps::addresses::WSOL;
use swaps::dex::DexKind;
let req = SwapRequest::new(
DexKind::PumpFun,
user,
/* token_in */ WSOL,
/* token_out */ pumpfun_mint,
/* amount_in */ 1_000_000,
/* min_amount_out */ 0,
);
let initial_plan = swaps::fetch_plan(&req);
let initial_keys: Vec<_> = initial_plan.addresses().copied().collect();
let initial_data: Vec<Vec<u8>> = my_rpc.get_multiple_accounts(&initial_keys).await?;
let followup_data = match swaps::followup_keys(&req, &initial_data)? {
Some(plan) => {
let keys: Vec<_> = plan.addresses().copied().collect();
my_rpc.get_multiple_accounts(&keys).await?
}
None => Vec::new(),
};
let snap = swaps::decode_snapshot(&req, &initial_data, &followup_data)?;
let mut buf = InstructionBuf::new();
swaps::build_swap(&req, &snap, &mut buf)?;
let ix = buf.as_view();decode_snapshot accepts any AsRef<[u8]> account buffer, so callers can pass
Vec<Vec<u8>>, arrays of account data, or manually built &[&[u8]] without
allocating an intermediate refs vector.
InstructionBuf::as_view() is allocation-free and returns borrowed account and
data slices. lib/rpc boundary conversion is caller-owned.
the hot path is:
let snap = swaps::decode_snapshot(&req, &initial_data, &followup_data)?;
let mut buf = swaps::InstructionBuf::new();
swaps::build_swap(&req, &snap, &mut buf)?;
let ix = buf.as_view();ix is an InstructionView<'_>:
program_id: Addressaccounts: &[swaps::AccountMeta]data: &[u8]
this view borrows from InstructionBuf; it does not allocate or copy the
account/data arrays. use it directly if your transaction compiler, packet
encoder, or arena owns the final serialization step.
a SwapRequest describes a swap as token_in -> token_out.
dex: oneDexKindvariant for the target DEX.user: payer, signer, and token-account owner.token_in,token_out: mint addresses. DEX modules infer direction by matching these against pool state.pool: required for pool/market based DEXes, omitted for PumpFun bonding curves.amount_in,min_amount_out: caller-provided amounts. the lib does not quote or guess slippage.track_volume: PumpFun/PumpSwap volume-tracking option, defaultSome(true).token_in_program,token_out_program: default classic SPL Token; override for Token-2022 when the DEX uses request-side token programs.scorch_swap_id_le: scorch/jupiter route swap id bytes, set withwith_scorch_swap_id_le_bytes.
builder methods: with_pool, with_track_volume, with_token_programs,
with_scorch_swap_id_le_bytes.
PumpFun uses WSOL only as the API marker for the native SOL side. the on-chain
PumpFun instruction uses raw lamports.
most DEXes are one-round: fetch the initial plan, pass empty follow-up data, decode and build.
two-round dexes:
| dex | initial fetch | follow-up fetch |
|---|---|---|
| Raydium AMM v4 | AMM info | OpenBook market from AMM state |
| Meteora Pools | DAMM v1 pool | Two linked Meteora vault accounts |
| Meteora DBC | Virtual pool | Pool config account |
| Stabble stable swap | Pool | Linked Stabble vault account |
| Stabble weighted swap | Pool | Linked Stabble vault account |
| Jupiter Perps | Pool | Linked custody accounts |
one-round DEXes include PumpFun, PumpSwap, Raydium CLMM/CPMM/Launchpad, Orca Whirlpool, Meteora DAMM v2/DLMM, Bonkswap, HumidiFi, SolFi V2, PancakeSwap, Byreal, Fusion AMM, GooseFX Gamma, Tessera V1, Obric, BisonFi, and Scorch.
all DEX features are enabled by default:
[dependencies]
swaps = { path = "../swaps", default-features = false, features = ["pumpfun"] }available features: pumpfun, pumpswap, raydium-amm-v4, raydium-clmm,
raydium-cpmm, raydium-launchpad, orca-whirlpool, meteora-pools,
meteora-damm-v2, meteora-dlmm, meteora-dbc, bonkswap, humidifi,
stable-swap, stabble-weighted-swap, solfi-v2, pancakeswap, byreal,
fusion-amm, goosefx-gamma, jupiter-perps, tessera-v1, obric,
bisonfi, and scorch.
see notes.md for protocol quirks, known limitations and reverse-engineered
adapter details that callers may need to account for.
cargo test --all-features
cargo clippy --all-features --all-targets -- -D warningscargo bench --bench hot_path
SWAPS_BENCH_ITERS=2000 cargo bench --bench hot_paththe hot-path bench reports mean, p50, p95, p99, max latency and allocation counts for stack-backed instruction building + PDA-heavy fetch/build paths.
MIT