Skill

Carbium Skill — AI Assistant Context File

Drop this into any AI assistant's context (system prompt or project instructions) to enable Carbium-aware Solana development.


What is Carbium?

Carbium is full-stack Solana infrastructure — Swiss-engineered, bare-metal, no cloud middlemen.
One platform covering the full transaction lifecycle:

ProductWhat it doesBase URL
RPCStandard JSON-RPC for Solana (reads, writes, subscriptions)https://rpc.carbium.io
gRPC / StreamReal-time Yellowstone-based Full Block streamingwss://grpc.carbium.io
Swap APIAggregated DEX quotes, routing, and swap executionhttps://api.carbium.io
DEXUI DEX (user-facing, wallet connect)https://carbium.io
DocsFull documentationhttps://docs.carbium.io

API Keys

⚠️

Programmatic key provisioning is not yet available. Keys must be created manually via the dashboards (free to start).

ProductSignup URLNotes
RPC + gRPChttps://rpc.carbium.io/signupOne key covers both RPC and gRPC endpoints
Swap APIhttps://api.carbium.io/loginFree account, key available instantly

Security rules (non-negotiable):

  • Never embed keys in frontend/client-side code
  • Never commit keys to version control
  • Use environment variables: CARBIUM_RPC_KEY, CARBIUM_API_KEY
  • Keys can be rotated at any time from the dashboard

RPC Tiers

TierPriceCredits/moMax RPSgRPC
Free$0500K10
Developer$32/mo10M50
Business$320/mo100M200
Professional$640/mo200M500

gRPC streaming requires Business tier or above.


Use Cases & Which Product to Use

I want to…UseKey needed
Read account data / balancesRPCRPC key
Send a transactionRPCRPC key
Build a wallet appRPC + Swap APIBoth
Get a token swap quoteSwap APIAPI key
Execute a swap programmaticallySwap APIAPI key
Execute a swap with Jito bundlingSwap API (bundle endpoint)API key
Snipe pump.fun tokens (pre-graduation)gRPC + direct bonding curve txRPC key (Business+)
React to on-chain events in real timegRPC (streaming)RPC key (Business+)
Index transactions for a programgRPC (streaming)RPC key (Business+)
Build an arbitrage / MEV botgRPC + Swap APIBoth
Monitor a specific walletgRPC (streaming)RPC key (Business+)
Portfolio trackerRPCRPC key

RPC — Usage

Endpoint:

https://rpc.carbium.io/?apiKey=YOUR_RPC_KEY

Standard Solana JSON-RPC. Any Solana SDK works: @solana/web3.js, solana-py, solana Rust crate.

TypeScript / Node.js

import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";

const connection = new Connection(
  `https://rpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`,
  "confirmed"
);

// Get balance
const pubkey = new PublicKey("YOUR_WALLET_ADDRESS");
const balance = await connection.getBalance(pubkey);
console.log(`Balance: ${balance / LAMPORTS_PER_SOL} SOL`);

// Send transaction
const sig = await connection.sendRawTransaction(transaction.serialize(), {
  skipPreflight: false,
  maxRetries: 3,
});
await connection.confirmTransaction(sig, "confirmed");

Python

from solana.rpc.api import Client
from solders.pubkey import Pubkey
import os

rpc = Client(f"https://rpc.carbium.io/?apiKey={os.environ['CARBIUM_RPC_KEY']}")

pubkey = Pubkey.from_string("YOUR_WALLET_ADDRESS")
resp = rpc.get_balance(pubkey)
print(f"Balance: {resp.value / 1e9} SOL")

Rust

use solana_client::rpc_client::RpcClient;
use solana_sdk::pubkey::Pubkey;
use std::str::FromStr;

let url = format!(
    "https://rpc.carbium.io/?apiKey={}",
    std::env::var("CARBIUM_RPC_KEY").unwrap()
);
let client = RpcClient::new(url);
let pubkey = Pubkey::from_str("YOUR_WALLET_ADDRESS").unwrap();
let balance = client.get_balance(&pubkey).unwrap();
println!("Balance: {} lamports", balance);

gRPC / Streaming — Usage

