• Pricing
  • Enterprise
  • Customers
  • Blog

The ultimate Solana developer guide: Master swaps, transfers, priority fees, Raydium and more

Imagine a blockchain that’s at the epitome of high performance, designed for mass adoption, and friendly to an array of use cases, from finance to gaming and payments. That’s what Solana is about. This network operates as a single, global state machine, encapsulating openness, interoperability, and decentralization.

Solana’s uniqueness lies in its capacity to store and execute code, transforming it into a massive, global computer. Users deploy code called a program, which some may refer to as a “smart contract” in other blockchains. As highlighted in the Solana developer workflows, these programs create an avenue for interaction with clients through transactions on the blockchain.

As we get into the intricate details of Solana, you’ll understand why it’s a befitting alternative for your blockchain needs. With benefits over features and a shiny track record, Solana is undoubtedly worth mastering whether you’re a developer, a DApp user, or a blockchain enthusiast who prioritizes speed and security.

What makes Solana unique?

Deciphering the Solana network’s uniqueness requires us to dig deeper into its features. Here are some distinguishing aspects of Solana:

  • Performance: Solana’s high performance is an exceptional characteristic. This innovative network is designed for unparalleled speed to handle surges in traffic without compromising performance or security.
  • Adaptable: The malleability of Solana allows it to suit myriads of applications, carrying tremendous implications for sectors like finance, NFTs, and gaming, to name a few.
  • Interoperable: Solana maintains an open and interoperable model, supporting a multitude of projects built on it. This decentralization gives developers the freedom and flexibility to bring to life an array of innovations.
  • Stateless programs: Solana introduces stateless programs (or “smart contracts”), thus eliminating the need for each node to execute the same instructions repeatedly.
  • Accelerated processing: Solana’s ability to accommodate concurrent transaction processing and improve scalability sets it apart from most blockchains.

By harnessing its unique properties, Solana provides users with a seamless transition from traditional financial systems to a future shaped by blockchain technology. Its high-speed performance, coupled with the powerful capabilities of its blockchain, positions Solana as an attractive choice for developing and deploying DApps.

Understanding Solana

Solana’s unique architecture and developer workflows set it apart as a platform not just for today’s needs but also for the future’s demands. The following sections delve into the core aspects of Solana, from its developer workflows to transaction processing, providing a comprehensive overview of its capabilities and how it’s pioneering the path for a decentralized future.

Overview of Solana developer workflows

Understanding the Solana network unfolds from its development workflows. At a high level, Solana takes on the appearance of a colossal global computer, open to anyone for storing and executing code, for an equivalent fee.

Such deployed code is labeled a “program,” often referred to as a “smart contract” in several other blockchains. To interact with a program entails dispatching a transaction on the blockchain from a client.

Figure 1: Solana developer workflows; Source: Solana

Conventionally, there are two primary workflows for development on Solana.

  1. Program development: This workflow entails pioneering and implementing custom Rust, C, and C++ programs directly to the blockchain. These deployed programs are accessible to anyone conversant with communicating with them.
  2. Client development: Operating from the DApp end, this workflow fosters DApp development to connect with the deployed programs. Apps can tender transactions bearing instructions to these programs via a client SDK, crafting a myriad of applications like exchanges, wallets, and more.

An amalgamation of these workflows births an expansive network of DApps and programs capable of interacting with each other, thereby updating the state and querying the blockchain.

Program development on Solana

In Solana’s ecosystem, the term ‘program’ indicates what is commonly known as a ‘smart contract’ in other blockchain networks. These programs, developed in Rust, C, or C++, can be deployed directly onto the Solana blockchain.

When you release a program on Solana, anyone who knows how to interact with it can do so. However, it’s crucial to remember that once deployed, these programs cannot be changed—a guiding principle of immutability in blockchain technology.

Program development involves creating instructions that dictate how state transitions happen. This process can be likened to developing an API for interacting with databases. Only, in the case of Solana, the chain itself acts as a database.

Those keen on stepping into the world of Solana-based program development, know that it requires a profound comprehension of the Solana programming model. Even so, the performance payoff is lucrative, as the potential capabilities of your Solana program can overshadow those of traditional smart contracts.

Wallets in Solana

