Gasless Token Swap

Learn to build a code to swap token to Solana without needing to hold initial $SOL. Use it by dropping contract address to the terminal.

To build a sample application using the Carbium Gasless Swap API, we will create a Node.js command-line interface (CLI) tool. This tool will allow a user to paste a token's Contract Address (CA) and swap that token for Solana (SOL) without needing SOL in their wallet for gas fees (as per the "Gasless" feature).

1. Prerequisites

  • Node.js: Ensure Node.js (v16+) is installed.
  • Solana Wallet: You need a Solana wallet keypair (e.g., a standard id.json file or a private key string).
  • Carbium API Key: Access to the Carbium API requires an API Key.
    • Action: Visit the Carbium Dashboard (or the "Log In" link on the docs page) to generate your key.

2. Project Setup

Open your terminal and create a new directory for your project.

mkdir carbium-swap-app
cd carbium-swap-app
npm init -y

Install the required dependencies. We will use @solana/web3.js for blockchain interaction, axios for API requests, bs58 for key management, and dotenv for security.

npm install @solana/web3.js axios bs58 dotenv prompt-sync

3. Configuration

Create a .env file in the root directory to store your sensitive information.

File: .env

# Your Carbium API Key
CARBIUM_API_KEY=your_api_key_here

# Your Solana Wallet Private Key (Base58 string)
# WARNING: Never share this key.
PRIVATE_KEY=your_private_key_base58_string

# RPC URL (Optional, uses public default if not set)
RPC_URL=https://api.mainnet-beta.solana.com

4. The Application Code

Create a file named swap.js. This script will:

  1. Read the user's input (Token CA).
  2. Fetch a gasless swap transaction from the Carbium API.
  3. Sign the transaction (user signs transfer authority).
  4. Submit the transaction to the Solana network.

File: swap.js

require('dotenv').config();
const axios = require('axios');
const { Connection, Keypair, VersionedTransaction, PublicKey } = require('@solana/web3.js');
const bs58 = require('bs58');
const prompt = require('prompt-sync')();

// Configuration
const CARBIUM_API_URL = 'https://api.carbium.io/api/v1/swap';
const API_KEY = process.env.CARBIUM_API_KEY;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const RPC_URL = process.env.RPC_URL;
const SOL_MINT = 'So11111111111111111111111111111111111111112'; // Wrapped SOL Mint

async function main() {
    console.log("=== Carbium Gasless Swap CLI ===");

    // 1. Setup Wallet and Connection
    if (!PRIVATE_KEY || !API_KEY) {
        console.error("Error: Missing PRIVATE_KEY or CARBIUM_API_KEY in .env file.");
        return;
    }
    const wallet = Keypair.fromSecretKey(bs58.decode(PRIVATE_KEY));
    const connection = new Connection(RPC_URL, 'confirmed');
    console.log(`Wallet loaded: ${wallet.publicKey.toString()}`);

    // 2. Get User Input (Token CA)
    const tokenCA = prompt('Paste Token Contract Address (CA) to sell: ').trim();
    if (!tokenCA) {
        console.error("Error: Token CA is required.");
        return;
    }

    // 3. Get Amount
    // Note: In a production app, you would fetch the decimals here to convert user input (e.g., "1.5") to raw units.
    // For this sample, we ask for raw units or a simple integer for demonstration.
    const amountStr = prompt('Enter amount to swap (in raw units/lamports): ').trim();
    if (!amountStr) return;

    try {
        console.log(`\nFetching Gasless Swap Transaction...`);
        console.log(`Input: ${tokenCA}`);
        console.log(`Output: SOL (${SOL_MINT})`);

        // 4. Call Carbium API
        // We assume standard parameter naming based on the docs. 
        // Verify these parameters at https://docs.carbium.io/reference/swap
        const response = await axios.get(CARBIUM_API_URL, {
            headers: {
                'x-api-key': API_KEY, // Adjust header name if docs specify otherwise (e.g., 'Authorization')
                'Content-Type': 'application/json'
            },
            params: {
                inputMint: tokenCA,
                outputMint: SOL_MINT,
                amount: amountStr,
                userPublicKey: wallet.publicKey.toString(),
                // 'slippageBps': 50 // Optional: 0.5%
            }
        });

        if (!response.data) {
            throw new Error("No data received from Carbium API");
        }

        // The API returns a base64 encoded transaction string
        const base64Transaction = response.data.transaction || response.data; 
        
        console.log("Transaction received. Deserializing...");

        // 5. Deserialize the Transaction
        const transactionBuffer = Buffer.from(base64Transaction, 'base64');
        const transaction = VersionedTransaction.deserialize(transactionBuffer);

        // 6. Sign the Transaction
        // The transaction returned by Carbium should already have the Fee Payer set (likely Carbium's relayer).
        // You only need to sign as the owner of the source funds.
        transaction.sign([wallet]);

        console.log("Transaction signed. Sending to Solana network...");

        // 7. Send and Confirm
        const signature = await connection.sendTransaction(transaction, {
            maxRetries: 5,
            preflightCommitment: 'processed'
        });

        console.log(`\nSwap Submitted! 🚀`);
        console.log(`Signature: ${signature}`);
        console.log(`Explorer: https://solscan.io/tx/${signature}`);

        const confirmation = await connection.confirmTransaction(signature, 'confirmed');
        if (confirmation.value.err) {
            console.error("Transaction failed:", confirmation.value.err);
        } else {
            console.log("Transaction Confirmed Successfully!");
        }

    } catch (error) {
        console.error("\nExecution Error:");
        if (error.response) {
            console.error(`API Status: ${error.response.status}`);
            console.error(`API Data:`, error.response.data);
        } else {
            console.error(error.message);
        }
    }
}

main();

5. How to Run

  1. Make sure your .env file is populated with your API Key and Private Key.
  2. Run the application:
    node swap.js
  3. Follow the prompts:
    • Paste Token CA: Enter the address of the token you want to sell (e.g., EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v for USDC).
    • Amount: Enter the raw amount (e.g., 1000000 for 1 USDC if it has 6 decimals).

Troubleshooting

  • 401 Unauthorized: Check your CARBIUM_API_KEY.
  • 400 Bad Request: This usually means an issue with parameters.
    • Common fix: Check if the API expects tokenIn instead of inputMint, or sender instead of userPublicKey. You can verify the exact parameter names on the API Reference page by clicking "Try It" or checking the schema.
  • Transaction Error: If the simulation fails, ensure you have enough of the input token to swap. You do not need SOL for gas, but you do need the token you are trying to swap.