Real-time Yellowstone-compatible Full Block stream. ~22ms latency. Atomic complete blocks — no shred reassembly needed.

Auth

MethodFormat
WebSocket query paramwss://grpc.carbium.io/?apiKey=YOUR_RPC_KEY
HTTP/2 header (Rust)x-token: YOUR_RPC_KEY

Requires Business tier or above (https://rpc.carbium.io/signup).

TypeScript / Node.js — Subscribe to program transactions

import WebSocket from "ws";

const PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"; // example: pump.fun

const ws = new WebSocket(
  `wss://grpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`
);

ws.on("open", () => {
  ws.send(JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "transactionSubscribe",
    params: [
      {
        vote: false,           // exclude vote transactions
        failed: false,         // exclude failed transactions
        accountInclude: [PROGRAM_ID], // ⚠️ at least one of accountInclude or accountRequired must be non-empty
        accountExclude: [],
        accountRequired: [],
      },
      {
        commitment: "confirmed",    // "processed" | "confirmed" | "finalized"
        encoding: "base64",         // "base64" | "base58" | "jsonParsed"
        transactionDetails: "full", // "full" | "signatures" | "none"
        showRewards: false,
        maxSupportedTransactionVersion: 0,
      },
    ],
  }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw.toString());
  if (msg.result !== undefined) {
    console.log(`Subscribed, ID: ${msg.result}`);
    return;
  }
  if (msg.method === "transactionNotification") {
    const { signature, slot } = msg.params.result;
    console.log(`tx ${signature} in slot ${slot}`);
  }
});

ws.on("close", (code) => {
  // Always reconnect with exponential backoff — see Operational Guardrails below
  console.warn(`Disconnected (${code}), reconnecting...`);
});

Python — Subscribe

import asyncio, json, os
import websockets

PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"

async def subscribe():
    uri = f"wss://grpc.carbium.io/?apiKey={os.environ['CARBIUM_RPC_KEY']}"
    async with websockets.connect(uri) as ws:
        await ws.send(json.dumps({
            "jsonrpc": "2.0", "id": 1,
            "method": "transactionSubscribe",
            "params": [
                {
                    "vote": False, "failed": False,
                    "accountInclude": [PROGRAM_ID],
                    "accountExclude": [], "accountRequired": [],
                },
                {
                    "commitment": "confirmed", "encoding": "base64",
                    "transactionDetails": "full", "showRewards": False,
                    "maxSupportedTransactionVersion": 0,
                },
            ],
        }))
        async for message in ws:
            data = json.loads(message)
            if "result" in data:
                print(f"Subscribed: {data['result']}")
            elif data.get("method") == "transactionNotification":
                print(f"tx: {data['params']['result']['signature'][:20]}...")

asyncio.run(subscribe())

Rust — HTTP/2 gRPC

use yellowstone_grpc_client::GeyserGrpcClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = GeyserGrpcClient::connect(
        "https://grpc.carbium.io",
        "YOUR_RPC_KEY",  // passed as x-token header automatically
        None,
    )?;
    let (_subscribe_tx, mut stream) = client.subscribe().await?;
    // define subscription filters and consume stream...
    Ok(())
}

Filter fields reference

FieldTypeDescription
voteboolInclude vote transactions
failedboolInclude failed transactions
accountIncludestring[]Include txs involving ANY of these accounts
accountExcludestring[]Exclude txs involving these accounts
accountRequiredstring[]Only include txs involving ALL of these accounts

Unsubscribe

{"jsonrpc": "2.0", "id": 2, "method": "transactionUnsubscribe", "params": [SUBSCRIPTION_ID]}

Swap API — Usage

Single API for: get quote → get swap transaction → execute on-chain.
Aggregates Solana DEX liquidity. Powered by the CQ1 engine (sub-ms quotes, binary-native state, ~10ms chain → queryable).

Base URL: https://api.carbium.io
API version: v2
Auth: X-API-KEY: YOUR_API_KEY header on all requests
Get your key: https://api.carbium.io/login (free account)

1. Get Quote

GET /api/v2/quote
ParamDescriptionExample
src_mintInput token mint addressSo111...112 (SOL)
dst_mintOutput token mint addressEPjFW...t1v (USDC)
amount_inInput amount in smallest unit (lamports)1000000000
slippage_bpsSlippage tolerance in basis points100 (= 1%)
// JavaScript
fetch(
  'https://api.carbium.io/api/v2/quote' +
  '?src_mint=So11111111111111111111111111111111111111112' +
  '&dst_mint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' +
  '&amount_in=1000000000' +
  '&slippage_bps=100',
  { headers: { 'X-API-KEY': process.env.CARBIUM_API_KEY } }
)
  .then(res => res.json())
  .then(console.log);
# Python
import httpx, os

resp = httpx.get(
    "https://api.carbium.io/api/v2/quote",
    params={
        "src_mint": "So11111111111111111111111111111111111111112",
        "dst_mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "amount_in": 1_000_000_000,
        "slippage_bps": 100,
    },
    headers={"X-API-KEY": os.environ["CARBIUM_API_KEY"]},
)
print(resp.json())

2. Get Swap Transaction

GET /api/v2/swap
ParamDescriptionExample
fromMintInput token mintSo111...112
toMintOutput token mintEPjFW...t1v
amountInput amount in smallest unit100000000
slippageSlippage in basis points100
providerDEX/AMM to route throughraydium
⚠️

Naming inconsistency: Quote uses src_mint/dst_mint/amount_in/slippage_bps; Swap uses fromMint/toMint/amount/slippage. Use the exact param names per endpoint or you'll get silent bad results.

Returns a serialized transaction (base64). Deserialize, sign with your wallet, then send via RPC.

// JavaScript
fetch(
  'https://api.carbium.io/api/v2/swap' +
  '?fromMint=So11111111111111111111111111111111111111112' +
  '&toMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' +
  '&amount=100000000' +
  '&slippage=100' +
  '&provider=raydium',
  { headers: { accept: 'text/plain', 'X-API-KEY': process.env.CARBIUM_API_KEY } }
)
  .then(res => res.json())
  .then(console.log);
// TypeScript — full execute flow
import { Connection, VersionedTransaction } from "@solana/web3.js";

const connection = new Connection(
  `https://rpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`,
  "confirmed"
);

// Get serialized swap tx
const res = await fetch(
  `https://api.carbium.io/api/v2/swap` +
  `?fromMint=So11111111111111111111111111111111111111112` +
  `&toMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` +
  `&amount=100000000&slippage=100&provider=raydium`,
  { headers: { accept: "text/plain", "X-API-KEY": process.env.CARBIUM_API_KEY! } }
);
const { transaction } = await res.json(); // base64 encoded

// Deserialize → sign → send
const tx = VersionedTransaction.deserialize(Buffer.from(transaction, "base64"));
// tx.sign([yourKeypair]);
const sig = await connection.sendRawTransaction(tx.serialize(), { maxRetries: 3 });
await connection.confirmTransaction(sig, "confirmed");
console.log("Swap confirmed:", sig);

3. Jito Bundle (MEV-protected execution)

GET /api/v2/swap/bundle
fetch('https://api.carbium.io/api/v2/swap/bundle', {
  headers: { accept: 'application/json', 'X-API-KEY': process.env.CARBIUM_API_KEY }
})
  .then(res => res.json())
  .then(console.log);

Pump.fun Pre-Graduation Token Sniping

Carbium Swap API cannot route pump.fun / Raydium CPMM tokens (returns 0 routes). The correct approach for pre-graduation tokens is: gRPC stream to detect launches → build raw bonding curve transactions → submit via RPC.

Requires Business tier RPC key (gRPC access).

Key Constants

const PUMP_PROGRAM       = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
const PUMP_GLOBAL        = "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf";
const PUMP_FEE_RECIPIENT = "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM";
const PUMP_EVENT_AUTH    = "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1";
const GRADUATION_SOL     = 85_000_000_000n; // 85 SOL in lamports
const TOTAL_SUPPLY       = 1_000_000_000_000_000n; // 1 quadrillion (6 decimals)

const DISCRIMINATORS = {
  create: [0xe4, 0x45, 0xa5, 0x2e, 0x51, 0xcb, 0x9a, 0x1d],
  buy:    [0x66, 0x06, 0x3d, 0x12, 0x01, 0xda, 0xeb, 0xea],
  sell:   [0x33, 0xe6, 0x85, 0xa4, 0x01, 0x7f, 0x83, 0xad],
};