In Solana, wallets function as the key gateway for users and developers to interact with the Solana network. A wallet in Solana primarily serves two functions:

  1. Account management: Wallets store the public and private keys for one or more accounts. They handle details like account creation, key management, and transaction signing.
  2. Transaction interaction: Wallets make it possible to communicate with programs on the blockchain by forming and broadcasting transactions.

Different types of wallets cater to varied user requirements. These include:

  • Web wallets: These are accessible from web browsers and offer an easy starting point for new users. e.g., Solflare.
  • Hardware wallets: These provide increased security as they store private keys offline in a physical device. e.g., Trezor.
  • Software wallets: These are programs downloaded to a computer or mobile, providing a varied range of features. e.g., Trust.

Understanding wallets is an essential part of mastering Solana as it allows seamless interaction with the Solana network and DApps built upon it.

Transactions on Solana

In Solana, a transaction is a bundled set of instructions with a single goal—to atomically update the state of the blockchain. Transactions highlight the interaction between clients and programs, thereby forming the backbone of Solana’s operations.

Every transaction in Solana includes:

  • Signatures: Identifications provided by the initiating parties.
  • Message: Contains the instructions which include the program ID, accounts involved, and data passed to the program.

Here’s what typically happens:

  1. A client (user or DApp) creates a transaction, signing it with the private key of the sender’s account.
  2. The transaction is then sent to one of Solana’s validator nodes.
  3. This node validates the transaction’s signatures and executes the instructions.
  4. If the transaction is valid, it gets added to Solana’s transaction pool and awaits final processing.

An intuitive insight into transactions is key to leveraging the power of Solana’s blockchain. From DApp interactions to wallet functions, transactions pave the way for a spectrum of activities within the Solana network.

Figure 2: Visual layout of a Solana transaction; Source: Solana

Instructions in Solana transactions

Every Solana transaction embeds one or more instructions that each contain the data (input), an ordered list of accounts it operates on, and the program ID.

Figure 3: Components of a Solana transaction instruction; Source: Solana

The instruction data, a byte array, interprets differently for each program. The program may decide to interpret it as an array, a struct, or as a combination of various data types. The crux is that the instruction data carries the payload borne by the transaction to interact with a specific program on Solana.

Any changes made to the accounts are visible instantly by other instructions in the same transaction and to subsequent transactions. This unique utility ensures an atomic commitment to the ledger, meaning all instructions in a transaction succeed or fail together, thus maintaining consistency in the state of the chain.

Understanding instructions is critical when creating transactions, as it influences how programs interact with the state stored in accounts.

// Sample Solana instructions snippet
pub fn create_account(
    from_pubkey: &Pubkey,
    to_pubkey: &Pubkey,
    lamports: u64,
    space: u64,
    owner: &Pubkey,
) -> Instruction {
    let account_metas = vec![
        AccountMeta::new(*from_pubkey, true),
        AccountMeta::new(*to_pubkey, true),
    ];
    Instruction::new_with_bincode(
        system_program::id(),
        &SystemInstruction::CreateAccount {
            lamports,
            space,
            owner: *owner,
        },
        account_metas,
    )
}

Transaction fees on Solana

On the Solana network, transactions aren’t free. They come with a cost, a “transaction fee,” that clients need to pay whenever they make a transaction. These fees primarily perform two functions:

  1. Prevent DDoS attacks: By adding a fee, Solana ensures that it would be prohibitively expensive for anyone to flood the network with transactions, thus maintaining network health.
  2. Compensate validators: Transaction fees serve as incentives for validators. As validators commit resources and time to process transactions, the fees serve as compensation for their efforts.

The fee for a transaction in Solana varies based on the current congestion level of the network. When the network is busy, fees rise, and when it quietens, the fees decrease.

But how does Solana calculate these fees? It’s simple, and it’s all performed automatically:

  1. Solana determines a base fee for an instruction based on its current cost model.
  2. It then adds any additional fees for the execution of built-in instructions.
  3. Finally, it multiplies the cumulative fee by the current network fee multiplier, setting the final fee.

Making sense of transaction fees is crucial in understanding Solana’s economics and will aid you in navigating this vibrant ecosystem more effectively.

# Solana getFees RPC API method snippet
$ curl <http://api.mainnet-beta.solana.com> -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getFees"}
'
# Response
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 106818885
    },
    "value": {
      "blockhash": "78e3YBCMXJBiPD1HpyVtVfFzZFPG6nUycnQcyNMSUQzB",
      "feeCalculator": {
        "lamportsPerSignature": 5000
      },
      "lastValidBlockHeight": 96137823
    }
  },
  "id": 1
}

