Skip to content

jupiter swap ​

Execute multiple Jupiter swaps as an atomic bundle.

Use Case ​

Bundle multiple swaps together:

  • Multi-hop arbitrage
  • Portfolio rebalancing
  • Atomic DEX aggregation

JavaScript Example ​

javascript
import {
  Connection,
  Keypair,
  PublicKey,
  SystemProgram,
  TransactionMessage,
  VersionedTransaction,
} from "@solana/web3.js";

const BLOCKSPRINT_ENDPOINT = "https://fra.blocksprint.io/bundle/v1/YOUR_API_KEY";
const JUPITER_API = "https://api.jup.ag/swap/v1";
// BlockSprint tip address, tip at least 0.001 SOL
const TIP_ADDRESS = new PublicKey("Sp4JHSh9cksfzXbgK7Pq2ovtn8LirLQydaJKTsiNT77");

export async function getJupiterSwapTransaction(
  inputMint,
  outputMint,
  amount,
  userPublicKey,
  options = {}
) {
  // Get quote
  const dexes = options.dexes ? `&dexes=${options.dexes.join(",")}` : "";
  const quoteResponse = await fetch(
    `${JUPITER_API}/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=50${dexes}`
  );
  const quote = await quoteResponse.json();

  // Get swap transaction
  const swapResponse = await fetch(`${JUPITER_API}/swap`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      quoteResponse: quote,
      userPublicKey: userPublicKey.toString(),
      wrapAndUnwrapSol: true,
    }),
  });

  const { swapTransaction } = await swapResponse.json();
  return VersionedTransaction.deserialize(
    Buffer.from(swapTransaction, "base64")
  );
}

// Tip transaction: 0.001 SOL to a BlockSprint tip address
export function buildTipTransaction(wallet, recentBlockhash) {
  const message = new TransactionMessage({
    payerKey: wallet.publicKey,
    recentBlockhash,
    instructions: [
      SystemProgram.transfer({
        fromPubkey: wallet.publicKey,
        toPubkey: TIP_ADDRESS,
        lamports: 1_000_000,
      }),
    ],
  }).compileToLegacyMessage();
  const tx = new VersionedTransaction(message);
  tx.sign([wallet]);
  return tx;
}

export async function sendBundle(transactions) {
  const serializedTxs = transactions.map((tx) =>
    Buffer.from(tx.serialize()).toString("base64")
  );

  const response = await fetch(BLOCKSPRINT_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "sendBundle",
      params: [
        serializedTxs,
        { encoding: "base64", skipPreflight: true },
      ],
    }),
  });

  const result = await response.json();
  if (result.error) throw new Error(result.error.message);
  return result.result;
}

async function executeSwapBundle(wallet, swaps) {
  // Build all swap transactions
  const transactions = await Promise.all(
    swaps.map((swap) =>
      getJupiterSwapTransaction(
        swap.inputMint,
        swap.outputMint,
        swap.amount,
        wallet.publicKey
      )
    )
  );

  // Sign all transactions
  transactions.forEach((tx) => tx.sign([wallet]));

  // Add the tip transaction
  transactions.push(
    buildTipTransaction(wallet, transactions[0].message.recentBlockhash)
  );

  // Send as bundle
  const result = await sendBundle(transactions);

  console.log("Bundle ID:", result.bundle_id);
  result.signatures.forEach((sig, i) => {
    console.log(`Swap ${i + 1}: https://solscan.io/tx/${sig}`);
  });

  return result;
}

// Example: Swap SOL -> USDC and USDC -> BONK atomically
async function main() {
  const wallet = Keypair.fromSecretKey(/* your key */);

  const SOL = "So11111111111111111111111111111111111111112";
  const USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
  const BONK = "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263";

  await executeSwapBundle(wallet, [
    { inputMint: SOL, outputMint: USDC, amount: 100_000_000 },
    { inputMint: USDC, outputMint: BONK, amount: 10_000_000 },
  ]);
}

Arbitrage Bundle ​

Execute a buy and sell atomically:

javascript
import {
  buildTipTransaction,
  getJupiterSwapTransaction,
  sendBundle,
} from "./jupiter-bundle.js";

