Mastering Solana
Solana: Listening to programs using Geyser and Yellowstone gRPC in Node.js
Platform
Web3 [de]coded
- Introduction
- Protocols
- Chainstack Subgraphs
- Chainstack Marketplace
- Blockchain APIs guides
- Best practices handbook
- Mastering Solana
- Overview
- Solana: Creating a trading and sniping pump.fun bot
- Solana: Listening to pump.fun migrations to Raydium
- Solana: Listening to pump.fun token mints using only logsSubscribe
- Solana: Priority fees for a Jupiter Swap in Python
- Solana: Analyzing adjacent transactions for priority fees
- Migrating from Helius getTokenAccounts to standard Solana RPC methods
- Solana: How to perform token swaps using the Raydium SDK
- Solana: How to build actions and blinks
- Solana: Creating a token and vesting the token in your program
- Solana: Transferring SPL tokens in TypeScript
- Solana: Enhancing SPL Token Transfers with Retry Logic
- Solana account retrieval methods: getAccountInfo vs getMultipleAccounts
- Solana's getTokenLargestAccounts RPC method: How to view top SLP holder distribution
- Solana: How to Use Priority Fees to Unlock Faster Transactions
- Solana: Estimate priority fees with getRecentPrioritizationFees
- Solana: How to use multiple RPC endpoints to optimize dApp performance
- Solana: How to handle the transaction expiry error
- Solana Agave 2.0 upgrade reference
- Solana: Understanding the Difference Between Blocks and Slots
- Solana: Optimize your getBlock performance
- Solana: Understanding Block Time
- Solana: Listening to pump.fun token mint using Geyser
- Solana: Listening to programs using Geyser and Yellowstone gRPC in Node.js
- Web3pedia
IPFS storage
Chainstack Compare
Chainstack ChatGPT plugin
Chainstack DLP browser extension
Protocols
Advanced APIs
- Introduction
- Warp Transactions
- Debug & Trace APIs
Tooling
- Introduction
- Ethereum tooling
- Solana tooling
- BNB Smart Chain tooling
- Polygon tooling
- Arbitrum tooling
- Base tooling
- Optimism tooling
- Avalanche tooling
- TON tooling
- Ronin tooling
- Blast tooling
- zkSync Era tooling
- Starknet tooling
- Scroll tooling
- Aptos tooling
- Sonic tooling
- Fantom tooling
- TRON tooling
- Cronos tooling
- Gnosis Chain tooling
- Kaia (ex. Klaytn) tooling
- Celo tooling
- Moonbeam tooling
- Aurora tooling
- Oasis Sapphire tooling
- Polygon zkEVM tooling
- Bitcoin tooling
- Harmony tooling
- opBNB tooling
- Tezos tooling
- Filecoin tooling
- NEAR tooling
- Fuse tooling
Mastering Solana
Solana: Listening to programs using Geyser and Yellowstone gRPC in Node.js
Learn how to use Geyser to stream Solana transactions over gRPC using the @triton-one/yellowstone-grpc client in Node.js.
Overview
This quick guide shows you how to:
- Check the Geyser connection using the @triton-one/yellowstone-grpc client in Node.js
- Stream the programs using the @triton-one/yellowstone-grpc client in Node.js
Prerequisites
- Get the Yellowstone gRPC Geyser plugin.
- Install Yellowstone Node.js gRPC client.
Implementation
Once you have the Chainstack Yellowstone gRPC Geyser endpoint and the authentication token, use the following examples to check the connection and to monitor programs.
Connection checker
const { default: Client } = require("@triton-one/yellowstone-grpc");
const ENDPOINT = "CHAINSTACK_GEYSER_URL"; // Replace with your actual endpoint
const TOKEN = "CHAINSTACK_GEYSER_TOKEN"; // Replace with your actual token
(async () => {
const client = new Client(ENDPOINT, TOKEN);
const version = await client.getVersion();
console.log(version);
})();
This will print the connection status and the Geyser client version.
Program watcher
Note the use of ping every 10 seconds to keep the connection alive as specified in the docs: Sending pings to keep the stream alive.
const { default: Client } = require("@triton-one/yellowstone-grpc");
const Base58 = require('bs58');
const ENDPOINT = "CHAINSTACK_GEYSER_URL"; // Replace with your actual endpoint
const TOKEN = "CHAINSTACK_GEYSER_TOKEN"; // Replace with your actual token
const PING_INTERVAL_MILLISECONDS = 10000; // Send ping every 10 seconds
// DEX Program IDs to watch
const DEX_PROGRAM_IDS = [
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK",
"CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo",
"Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB",
"MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG",
"FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X",
"whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"
];
async function main() {
const client = new Client(ENDPOINT, TOKEN);
try {
console.log('Connecting to Solana...');
const stream = await client.subscribe();
// Prepare ping request
const pingRequest = {
ping: { id: 1 },
accounts: {},
accountsDataSlice: [],
transactions: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
slots: {},
};
// Set up periodic ping to keep the stream alive
const pingInterval = setInterval(async () => {
try {
await new Promise((resolve, reject) => {
stream.write(pingRequest, (err) => {
if (err === null || err === undefined) {
resolve();
} else {
reject(err);
}
});
});
console.log("Ping sent to keep stream alive");
} catch (error) {
console.error("Error sending ping:", error);
}
}, PING_INTERVAL_MILLISECONDS);
const request = {
accounts: {},
slots: {},
transactions: {
dex: {
vote: false,
failed: false,
accountExclude: [],
accountRequired: [],
accountInclude: DEX_PROGRAM_IDS
}
},
transactionsStatus: {},
entry: {},
blocks: {},
blocksMeta: {},
commitment: 'confirmed',
accountsDataSlice: [],
};
stream.write(request);
console.log('Connection established - watching DEX transactions\n');
console.log('Monitoring programs:', DEX_PROGRAM_IDS);
stream.on('data', (data) => {
// Handle pong responses
if (data.pong) {
console.log("Received Pong response");
return;
}
if (data.transaction && data.transaction.transaction) {
const tx = data.transaction;
try {
// Convert signature to string
const signature = tx.transaction.signature.toString('hex');
// Find which DEX program was involved in this transaction
let involvedPrograms = [];
if (tx.transaction.transaction.message.accountKeys) {
involvedPrograms = DEX_PROGRAM_IDS.filter(progId =>
tx.transaction.transaction.message.accountKeys.includes(progId));
}
console.log('New DEX Transaction:', {
signature: signature,
slot: tx.slot,
success: tx.transaction.meta?.err === null,
accounts: tx.transaction.transaction.message.accountKeys.length,
instructions: tx.transaction.transaction.message.instructions.length,
lamportFee: tx.transaction.meta?.fee || 0,
computeUnits: tx.transaction.meta?.computeUnitsConsumed || 0,
involvedDEX: involvedPrograms
});
// Log transaction details
if (tx.transaction.meta?.logMessages) {
console.log('Transaction logs:');
tx.transaction.meta.logMessages.forEach(log => console.log(log));
}
console.log('----------------------------------------');
} catch (err) {
console.error('Error processing transaction:', err);
console.error('Raw signature:', tx.transaction.signature);
}
}
});
stream.on("error", (error) => {
console.error('Stream error:', error);
clearInterval(pingInterval); // Clean up the ping interval on error
});
// Clean up on stream close
stream.on("close", () => {
console.log("Stream closed");
clearInterval(pingInterval);
});
} catch (error) {
console.error('Error in subscription process:', error);
}
}
// Run the main function
main().catch((err) => {
console.error('Unhandled error in main:', err);
});
// Handle shutdown
process.on('SIGINT', () => {
console.log('Shutting down...');
process.exit();
});
This will stream the data from the Solana program IDs as provided in DEX_PROGRAM_IDS
.
For a Python example, see Solana: Listening to pump.fun token mint using Geyser.
Was this page helpful?