Submit Transactions
How to submit transaction
Astralane provides a multitude of options for your needs, here are some of RPC methods we offer for Transaction sending.
sendTransation
This RPC call is fully compatible with all Solana libraries , making it a simple drop-in replacement for your existing workflows. It routes through our partner SWQoS clients, including Jito and Paladin (higher min tip), ensuring optimized transaction processing and maximum reliability.
Just insert the URL where you would place a RPC URL and send your txns how you send normally. The only change is to add an instruction to tip.
const TIP: Pubkey = pubkey!("astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"); // Use tip wallet depending on region of access
const MIN_TIP_AMOUNT: u64 = 100_000; // added for spam prevention
fn send_tx_tipped(
ixs: &mut Vec<Instruction>,
signer: &Keypair,
rpc_client: &RpcClient, // https://api.mainnet-beta.solana.com
astralane_txn_sender: &RpcClient // Astralane RPC
) {
let tip_ix = system_instruction::transfer(&signer.pubkey(), &TIP, MIN_TIP_AMOUNT);
ixs.push(tip_ix);
let blockhash = rpc_client.get_latest_blockhash().unwrap();
let tx = Transaction::new_signed_with_payer(ixs, Some(&signer.pubkey()), &[signer], blockhash);
astralane_txn_sender.send_transaction_with_config(
&transaction,
RpcSendTransactionConfig {
skip_preflight: true,
encoding: Some(UiTransactionEncoding::Base64),
},
).unwrap();
}
sendBundle
If your operation depends on atomic txn execution then use our sendBundle endpoint to send atomically executing transactions.
Send up to 4 transactions in a single atomic bundle. These transactions are executed sequentially , ensuring precision and reliability. If any transaction fails, the entire bundle is reverted—guaranteeing consistency and eliminating partial failures.
const TIP: Pubkey = pubkey!("astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"); // Use tip wallet depending on region of access
const MIN_TIP_AMOUNT: u64 = 100_000; // added for spam prevention
async fn send_bundle(
ixs: &mut Vec<Instruction>,
signer: &Keypair,
client: reqwest::Client,
blockhash: Hash,
url: String,
) {
let tip_ix = system_instruction::transfer(&signer.pubkey(), &TIP, MIN_TIP_AMOUNT);
ixs.push(tip_ix);
let tx = Transaction::new_signed_with_payer(ixs, Some(&signer.pubkey()), &[signer], blockhash);
let encoded_tx = base64::prelude::BASE64_STANDARD.encode(&bincode::serialize(tx).unwrap());
let response = client
.post(url)
.header("api_key", "xxx")
.json(&json! ({
"jsonrpc": "2.0",
"id": 1,
"method": "sendBundle",
"params": [[encoded_tx]],
}))
.send()
.await;
}
Request:
{
"id": 1,
"jsonrpc": "2.0",
"method": "sendBundle",
"params": [
[
"base64_encoded_txn1",
"base64_encoded_txn2",
"base64_encoded_txn3"
],
{
"encoding": "base64",
"mevProtect": true
}
]
}
Response:
List of signatures for your transaction
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"37Dxw2nJYw3T8JVqenPQMf39VJ9CNZYCyQm67b6nRj6fa6UjQ1UuLqFvh3wJ2G7LcMuZn4oq5kDt2A2CEXfi8D8"
]
}
sendIdeal
Perfect for snipers! Due to the segregation in validators as JITO validators and normal ones, traders are often conflicted between spending more on jito tips vs more in priority fees. Durable nonces offer a way to mitigate this issue.
Our sendIdeal RPC method accepts two transactions:
One with a high priority fee + min tip
Another with a high tip + lower priority fee
We route them through our advanced SWQoS and bundling pipelines. Using durable nonces, once one transaction lands, the other is automatically canceled—ensuring optimal efficiency and cost savings. if you don't want to manage the durable nonce accounts on your own we also provide a managed service for this, We create a nonce account for each api-key you use and you can query them using our getNonce rpc call. Follow the below integration steps for best utilization of this feature:
Step 1 : Generate Nonce instruction
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{EncodableKey, Keypair, Signer};
async fn get_nonce(
client: reqwest::Client,
url: String,
auth_key: String,
) {
let response = client
.post(url)
.header("api_key", "xxx")
.json(&json! ({
"jsonrpc": "2.0",
"id": 1,
"method": "getNonce",
"params": [api_key], // provided during onboarding
}))
.send()
.await;
let result = response["result"].clone();
let nonce = result["nonce"].as_str().unwrap();
let nonce_account = Pubkey::from_str(result["nonceAccount"].as_str().unwrap()).unwrap();
let nonce_authority =
Pubkey::from_str(result["nonceAuthority"].as_str().unwrap()).unwrap();
let nonce_as_hash = Hash::from_str(nonce).unwrap();
}
To use this nonce, just include an advance nonce instruction as the first instruction in your transactions.
Step 2 : Generate your txn and Partial Sign it before submission
const TIP: Pubkey = pubkey!("astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm"); // Use tip wallet depending on region of access
const MIN_TIP_AMOUNT: u64 = 100_000; // added for spam prevention
async fn send_ideal(
signer: &Keypair,
client: reqwest::Client,
nonce: Hash,
instructions: Vec<Instruction>,
nonce_authority: &Pubkey,
nonce_account: &Pubkey,
) {
// add advance nonce instruction
let advance_nonce = solana_sdk::system_instruction::advance_nonce_account(nonce_account, nonce_authority);
let low_tip_high_fee_ixs = vec![
advance_nonce.clone(),
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
10 * MICRO_LAMPORTS_PER_LAMPORTS,
),
// add your instructions here
solana_sdk::system_instruction::transfer(&signer.pubkey(), &TIP, MIN_TIP_AMOUNT),
];
let high_tip_low_fee_ixs = vec![
advance_nonce,
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
100,
),
// add your instructions here
solana_sdk::system_instruction::transfer(&signer.pubkey(), &TIP, 100 * MIN_TIP_AMOUNT),
];
//add high transaction priority fee and min tip
let mut low_tip_high_fee_tx = Transaction::new_with_payer(&low_tip_high_fee_ixs, Some(&signer.pubkey()));
low_tip_high_fee_tx.partial_sign(&[&signer], nonce);
let mut high_tip_low_fee_tx = Transaction::new_with_payer(&high_tip_low_fee_ixs, Some(&signer.pubkey()));
high_tip_low_fee_tx.partial_sign(&[&signer], nonce);
let low_tip_high_fee_tx_encoded = base64::prelude::BASE64_STANDARD.encode(&bincode::serialize(low_tip_high_fee_tx).unwrap());
let high_tip_low_fee_tx_encoded = base64::prelude::BASE64_STANDARD.encode(&bincode::serialize(high_tip_low_fee_tx).unwrap());
let response = client
.post(url)
.json(&json! ({
"jsonrpc": "2.0",
"id": 1,
"method": "sendIdeal",
"params": [[low_tip_high_fee_tx_encoded, high_tip_low_fee_tx_encoded]],
}))
.send()
.await;
}
Request:
{
"id": 1,
"jsonrpc": "2.0",
"method": "sendIdeal",
"params": [[
"transction_with_large_tip_low_priority_fee",
"transaction_with_large_priority_fee_low_tip"
]]
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"<signature A>",
"<signature B>"
]
}
The latency performance for your transactions will depend on current network dynamics. Kindly reach out to us on telegram for recommendations on ideal setup for your operation
sendPaladin (Beta)
Paladin is a custom TPU port implementation which provides a more efficient way to send your transactions directly to the leaders. The paladin client is currently running on 10% of the Solana network (as per 10th March 2025). Read more
Step 1 : Tracking Paladin leaders
Since paladin validators are not present for all slots, we provided a paladin leader tracker endpoint which can be used for knowing which slots we have a paladin leader. Here are some general guidelines for tracker integration to dynamically send txns based on leader info:
Fetch all Palidator public keys for current epoch
⚔️ GET /api/palidators
[
"Ss...Z77",
"ACv...mi",
"7Z...Z84",
]
Get next Palidator leader slots
⚔️ GET /api/next_palidator
{
"pubkey": "Csd...def",
"leader_slot": 42424242,
"context_slot": 42424242
}
Get next leader Palidator on or after given slot
⚔️ GET /api/next_palidator/{slot}
{
"pubkey": "Csd...def",
"leader_slot": 42424242,
"context_slot": 42424242
}
NOTE: Sometimes certain malicious operators might mimick themselves as using paladin, so to prevent getting exploited on these scenarios we recommend you implement proactive blocklists for malicious operators. Reach out to us on our discord, if you are confused on how to achieve this. There is a very small minimum limit of 10 lamports/cu, on txns being sent to paladin validators.
Step 2: Crafting paladin transaction
Use the sendPaladin
method, to send the transactions during these slots. Please make sure to respect the min tip requirements and min priority fee requirements while sending txns on this endpoint.
All transactions sent to this endpoint, go through a small auction and the ordering will based on:
Priority fees
Any tiebreakers will be decided by tip to Astralane tip addresses
revertProtection
Boolean
Optional, A failed transaction will be dropped rather than landed as failed when enabled. Default is false
enableFallback
Boolean
Optional, When enabled, if your transaction has not been able to win the paladin auction, they will be sent via SwQOS / JITO. Default is false
{
"id": 1,
"jsonrpc": "2.0",
"method": "sendPaladin",
"params": [
"<base 64 tx>",
{
"revertProtection": false,
"enableFallback" : false
}
]
}
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"<signature A>",
]
}
Need Help?
Join our Discord for technical guides, integration support, and live updates.
Last updated