Skip to main content
An aggregator’s job is to give a user the best possible price across many pools, possibly splitting a single input across multiple pool routes, and execute it atomically. This page documents the Raydium-specific pieces of that job: discovery, quoting, and transaction assembly.

Discovery

Pool inventory

You need the full list of live Raydium pools for each product. Three options:
  1. REST API (simplest): GET https://api-v3.raydium.io/pools/info/list?poolType=all&pageSize=1000&page=1 returns pools in batches of 1000. Paginate until you have them all. Cache for 1–5 minutes.
  2. On-chain scan: getProgramAccounts on CPMM, CLMM, and AMM v4 program IDs, filtered by the state account discriminator. Yields ~every live pool with ~10s of RPC time. Useful when the API is down or rate-limited.
  3. Hybrid: use the API as the primary source; run a daily on-chain scan as a sanity check. The team commits to keeping the API comprehensive, but pools created through direct CPI (no frontend) can occasionally lag.

Mint-pair lookup

For a specific (mintA, mintB) pair, use GET /pools/info/mint?mint1=...&mint2=...&poolType=all&sort=liquidity. Returns every pool at any fee tier and product type. Up to ~10 results per pair is common on well-trafficked mints; sort by TVL and take the top few for routing.

Quoting

Quote math differs per product. Use the SDK’s pure math functions so you don’t re-implement:
Returns for all three: { amountOut, fee, priceImpact, minAmountOut }. For aggregator comparison, use amountOut (pre-slippage).

Cache freshness

Pool state gets stale fast. Recommended freshness targets: For an aggregator taking quotes at interactive latency, subscribe to WebSocket account updates (accountSubscribe) on each relevant pool state. That flips the model from polling to push.

Token-2022 adjustments

If any mint in the route has a Token-2022 transfer fee, the quote math must adjust inputs and outputs per algorithms/token-2022-transfer-fees. The SDK handles this if the poolInfo.mintA.extensions.transferFeeConfig is populated. Confirm by looking at the .extensions field before trusting the quote.

Routing

Single-pool routes

Most routes are single-pool. Pick the pool whose amountOut is highest. If multiple are close, tie-break by fee tier (lower is better), then by TVL (more is safer).

Split routing

For large trades where a single pool has >5% price impact, split across pools. A simple greedy algorithm:
This produces a routing vector [(pool_A, 0.6), (pool_B, 0.3), (pool_C, 0.1)] that minimizes aggregate impact. A proper convex-optimization solution (e.g. equalize marginal prices across pools) is within ~1% of the greedy result in practice.

Multi-hop routes

USDC → RAY → SOL via two separate pools is common when no direct USDC-SOL pool gives a good quote (rare). Apply per-hop slippage bounds; each hop enforces its own minAmountOut. See algorithms/slippage-and-price-impact. Multi-hop across the same pool (e.g. two CLMM hops on SOL-USDC) is always suboptimal vs a single hop — do not generate such routes.

Transaction assembly

Single-hop, single-pool

Use the SDK’s raydium.trade.swap directly:

Split and multi-hop

Compose ATAs + instructions manually. Pattern:
All inside one transaction for atomicity. For a 3-pool split on V0 with address lookup tables, this typically fits in ~1100 bytes. For 4+ pools, the transaction size cap forces either multi-tx or consolidation at a hub mint.

Atomicity

Aggregators must guarantee atomicity: either the full route lands or none of it does. Raydium’s swap instructions revert on ExceededSlippage, so a multi-pool route where one hop fails causes the whole transaction to revert. Free. The one exception: if your route goes through Raydium + a third-party DEX, make sure that DEX also has a revert-on-slippage model. Some programs ignore slippage bounds (rare).

Pitfalls

1. Stale quotes

Between the user seeing “You receive 125.43 RAY” and the transaction landing, reserves can shift. Re-fetch pool state immediately before submission; re-quote; if the new quote is >1% worse, pause and re-confirm with the user.

2. Pool blacklists

Some Raydium pools are scam tokens with transfer fees set to 99% or with non-transferable extensions. The REST API tags these (see the tags field); skip any pool tagged scam or honeypot. Running your own safety checks on top of Raydium’s tags is prudent.

3. Observation-state requirement on CLMM

CLMM SwapV2 takes an observation_state account. The SDK populates it for you; hand-built instructions often forget, which causes the program to revert with AccountNotFound. Always include it.

4. Address lookup tables

Raydium maintains public lookup tables for its most-used accounts (main mints, program IDs, AmmConfigs). Aggregators should consume these — it saves ~100 bytes per transaction and enables larger routes to fit in V0. Pulling the LUT addresses:

5. Handling congestion

During high-volume windows, transactions can sit in the mempool for multiple blocks. Aggressive retry on TX expiry (not on revert — reverts are deterministic) is recommended. The SDK’s sendAndConfirm option does basic retries; production aggregators layer their own logic (Jito bundles, multi-RPC broadcast) on top.

Checklist

Before going live, verify:
  • Pool discovery covers CPMM + CLMM + AMM v4 comprehensively.
  • Quotes match Raydium’s own UI quote within 1 basis point on a handful of test trades.
  • Split routing kicks in for trades >5% impact on any single pool.
  • Priority fees are sized against recent pool-program fees (see integration-guides/priority-fee-tuning).
  • Token-2022 transfer fees are computed and displayed to the user.
  • Transactions revert cleanly when slippage is exceeded.
  • Retry logic distinguishes tx expiry (retry) from revert (don’t retry).

Pointers

Sources: