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:
| Product | What it does | Base URL |
|---|---|---|
| RPC | Standard JSON-RPC for Solana (reads, writes, subscriptions) | https://rpc.carbium.io |
| gRPC / Stream | Real-time Yellowstone-based Full Block streaming | wss://grpc.carbium.io |
| Swap API | Aggregated DEX quotes, routing, and swap execution | https://api.carbium.io |
| DEX | UI DEX (user-facing, wallet connect) | https://carbium.io |
| Docs | Full documentation | https://docs.carbium.io |
API Keys
Programmatic key provisioning is not yet available. Keys must be created manually via the dashboards (free to start).
| Product | Signup URL | Notes |
|---|---|---|
| RPC + gRPC | https://rpc.carbium.io/signup | One key covers both RPC and gRPC endpoints |
| Swap API | https://api.carbium.io/login | Free 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
| Tier | Price | Credits/mo | Max RPS | gRPC |
|---|---|---|---|---|
| Free | $0 | 500K | 10 | ❌ |
| Developer | $32/mo | 10M | 50 | ❌ |
| Business | $320/mo | 100M | 200 | ✅ |
| Professional | $640/mo | 200M | 500 | ✅ |
gRPC streaming requires Business tier or above.
Use Cases & Which Product to Use
| I want to… | Use | Key needed |
|---|---|---|
| Read account data / balances | RPC | RPC key |
| Send a transaction | RPC | RPC key |
| Build a wallet app | RPC + Swap API | Both |
| Get a token swap quote | Swap API | API key |
| Execute a swap programmatically | Swap API | API key |
| Execute a swap with Jito bundling | Swap API (bundle endpoint) | API key |
| Snipe pump.fun tokens (pre-graduation) | gRPC + direct bonding curve tx | RPC key (Business+) |
| React to on-chain events in real time | gRPC (streaming) | RPC key (Business+) |
| Index transactions for a program | gRPC (streaming) | RPC key (Business+) |
| Build an arbitrage / MEV bot | gRPC + Swap API | Both |
| Monitor a specific wallet | gRPC (streaming) | RPC key (Business+) |
| Portfolio tracker | RPC | RPC 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
| Method | Format |
|---|---|
| WebSocket query param | wss://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
| Field | Type | Description |
|---|---|---|
vote | bool | Include vote transactions |
failed | bool | Include failed transactions |
accountInclude | string[] | Include txs involving ANY of these accounts |
accountExclude | string[] | Exclude txs involving these accounts |
accountRequired | string[] | 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
| Param | Description | Example |
|---|---|---|
src_mint | Input token mint address | So111...112 (SOL) |
dst_mint | Output token mint address | EPjFW...t1v (USDC) |
amount_in | Input amount in smallest unit (lamports) | 1000000000 |
slippage_bps | Slippage tolerance in basis points | 100 (= 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
| Param | Description | Example |
|---|---|---|
fromMint | Input token mint | So111...112 |
toMint | Output token mint | EPjFW...t1v |
amount | Input amount in smallest unit | 100000000 |
slippage | Slippage in basis points | 100 |
provider | DEX/AMM to route through | raydium |
Naming inconsistency: Quote usessrc_mint/dst_mint/amount_in/slippage_bps; Swap usesfromMint/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
| Error | Cause | Fix |
|---|---|---|
| Blockhash expired | Tx took too long | Fresher blockhash; reduce latency |
| Insufficient funds | Not enough SOL | Balance must cover amount + fees (~0.005 SOL) |
| Account not found | Token just created | Retry with small delay (50–100ms) |
| Slippage exceeded | Price moved | Increase 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 retrysendTransaction— checkgetSignatureStatusfirst 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
| Failure | What to do |
|---|---|
| Quote: no route found | Retry with wider slippage or different provider |
| Simulation failed | Do NOT send — inspect error, log, alert |
| sendTransaction failed | Check getSignatureStatus before retry |
| Transaction not confirmed | Poll with timeout; check for expiry (blockhash) |
| Stream disconnected | Reconnect with exponential backoff |
| HTTP 429 rate limit | Back off immediately; retry after delay |
Error Reference
| HTTP Code | Meaning | Action |
|---|---|---|
| 401 | Invalid / missing API key | Check key and auth format |
| 403 | Plan restriction (e.g. gRPC on free tier) | Upgrade at rpc.carbium.io |
| 429 | Rate limit exceeded | Backoff + retry |
| 500 | Server error | Retry after 1s |
| 503 | Temporary unavailability | Retry 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/bundlefor Jito-bundled execution. - Gasless swaps: Supported via Swap API.
- Commitment levels:
processed(fastest, may roll back) →confirmed(recommended) →finalized(slowest, guaranteed).
Further Reading
| Topic | URL |
|---|---|
| Ecosystem overview | https://docs.carbium.io/docs/the-carbium-ecosystem |
| RPC Quick Start | https://docs.carbium.io/docs/quick-start-rpc |
| Swap API Quick Start | https://docs.carbium.io/docs/quick-start-dex-api |
| DEX Quick Start | https://docs.carbium.io/docs/quick-start-dex |
| gRPC / Streaming | https://docs.carbium.io/docs/solana-grpc |
| CQ1 Engine | https://docs.carbium.io/docs/cq1-engine-overview |
| CQ1 Data Layer | https://docs.carbium.io/docs/cq1-data-layer |
| RPC Pricing | https://docs.carbium.io/docs/carbium-rpc-pricing |
| API Recipes | https://docs.carbium.io/recipes |
| FAQ | https://docs.carbium.io/docs/faq |
This is the Carbium Skill file — a self-contained context document for AI assistants. For support: https://discord.gg/jW7BUkQS5U