Demystifying accounts on Solana

Accounts in Solana are ubiquitous. Each transaction in Solana requires an account for operation, from paying transaction fees to holding data manipulated by programs (smart contracts).

The significant features of Solana accounts include:

  • Key pairs: Each account is associated with a private-public key pair. The public key acts as the account’s address, and the private key is used to authorize transactions.
  • Data storage: Each account carries data which is an array of bytes. The data entries can be manipulated and read through programs, but only the owner program can modify its data.
  • Nonce accounts: Solana’s unique nonce accounts, a type of account, can be used for transaction processing. They also serve as a replacement for the “recent blockhash queue” that the system uses for managing transaction lifetimes.
  • Assets management: An account can hold native or tokenized assets, making it similar to an Ethereum address.

Being aware of the account operations on Solana is as crucial as understanding its transaction model. This understanding sets the foundation for interacting with Solana’s blockchain more comprehensively.

Role of programs in Solana’s ecosystem

Programs in Solana occupy a central role in the network’s operation. Sometimes referred to as ‘smart contracts’ in other blockchain networks, programs in Solana interpret and execute instructions within a transaction.

Some notable features of Solana’s program model include:

  1. Stateful operations: Programs can maintain a persistent state across transactions, thereby allowing complex operations and interactions.
  2. Multi-language support: Solana-specific programs can be developed using languages that can compile to BPF (Berkeley Packet Filter), such as Rust and C. This provides developers the flexibility to build in familiar languages.
  3. On-chain programs: Once a program is deployed to the network, it is available to anyone who can form a valid instruction.
  4. Interoperability: Different programs on Solana can interact with one another. A single transaction can contain instructions for multiple programs.

In the Solana network, programs are the equivalent of CPUs in conventional computers. Grasping the concept of programs will provide a more holistic view of how Solana’s blockchain functions.

Development environments for Solana

Having a safe and efficient environment to test and develop is vital for all developers. Luckily for Solana developers, the network provides several environments:

  • Local development environment: Solana allows developers to run a local test validator. This environment is used for quick testing during the development phase and does not require any transaction fees.
  • Devnet: This is a publicly accessible test network maintained by the Solana team. It replicates the conditions of the Mainnet and is optimal for final testing before deploying onto the main network.
  • Testnet: This environment is used to beta-test the latest Solana software under a highly adversarial condition. It permits developers and validators to participate in various testing scenarios.
  • Mainnet: This is the main Solana network where real transactions occur. Once testing on Devnet and Testnet is satisfactory, developers can transition to the Mainnet.

Understanding the appropriate environment for each stage of development and testing is crucial to creating effective and robust programs on Solana.

How to deploy a Solana node for free on Chainstack

In keeping with the ethos of decentralization and fostering inclusivity, Chainstack offers an easy-to-use platform for deploying Solana nodes for free. Here’s a simple guide on how to get your Solana node up and running on Chainstack:

  1. Sign up: Start by creating a Chainstack account.
  2. Create a project: After you’re signed in, click Create a Project.
  3. Add network: Click Add Network and select ‘Solana’ under the protocol option.
  4. Create the deployment: After clicking ‘Next’, set the node details and click Create.
  5. Get your endpoint: Once deployed, click on your node and find your access details.
Figure 4: How to deploy a node for free on Chainstack; Source: Chainstack

Remember, while Chainstack offers the ease and convenience of deploying Solana nodes for free, our platform also provides tiered pricing options for more advanced needs.

Master Solana development in code

We offer a series of Solana mastering tutorials, focusing on various aspects of the protocol to help Web3 developers acquire in-depth knowledge. Some of the topics now included in our tutorial series that we will share snippets from in the coming sections are:

  • Token swaps using the Raydium SDK: Dive deep into performing token swaps on the Solana blockchain, utilizing the Raydium SDK for efficient and cost-effective transactions.
  • Transferring SPL tokens with TypeScript: Explore the nuances of SPL token transfers within the Solana ecosystem, leveraging TypeScript for a streamlined development process.
  • Retry logic for SPL token transfers: Learn advanced techniques to bolster the reliability of SPL token transfers, incorporating retry logic to handle transaction failures gracefully.
  • Solana account retrieval methods: Gain clarity on the distinct methods available for account retrieval in Solana, including getAccountInfo and getMultipleAccounts, and their use cases.
  • SPL token distribution: Discover how to leverage Solana’s getTokenLargestAccounts RPC method to analyze the distribution of SPL tokens among holders, providing insights into tokenomics.
  • Priority fees for faster transactions: Get to know the basics of priority fees on Solana, how to set and implement them in your project, and send faster priority transactions using TypeScript.
  • Estimate Priority Fees: Explore the getRecentPrioritizationFees method, its operational mechanics, and role in enhancing transaction efficiency by estimating Priority Fees.

