Parameters

transaction
string
required

Fully-signed transaction as a base-64 encoded string

config
object

Configuration object containing:

encoding
string

Encoding format for the transaction (base58, base64, json)

commitment
string

Commitment level (processed, confirmed, finalized)

preflightCommitment
string

Commitment level for preflight (processed, confirmed, finalized)

skipPreflight
boolean

If true, skip the preflight transaction checks

maxRetries
number

Maximum number of times for the RPC node to retry sending the transaction to the leader

minContextSlot
number

The minimum slot that the request can be evaluated at

Response

result
string

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

  1. Submits a signed transaction to the cluster
  2. The transaction must be fully signed
  3. The response is the transaction signature
  4. The transaction must be confirmed before changes are applied
  5. The transaction must include a recent blockhash

Best Practices

  1. Use appropriate commitment level based on your needs
  2. Wait for transaction confirmation before proceeding
  3. Handle rate limits and network errors
  4. Monitor transaction status for failures
  5. Consider using preflight checks for validation

Common Errors

CodeMessageSolution
-32601Method not foundVerify you’re connected to a Solana RPC node
-32602Invalid paramsCheck transaction format and encoding
-32003Transaction simulation failedVerify transaction validity and account balances
-32004Blockhash not foundUse a more recent blockhash
-32005Node is behindTry a different RPC node
-32006Transaction already processedTransaction was already submitted
-32007Transaction signature verification failedCheck transaction signatures

Use Cases

  1. 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));
          }
        }
      }
    }
    
  2. 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;
      }
    }
    
  3. 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;
      }
    }