# Submit Single Transaction

Submit individual transactions to NextBlock using Rust and the Solana SDK.

If you want to send raw signed transaction bytes over QUIC instead of gRPC, see [QUIC Transaction Submission](/api/examples/rust/quic.md).

This example shows transaction construction and the request shape you send to NextBlock. Replace the placeholder generated client types with the client generated from `nextblock-proto`.

## Example

<pre class="language-rust"><code class="lang-rust"><strong>use solana_sdk::{
</strong>    instruction::Instruction,
    message::Message,
    pubkey::Pubkey,
    signature::{Keypair, Signature, Signer},
    system_instruction,
    transaction::Transaction,
    hash::Hash,
};
use solana_client::rpc_client::RpcClient;
use rand::seq::SliceRandom;
use std::str::FromStr;

<strong>// NextBlock tip wallets for load balancing
</strong>const NEXTBLOCK_TIP_WALLETS: [&#x26;str; 8] = [
    "NEXTbLoCkB51HpLBLojQfpyVAMorm3zzKg7w9NFdqid",
    "nextBLoCkPMgmG8ZgJtABeScP35qLa2AMCNKntAP7Xc", 
    "NextbLoCkVtMGcV47JzewQdvBpLqT9TxQFozQkN98pE",
    "NexTbLoCkWykbLuB1NkjXgFWkX9oAtcoagQegygXXA2",
    "NeXTBLoCKs9F1y5PJS9CKrFNNLU1keHW71rfh7KgA1X",
    "NexTBLockJYZ7QD7p2byrUa6df8ndV2WSd8GkbWqfbb",
    "neXtBLock1LeC67jYd1QdAa32kbVeubsfPNTJC1V5At",
    "nEXTBLockYgngeRmRrjDV31mGSekVPqZoMGhQEZtPVG",
];

<strong>// Get random tip wallet for load balancing
</strong>fn get_random_nextblock_tip_wallet() -> Result&#x3C;Pubkey, Box&#x3C;dyn std::error::Error>> {
    let mut rng = rand::thread_rng();
    let wallet_str = NEXTBLOCK_TIP_WALLETS.choose(&#x26;mut rng)
        .ok_or("No tip wallets available")?;
    Ok(Pubkey::from_str(wallet_str)?)
}

<strong>// Build transaction with tip and instructions
</strong>fn build_transaction_with_tip(
    payer: &#x26;Keypair,
    recent_blockhash: Hash,
    tip_amount: u64,
    instructions: Vec&#x3C;Instruction>,
) -> Result&#x3C;Transaction, Box&#x3C;dyn std::error::Error>> {
    let tip_wallet = get_random_nextblock_tip_wallet()?;
    
<strong>    // Create tip instruction (should be first)
</strong>    let tip_instruction = system_instruction::transfer(
        &#x26;payer.pubkey(),
        &#x26;tip_wallet,
        tip_amount,
    );
    
<strong>    // Combine tip instruction with user instructions
</strong>    let mut all_instructions = vec![tip_instruction];
    all_instructions.extend(instructions);
    
<strong>    // Create and sign transaction
</strong>    let message = Message::new(&#x26;all_instructions, Some(&#x26;payer.pubkey()));
    let mut transaction = Transaction::new_unsigned(message);
    transaction.sign(&#x26;[payer], recent_blockhash);
    
    Ok(transaction)
}

<strong>// Submit transaction to NextBlock
</strong>async fn submit_single_transaction(
    // nextblock_client: &#x26;mut YourGeneratedApiClient,
    rpc_client: &#x26;RpcClient,
    signer: &#x26;Keypair,
    recipient: Pubkey,
    transfer_amount: u64,
    tip_amount: u64,
) -> Result&#x3C;Signature, Box&#x3C;dyn std::error::Error>> {
<strong>    // Get recent blockhash
</strong>    let recent_blockhash = rpc_client.get_latest_blockhash()?;
    
<strong>    // Create transfer instruction
</strong>    let transfer_instruction = system_instruction::transfer(
        &#x26;signer.pubkey(),
        &#x26;recipient,
        transfer_amount,
    );
    
<strong>    // Build transaction with tip
</strong>    let transaction = build_transaction_with_tip(
        signer,
        recent_blockhash,
        tip_amount,
        vec![transfer_instruction],
    )?;
    
<strong>    // Convert to base64 for submission
</strong>    let serialized_tx = bincode::serialize(&#x26;transaction)?;
    let base64_tx = base64::encode(serialized_tx);
    
<strong>    // Configure submission options
</strong>    let front_running_protection = false;
    let revert_on_fail = false;
    let disable_retries = false;
    let snipe_transaction = false;
    
<strong>    // Submit to NextBlock
</strong>    /* Uncomment when you have the generated API client
    let request = tonic::Request::new(PostSubmitRequest {
        transaction: Some(TransactionMessage {
            content: base64_tx,
        }),
        skip_pre_flight: Some(true),
        snipe_transaction: Some(snipe_transaction),
        front_running_protection: Some(front_running_protection),
        disable_retries: Some(disable_retries),
        revert_on_fail: Some(revert_on_fail),
    });
    
    let response = nextblock_client.post_submit_v2(request).await?;
    let submit_response = response.into_inner();
    
    println!("Transaction submitted successfully!");
    println!("Signature: {}", submit_response.signature);
    println!("UUID: {}", submit_response.uuid);
    
    Ok(Signature::from_str(&#x26;submit_response.signature)?)
    */
    
    println!("Local transaction built successfully: {}", transaction.signatures[0]);
    Ok(transaction.signatures[0])
}

<strong>// Example with dynamic tip calculation
</strong>async fn submit_with_optimal_tip(
    // nextblock_client: &#x26;mut YourGeneratedApiClient,
    rpc_client: &#x26;RpcClient,
    signer: &#x26;Keypair,
    recipient: Pubkey,
    transfer_amount: u64,
) -> Result&#x3C;Signature, Box&#x3C;dyn std::error::Error>> {
<strong>    // Get optimal tip amount (implement tip floor API call)
</strong>    let optimal_tip = get_optimal_tip_amount().await?;
    
    submit_single_transaction(
        // nextblock_client,
        rpc_client,
        signer,
        recipient,
        transfer_amount,
        optimal_tip,
    ).await
}