These topics offer a pathway for you as a developer to deepen your understanding of Solana’s capabilities, addressing specific challenges and opportunities within the network’s expansive ecosystem.

How to perform token swaps using the Raydium SDK

Raydium is an automated market maker (AMM) and liquidity provider built on the Solana blockchain for the Serum decentralized exchange (DEX). The Raydium SDK offers a range of functionalities, including the ability to perform token swaps.

Here’s a simplified process from the full tutorial:

  1. Get a Solana node: Deploy a Solana node for free in minutes on Chainstack.
  2. Set up environment: Add your RPC endpoint and private key to a .env file.
  3. Installation: Clone the example repository locally and install the dependencies.
  4. Configuration: Set swap status, amount, tokens, and liquidity pool information.
  5. Confirmation: Upon a successful swap, you’ll receive block confirmation details.
// Sample swapConfig.ts setup snippet
export const swapConfig = {
  executeSwap: false, // Send tx when true, simulate tx when false
  useVersionedTransaction: true,
  tokenAAmount: 0.01, // Swap 0.01 SOL for USDT in this example
  tokenAAddress: "So11111111111111111111111111111111111111112", // Token to swap for the other, SOL in this case
  tokenBAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC address
  maxLamports: 1000000, // Max lamports allowed for fees
  direction: "in" as "in" | "out", // Swap direction: 'in' or 'out'
  liquidityFile: "<https://api.raydium.io/v2/sdk/liquidity/mainnet.json>",
  maxRetries: 10
};

Understanding how to integrate and interact with the Raydium SDK significantly widens the possibilities of what you as a developer can accomplish on the Solana network.

How to transfer SPL Tokens in TypeScript

Solana is known for its rapid and secure transaction capabilities, particularly for transferring SPL tokens that span digital currencies to various assets. It showcases the efficiency and flexibility of token transactions within Solana’s ecosystem, highlighting the platform’s strength in handling digital assets.

This capacity is essential for developers and blockchain enthusiasts aiming to navigate and innovate within the expansive domain of blockchain technology. Here’s a snippet of the main function outlined in the dedicated TypeScript tutorial:

// SPL token transfer script snippet
  // Main function orchestrates sending tokens by calling the defined functions in order.
  async function main() {
    console.log("Starting Token Transfer Process");
  
    const connection = initializeConnection();
    const fromKeypair = initializeKeypair();
  
    // Address receiving the tokens
    const destinationWallet = new PublicKey(
      "CzNGm14nMopjGYyycMbWqEF2e1aEHcJLKk2CHw9BiZwC"
    );
  
    // The SLP token being transferred, this is the address for USDC
    const mintAddress = new PublicKey(
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
    );
  
    // Config priority fee and amount to transfer
    const PRIORITY_RATE = 12345; // MICRO_LAMPORTS
    const transferAmount = 0.01;
    // Instruction to set the compute unit price for priority fee
    const PRIORITY_FEE_INSTRUCTIONS = ComputeBudgetProgram.setComputeUnitPrice({microLamports: PRIORITY_RATE});
  
    console.log("----------------------------------------");
    const decimals = await getNumberDecimals(mintAddress, connection);
  

Understanding how to transfer SPL tokens lays crucial foundation for developers like yourself aiming to build DApps or systems involving Solana-based digital assets.

How to improve SPL token transfers with retry logic

Introduce a retry logic to enhance your SPL token transfers, addressing transient network issues or node overloads by automatically reattempting failed transactions. This boosts DApp resilience, reliability, and user experience, setting the stage for further performance enhancements. Following are several snippets from the full tutorial that you can use as template guidelines.

How to wrap the transaction send logic in a retry loop

// How to wrap the transaction send logic in a retry loop snippet
const retryCount = Number(process.env.MAX_RETRY_FUNCTION);
// Default retry count set to 5
for (let attempt = 1; attempt <= retryCount; attempt++) {
  try {
// Transaction send logic goes here
    ...
    return;// Exit the function on a successful transaction
  } catch (error) {
// Handle errors and retry logic
    ...
  }
}

How to handle different error types

// How to handle different error types snippet
catch (error) {
  console.error(`Attempt ${attempt} failed with error: ${error}`);
  if (attempt === retryCount) {
    // Last attempt failed, throw the error
    throw new Error(`Transaction failed after ${retryCount} attempts.`);
  }
  // Additional error handling or logging can be added here
  ...
}

How to implement a delay or backoff strategy between retries

// How to implement a delay or backoff strategy between retries snippet
// Wait for 2 seconds before retrying
await new Promise((resolve) => setTimeout(resolve, 2000));

How to log or report retry attempts

// How to log or report retry attempts snippet
console.log(`Attempt ${attempt}: Starting Token Transfer Process`);
...
console.error(`Attempt ${attempt} failed with error: ${error}`);

Solana account retrieval methods

In Solana development, efficient data retrieval is crucial. The getAccountInfo and getMultipleAccounts methods serve this need with distinct advantages.

getAccountInfo offers a straightforward, precise approach for accessing individual account information with its public key, making it suitable for detailed account queries. On the other hand, getMultipleAccounts provides a bulk data retrieval option, enabling efficient data gathering for multiple accounts in one go, ideal for batch processing and complex tasks.

Grasping the differences and applications of these methods is essential for you as a developer aiming to enhance performance and data management on Solana. Below are several examples from the full tutorial of how to use these methods in various scenarios.

How to use getAccountInfo

# How to use getAccountInfo snippet
curl YOUR_CHAINSTACK_ENDPOINT -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getAccountInfo",
    "params": [
      "Hr5GK3f5WqqLsr4TJ7cgVCnDaM5gY8QrD2GTPZ7K3Kpz",
      {
        "encoding": "base58"
      }
    ]
  }
'

How to use getMultipleAccounts

# How to use getMultipleAccounts snippet
curl --location 'CHAINSTACK_SOLANA_RPC' \\
--header 'Content-Type: application/json' \\
--data '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getMultipleAccounts",
    "params": [
      [
        "Hr5GK3f5WqqLsr4TJ7cgVCnDaM5gY8QrD2GTPZ7K3Kpz",
        "EAaijviraKWCWsVZtiZ5thhXoyoB5RP3HH1ZiLeLDcuv"
      ],
      {
        "encoding": "base58"
      }
    ]
  }
'

How to run the getMultipleAccounts method in JavaScript

// How to run the getMultipleAccounts method in JavaScript snippet
const { Connection, PublicKey } = require('@solana/web3.js');
async function fetchMultipleAccountsInfo() {
    // Initialize connection to the Solana endpoint
    const connection = new Connection('YOUR_CHAINSTACK_ENDPOINT');
    // Array of public keys for multiple accounts
    const accountPublicKeys = [
        new PublicKey('Hr5GK3f5WqqLsr4TJ7cgVCnDaM5gY8QrD2GTPZ7K3Kpz'),
        new PublicKey('EAaijviraKWCWsVZtiZ5thhXoyoB5RP3HH1ZiLeLDcuv'),
        // Add more account public keys as needed
    ];
    // Fetch information for multiple accounts
    const multipleAccountsInfo = await connection.getMultipleAccountsInfo(accountPublicKeys);
    // Process and display multiple accounts information
    console.log(multipleAccountsInfo);
}
fetchMultipleAccountsInfo().catch(error => {
    console.error('Error fetching multiple accounts info:', error);
});

How to run the getMultipleAccounts method in Python

# How to run the getMultipleAccounts method in Python snippet
from solana.rpc.api import Client
from solders.pubkey import Pubkey
# Initialize connection to the Solana cluster
solana_client = Client("YOUR_CHAINSTACK_ENDPOINT")
# Array of public keys for multiple accounts
public_keys = [
    Pubkey.from_string("Hr5GK3f5WqqLsr4TJ7cgVCnDaM5gY8QrD2GTPZ7K3Kpz"),
    Pubkey.from_string("EAaijviraKWCWsVZtiZ5thhXoyoB5RP3HH1ZiLeLDcuv"),
    # Convert additional public keys to PublicKey objects as needed
]
# Fetch information for multiple accounts
multiple_accounts_info = solana_client.get_multiple_accounts(public_keys)
# Process and display multiple accounts' information
print(multiple_accounts_info)