Step 1 — Subscribe to pump.fun launches via gRPC

import WebSocket from "ws";

const ws = new WebSocket(
  `wss://grpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`
);

ws.on("open", () => {
  ws.send(JSON.stringify({
    jsonrpc: "2.0", id: 1,
    method: "transactionSubscribe",
    params: [
      { vote: false, failed: false, accountInclude: [PUMP_PROGRAM] },
      { commitment: "confirmed", encoding: "jsonParsed",
        transactionDetails: "full", showRewards: false,
        maxSupportedTransactionVersion: 0 },
    ],
  }));
});

// WS keepalive — send ping every 30s
setInterval(() => ws.ping(), 30_000);

ws.on("message", (raw) => {
  const msg = JSON.parse(raw.toString());
  if (msg.method !== "transactionNotification") return;

  const { signature, transaction } = msg.params.result;
  const logs = transaction.meta.logMessages || [];

  for (const log of logs) {
    if (log.includes("Instruction: Create")) {
      const mint = transaction.meta.postTokenBalances[0]?.mint;
      if (mint) handleNewToken(mint, signature);
    }
  }
});

Step 2 — Derive bonding curve PDA

import { PublicKey } from "@solana/web3.js";

function deriveBondingCurve(mint: string): PublicKey {
  const [address] = PublicKey.findProgramAddressSync(
    [Buffer.from("bonding-curve"), new PublicKey(mint).toBuffer()],
    new PublicKey(PUMP_PROGRAM)
  );
  return address;
}

Step 3 — Fetch & parse bonding curve state

// Bonding curve layout (81 bytes):
// [0-7]   discriminator
// [8-15]  virtualTokenReserves (u64 LE)
// [16-23] virtualSolReserves   (u64 LE)
// [24-31] realTokenReserves    (u64 LE)
// [32-39] realSolReserves      (u64 LE)
// [40-47] tokenTotalSupply     (u64 LE)
// [72]    complete             (bool)

async function fetchBondingCurve(bondingCurveAddress: PublicKey) {
  const res = await fetch(`https://rpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0", id: 1,
      method: "getAccountInfo",
      params: [bondingCurveAddress.toBase58(), { encoding: "base64" }],
    }),
  });
  const { result } = await res.json();
  const data = Buffer.from(result.value.data[0], "base64");

  return {
    virtualTokenReserves: data.readBigUInt64LE(8),
    virtualSolReserves:   data.readBigUInt64LE(16),
    realTokenReserves:    data.readBigUInt64LE(24),
    realSolReserves:      data.readBigUInt64LE(32),
    complete:             data.readUInt8(72) === 1,
  };
}

function calcMetrics(curve: Awaited<ReturnType<typeof fetchBondingCurve>>) {
  const bondingPct = Math.min(100,
    (Number(curve.realSolReserves) / Number(GRADUATION_SOL)) * 100
  );
  return {
    bondingCurvePercent: bondingPct,
    isGraduated: curve.complete || bondingPct >= 100,
  };
}

Step 4 — Quote (constant product AMM)

// Buy: how many tokens for X SOL
function quoteBuy(curve: ReturnType<typeof parseBondingCurve>, solLamports: number): bigint {
  const num = curve.virtualTokenReserves * BigInt(solLamports);
  const den = curve.virtualSolReserves + BigInt(solLamports);
  return num / den;
}

// Sell: how much SOL for X tokens
function quoteSell(curve: ReturnType<typeof parseBondingCurve>, tokens: bigint): bigint {
  const num = curve.virtualSolReserves * tokens;
  const den = curve.virtualTokenReserves + tokens;
  return num / den;
}

Step 5 — Build & submit buy transaction

// Buy instruction accounts (order matters):
// 0  PUMP_GLOBAL          (read)
// 1  PUMP_FEE_RECIPIENT   (write)
// 2  mint                 (read)
// 3  bondingCurve         (write)
// 4  bondingCurve ATA     (write)
// 5  user ATA             (write)
// 6  user/payer           (write, signer)
// 7  SystemProgram
// 8  TokenProgram
// 9  AssociatedTokenProgram
// 10 Rent sysvar
// 11 PUMP_EVENT_AUTH      (read)
// 12 PUMP_PROGRAM         (read)

// Submit via RPC (skipPreflight: true saves ~200ms)
const submitRes = await fetch(
  `https://rpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`,
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0", id: 1,
      method: "sendTransaction",
      params: [
        signedTxBase64,
        { skipPreflight: true, preflightCommitment: "confirmed", maxRetries: 3 },
      ],
    }),
  }
);

