Parameters
Fully-signed transaction as a base-64 encoded string
Configuration object containing:Encoding format for the transaction (base58, base64, json)
Commitment level (processed, confirmed, finalized)
Commitment level for preflight (processed, confirmed, finalized)
If true, skip the preflight transaction checks
Maximum number of times for the RPC node to retry sending the transaction to the leader
The minimum slot that the request can be evaluated at
Response
First transaction signature embedded in the transaction (base-58 encoded)
Code Examples
Basic Request
curl https://rpc.orbitflare.com -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTFNhyKNMr3WNFCrXgDS7uV7u",
{
"encoding": "base64",
"commitment": "confirmed"
}
]
}'
Using web3.js
import { Connection, Transaction, PublicKey, SystemProgram } from '@solana/web3.js';
const connection = new Connection('https://rpc.orbitflare.com');
// Create and send transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey('83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri'),
toPubkey: new PublicKey('J7rBdM6AecPDEZp8aPq5tPmsPzPhQG4HD6YtAcQBDfJj'),
lamports: 1000000000
})
);
const signature = await connection.sendTransaction(transaction, [signer]);
console.log('Transaction signature:', signature);
// Send transaction with confirmation
async function sendTransactionWithConfirmation(
transaction: Transaction,
signers: Array<Signer>,
config: {
commitment?: string;
preflightCommitment?: string;
skipPreflight?: boolean;
maxRetries?: number;
}
) {
const signature = await connection.sendTransaction(
transaction,
signers,
config
);
// Wait for confirmation
const confirmation = await connection.confirmTransaction(signature, config.commitment);
return {
signature,
confirmation: {
status: confirmation.value.err ? 'failed' : 'success',
slot: confirmation.context.slot
},
transaction: {
recentBlockhash: transaction.recentBlockhash,
feePayer: transaction.feePayer?.toBase58(),
instructions: transaction.instructions.length
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment
}
};
}
Notes
- Submits a signed transaction to the cluster
- The transaction must be fully signed
- The response is the transaction signature
- The transaction must be confirmed before changes are applied
- The transaction must include a recent blockhash
Best Practices
- Use appropriate commitment level based on your needs
- Wait for transaction confirmation before proceeding
- Handle rate limits and network errors
- Monitor transaction status for failures
- Consider using preflight checks for validation
Common Errors
Code | Message | Solution |
---|
-32601 | Method not found | Verify you’re connected to a Solana RPC node |
-32602 | Invalid params | Check transaction format and encoding |
-32003 | Transaction simulation failed | Verify transaction validity and account balances |
-32004 | Blockhash not found | Use a more recent blockhash |
-32005 | Node is behind | Try a different RPC node |
-32006 | Transaction already processed | Transaction was already submitted |
-32007 | Transaction signature verification failed | Check transaction signatures |
Use Cases
-
Transaction Management
interface TransactionRequest {
transaction: {
signature: string;
blockhash: string;
feePayer: string;
instructions: number;
};
status: {
state: 'pending' | 'success' | 'failed';
confirmations: number;
slot?: number;
error?: string;
};
metadata: {
timestamp: number;
commitment?: string;
retries: number;
};
}
class TransactionManager {
private readonly maxRetries = 3;
private readonly confirmationTimeout = 30000; // 30 seconds
async sendTransaction(
transaction: Transaction,
signers: Array<Signer>,
config: {
commitment?: string;
preflightCommitment?: string;
skipPreflight?: boolean;
}
): Promise<TransactionRequest> {
let retries = 0;
let signature: string;
while (retries < this.maxRetries) {
try {
// Get a new blockhash if retrying
if (retries > 0) {
const { blockhash } = await connection.getRecentBlockhash();
transaction.recentBlockhash = blockhash;
}
signature = await connection.sendTransaction(
transaction,
signers,
config
);
// Wait for confirmation
const confirmation = await connection.confirmTransaction(signature, config.commitment);
if (!confirmation.value.err) {
return {
transaction: {
signature,
blockhash: transaction.recentBlockhash,
feePayer: transaction.feePayer?.toBase58(),
instructions: transaction.instructions.length
},
status: {
state: 'success',
confirmations: 1,
slot: confirmation.context.slot
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment,
retries
}
};
}
throw new Error(confirmation.value.err.toString());
} catch (error) {
retries++;
if (retries === this.maxRetries) {
return {
transaction: {
signature,
blockhash: transaction.recentBlockhash,
feePayer: transaction.feePayer?.toBase58(),
instructions: transaction.instructions.length
},
status: {
state: 'failed',
confirmations: 0,
error: error.message
},
metadata: {
timestamp: Date.now(),
commitment: config.commitment,
retries
}
};
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
}
}
-
Transaction Monitoring
interface TransactionStatus {
transaction: {
signature: string;
slot?: number;
};
status: {
confirmations: number;
err: any;
};
history: Array<{
timestamp: number;
confirmations: number;
error?: string;
}>;
}
class TransactionMonitor {
private transactions: Map<string, TransactionStatus> = new Map();
async monitorTransaction(
signature: string
): Promise<TransactionStatus> {
let status = this.transactions.get(signature);
const now = Date.now();
const confirmation = await connection.getSignatureStatus(signature);
if (!status) {
status = {
transaction: {
signature,
slot: confirmation?.slot
},
status: {
confirmations: confirmation?.confirmations || 0,
err: confirmation?.err
},
history: [{
timestamp: now,
confirmations: confirmation?.confirmations || 0,
error: confirmation?.err?.toString()
}]
};
} else {
status.status.confirmations = confirmation?.confirmations || 0;
status.status.err = confirmation?.err;
status.history.push({
timestamp: now,
confirmations: confirmation?.confirmations || 0,
error: confirmation?.err?.toString()
});
}
this.transactions.set(signature, status);
return status;
}
}
-
Transaction Planning
interface TransactionPlan {
transaction: {
instructions: number;
signers: number;
estimatedFee: number;
};
recommendations: Array<{
type: 'proceed' | 'split' | 'abort';
reason: string;
}>;
metadata: {
timestamp: number;
};
}
class TransactionPlanner {
private readonly maxInstructions = 10;
private readonly maxSigners = 8;
async planTransaction(
transaction: Transaction
): Promise<TransactionPlan> {
const { feeCalculator } = await connection.getRecentBlockhash();
const estimatedFee = feeCalculator.lamportsPerSignature * transaction.signatures.length;
const recommendations: Array<{
type: 'proceed' | 'split' | 'abort';
reason: string;
}> = [];
if (transaction.instructions.length > this.maxInstructions) {
recommendations.push({
type: 'split',
reason: `Transaction has ${transaction.instructions.length} instructions, exceeding maximum of ${this.maxInstructions}`
});
}
if (transaction.signatures.length > this.maxSigners) {
recommendations.push({
type: 'split',
reason: `Transaction has ${transaction.signatures.length} signers, exceeding maximum of ${this.maxSigners}`
});
}
if (recommendations.length === 0) {
recommendations.push({
type: 'proceed',
reason: 'Transaction is within limits'
});
}
return {
transaction: {
instructions: transaction.instructions.length,
signers: transaction.signatures.length,
estimatedFee
},
recommendations,
metadata: {
timestamp: Date.now()
}
};
}
async splitTransaction(
transaction: Transaction
): Promise<Array<{
transaction: Transaction;
signers: Array<PublicKey>;
}>> {
const chunks: Array<{
transaction: Transaction;
signers: Array<PublicKey>;
}> = [];
let currentChunk = new Transaction();
let currentSigners: Array<PublicKey> = [];
for (let i = 0; i < transaction.instructions.length; i++) {
const instruction = transaction.instructions[i];
if (currentChunk.instructions.length >= this.maxInstructions) {
chunks.push({
transaction: currentChunk,
signers: currentSigners
});
currentChunk = new Transaction();
currentSigners = [];
}
currentChunk.add(instruction);
// Add unique signers
instruction.keys
.filter(key => key.isSigner)
.forEach(key => {
if (!currentSigners.find(signer => signer.equals(key.pubkey))) {
currentSigners.push(key.pubkey);
}
});
}
if (currentChunk.instructions.length > 0) {
chunks.push({
transaction: currentChunk,
signers: currentSigners
});
}
return chunks;
}
}