All articles
solanadeveloper-toolsapiliquid-stakinglsttransactionsdefi

Sanctum for developers: LST swap API, Gateway transaction delivery, and on-chain programs

Sanctum exposes two distinct developer surfaces: the LST swap API (ExactIn/ExactOut routes across 200+ LSTs via Ironforge) and Sanctum Gateway (JSON-RPC transaction delivery aggregator routing through Jito, SWQoS RPCs, Helius, Nozomi, and more). Here is how to use both.

Share
devrels.xyz/a/121short link

Sanctum has two products that matter to developers. The first is the LST swap API: a unified REST interface for staking, unstaking, and swapping across 200+ liquid staking tokens on Solana, routing through the Infinity pool, the Sanctum Router, and Jupiter. The second is Sanctum Gateway: a JSON-RPC transaction delivery aggregator that routes signed transactions through traditional RPCs, SWQoS connections, Jito bundles, and specialist senders — with a refund on Jito tips if your transaction lands via RPC instead.

The LST swap API

The Sanctum API is hosted at https://sanctum-api.ironforge.network. It exposes three operation types: SOL deposits (stake SOL, receive an LST), SOL withdrawals (burn an LST, receive SOL), and stake account operations (deposit or withdraw a raw Solana stake account). All routes go through a best-quote step before returning a transaction.

bash
# Base URL
https://sanctum-api.ironforge.network

# ── Quote endpoints (no signer required) ───────────────────────────
GET /swap/quote
  ?input=<LST mint or stake account vote pubkey>
  &output=<LST mint or vote account>
  &amount=<lamports>
  &mode=ExactIn|ExactOut
  &swapSrc=Inf,SanctumRouter,Jup   # optional: filter sources
  # Returns: best quote across all enabled sources

# ── Transaction endpoints (signer required) ─────────────────────────
GET /swap/depositSol/order     # SOL → LST
GET /swap/withdrawSol/order    # LST → SOL
GET /swap/depositStake/order   # stake account → LST
GET /swap/withdrawStake/order  # LST → stake account

# Shared query params:
#   input, output, amount, mode (ExactIn|ExactOut)
#   slippageBps: tolerance in basis points (default 30 = 0.3%)
#   signer: your wallet pubkey (required for tx endpoint)
#   swapSrc: comma-separated filter (Inf | SanctumRouter | Jup)
#   lstAcc: specific LST token account (defaults to signer's ATA)
#   stakeAcc: specific stake account pubkey (for stake-based ops)
typescript
// Stake 1 SOL into jupSOL — get back a transaction to sign
const JUPSOL_MINT = "jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v";
const signer = wallet.publicKey.toBase58();

const url = new URL("https://sanctum-api.ironforge.network/swap/depositSol/order");
url.searchParams.set("input",      "So11111111111111111111111111111111111111112"); // SOL
url.searchParams.set("output",     JUPSOL_MINT);
url.searchParams.set("amount",     String(1e9));   // 1 SOL in lamports
url.searchParams.set("mode",       "ExactIn");
url.searchParams.set("slippageBps","50");           // 0.5%
url.searchParams.set("signer",     signer);

const { tx, outAmount } = await fetch(url).then(r => r.json());
// tx: base64-encoded versioned transaction ready to sign
// outAmount: how many jupSOL lamports you'll receive

const txBytes = Buffer.from(tx, "base64");
const vtx = VersionedTransaction.deserialize(txBytes);
vtx.sign([wallet]);
const sig = await connection.sendRawTransaction(vtx.serialize());
typescript
// Swap any LST to any other LST (e.g. jupSOL → mSOL)
const MSOL_MINT = "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So";

const url = new URL("https://sanctum-api.ironforge.network/swap/quote");
url.searchParams.set("input",     JUPSOL_MINT);
url.searchParams.set("output",    MSOL_MINT);
url.searchParams.set("amount",    String(5e9));      // 5 jupSOL
url.searchParams.set("mode",      "ExactIn");
url.searchParams.set("swapSrc",   "Inf,SanctumRouter"); // skip Jupiter

const quote = await fetch(url).then(r => r.json());
// { route: "Inf", outAmount: "4991234567", priceImpactPct: "0.02" }

// Then call /swap/depositSol/order with the same params + signer to get the tx

The LST registry