Sniping flow summary

gRPC "Create" event → extract mint
  → deriveBondingCurve(mint)
  → [optional] fetchBondingCurve() for price check
  → build buy instruction with desired SOL
  → sendTransaction(skipPreflight: true)
  → monitor bonding curve state for exit
  → sell when target % reached or graduation imminent

Pump.fun error handling

ErrorCauseFix
Blockhash expiredTx took too longFresher blockhash; reduce latency
Insufficient fundsNot enough SOLBalance must cover amount + fees (~0.005 SOL)
Account not foundToken just createdRetry with small delay (50–100ms)
Slippage exceededPrice movedIncrease maxSolCost or reduce size

Latency tips

  • skipPreflight: true — saves ~200ms
  • Pre-build tx templates — just swap in mint at launch time
  • Fetch bonding curve in parallel while building tx
  • WS keepalive ping every 30s to avoid silent disconnects

Operational Guardrails (Required for Production)

Timeouts

  • RPC read calls: 5–10s
  • Swap quote: 3–5s
  • Transaction confirmation: 30–60s with polling

Retries with backoff

const delay = (ms: number) => new Promise(r => setTimeout(r, ms));

async function withRetry<T>(fn: () => Promise<T>, retries = 3, baseMs = 300): Promise<T> {
  for (let i = 0; i < retries; i++) {
    try { return await fn(); }
    catch (e) {
      if (i === retries - 1) throw e;
      await delay(baseMs * 2 ** i + Math.random() * 100); // exponential + jitter
    }
  }
  throw new Error("unreachable");
}

// Usage
const quote = await withRetry(() => fetchQuote(...));
⚠️

Do NOT blindly retry sendTransaction — check getSignatureStatus first to confirm the tx didn't already land.

Stream reconnect (gRPC/WS)

async function connectWithReconnect() {
  let backoff = 1000;
  while (true) {
    try {
      await connect(); // your ws connect logic
      backoff = 1000;  // reset on success
    } catch {
      await delay(backoff);
      backoff = Math.min(backoff * 2, 30_000); // cap at 30s
    }
  }
}

Failure handling by type

FailureWhat to do
Quote: no route foundRetry with wider slippage or different provider
Simulation failedDo NOT send — inspect error, log, alert
sendTransaction failedCheck getSignatureStatus before retry
Transaction not confirmedPoll with timeout; check for expiry (blockhash)
Stream disconnectedReconnect with exponential backoff
HTTP 429 rate limitBack off immediately; retry after delay

Error Reference

HTTP CodeMeaningAction
401Invalid / missing API keyCheck key and auth format
403Plan restriction (e.g. gRPC on free tier)Upgrade at rpc.carbium.io
429Rate limit exceededBackoff + retry
500Server errorRetry after 1s
503Temporary unavailabilityRetry with backoff

Key Concepts

  • CQ1 engine: Carbium's DEX routing — decoupled write/read paths, binary-native state. ~10ms chain → queryable. Sub-ms quote generation.
  • Full Blocks vs Shreds: Carbium streams Full Blocks (~22ms). Shreds (~9ms) require client-side reassembly. The difference is negligible vs ~400ms Solana slot time.
  • MEV protection + Jito bundling: Built into Swap API. Use /api/v2/swap/bundle for Jito-bundled execution.
  • Gasless swaps: Supported via Swap API.
  • Commitment levels: processed (fastest, may roll back) → confirmed (recommended) → finalized (slowest, guaranteed).

Further Reading


This is the Carbium Skill file — a self-contained context document for AI assistants. For support: https://discord.gg/jW7BUkQS5U