Solana: Analyzing adjacent transactions for priority fees

This guide shows you how to analyze transaction priority fees for transactions adjacent to your target transaction on Solana. This is particularly useful when developing trading strategies or troubleshooting transaction execution on programs like pump.fun.

What the script in this tutorial does is look for transactions adjacent to the one you specify (usually your own) and checks all other transactions involving the same program and prints the priority fees in the same block and the adjacent blocks to easily see how your particular transaction stacks up and how you can tune it to win more races.

Prerequisites

👍

Get you own node endpoint today

Start for free and get your app to production levels immediately. No credit card required.

You can sign up with your GitHub, X, Google, or Microsoft account.

  • Python 3.7+
  • Packages: pip install solana base58

Understanding Solana fees

The recommended reading list:

Implementation

If you end up in this specific scenario as outlined in the beginning of the article, here's things that you need to have to get the results:

The script itself:

from solana.rpc.api import Client
from solana.rpc.commitment import Commitment
from solana.transaction import Signature
import base58
import json
from typing import List, Optional, Tuple

PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
COMPUTE_BUDGET_ID = "ComputeBudget111111111111111111111111111111"

def get_transaction_slot(client: Client, signature_str: str) -> Optional[int]:
    try:
        signature_bytes = base58.b58decode(signature_str)
        signature = Signature(signature_bytes)
        
        response = client.get_transaction(
            signature,
            max_supported_transaction_version=0
        )
        if hasattr(response, 'value') and response.value:
            return response.value.slot
        return None
    except Exception as e:
        print(f"Error getting transaction slot: {e}")
        return None

def calculate_transaction_fees(tx) -> Tuple[float, float]:

    total_fee_lamports = tx.meta.fee
    total_fee_sol = total_fee_lamports / 1_000_000_000
    
    cu_price_micro_lamports = None
    cu_limit = None
    

    for ix in tx.transaction.message.instructions:
        program_id = tx.transaction.message.account_keys[ix.program_id_index]
        if str(program_id) == COMPUTE_BUDGET_ID:
            data = base58.b58decode(ix.data)
            if len(data) >= 9 and data[0] == 3:  
                cu_price_micro_lamports = int.from_bytes(data[1:9], 'little')
            elif len(data) >= 4 and data[0] == 2:  
                cu_limit = int.from_bytes(data[1:4], 'little')
    

    if cu_price_micro_lamports is not None and cu_limit is not None:
        priority_fee_lamports = (cu_price_micro_lamports * cu_limit) // 1_000_000
        priority_fee_sol = priority_fee_lamports / 1_000_000_000
    else:
        priority_fee_sol = 0
    
    return total_fee_sol, priority_fee_sol

def get_block_transactions(client: Client, slot: int, target_signature: str) -> List[tuple]:
    try:
        response = client.get_block(slot, max_supported_transaction_version=0)
        if not response.value:
            return []
        
        transactions = []
        for tx in response.value.transactions:

            if any(str(account) == PROGRAM_ID for account in tx.transaction.message.account_keys):
                signature = str(tx.transaction.signatures[0])
                total_fee, priority_fee = calculate_transaction_fees(tx)
                
                writable_accounts = []
                for idx, account in enumerate(tx.transaction.message.account_keys):

                    if idx < tx.transaction.message.header.num_required_signatures:
                        writable_accounts.append(str(account))
                

                compute_units = tx.meta.compute_units_consumed if hasattr(tx.meta, 'compute_units_consumed') else None
                
                tx_info = {
                    'signature': signature,
                    'total_fee': total_fee,
                    'priority_fee': priority_fee,
                    'block': slot,
                    'writable_accounts': writable_accounts,
                    'compute_units': compute_units
                }
                
                if signature == target_signature:
                    transactions.insert(0, tx_info)
                else:
                    transactions.append(tx_info)
                    
        return transactions
    except Exception as e:
        print(f"Error getting block transactions for slot {slot}: {e}")
        return []