const SOL_MINT = "So11111111111111111111111111111111111111112";

async function executeArbitrage(wallet, token, buyDex, sellDex, amount, expectedTokenAmount) {
  // Get buy swap (SOL -> Token on DEX A)
  const buyTx = await getJupiterSwapTransaction(
    SOL_MINT,
    token,
    amount,
    wallet.publicKey,
    { dexes: [buyDex] }
  );

  // Get sell swap (Token -> SOL on DEX B)
  const sellTx = await getJupiterSwapTransaction(
    token,
    SOL_MINT,
    expectedTokenAmount,
    wallet.publicKey,
    { dexes: [sellDex] }
  );

  // Sign both
  buyTx.sign([wallet]);
  sellTx.sign([wallet]);

  // Send as atomic bundle (with the tip transaction)
  // If sell fails, buy also reverts - no stuck inventory
  return sendBundle([
    buyTx,
    sellTx,
    buildTipTransaction(wallet, buyTx.message.recentBlockhash),
  ]);
}

Python Example ​

python
import requests
import base64
from solders.keypair import Keypair
from solders.pubkey import Pubkey
from solders.system_program import TransferParams, transfer
from solders.transaction import Transaction, VersionedTransaction

BLOCKSPRINT_ENDPOINT = "https://fra.blocksprint.io/bundle/v1/YOUR_API_KEY"
JUPITER_API = "https://api.jup.ag/swap/v1"
TIP_ADDRESS = Pubkey.from_string("Sp4JHSh9cksfzXbgK7Pq2ovtn8LirLQydaJKTsiNT77")  # BlockSprint tip address

def get_jupiter_swap_tx(input_mint, output_mint, amount, user_pubkey):
    # Get quote
    quote = requests.get(
        f"{JUPITER_API}/quote",
        params={
            "inputMint": input_mint,
            "outputMint": output_mint,
            "amount": str(amount),
            "slippageBps": "50",
        }
    ).json()

    # Get swap transaction
    swap = requests.post(
        f"{JUPITER_API}/swap",
        json={
            "quoteResponse": quote,
            "userPublicKey": user_pubkey,
            "wrapAndUnwrapSol": True,
        }
    ).json()

    return swap["swapTransaction"]

def send_bundle(transactions_base64):
    response = requests.post(
        BLOCKSPRINT_ENDPOINT,
        json={
            "jsonrpc": "2.0",
            "id": 1,
            "method": "sendBundle",
            "params": [
                transactions_base64,
                {"encoding": "base64", "skipPreflight": True}
            ]
        }
    )
    result = response.json()
    if "error" in result:
        raise Exception(result["error"]["message"])
    return result["result"]

# Example
def execute_swap_bundle(wallet: Keypair, swaps):
    transactions = [
        get_jupiter_swap_tx(
            swap["input"],
            swap["output"],
            swap["amount"],
            str(wallet.pubkey())
        )
        for swap in swaps
    ]

    # Sign the swap transactions
    signed = []
    for tx_base64 in transactions:
        tx = VersionedTransaction.from_bytes(base64.b64decode(tx_base64))
        signed.append(VersionedTransaction(tx.message, [wallet]))

    # Tip transaction: 0.001 SOL to a BlockSprint tip address
    tip = transfer(TransferParams(from_pubkey=wallet.pubkey(), to_pubkey=TIP_ADDRESS, lamports=1_000_000))
    signed.append(Transaction.new_signed_with_payer(
        [tip], wallet.pubkey(), [wallet], signed[0].message.recent_blockhash
    ))

    result = send_bundle([base64.b64encode(bytes(tx)).decode("utf-8") for tx in signed])
    print(f"Bundle ID: {result['bundle_id']}")
    return result

Notes ​

Same blockhash ​

All transactions in a bundle should use the same recent blockhash

Atomic execution ​

All swaps succeed or all fail together

Tip required ​

Include a tip of at least 0.001 SOL to a BlockSprint tip address in one of the transactions

Max 4 transactions ​

Bundle limit is 4 transactions