How to view top SPL holder distribution

Exploring holder distribution of a particular SPL Token gives developers insight into the liquidity and market depth of that token. Next are a few examples from the full tutorial for you to explore top SPL holder distribution using Solana’s JavaScript/TypeScript SDK.

How to use the getTokenLargestAccounts RPC method

# How to use the getTokenLargestAccounts RPC method snippet
curl YOUR_CHAINSTACK_ENDPOINT -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenLargestAccounts",
    "params": [
      "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R",
      {
        "commitment": "finalized"
      }
    ]
  }
'

How to integrate getTokenLargestAccounts into JavaScript

// How to integrate getTokenLargestAccounts into JavaScript snippet
const { Connection, PublicKey } = require('@solana/web3.js');
async function fetchTokenLargestAccounts() {
    const connection = new Connection('YOUR_CHAINSTACK_ENDPOINT');
    const tokenMintPublicKey = new PublicKey('4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R');
    const largestAccounts = await connection.getTokenLargestAccounts(tokenMintPublicKey, 'finalized');
    console.log(largestAccounts);
}
fetchTokenLargestAccounts().catch(error => console.error('Error fetching token largest accounts:', error));

How to integrate getTokenLargestAccounts into Python

# How to integrate getTokenLargestAccounts into Python snippet
from solana.rpc.api import Client
from solders.pubkey import Pubkey
solana_client = Client("YOUR_CHAINSTACK_ENDPOINT")
token_mint_public_key = Pubkey.from_string("4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R")
largest_accounts = solana_client.get_token_largest_accounts(token_mint_public_key)
# Display raw response
#print(largest_accounts)
# Display the information in a nicer format
print("Largest SPL Token Accounts:\\n")
# Accessing slot and api version
slot = largest_accounts.context.slot
api_version = getattr(largest_accounts.context, 'api_version', 'Unknown')
# Print the data in a nice format
print(f"Slot: {slot}\\nAPI Version: {api_version}\\n")
for account in largest_accounts.value:
    address = account.address
    ui_amount = account.amount.ui_amount
    decimals = account.amount.decimals
    amount = account.amount.amount
    print(f"Address: {address}\\nAmount: {ui_amount} (Decimals: {decimals}, Raw: {amount})\\n")

Analyzing top SPL holder distribution can provide useful insights into token usage and dissemination, crucial for strategic decision-making in the Solana ecosystem.

How to use priority fees for faster transactions

Solana supports priority fees to help increase the processing speed of a transaction. In simple terms, by paying a higher network fee, you can expedite the processing of your transaction.

Find out how to programmatically set a priority fee for your Solana transactions with this snippet from the full tutorial:

// Key components of sending Solana priority transactions 
// 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
  ];

Remember, setting a higher fee does not always guarantee immediate processing, as the network might be congested with other high-fee transactions.

How to estimate priority fees with getRecentPrioritizationFees

Solana’s getRecentPrioritizationFees method offers developers current insights into prioritization fees. This allows you to understand the fees associated with successful transactions and dynamically estimate the priority fee for your transactions.

How to use the getRecentPrioritizationFees RPC method

# How to use the **getRecentPrioritizationFees** RPC method snippet
curl --request POST \\
     --url YOUR_SOLANA_ENDPOINT \\
     --header 'accept: application/json' \\
     --header 'content-type: application/json' \\
     --data '
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "getRecentPrioritizationFees",
  "params": [
    [
      "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
    ]
  ]
}
'

How to integrate getRecentPrioritizationFees in JavaScript

// How to integrate getRecentPrioritizationFees in JavaScript snippet
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);
    }
};

Sending Solana transactions using solana/web3.js

Solana’s JavaScript API, solana/web3.js, provides a simple and efficient way to create and submit transactions to the Solana network. Here’s a quick walkthrough from the full recipe:

  1. Initial setup: Install node.js if you haven’t done so already, as well as thesolana/web3.js and bs58 libraries.
  2. Set up two accounts: Create one using a private key and generate another on the fly to be a fresh recipient.
  3. Create a transfer function: Draft an async function to transfer Lamports from the first to the second account.
  4. Run your script: Execute your code to send your transaction between the two accounts you’ve chosen earlier.