The canonical list of all LSTs in the Sanctum ecosystem lives at github.com/igneous-labs/sanctum-lst-list as a sanctum-lst-list.toml file. Each entry has the mint address, name, symbol, vote account (validator), and pool type. This is the source of truth for which tokens the API will accept as inputs or outputs.

bash
# Fetch the LST registry and find a specific LST
curl -s https://raw.githubusercontent.com/igneous-labs/sanctum-lst-list/master/sanctum-lst-list.toml \
  | grep -A5 'symbol = "jupSOL"'

# Output:
# [[sanctum_lst_list]]
# symbol = "jupSOL"
# mint = "jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v"
# vote_account = "..."
# pool = { type = "SplStakePool", ... }

Sanctum Gateway: transaction delivery

Sanctum Gateway is a separate product from the LST API. It is a JSON-RPC endpoint that takes your signed or unsigned transaction and routes it through multiple delivery channels simultaneously to maximise the chance of landing. It does not replace your wallet or connection — it sits in front of the normal sendTransaction call.

The two JSON-RPC methods are buildGatewayTransaction and sendTransaction. The flow is:

  1. Build your transaction, serialize it to base64 (unsigned or partially signed).
  2. Call buildGatewayTransaction — Gateway wraps it with optimised priority fees and tip accounts.
  3. Sign the returned transaction locally with your private key.
  4. Call sendTransaction — Gateway routes it through all configured delivery methods.
typescript
const GATEWAY_URL = `https://gateway.sanctum.so/rpc?cluster=mainnet-beta&apiKey=${API_KEY}`;

async function sendViaGateway(connection: Connection, tx: Transaction, wallet: Keypair) {
  // 1. Serialize unsigned transaction
  tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
  tx.feePayer = wallet.publicKey;
  const unsignedBase64 = tx.serialize({ requireAllSignatures: false }).toString("base64");

  // 2. Build through Gateway (adds priority fees, Jito tip accounts)
  const buildRes = await fetch(GATEWAY_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "buildGatewayTransaction",
      params: [unsignedBase64, { encoding: "base64" }],
    }),
  }).then(r => r.json());

  const optimizedTx = Transaction.from(Buffer.from(buildRes.result, "base64"));

  // 3. Sign locally
  optimizedTx.sign(wallet);
  const signedBase64 = optimizedTx.serialize().toString("base64");

  // 4. Send through Gateway delivery network
  const sendRes = await fetch(GATEWAY_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 2,
      method: "sendTransaction",
      params: [signedBase64, { encoding: "base64" }],
    }),
  }).then(r => r.json());

  return sendRes.result; // transaction signature
}

The delivery channels Gateway routes through simultaneously:

  • Traditional RPCs — standard Solana RPC endpoints
  • SWQoS RPCs — stake-weighted quality of service connections
  • Jito bundles — MEV-protected submission through Jito block engine
  • Triton Cascade — Triton's multi-path sender
  • Paladin — validator-direct submission
  • Helius Sender, Nozomi, Astralane — specialist transaction relay services

The Jito tip refund is worth noting: if your transaction lands via an RPC path rather than the Jito bundle path, Gateway refunds the Jito tip. You pay only for the path that actually worked.

Project configuration and observability

Gateway has a dashboard at gateway.sanctum.so where you configure delivery methods, manage API keys per environment (mainnet/devnet), and view per-project transaction analytics — success rate, confirmation latency, which delivery channel landed each transaction. The dashboard is the fastest way to tune delivery method priority without code changes.

On-chain programs

For deeper integration, Sanctum's on-chain programs are maintained by igneous-labs. The S Controller Program manages the multi-LST AMM (the “Curve of LSTs”) that holds hundreds of LSTs and enables capital-efficient LST-LST swaps. The Router Program handles staking and unstaking routing. The INF 1.5 repository is the current Infinity pool implementation.

bash
# Key repos under github.com/igneous-labs
sanctum-router-sdk     # Rust + TypeScript Router Program SDK
sanctum-lst-list       # Canonical LST registry (TOML)
sanctum-solana-utils   # Shared Solana utilities
sol-val-calc           # SOL value calculator SDK and programs
inf-1.5                # Infinity pool v1.5 (active)
S                      # S Controller Program (archived, see inf-1.5)

Keep reading

Get new articles in your inbox

Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.

Sanctum for developers: LST swap API, Gateway transaction delivery, and on-chain programs | devrels.xyz