Transaction Handling
Advanced transaction management and custom flows.
Overview
The SDK handles transaction building, signing, and confirmation. This guide covers advanced patterns for custom transaction flows.
Instruction Builders
Instead of sending transactions directly, you can build instructions for more control:
typescript
// Get instruction without sending
const instruction = await sdk.instructions.placeWagerV2({
bet: betAddress,
amount: 25,
side: Outcome.For,
});
// Build custom transaction
const transaction = new Transaction().add(instruction);Available Instruction Builders
All transaction methods have corresponding instruction builders:
typescript
// User
const createUserIx = await sdk.instructions.createUser({...});
// Bets
const initBetIx = await sdk.instructions.initializeBetV2Ix({...});
const wagerIx = await sdk.instructions.placeWagerV2({...});
const initiateVoteIx = await sdk.instructions.initiateVoteV2({...});
const voteIx = await sdk.instructions.placeVoteV2({...});
const settleIx = await sdk.instructions.settleBetBatchV2({...});
// Games
const createGameIx = await sdk.instructions.createGameIx({...});
const gameWagerIx = await sdk.instructions.placeGameWagerIx({...});Custom Transaction Building
Build transactions with multiple instructions:
typescript
import { Transaction, ComputeBudgetProgram } from "@solana/web3.js";
async function buildCustomTransaction() {
// Add compute budget for complex transactions
const computeIx = ComputeBudgetProgram.setComputeUnitLimit({
units: 400_000,
});
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: 1000,
});
// Get SDK instructions
const wagerIx = await sdk.instructions.placeWagerV2({
bet: betAddress,
amount: 50,
side: Outcome.For,
});
// Build transaction
const tx = new Transaction()
.add(computeIx)
.add(priorityFeeIx)
.add(wagerIx);
// Get recent blockhash
const { blockhash } = await connection.getLatestBlockhash();
tx.recentBlockhash = blockhash;
tx.feePayer = wallet.publicKey;
return tx;
}Pre-instructions
Add instructions before the main operation:
typescript
await sdk.placeWagerV2({
bet: betAddress,
amount: 25,
side: Outcome.For,
preinstructions: [
// Create ATA if needed
createAssociatedTokenAccountInstruction(...),
],
signers: [wallet],
});Fee Payer Override
Specify a different fee payer:
typescript
await sdk.placeWagerV2({
bet: betAddress,
amount: 25,
side: Outcome.For,
feePayerOverride: sponsorWallet.publicKey,
signers: [wallet, sponsorWallet],
});Transaction Confirmation
Control confirmation behavior:
typescript
await sdk.placeWagerV2({
bet: betAddress,
amount: 25,
side: Outcome.For,
confirmOptions: {
commitment: "finalized", // Wait for finalization
maxRetries: 10, // More retries
skipPreflight: false, // Enable simulation
preflightCommitment: "processed",
},
signers: [wallet],
});Retrying Failed Transactions
Implement retry logic for network issues:
typescript
async function sendWithRetry(
fn: () => Promise<string>,
maxRetries = 3
): Promise<string> {
let lastError: Error | undefined;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
// Check if retryable
if (error.message.includes("blockhash not found")) {
console.log(`Attempt ${attempt + 1} failed, retrying...`);
await new Promise((r) => setTimeout(r, 1000 * (attempt + 1)));
continue;
}
throw error;
}
}
throw lastError;
}
// Usage
const txHash = await sendWithRetry(() =>
sdk.placeWagerV2({
bet: betAddress,
amount: 25,
side: Outcome.For,
signers: [wallet],
})
);Transaction Simulation
Simulate before sending:
typescript
import { Transaction } from "@solana/web3.js";
async function simulateTransaction(tx: Transaction) {
const simulation = await connection.simulateTransaction(tx);
if (simulation.value.err) {
console.error("Simulation failed:", simulation.value.err);
console.log("Logs:", simulation.value.logs);
throw new Error("Transaction would fail");
}
console.log("Compute units used:", simulation.value.unitsConsumed);
return simulation;
}Versioned Transactions
The SDK supports versioned transactions for address lookup tables:
typescript
import { VersionedTransaction, TransactionMessage } from "@solana/web3.js";
// Build with address lookup tables
const message = new TransactionMessage({
payerKey: wallet.publicKey,
recentBlockhash: blockhash,
instructions: [wagerIx],
}).compileToV0Message([lookupTable]);
const versionedTx = new VersionedTransaction(message);Transaction Batching
Send multiple operations efficiently:
typescript
async function batchWagers(
bets: { address: PublicKey; amount: number; side: Outcome }[]
) {
const results = await Promise.allSettled(
bets.map((bet) =>
sdk.placeWagerV2({
bet: bet.address,
amount: bet.amount,
side: bet.side,
signers: [wallet],
})
)
);
const successful = results.filter((r) => r.status === "fulfilled");
const failed = results.filter((r) => r.status === "rejected");
console.log(`${successful.length} succeeded, ${failed.length} failed`);
return results;
}Monitoring Transactions
Track transaction status:
typescript
async function waitForConfirmation(
signature: string,
commitment: Commitment = "confirmed"
) {
const start = Date.now();
const result = await connection.confirmTransaction(signature, commitment);
if (result.value.err) {
throw new Error(`Transaction failed: ${result.value.err}`);
}
console.log(`Confirmed in ${Date.now() - start}ms`);
return result;
}