Skip to main content
In this guide, you’ll learn how to get trade quotes and execute token swaps using the Bags TypeScript SDK with Node.js. The trade service allows you to swap tokens across various DEXs and liquidity pools on Solana.

Prerequisites

Before starting, make sure you have:
Transaction Fees: Trading tokens requires Solana transactions. Make sure your wallet has sufficient SOL balance to pay for transaction fees.

1. Set Up Environment Variables

This guide requires your wallet’s private key. Add it to your base .env file:
# .env
BAGS_API_KEY=your_api_key_here
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
PRIVATE_KEY=your_base58_encoded_private_key_here  # Required for this guide
You can export your private key from wallets like Bags, Phantom, or Backpack.

2. The Token Trading Script

Here is a complete script to get a trade quote and execute a swap. Save it as trade-tokens.ts. The script follows this flow:
  1. Get a trade quote
  2. Review the quote details
  3. Create a swap transaction
  4. Sign and send the transaction
import dotenv from "dotenv";
dotenv.config({ quiet: true });

import { BagsSDK, signAndSendTransaction } from "@bagsfm/bags-sdk";
import { Keypair, PublicKey, Connection } from "@solana/web3.js";
import bs58 from "bs58";

// Initialize SDK
const BAGS_API_KEY = process.env.BAGS_API_KEY;
const SOLANA_RPC_URL = process.env.SOLANA_RPC_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;

if (!BAGS_API_KEY || !SOLANA_RPC_URL || !PRIVATE_KEY) {
    throw new Error("BAGS_API_KEY, SOLANA_RPC_URL, and PRIVATE_KEY are required");
}

const connection = new Connection(SOLANA_RPC_URL);
const sdk = new BagsSDK(BAGS_API_KEY, connection, "processed");

async function executeSwap(
    inputMint: PublicKey,
    outputMint: PublicKey,
    amount: number,
    slippageMode: "auto" | "manual" = "auto",
    slippageBps?: number
) {
    try {
        if (!PRIVATE_KEY) {
            throw new Error("PRIVATE_KEY is not set");
        }

        const keypair = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY));
        const commitment = sdk.state.getCommitment();

        console.log(`💱 Getting trade quote...`);
        console.log(`   Input: ${inputMint.toBase58()}`);
        console.log(`   Output: ${outputMint.toBase58()}`);
        console.log(`   Amount: ${amount}`);
        console.log(`   Slippage Mode: ${slippageMode}`);

        // Step 1: Get a trade quote
        const quote = await sdk.trade.getQuote({
            inputMint: inputMint,
            outputMint: outputMint,
            amount: amount,
            slippageMode: slippageMode,
            slippageBps: slippageBps,
        });

        console.log("\n📊 Quote Details:");
        console.log(`   Request ID: ${quote.requestId}`);
        console.log(`   Input Amount: ${quote.inAmount}`);
        console.log(`   Output Amount: ${quote.outAmount}`);
        console.log(`   Min Output Amount: ${quote.minOutAmount}`);
        console.log(`   Price Impact: ${quote.priceImpactPct}%`);
        console.log(`   Slippage: ${quote.slippageBps / 100}%`);
        console.log(`   Route Plan: ${quote.routePlan.length} leg(s)`);

        // Display route plan details
        if (quote.routePlan.length > 0) {
            console.log("\n🛣️  Route Plan:");
            quote.routePlan.forEach((leg, index) => {
                console.log(`   Leg ${index + 1}:`);
                console.log(`      Venue: ${leg.venue}`);
                console.log(`      Input: ${leg.inAmount} (${leg.inputMint})`);
                console.log(`      Output: ${leg.outAmount} (${leg.outputMint})`);
            });
        }

        // Display platform fee if present
        if (quote.platformFee) {
            console.log("\n💰 Platform Fee:");
            console.log(`   Amount: ${quote.platformFee.amount}`);
            console.log(`   Fee BPS: ${quote.platformFee.feeBps}`);
            console.log(`   Fee Account: ${quote.platformFee.feeAccount}`);
        }

        // Step 2: Create swap transaction
        console.log("\n🎯 Creating swap transaction...");
        const swapResult = await sdk.trade.createSwapTransaction({
            quoteResponse: quote,
            userPublicKey: keypair.publicKey,
        });

        console.log(`   Compute Unit Limit: ${swapResult.computeUnitLimit}`);
        console.log(`   Prioritization Fee: ${swapResult.prioritizationFeeLamports} lamports`);

        // Step 3: Sign and send transaction
        console.log("\n🔑 Signing and sending swap transaction...");
        const signature = await signAndSendTransaction(connection, commitment, swapResult.transaction, keypair);

        console.log("\n🎉 Swap executed successfully!");
        console.log(`   Transaction Signature: ${signature}`);
        console.log(`   View on Solana Explorer: https://solscan.io/tx/${signature}`);

        return {
            signature,
            quote,
            swapResult,
        };
    } catch (error) {
        console.error("🚨 Swap execution failed:", error);
        throw error;
    }
}

// Example: Swap 100,000 tokens (adjust decimals based on token)
// Replace with your actual token mint addresses
const INPUT_MINT = new PublicKey("YOUR_INPUT_TOKEN_MINT_ADDRESS");
const OUTPUT_MINT = new PublicKey("YOUR_OUTPUT_TOKEN_MINT_ADDRESS");
const AMOUNT = 100_000; // Amount in token's smallest unit (e.g., if token has 6 decimals, 100000 = 0.1 tokens)

// Execute swap with auto slippage
executeSwap(INPUT_MINT, OUTPUT_MINT, AMOUNT, "auto")
    .then((result) => {
        console.log("\n✨ Swap completed successfully!");
    })
    .catch((error) => {
        console.error("🚨 Unexpected error occurred:", error);
    });

// Example: Execute swap with manual slippage (1% = 100 bps)
// executeSwap(INPUT_MINT, OUTPUT_MINT, AMOUNT, "manual", 100)
//     .then((result) => {
//         console.log("\n✨ Swap completed successfully!");
//     })
//     .catch((error) => {
//         console.error("🚨 Unexpected error occurred:", error);
//     });

3. Understanding Trade Quotes

A trade quote provides information about a potential swap before you execute it:

Quote Parameters

  • inputMint: The token you want to swap from (PublicKey)
  • outputMint: The token you want to swap to (PublicKey)
  • amount: The amount to swap (in the token’s smallest unit, e.g., lamports for SOL)
  • slippageMode: Either "auto" (automatic slippage calculation) or "manual" (you specify slippage)
  • slippageBps: Basis points for slippage tolerance (0-10000, where 10000 = 100%). Required when slippageMode is "manual"

Quote Response

The quote response includes:
  • inAmount: The input amount (as string)
  • outAmount: The expected output amount (as string)
  • minOutAmount: The minimum output amount considering slippage
  • priceImpactPct: The price impact percentage (as string)
  • slippageBps: The slippage tolerance in basis points
  • routePlan: Array of route legs showing the swap path through different venues
  • platformFee: Optional platform fee information
  • requestId: Unique identifier for the quote request

Route Plan

The route plan shows how your swap will be executed across different venues (DEXs, liquidity pools, etc.). Each leg represents one step in the swap path.

4. Slippage Modes

Auto Slippage

When using slippageMode: "auto", the SDK automatically calculates an appropriate slippage tolerance based on market conditions. This is recommended for most use cases.
const quote = await sdk.trade.getQuote({
    inputMint: inputMint,
    outputMint: outputMint,
    amount: amount,
    slippageMode: "auto",
});

Manual Slippage

When using slippageMode: "manual", you must specify slippageBps. This gives you full control over slippage tolerance.
const quote = await sdk.trade.getQuote({
    inputMint: inputMint,
    outputMint: outputMint,
    amount: amount,
    slippageMode: "manual",
    slippageBps: 100, // 1% slippage tolerance
});
Slippage BPS Examples:
  • 50 = 0.5% slippage tolerance
  • 100 = 1% slippage tolerance
  • 500 = 5% slippage tolerance
  • 1000 = 10% slippage tolerance

5. Swap Transaction Details

When you create a swap transaction, you receive:
  • transaction: A VersionedTransaction ready to be signed and sent
  • computeUnitLimit: The compute unit limit for the transaction
  • lastValidBlockHeight: The last valid block height for the transaction
  • prioritizationFeeLamports: The prioritization fee in lamports
The transaction is already configured with compute units and prioritization fees, so you can sign and send it directly.

6. Running the Script

To execute a swap, edit the script with your token mint addresses and amount:
  1. Set INPUT_MINT to the token you want to swap from
  2. Set OUTPUT_MINT to the token you want to swap to
  3. Set AMOUNT to the amount in the token’s smallest unit (consider token decimals)
Then, run the script from your terminal:
npx ts-node trade-tokens.ts

7. Getting a Quote Only

If you just want to check a quote without executing a swap:
async function getQuoteOnly(inputMint: PublicKey, outputMint: PublicKey, amount: number) {
    const quote = await sdk.trade.getQuote({
        inputMint: inputMint,
        outputMint: outputMint,
        amount: amount,
        slippageMode: "auto",
    });

    console.log(`Expected output: ${quote.outAmount}`);
    console.log(`Min output (with slippage): ${quote.minOutAmount}`);
    console.log(`Price impact: ${quote.priceImpactPct}%`);
    
    return quote;
}

8. Error Handling

The script includes comprehensive error handling for:
  • Invalid Token Mints: Ensure the mint addresses are valid Solana public keys
  • Insufficient Liquidity: The quote may fail if there’s not enough liquidity for the swap
  • Invalid Amount: The amount must be a positive number
  • Slippage Errors: If using manual slippage, ensure slippageBps is between 0 and 10000
  • Transaction Failures: Network issues or insufficient SOL for fees

9. Troubleshooting

Common issues include:
  • No Quote Available: Check that both tokens have sufficient liquidity and are tradeable
  • High Price Impact: Large swaps may have high price impact. Consider splitting into smaller swaps
  • Insufficient SOL: Your wallet needs SOL for transaction fees
  • Invalid Amount: Make sure the amount is in the token’s smallest unit (not in human-readable format)
For more details, see the API Reference.