<strong>// Get optimal tip amount from tip floor API
</strong>async fn get_optimal_tip_amount() -> Result&#x3C;u64, Box&#x3C;dyn std::error::Error>> {
<strong>    // This should call the tip floor API to get current percentiles
</strong>    // For now, return a reasonable default
    Ok(1_000_000) // 0.001 SOL
}
</code></pre>

## Usage Example

<pre class="language-rust"><code class="lang-rust"><strong>#[tokio::main]
</strong>async fn main() -> Result&#x3C;(), Box&#x3C;dyn std::error::Error>> {
<strong>    // Initialize configuration
</strong>    let signer = Keypair::new(); // Use your actual keypair
    let recipient = Pubkey::from_str("&#x3C;recipient-public-key>")?;
    let rpc_client = RpcClient::new("https://api.mainnet-beta.solana.com".to_string());
    
<strong>    // Connect to NextBlock (see connection.md)
</strong>    // let config = NextBlockConfig::default();
    // let mut nextblock_client = create_nextblock_client(config).await?;
    
<strong>    // Submit transaction
</strong>    let signature = submit_single_transaction(
        // &#x26;mut nextblock_client,
        &#x26;rpc_client,
        &#x26;signer,
        recipient,
        10_000,     // Transfer 10,000 lamports
        1_000_000,  // Tip 1,000,000 lamports (0.001 SOL)
    ).await?;
    
    println!("Transaction submitted with signature: {}", signature);
    
<strong>    // Alternative: Submit with optimal tip
</strong>    let signature2 = submit_with_optimal_tip(
        // &#x26;mut nextblock_client,
        &#x26;rpc_client,
        &#x26;signer,
        recipient,
        20_000, // Transfer 20,000 lamports
    ).await?;
    
    println!("Optimally tipped transaction: {}", signature2);
    Ok(())
}
</code></pre>

## Advanced Features

### Custom Instruction Building

<pre class="language-rust"><code class="lang-rust"><strong>use solana_sdk::instruction::{AccountMeta, Instruction};
</strong>
<strong>// Build custom program instruction
</strong>fn build_custom_instruction(
    program_id: Pubkey,
    accounts: Vec&#x3C;AccountMeta>,
    data: Vec&#x3C;u8>,
) -> Instruction {
    Instruction {
        program_id,
        accounts,
        data,
    }
}

<strong>// Example: Token transfer instruction
</strong>fn build_token_transfer_instruction(
    source: Pubkey,
    destination: Pubkey,
    authority: Pubkey,
    amount: u64,
) -> Instruction {
    // This is a simplified example - use spl-token crate for real token transfers
    let accounts = vec![
        AccountMeta::new(source, false),
        AccountMeta::new(destination, false),
        AccountMeta::new_readonly(authority, true),
    ];
    
    build_custom_instruction(
        spl_token::id(),
        accounts,
        amount.to_le_bytes().to_vec(),
    )
}
</code></pre>

### Error Handling and Retries

<pre class="language-rust"><code class="lang-rust"><strong>use tokio::time::{sleep, Duration};
</strong>
<strong>// Retry logic with exponential backoff
</strong>async fn submit_with_retry(
    // nextblock_client: &#x26;mut YourGeneratedApiClient,
    rpc_client: &#x26;RpcClient,
    signer: &#x26;Keypair,
    recipient: Pubkey,
    transfer_amount: u64,
    tip_amount: u64,
    max_retries: u32,
) -> Result&#x3C;Signature, Box&#x3C;dyn std::error::Error>> {
    let mut retry_count = 0;
    let mut delay = Duration::from_millis(1000);
    
    loop {
        match submit_single_transaction(
            // nextblock_client,
            rpc_client,
            signer,
            recipient,
            transfer_amount,
            tip_amount,
        ).await {
            Ok(signature) => return Ok(signature),
            Err(e) if retry_count &#x3C; max_retries => {
                println!("Attempt {} failed: {}. Retrying in {:?}...", 
                        retry_count + 1, e, delay);
                sleep(delay).await;
                retry_count += 1;
                delay *= 2; // Exponential backoff
            }
            Err(e) => return Err(e),
        }
    }
}
</code></pre>

## Best Practices

1. **Always include tips**: NextBlock prioritizes transactions with appropriate tips
2. **Use random tip wallets**: Distribute load across multiple tip addresses
3. **Monitor tip floors**: Adjust tips based on current network conditions
4. **Handle errors gracefully**: Implement retry logic for network issues
5. **Validate inputs**: Always validate public keys and amounts before submission
6. **Use appropriate RPC endpoints**: Choose reliable RPC providers
7. **Keep connections alive**: Reuse gRPC connections for better performance


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.nextblock.io/api/examples/rust/submit-single-transactions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
