Learn how to use Geyser to stream Solana transactions over gRPC using the @triton-one/yellowstone-grpc client in Node.js.
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);
})();
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();
});
DEX_PROGRAM_IDS
.
For a Python example, see Solana: Listening to pump.fun token mint using Geyser.