def analyze_slots(rpc_url: str, signature: str, slots_back: int, slots_forward: int):
    client = Client(rpc_url)
    current_slot = get_transaction_slot(client, signature)
    if not current_slot:
        print("Could not find transaction slot")
        return
    
    print(f"\nAnalyzing slots {current_slot-slots_back} to {current_slot+slots_forward}")
    print("=" * 80)
    
    for slot in range(current_slot - slots_back, current_slot + slots_forward + 1):
        transactions = get_block_transactions(client, slot, signature)
        
        print(f"\nSlot {slot}:")
        print("-" * 40)
        
        if transactions:
            target_tx = None
            other_txs = []
            
            for tx in transactions:
                if tx['signature'] == signature:
                    target_tx = tx
                else:
                    other_txs.append(tx)
            

            other_txs.sort(key=lambda x: x['priority_fee'], reverse=True)
            
            if target_tx:
                print("\n" + "⭐️" * 40)
                print("🎯 TARGET TRANSACTION FOUND 🎯")
                print("⭐️" * 40)
                print(f"\nSignature: {target_tx['signature']}")
                print(f"Block: {target_tx['block']}")
                print(f"{'Total fee:':<15} {target_tx['total_fee']:>12.8f} SOL")
                print(f"{'Priority fee:':<15} {target_tx['priority_fee']:>12.8f} SOL")
                print(f"{'Base fee:':<15} {(target_tx['total_fee'] - target_tx['priority_fee']):>12.8f} SOL")
                print(f"Compute Units: {target_tx['compute_units']}")
                print("\nWritable Accounts:")
                for account in target_tx['writable_accounts']:
                    print(f"  {account}")
                print("⭐️" * 40 + "\n")
            
            if other_txs:
                print(f"Other transactions in slot {slot} (sorted by priority fee):")
                print("-" * 40)
                
                for tx in other_txs:
                    print(f"\nSignature: {tx['signature']}")
                    print(f"Block: {tx['block']}")
                    print(f"Fee: {tx['total_fee']:.8f} SOL (Priority: {tx['priority_fee']:.8f} SOL)")
                    print(f"Compute Units: {tx['compute_units']}")
                    print("Writable Accounts:")
                    for account in tx['writable_accounts']:
                        print(f"  {account}")
                    print("-" * 40)
        else:
            print("No relevant transactions")

def main():
    RPC_URL = "CHAINSTACK_NODE_RPC"
    SIGNATURE = "TRANSACTION_SIGNATURE"
    SLOTS_BACK = 1  # Number of slots to check back
    SLOTS_FORWARD = 1  # Number of slots to check forward
    
    analyze_slots(RPC_URL, SIGNATURE, SLOTS_BACK, SLOTS_FORWARD)

if __name__ == "__main__":
    main()

In the script:

  • PROGRAM_ID — set to the pump.fun executable. Set it to any executable on-chain program you interact with.
  • COMPUTE_BUDGET_ID — set to the Solana system program responsible for compute units and fees. We use in the script to find and decode the priority fees.
  • RPC_URL — tour Chainstack Solana node endpoint.
  • SIGNATURE — the transactions signature (hash) around which you want to analyze similar transactions.
  • SLOTS_BACK — number of slots to travel back from the slot where you transaction landed (was included in the block).
  • SLOTS_FORWARD — number of slot to travel forward to see who used what fees after you transaction landed.

To use the script, just run python check_adjacent.py or whatever you name it.

Example output:

Slot 309220412:
----------------------------------------

⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️
🎯 TARGET TRANSACTION FOUND 🎯
⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️

Signature: 3Bd4wJ3pZrPYbhnHpUbZFXfunD2A1dciNx8umhhTEg4KLYmP1nERNbKEbHP9j6K8CcJgdekRi3PhUqVjdsHcsMSA
Block: 309220412
Total fee:        0.00200500 SOL
Priority fee:     0.00200000 SOL
Base fee:         0.00000500 SOL
Compute Units: 57900

Writable Accounts:
  8SDfmRCMwn4qNvBpnvMTX7hunGHXWEJ5odhazNVcFyBw
⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️

Other transactions in slot 309220412 (sorted by priority fee):
----------------------------------------

Use cases

This tool is particularly useful for:

  • Analyzing competitor trading strategies
  • Optimizing your own priority fees
  • Troubleshooting failed transactions
  • Understanding market competition in specific slots
  • Developing automated trading systems

Conclusion

Understanding transaction priority fees and their impact on execution is crucial for successful trading on Solana. This tool helps you analyze the competitive landscape and optimize your trading strategy by providing insights into how other traders are setting their priority fees.

For more Solana development tools and guides, see Mastering Solana.

Ake

🛠️ Developer Experience Director @ Chainstack
💸 Talk to me all things Web3 infrastructure and I'll save you the costs
Ake | Warpcast Ake | GitHub Ake | Twitter Ake | LinkedIN