In this guide, you will learn how to construct a Solana sniper bot that leverages real-time blockchain data subscriptions and a decentralized exchange aggregator API to execute token swaps. This bot is designed to monitor specific on-chain instructions and perform automated actions based on those events.
Prerequisites
Before starting, ensure you have the following components ready:
- A working installation of Node.js and npm on your system.
- A Bitquery Developer Account to gain access to real-time blockchain streaming data.
- A Solana wallet with a small amount of SOL to cover necessary transaction fees.
Step 1: Project Setup and Initialization
The first step involves creating the foundation for your Node.js application and installing the required packages.
Create a new project directory and initialize it. Open your terminal and run the following commands:
mkdir solana-sniper-bot cd solana-sniper-bot npm init -yInstall the necessary dependencies that will enable interaction with the Solana blockchain, data fetching, and utility functions.
npm install @solana/web3.js cross-fetch lodash @project-serum/anchor bs58
Step 2: Developing the Core Bot Logic
This phase involves writing the main code that powers the bot's functionality.
- Create a new file named
index.jsto house your bot's code. Add the required imports at the top of your file to include the libraries you just installed.
const { Connection, PublicKey, VersionedTransaction, Keypair, } = require("@solana/web3.js"); const fetch = require("cross-fetch"); const lodash = require("lodash"); const { Wallet } = require("@project-serum/anchor"); const bs58 = require("bs58");Define the GraphQL query for Bitquery. This query is configured to listen for a specific initialization instruction on the Raydium DEX, which often signals a new liquidity pool.
const gql = (strings, ...values) => strings.reduce((final, str, i) => final + str + (values[i] || ""), ""); const query = gql` { Solana { Instructions( where: { Transaction: { Result: { Success: true } } Instruction: { Program: { Method: { is: "initializeUserWithNonce" } Address: { is: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8" } } } } limit: { count: 1 } orderBy: { ascending: Block_Date } ) { Instruction { Accounts { Address } } } } } `;For real-time, continuous monitoring, you would use a subscription query instead of the one above.
Configure the Solana connection and wallet. Here, you establish a connection to the Solana mainnet and load your wallet using its secret key.
const connection = new Connection("https://api.mainnet-beta.solana.com"); const walletPublicKey = new PublicKey("YOUR_PUBLIC_KEY"); const secretKeyUint8Array = new Uint8Array([/* YOUR_SECRET_KEY_ARRAY */]); const wallet = new Wallet(Keypair.fromSecretKey(secretKeyUint8Array));Create a function to fetch data from the Bitquery API. This function sends your GraphQL query to the streaming endpoint and returns the response.
async function fetchGraphQL(query) { const response = await fetch("https://streaming.bitquery.io/eap", { method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer YOUR_BITQUERY_OAUTH_TOKEN", }, body: JSON.stringify({ query }), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); }Extract pool addresses from the query response. This function processes the data returned by Bitquery to identify the new pool and its associated token addresses.
async function getPoolAddresses() { try { const data = await fetchGraphQL(query); const instructions = lodash.get(data, "data.Solana.Instructions", []); return instructions.map(({ Instruction: { Accounts } }) => ({ poolAddress: Accounts.length > 4 ? Accounts[4].Address : undefined, tokenA: Accounts.length > 8 ? Accounts[8].Address : undefined, tokenB: Accounts.length > 9 ? Accounts[9].Address : undefined, }))[0]; } catch (error) { console.error("Error fetching data:", error); return { poolAddress: "", tokenA: "", tokenB: "" }; } }Implement the token swap execution logic. This function uses the Jupiter Swap API to get a quote for a swap and then executes the transaction if a valid route is found. It includes checks for common API response delays.
async function swapTokens(tokenA, tokenB) { try { const quoteUrl = `https://quote-api.jup.ag/v6/quote?inputMint=${tokenB}&outputMint=${tokenA}&amount=10000&slippageBps=150`; console.log("quote url ", quoteUrl); const quoteResponse = await fetch(quoteUrl); const quoteData = await quoteResponse.json(); if ( quoteData["errorCode"] != "TOKEN_NOT_TRADABLE" && quoteData["errorCode"] != "COULD_NOT_FIND_ANY_ROUTE" ) { const swapTransactionResponse = await fetch( "https://quote-api.jup.ag/v6/swap", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ quoteResponse: quoteData, userPublicKey: wallet.publicKey.toString(), wrapAndUnwrapSol: true, }), } ); const { swapTransaction } = await swapTransactionResponse.json(); const swapTransactionBuf = Buffer.from(swapTransaction, "base64"); console.log("swapTransactionBuf ", swapTransactionBuf); const transaction = VersionedTransaction.deserialize(swapTransactionBuf); transaction.sign([wallet.payer]); const rawTransaction = transaction.serialize(); const txid = await connection.sendRawTransaction(rawTransaction, { skipPreflight: false, maxRetries: 4, preflightCommitment: "confirmed", commitment: "confirmed", }); const confirmation = await connection.confirmTransaction( txid, "confirmed" ); console.log( `Transaction confirmed: ${confirmation.value.err ? "Error" : "Success"}` ); console.log(`Transaction successful: https://solscan.io/tx/${txid}`); } } catch (error) { console.error("Error during token swap:", error); } }Create a main function to orchestrate the entire process: fetching the new pool data and then attempting a swap.
async function main() { const { tokenA, tokenB } = await getPoolAddresses(); await swapTokens(tokenA, tokenB); } main();
Step 3: Execution and Operation
With the code written, the final step is to configure and run your bot.
Update all placeholders in the
index.jsfile:- Replace
YOUR_PUBLIC_KEYwith your Solana wallet's public key. - Replace
YOUR_SECRET_KEY_ARRAYwith your wallet's secret key, formatted as a Uint8Array. - Replace
YOUR_BITQUERY_OAUTH_TOKENwith the authentication token from your Bitquery account.
- Replace
- Launch the bot by running the command
node index.jsin your terminal. 👉 Explore more strategies for optimizing your bot's performance and success rate.
Frequently Asked Questions
What is a Solana sniper bot?
A Solana sniper bot is an automated software program that monitors the Solana blockchain for specific events, such as the creation of new liquidity pools or tokens. When it detects a predefined trigger, it automatically executes a trade or swap, aiming to act before the majority of the market.
Why are real-time data subscriptions crucial for this bot?
Real-time data is essential because it provides the lowest possible latency between an on-chain event occurring and your bot being notified. In the highly competitive environment of decentralized finance, even a few seconds' delay can be the difference between a successful trade and a missed opportunity. Using a reliable data provider is key to gaining this edge.
How does the Jupiter API integrate into this process?
The Jupiter Swap API is a decentralized exchange aggregator on Solana. It finds the best possible swap route across multiple DEXs to provide optimal trade execution. The bot uses this API first to get a quote for the desired swap and then to build and return the transaction data needed to execute it, simplifying the complex process of on-chain trading.
What are the main risks involved in running such a bot?
The primary risks include financial loss due to market volatility, smart contract vulnerabilities in new tokens or pools, slippage on trades, and potential code errors in your bot's logic. There is also the risk of "rug pulls," where developers maliciously abandon a project. Always conduct thorough research and never invest more than you can afford to lose.
Can this bot code be modified for other blockchains?
The core concept is transferable, but the implementation is blockchain-specific. This code uses Solana's Web3.js library and queries Solana data. To adapt it for another chain like Ethereum or BSC, you would need to use that chain's respective libraries (e.g., Ethers.js or Web3.js for Ethereum) and find compatible data providers and swap APIs for that ecosystem.
Is it necessary to run this bot 24/7?
For catching the earliest possible opportunities, running the bot continuously is ideal. However, you can configure it to run during specific market hours or in response to other criteria. Be aware that the most lucrative events can happen at any time, so intermittent operation may cause you to miss signals.
Conclusion
You have now built a functional Solana sniper bot capable of listening for specific on-chain instructions and executing token swaps. This project demonstrates the powerful combination of real-time blockchain data and decentralized finance APIs for creating automated trading tools. Remember that this is a foundational example; always test extensively in a development environment before using real funds, and continuously monitor your bot's activity.