How Chainstack supports high-performance trading on Solana
In an era where speed equates to success, ensuring the swift and seamless processing of transactions is a priority for Web3 developers. At Chainstack, we understand the importance of this demand, and we are dedicated to delivering solutions that empower developers, optimize efficiency, and elevate projects.
Our Solana trader nodes embody this commitment. These nodes enhance Solana transactions by ensuring 100% landing rates, rapid block inclusion, and highly efficient transaction routing. Not just that, our unique integration with the bloXroute Trader API brings a new edge to your traditional trading setup.
Without any need for custom setups or alterations, developers can experience the combined power of Chainstack and bloXroute, boosting transaction speeds significantly. Let’s explore the core features of Chainstack Solana trader nodes and their impact on transaction speed and efficiency.
How Chainstack Trader nodes transform your Solana project
From an outset, setting up your trading project to utilize our Chainstack Solana Trader nodes is a straight-forward process, and the benefits are immediate. All it needs is a simple endpoint swap to the Trader node one and your project gets transformed into a high-speed powerhouse.
This seamless transition comes with a host of benefits. For starters, it guarantees 100% landing for all transactions—a feat achieved by going through some of the biggest and most reputable SwQoS Solana validators.
Moreover, all your project requests pour through Chainstack Solana Trader nodes apart from the sendTransaction
requests, which are smartly routed through the bloXroute infrastructure. Consequently, you relish the best of both worlds.
Consider this: 75% of transactions are included in less than five blocks. Within this, 37% land within two blocks, 79% within four, and 95% within six. By the time we reach the tenth block, we’re looking at 99% of transactions landing. Full landing is achieved within 14 blocks.
And remember, you get all this without any substantial change to your existing setup. No need for crafting custom, non-standard transactions or unnecessary upheavals to your current operations—it’s all there from the start.
How Solana Trader nodes approach transaction prioritization
When it comes to elevating transaction speed and ensuring swift processing, priority fees play an indispensable role. However, one aspect that we’ve consciously decided not to include in our Solana Trader nodes is the front-running protection.
Why? Simply because incorporating such a safeguard would shrink the number of validators who can receive the transaction, thereby delaying the transaction—a trade-off that could compromise the speed we guarantee.
However, this does not imply that your transactions are left vulnerable. On the contrary, by leveraging bloXroute for your transactions, you’re placed at the very top of users, which significantly narrows down any front-running opportunities for potential adversaries.
Having said that, if you want to take it a step up and further increase your chances of being included in the first two blocks, Priority Fees can be a game-changer. These fees serve as your ticket to get an earlier placement within a block and even in the earliest blocks.
With Chainstack Solana Trader nodes, you can experience the power of Priority Fees and, consequently, expedite your transaction processing. Let’s explore how!
How to implement Solana Priority Fees
As a blockchain network famed for its high throughput and low latency, Solana offers priority fees to help users expedite their transactions. This feature becomes a critical tool for times when you need to override others, especially during high network congestion.
Priority fees on the Solana network allow users to attach a higher fee to their transactions, encouraging validators to prioritize and process them quicker. Opting to set a higher compute unit price gives your transaction precedence over those with lower fees, ensuring faster confirmation times. This specific feature highly benefits time-sensitive operations like DEX trading or running high-demand events like NFT minting.
To give you a clear picture, let’s walk through a practical example. In our scenario, we will demonstrate how to include priority fees in your Solana programs using the web3.js library and TypeScript. As such, you will get a comprehensive insight into priority fees, how to integrate them, and their contribution towards enhancing the performance of your Chainstack Trader node projects.
// main.ts
import { ComputeBudgetProgram, Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, TransactionInstruction, TransactionMessage, VersionedTransaction } from "@solana/web3.js";
import bs58 from "bs58";
import 'dotenv/config';
const CHAINSTACK_RPC = process.env.SOLANA_RPC || "";
const SOLANA_CONNECTION = new Connection(CHAINSTACK_RPC, {wsEndpoint:process.env.SOLANA_WSS, commitment: "confirmed"});
console.log(`Connected to Solana RPC at ${CHAINSTACK_RPC.slice(0, -36)}`);
// Decodes the provided environment variable private key and generates a Keypair.
const privateKey = new Uint8Array(bs58.decode(process.env.PRIVATE_KEY!));
const FROM_KEYPAIR = Keypair.fromSecretKey(privateKey);
console.log(`Initial Setup: Public Key - ${FROM_KEYPAIR.publicKey.toString()}`);
// Config priority fee and amount to transfer
const PRIORITY_RATE = 25000; // MICRO_LAMPORTS
const AMOUNT_TO_TRANSFER = 0.001 * LAMPORTS_PER_SOL;
// Instruction to set the compute unit price for priority fee
const PRIORITY_FEE_INSTRUCTIONS = ComputeBudgetProgram.setComputeUnitPrice({microLamports: PRIORITY_RATE});
async function sendTransactionWithPriorityFee() {
// Create instructions for the transaction
const instructions: TransactionInstruction[] = [
SystemProgram.transfer({
fromPubkey: FROM_KEYPAIR.publicKey,
toPubkey: FROM_KEYPAIR.publicKey,
lamports: AMOUNT_TO_TRANSFER
}),
PRIORITY_FEE_INSTRUCTIONS
];
// Get the latest blockhash
let latestBlockhash = await SOLANA_CONNECTION.getLatestBlockhash('confirmed');
console.log(" ✅ - Fetched latest blockhash. Last Valid Height:", latestBlockhash.lastValidBlockHeight);
// Generate the transaction message
const messageV0 = new TransactionMessage({
payerKey: FROM_KEYPAIR.publicKey,
recentBlockhash: latestBlockhash.blockhash,
instructions: instructions
}).compileToV0Message();
console.log(" ✅ - Compiled Transaction Message");
// Create a VersionedTransaction and sign it
const transaction = new VersionedTransaction(messageV0);
transaction.sign([FROM_KEYPAIR]);
console.log(" ✅ - Transaction Signed");
console.log(`Sending ${AMOUNT_TO_TRANSFER / LAMPORTS_PER_SOL} SOL from ${FROM_KEYPAIR.publicKey} to ${FROM_KEYPAIR.publicKey} with priority fee rate ${PRIORITY_RATE} microLamports`);
try {
// Send the transaction to the network
const txid = await SOLANA_CONNECTION.sendTransaction(transaction, { maxRetries: 15 });
console.log(" ✅ - Transaction sent to network");
// Confirm the transaction
const confirmation = await SOLANA_CONNECTION.confirmTransaction({
signature: txid,
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
});
if (confirmation.value.err) {
throw new Error("🚨 Transaction not confirmed.");
}
// Get the transaction result
const txResult = await SOLANA_CONNECTION.getTransaction(txid, {maxSupportedTransactionVersion: 0})
console.log('🚀 Transaction Successfully Confirmed!', '\\n', `https://solscan.io/tx/${txid}`);
console.log(`Transaction Fee: ${txResult?.meta?.fee} Lamports`);
} catch (error) {
console.log(error);
}
}
// Call the function to send the transaction with a priority fee
sendTransactionWithPriorityFee();
For greater detail on how to set up your Solana Priority Fees project please refer to our dedicated guide here.
How to estimate Priority Fees with getRecentPrioritizationFees
Efficiency is a cornerstone of transaction processing, and a pivotal element to this lies within Solana’s feature, getRecentPrioritizationFees
. This method equips users with the latest insights on these fees, allowing them to gain a clear understanding of the current fees attached to successful transactions. With this information, users can dynamically adjust the Priority Fees attached to their transactions.
When you integrate this feature into your programs, you can tap into real-time trends and patterns on the network’s current Priority Fees. This information is not just abstract data; it serves as a strategic input, helping you decide your transaction’s fee to ensure quicker processing.
To give you a better understanding, let’s look at this in action. Firstly, let’s deploy a Solana node on Chainstack, providing you direct blockchain access—crucial for effectively exploring unique features like the getRecentPrioritizationFees
method.
Once you deploy the node, and familiarize yourself with the getRecentPrioritizationFees
method, you will develop an understanding of how you can strategically pay a prioritization fee that considerably enhances your transaction’s chance of getting included in the forthcoming block.
// main.ts
import { Connection, PublicKey } from '@solana/web3.js';
import 'dotenv/config';
// Strongly type the environment variable getter
function getEnvVariable(key: string): string {
const value = process.env[key];
if (!value) {
throw new Error(`Environment variable ${key} is not set.`);
}
return value;
}
// Define interfaces for more explicit typing
interface PrioritizationFeeObject {
slot: number;
prioritizationFee: number;
}
interface Config {
lockedWritableAccounts: PublicKey[];
}
const getPrioritizationFees = async () => {
try {
const SOLANA_RPC = getEnvVariable('SOLANA_RPC');
const connection = new Connection(SOLANA_RPC);
const publicKey = new PublicKey('JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4');
const config: Config = {
lockedWritableAccounts: [publicKey]
};
const prioritizationFeeObjects = await connection.getRecentPrioritizationFees(config) as PrioritizationFeeObject[];
if (prioritizationFeeObjects.length === 0) {
console.log('No prioritization fee data available.');
return;
}
// Extract slots and sort them
const slots = prioritizationFeeObjects.map(feeObject => feeObject.slot).sort((a, b) => a - b);
// Extract slots range
const slotsRangeStart = slots[0];
const slotsRangeEnd = slots[slots.length - 1];
// Calculate the average including zero fees
const averageFeeIncludingZeros = prioritizationFeeObjects.length > 0
? Math.floor(prioritizationFeeObjects.reduce((acc, feeObject) => acc + feeObject.prioritizationFee, 0) / prioritizationFeeObjects.length)
: 0;
// Filter out prioritization fees that are equal to 0 for other calculations
const nonZeroFees = prioritizationFeeObjects
.map(feeObject => feeObject.prioritizationFee)
.filter(fee => fee !== 0);
// Calculate the average of the non-zero fees
const averageFeeExcludingZeros = nonZeroFees.length > 0
? Math.floor(nonZeroFees.reduce((acc, fee) => acc + fee, 0) / nonZeroFees.length )
: 0;
// Calculate the median of the non-zero fees
const sortedFees = nonZeroFees.sort((a, b) => a - b);
let medianFee = 0;
if (sortedFees.length > 0) {
const midIndex = Math.floor(sortedFees.length / 2);
medianFee = sortedFees.length % 2 !== 0
? sortedFees[midIndex]
: Math.floor((sortedFees[midIndex - 1] + sortedFees[midIndex]) / 2);
}
console.log(`Slots examined for priority fees: ${prioritizationFeeObjects.length}`)
console.log(`Slots range examined from ${slotsRangeStart} to ${slotsRangeEnd}`);
console.log('====================================================================================')
// You can use averageFeeIncludingZeros, averageFeeExcludingZeros, and medianFee in your transactions script
console.log(` 💰 Average Prioritization Fee (including slots with zero fees): ${averageFeeIncludingZeros} micro-lamports.`);
console.log(` 💰 Average Prioritization Fee (excluding slots with zero fees): ${averageFeeExcludingZeros} micro-lamports.`);
console.log(` 💰 Median Prioritization Fee (excluding slots with zero fees): ${medianFee} micro-lamports.`);
} catch (error) {
console.error('Error fetching prioritization fees:', error);
}
};
getPrioritizationFees();
For greater detail on how to set up your Solana Priority Fees estimator project please refer to our dedicated guide here.
How to set Priority Fees on a Jupiter swap
Jupiter stands as one of the top DEX aggregators on Solana, boasting a cumulative volume in USD billions. As a Web3 developer, you might find yourself needing to add Priority Fees to a token pair swap through a Jupiter aggregator.
In our case, let’s examine how to do this using Python. Although at the time of writing this, Jupiter does not have a Python SDK, it’s equally effective when implemented in Python. For JavaScript, you can refer to their Jupiter SDK.
# jupiter_swap.py
import asyncio
import base58
import base64
import aiohttp
import statistics
import time
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.transaction import VersionedTransaction
from solders.compute_budget import set_compute_unit_price
# Configuration
PRIVATE_KEY = "PRIVATE_KEY"
# trader node
RPC_ENDPOINT = "CHAINSTACK_NODE"
# regular node
# RPC_ENDPOINT = "CHAINSTACK_NODE"
INPUT_MINT = "So11111111111111111111111111111111111111112" # SOL
OUTPUT_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" # USDC
AMOUNT = 1000000 # 0.001 SOL in lamports
AUTO_MULTIPLIER = 1.1 # a 10% bump to the median of getRecentPrioritizationFees over last 150 blocks
SLIPPAGE_BPS = 1000 # 10% slippage tolerance
async def get_recent_blockhash(client: AsyncClient):
response = await client.get_latest_blockhash()
return response.value.blockhash, response.value.last_valid_block_height
# Get the data on the priority fees over the last 150 blocks.
# Note that it calculates the priority fees median from the returned data.
# And if the majority of fees over the past 150 blocks are 0, you'll get a 0 here as well.
# I found the median approach more reliable and peace of mind over something like getting some
# fluke astronomical fee and using it. This can be easily drain your account.
async def get_recent_prioritization_fees(client: AsyncClient, input_mint: str):
body = {
"jsonrpc": "2.0",
"id": 1,
"method": "getRecentPrioritizationFees",
"params": [[input_mint]]
}
await client.is_connected()
async with aiohttp.ClientSession() as session:
async with session.post(client._provider.endpoint_uri, json=body) as response:
json_response = await response.json()
print(f"Prioritization fee response: {json_response}")
if json_response and "result" in json_response:
fees = [fee["prioritizationFee"] for fee in json_response["result"]]
return statistics.median(fees)
return 0
async def jupiter_swap(input_mint, output_mint, amount, auto_multiplier):
print("Initializing Jupiter swap...")
private_key = Keypair.from_bytes(base58.b58decode(PRIVATE_KEY))
WALLET_ADDRESS = private_key.pubkey()
print(f"Wallet address: {WALLET_ADDRESS}")
async with AsyncClient(RPC_ENDPOINT) as client:
print("Getting recent blockhash...")
recent_blockhash, last_valid_block_height = await get_recent_blockhash(client)
print(f"Recent blockhash: {recent_blockhash}")
print(f"Last valid block height: {last_valid_block_height}")
print("Getting recent prioritization fees...")
prioritization_fee = await get_recent_prioritization_fees(client, input_mint)
prioritization_fee *= auto_multiplier
print(f"Prioritization fee: {prioritization_fee}")
total_amount = int(amount + prioritization_fee)
print(f"Total amount (including prioritization fee): {total_amount}")
print("Getting quote from Jupiter...")
quote_url = f"<https://quote-api.jup.ag/v6/quote?inputMint={input_mint}&outputMint={output_mint}&amount={total_amount}&slippageBps={SLIPPAGE_BPS}>"
try:
async with aiohttp.ClientSession() as session:
async with session.get(quote_url, timeout=10) as response:
response.raise_for_status()
quote_response = await response.json()
print(f"Quote response: {quote_response}")
except aiohttp.ClientError as e:
print(f"Error getting quote from Jupiter: {e}")
return None
print("Getting swap data from Jupiter...")
swap_url = "<https://quote-api.jup.ag/v6/swap>"
swap_data = {
"quoteResponse": quote_response,
"userPublicKey": str(WALLET_ADDRESS),
"wrapUnwrapSOL": True
}
try:
async with aiohttp.ClientSession() as session:
async with session.post(swap_url, json=swap_data, timeout=10) as response:
response.raise_for_status()
swap_response = await response.json()
print(f"Swap response: {swap_response}")
except aiohttp.ClientError as e:
print(f"Error getting swap data from Jupiter: {e}")
return None
print("Creating and signing transaction...")
async with AsyncClient(RPC_ENDPOINT) as client:
try:
swap_transaction = swap_response['swapTransaction']
print(f"Swap transaction length: {len(swap_transaction)}")
print(f"Swap transaction type: {type(swap_transaction)}")
transaction_bytes = base64.b64decode(swap_transaction)
print(f"Decoded transaction length: {len(transaction_bytes)}")
unsigned_tx = VersionedTransaction.from_bytes(transaction_bytes)
print(f"Deserialized transaction: {unsigned_tx}")
# Add ComputeBudget instruction to do the prioritization fee as implemented in solders
compute_budget_ix = set_compute_unit_price(int(prioritization_fee))
unsigned_tx.message.instructions.insert(0, compute_budget_ix)
signed_tx = VersionedTransaction(unsigned_tx.message, [private_key])
print(f"Final transaction to be sent: {signed_tx}")
print("Sending transaction...")
result = await client.send_transaction(signed_tx)
print("Transaction sent.")
tx_signature = result.value
tx_details = await client.get_transaction(tx_signature)
print(f"Confirmed transaction details: {tx_details}")
return result
except Exception as e:
print(f"Error creating or sending transaction: {str(e)}")
return None
async def wait_for_confirmation(client, signature, max_timeout=60):
start_time = time.time()
while time.time() - start_time < max_timeout:
try:
status = await client.get_signature_statuses([signature])
if status.value[0] is not None:
return status.value[0].confirmation_status
except Exception as e:
print(f"Error checking transaction status: {e}")
await asyncio.sleep(1)
return None
async def main():
try:
print("Starting Jupiter swap...")
print(f"Input mint: {INPUT_MINT}")
print(f"Output mint: {OUTPUT_MINT}")
print(f"Amount: {AMOUNT} lamports")
print(f"Auto multiplier: {AUTO_MULTIPLIER}")
result = await jupiter_swap(INPUT_MINT, OUTPUT_MINT, AMOUNT, AUTO_MULTIPLIER)
if result:
tx_signature = result.value
solscan_url = f"<https://solscan.io/tx/{tx_signature}>"
print(f"Transaction signature: {tx_signature}")
print(f"Solscan link: {solscan_url}")
print("Waiting for transaction confirmation...")
async with AsyncClient(RPC_ENDPOINT) as client:
confirmation_status = await wait_for_confirmation(client, tx_signature)
print(f"Transaction confirmation status: {confirmation_status}")
except Exception as e:
print(f"An error occurred: {str(e)}")
if __name__ == "__main__":
asyncio.run(main())
You can find the full project details in our dedicated guide here. To underscore the simplicity, here’s a brief walk-through:
- Use the Jupiter API to get a token pair price quote.
- Then, use the
getRecentPrioritizationFees
call from your node to gather Priority Fees data from the last 150 blocks. - Calculate the Priority Fees to include in your transaction based on the data collected.
- With priority fee in hand, use the Jupiter API quote to prepare your swap transaction.
- Finally, submit the transaction through your Chainstack Solana Trader node.
This approach not only guarantees faster transactions but also ensures you are managing costs effectove;y. It puts you ahead of the competition by providing you with a unique Chainstack Solana Trader node endpoint that is reliable and efficient.
Further reading
- How to prepare for the Solana Agave 2.0 upgrade: Stay ahead with the Solana Agave 2.0 upgrade. Seamlessly build, deploy, and scale with updated APIs and resilient nodes.
- Solana reloaded and next gen RPCs: Explore our massive Solana infrastructure update to optimize latency, coverage, and speed for Global Elastic Nodes.
- How to use Program Derived Addresses: Learn how to use Program Derived Addresses for state management in Solana, their benefits, creation process, and practical applications.
- How to calculate transaction fees programmatically: Get to know Solana’s deterministic fee model and learn how to calculate transaction fees programmatically to optimize your project.
- How to retrieve historical data effectively: Learn how to retrieve historical data on Solana effectively, using transaction replay, Geyser plugins, 3rd-party services, and others.
- Master guide to troubleshooting common development errors: Learn how to tackle common Solana errors like Rust version conflicts, Borsh serialization issues, blockstore errors, and more.
- How to overcome the 1000 transaction limit: Learn to handle Solana’s 1000 transaction limit with getSignaturesForAddress. Use pagination and recursion to fetch large transaction lists.
- What is the right transaction commitment level: Get to know what transaction commitment levels are on Solana and how to make the right choice when it comes to your program use case.
- The ultimate Solana developer guide: Master Solana development all across the board with this ultimate guide, covering everything from pastable snippets to advanced integrations.
Bringing it all together
The Web3 development landscape is consistently evolving, and staying ahead of the curve involves leveraging innovative solutions and tools. By ensuring 100% transaction landing rates, routing through reliable SwQoS Solana validators, and allowing the use of Priority Fees for faster block placement, Chainstack Solana Trader nodes are driving an entirely new level of speed and efficiency.
By offering a deep understanding of speed metrics and ensuring seamless integration with tools like the Solana web3.js library, TypeScript, and the bloXroute infrastructure, we support Web3 developers in achieving frictionless flow across their transaction processes.
Additionally, with features like getRecentPrioritizationFees
, which offer insights into network-wide priority fee trends, Chainstack helps developers make data-backed, strategic decisions to optimize transaction speeds. All these elements come together to make Chainstack Solana Trader nodes an essential choice for Web3 developers looking for reliable high-performance solutions.
Power-boost your project on Chainstack
- Discover how you can save thousands in infra costs every month with our unbeatable pricing on the most complete Web3 development platform.
- Input your workload and see how affordable Chainstack is compared to other RPC providers.
- Connect to Ethereum, Solana, BNB Smart Chain, Polygon, Arbitrum, Base, Optimism, Avalanche, TON, Ronin, zkSync Era, Starknet, Scroll, Aptos, Fantom, Cronos, Gnosis Chain, Klaytn, Moonbeam, Celo, Aurora, Oasis Sapphire, Polygon zkEVM, Bitcoin, Tezos and Harmony mainnet or testnets through an interface designed to help you get the job done.
- To learn more about Chainstack, visit our Developer Portal or join our Discord server and Telegram group.
- Are you in need of testnet tokens? Request some from our faucets. Multi-chain faucet, Sepolia faucet, Holesky faucet, BNB faucet, zkSync faucet, Scroll faucet.
Have you already explored what you can achieve with Chainstack? Get started for free today.