// How to send Solana transactions using @solana-web3.js recipe
const web3 = require("@solana/web3.js");
const bs58 = require("bs58");
const connection = new web3.Connection('YOUR_CHAINSTACK_ENDPOINT');
const privateKey = new Uint8Array(bs58.decode('YOUR_PRIVATE_KEY'));
const account = web3.Keypair.fromSecretKey(privateKey);
const account2 = web3.Keypair.generate();
(async () => {
  const transaction = new web3.Transaction().add(
    web3.SystemProgram.transfer({
      fromPubkey: account.publicKey,
      toPubkey: account2.publicKey,
      lamports: web3.LAMPORTS_PER_SOL * 0.001,
    }),
  );
  const signature = await web3.sendAndConfirmTransaction(
    connection,
    transaction,
    [account],
  );
})();

It’s important to listen for transaction confirmation to determine whether it worked as expected. Solana/web3.js makes this simple with transaction confirmation utilities.

Minting SPL tokens with solana-web3.js

SPL tokens represent digital assets and are minted using the Token Program on the Solana blockchain. The solana/web3.js JavaScript API makes creating new tokens easy. Here’s a concise step-by-step guide extracted from the full recipe:

  1. Initial setup: Install the @solana/web3.js, @solana/spl-token, and bs58 packages.
  2. Connect to Solana: Pass your Chainstack endpoint using the connection variable.
  3. Create or import wallet: Create a fresh account with solanaWeb3.Keypair.generate() or import one via solanaWeb3.Keypair.fromSecretKey()
  4. Draft the script: Use the splToken.createMint method to pass the parameters needed to prepare for the mint.
  5. Create token account: Use the getOrCreateAssociatedTokenAccount function to make a corresponding token account for your SPL token.
  6. Mint your tokens: Take the mint and tokenAccount objects, in order to call the mintTo function to mint your SPL tokens.
// How to mint SPL tokens with @solana-web3.js recipe
const solanaWeb3 = require('@solana/web3.js');
const splToken = require('@solana/spl-token');
const bs58 = require("bs58");
async function main() {
  const connection = new solanaWeb3.Connection("CHAINSTACK_HTTPS_ENDPOINT", {wsEndpoint:"CHAINSTACK_WSS_ENDPOINT"});
  const walletKeyPair = solanaWeb3.Keypair.fromSecretKey(new Uint8Array(bs58.decode(process.env.PRIVATE_KEY)));
  const mint = await splToken.createMint(
    connection,
    walletKeyPair,
    walletKeyPair.publicKey,
    null,
    9,
    undefined,
    {},
    splToken.TOKEN_PROGRAM_ID,
  );
  const tokenAccount = await splToken.getOrCreateAssociatedTokenAccount(
    connection,
    walletKeyPair,
    mint,
    walletKeyPair.publicKey,
  );
  await splToken.mintTo(
    connection,
    walletKeyPair,
    mint,
    tokenAccount.address,
    walletKeyPair.publicKey,
    1000000000000,
  )

Bringing it all together

Solana, as a high-performance, open-source project, presents a broad spectrum of opportunities for developers willing to leverage blockchain for their applications. From understanding its key components, such as accounts and transaction architecture, to getting hands-on with coding using various SDKs, and implementing token swaps, the mastering guides on Solana offer deep insights and practical knowledge.

With this extensive overview, we aimed to unveil the attributes of one of the fastest blockchain networks available today. The journey we undertook covers discovering its unique features, understanding Solana’s native programs, exploring its developer workflows, and even delving into its token economics.

While we immerse ourselves in what Solana has to offer, remember that Web3 is rapidly evolving, and so is Solana. The platform consistently introduces novel features and improvements, providing developers with an even more robust foundation for creating decentralized applications and pushing the boundaries of what’s possible with blockchain technology.

Power-boost your project on Chainstack

Have you already explored what you can achieve with Chainstack? Get started for free today.

SHARE THIS ARTICLE

A StarkNet odyssey: Escaping Cairo hell

Cairo learning curve is pretty steep. In this article we review all the things that you need to know before writing your first line of code.

Antonio Ufano
May 20