typescript
Send a bundle using TypeScript with full type safety.
Types
typescript
export interface BundleParams {
encoding: "base64";
skipPreflight?: boolean;
}
export interface BundleResult {
bundle_id: string;
signatures: string[];
}
export interface JsonRpcResponse<T> {
jsonrpc: "2.0";
id: number;
result?: T;
error?: {
code: number;
message: string;
};
}Send Bundle Function
typescript
import { Transaction } from "@solana/web3.js";
import type { BundleParams, BundleResult, JsonRpcResponse } from "./types.js";
export const ENDPOINT = "https://fra.blocksprint.io/bundle/v1/YOUR_API_KEY";
export async function sendBundle(transactions: Transaction[]): Promise<BundleResult> {
const serializedTxs = transactions.map((tx) =>
Buffer.from(tx.serialize()).toString("base64")
);
const response = await fetch(ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "sendBundle",
params: [
serializedTxs,
{
encoding: "base64",
skipPreflight: true,
} as BundleParams,
],
}),
});
const data: JsonRpcResponse<BundleResult> = await response.json();
if (data.error) {
throw new Error(`Bundle error ${data.error.code}: ${data.error.message}`);
}
return data.result!;
}Full Example
typescript
import {
Connection,
Keypair,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { sendBundle } from "./sendBundle.js";
import type { BundleResult } from "./types.js";
// Your Solana RPC (for the blockhash)
const RPC_URL = "https://api.mainnet-beta.solana.com";
// BlockSprint tip address, tip at least 0.001 SOL
const TIP_ADDRESS = new PublicKey("Sp4JHSh9cksfzXbgK7Pq2ovtn8LirLQydaJKTsiNT77");
interface BundleStep {
instructions: TransactionInstruction[];
signers?: Keypair[];
}
async function createBundle(
connection: Connection,
payer: Keypair,
steps: BundleStep[]
): Promise<Transaction[]> {
const { blockhash } = await connection.getLatestBlockhash();
return steps.map((step) => {
const tx = new Transaction();
step.instructions.forEach((ix) => tx.add(ix));
tx.recentBlockhash = blockhash;
tx.feePayer = payer.publicKey;
const signers = [payer, ...(step.signers || [])];
tx.sign(...signers);
return tx;
});
}
async function executeBundle(
wallet: Keypair,
steps: BundleStep[]
): Promise<BundleResult> {
const connection = new Connection(RPC_URL);
const transactions = await createBundle(connection, wallet, steps);
return sendBundle(transactions);
}
// Usage
async function main() {
const wallet = Keypair.generate();
// 0.001 SOL tip
const tipInstruction = SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: TIP_ADDRESS,
lamports: 1_000_000,
});
const result = await executeBundle(wallet, [
{
instructions: [approveInstruction],
},
{
instructions: [swapInstruction, tipInstruction],
},
]);
console.log("Bundle ID:", result.bundle_id);
result.signatures.forEach((sig, i) => {
console.log(`Tx ${i + 1}: ${sig}`);
});
}Versioned Transactions
typescript
import { VersionedTransaction, TransactionMessage } from "@solana/web3.js";
import { ENDPOINT } from "./sendBundle.js";
import type { BundleResult, JsonRpcResponse } from "./types.js";
async function sendVersionedBundle(
transactions: VersionedTransaction[]
): Promise<BundleResult> {
const serializedTxs = transactions.map((tx) =>
Buffer.from(tx.serialize()).toString("base64")
);
const response = await fetch(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 data: JsonRpcResponse<BundleResult> = await response.json();
if (data.error) {
throw new Error(data.error.message);
}
return data.result!;
}