Below is an example of how to connect to a gRPC endpoint.
You can use this to confirm that you can connect to your node properly and start building your application.
Running the demo
- Save all files into a directory
- Set your dedicated node's gRPC endpoint and x-token in the
.env
file. - Install required packages with
npm install
- Run the script with
npm run yellowstone
.
You will see output from the script similar to the screenshot below

import YellowstoneGrpc, { CommitmentLevel } from '@triton-one/yellowstone-grpc';
const Client = YellowstoneGrpc.default || YellowstoneGrpc;
import dotenv from 'dotenv';
dotenv.config();
// gRPC Configuration
// Please set GRPC_ENDPOINT environment variable with your gRPC endpoint
const GRPC_ENDPOINT = process.env.GRPC_ENDPOINT || '';
// Please set GRPC_XTOKEN environment variable with your gRPC authentication token if required
const GRPC_XTOKEN = process.env.GRPC_XTOKEN || '';
class SolanaYellowstoneClient {
constructor() {
this.client = null;
this.stream = null;
this.pingInterval = null;
this.pingId = 0;
}
async initialize() {
console.log('🚀 Initializing Solana Yellowstone gRPC Client...\n');
console.log(`📡 Endpoint: ${GRPC_ENDPOINT}`);
console.log(`🔑 X-Token: ${GRPC_XTOKEN.substring(0, 10)}...`);
console.log('');
try {
// Create the Yellowstone client with configuration
this.client = new Client(GRPC_ENDPOINT, GRPC_XTOKEN, {
"grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB
"grpc.max_send_message_length": 64 * 1024 * 1024 // 64MiB
});
console.log('✅ Yellowstone gRPC client initialized successfully\n');
} catch (error) {
console.error('❌ Failed to initialize Yellowstone gRPC client:', error.message);
throw error;
}
}
async getVersion() {
console.log('📋 Getting server version...');
try {
const version = await this.client.getVersion();
console.log('✅ Server version:', version);
return version;
} catch (error) {
console.error('❌ Failed to get version:', error.message);
throw error;
}
}
async startSubscription() {
console.log('📊 Starting subscription stream via Yellowstone gRPC...\n');
// Example accounts to monitor (System Program and Token Program)
const accountsToMonitor = [
'11111111111111111111111111111111',
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
];
// Create subscription request for slots only (simplified to start)
const request = {
slots: {
'client': {}
},
commitment: CommitmentLevel.CONFIRMED
};
console.log('📤 Setting up subscription with:');
console.log(` - Slots: monitoring all slots`);
console.log(` - Accounts: ${accountsToMonitor.join(', ')}`);
console.log(` - Transactions: non-vote, successful only`);
console.log(` - Commitment: CONFIRMED`);
console.log('');
try {
// Use subscribeOnce with explicit parameters
this.stream = await this.client.subscribeOnce(
{}, // accounts
{ 'client': {} }, // slots
{}, // transactions
{}, // transactionsStatus
{}, // entry
{}, // blocks
{}, // blocksMeta
CommitmentLevel.CONFIRMED, // commitment
[] // accountsDataSlice
);
// Set up event handlers
this.stream.on('data', (data) => {
this.handleStreamData(data);
});
this.stream.on('error', (error) => {
console.error('❌ Yellowstone stream error:', error.message);
if (error.message.includes('Unauthenticated') || error.message.includes('401')) {
console.error('Authentication failed. Check your X-Token.');
} else if (error.message.includes('Internal')) {
console.error('Internal error details:', error);
} else if (error.message.includes('Unavailable')) {
console.error('Service unavailable. Check endpoint and network connection.');
}
});
this.stream.on('end', () => {
console.log('⚠️ Stream ended by server');
this.stopPingInterval();
});
this.stream.on('close', () => {
console.log('⚠️ Stream closed');
this.stopPingInterval();
});
this.stream.on('status', (status) => {
console.log('Stream status update:', status);
});
console.log('✅ Subscription request sent\n');
console.log('👀 Listening for events... (Press Ctrl+C to stop)\n');
} catch (error) {
console.error('❌ Failed to start subscription:', error);
throw error;
}
}
handleStreamData(data) {
// Get the filter label if available
const filterLabel = data.filters && data.filters.length > 0 ? data.filters[0] : '';
if (data.slot) {
console.log(`[Slot Update${filterLabel ? ' - ' + filterLabel : ''}]`);
console.log(` Slot: ${data.slot.slot}`);
console.log(` Parent: ${data.slot.parent || 'N/A'}`);
console.log(` Status: ${this.getCommitmentName(data.slot.status)}`);
console.log('');
}
if (data.account) {
const account = data.account;
console.log(`[Account Update${filterLabel ? ' - ' + filterLabel : ''}]`);
console.log(` Pubkey: ${account.account.pubkey}`);
console.log(` Lamports: ${account.account.lamports}`);
console.log(` Owner: ${account.account.owner}`);
console.log(` Slot: ${account.slot}`);
console.log(` Executable: ${account.account.executable}`);
console.log(` Data Length: ${account.account.data ? account.account.data.length : 0} bytes`);
console.log('');
}
if (data.transaction) {
const tx = data.transaction;
console.log(`[Transaction${filterLabel ? ' - ' + filterLabel : ''}]`);
console.log(` Signature: ${tx.transaction.signature}`);
console.log(` Slot: ${tx.slot}`);
console.log(` Is Vote: ${tx.transaction.isVote}`);
if (tx.transaction.meta) {
console.log(` Success: ${!tx.transaction.meta.err}`);
console.log(` Fee: ${tx.transaction.meta.fee} lamports`);
const logCount = tx.transaction.meta.logMessages ? tx.transaction.meta.logMessages.length : 0;
console.log(` Log Messages: ${logCount}`);
}
console.log('');
}
if (data.block) {
const block = data.block;
console.log(`[Block${filterLabel ? ' - ' + filterLabel : ''}]`);
console.log(` Slot: ${block.slot}`);
console.log(` Blockhash: ${block.blockhash}`);
console.log(` Parent Slot: ${block.parentSlot}`);
console.log(` Transactions Count: ${block.transactions ? block.transactions.length : 0}`);
console.log('');
}
if (data.blockMeta) {
const blockMeta = data.blockMeta;
console.log(`[Block Meta${filterLabel ? ' - ' + filterLabel : ''}]`);
console.log(` Slot: ${blockMeta.slot}`);
console.log(` Blockhash: ${blockMeta.blockhash}`);
console.log(` Parent Slot: ${blockMeta.parentSlot}`);
console.log(` Executed Transactions: ${blockMeta.executedTransactionCount}`);
console.log('');
}
if (data.ping) {
console.log(`[Ping] Keepalive ping sent`);
}
if (data.pong) {
console.log(`[Pong] Keepalive response received (id: ${data.pong.id})`);
}
}
startPingInterval() {
// Send ping every 30 seconds to keep connection alive
this.pingInterval = setInterval(() => {
if (this.stream && !this.stream.destroyed) {
const pingRequest = {
ping: {
id: this.pingId++
}
};
try {
this.stream.write(pingRequest, (err) => {
if (!err) {
console.log(`[Keepalive] Ping sent (id: ${this.pingId - 1})`);
} else {
console.error('Failed to send ping:', err.message);
}
});
} catch (error) {
console.error('Failed to send ping:', error.message);
}
}
}, 30000); // 30 seconds
}
stopPingInterval() {
if (this.pingInterval) {
clearInterval(this.pingInterval);
this.pingInterval = null;
}
}
getCommitmentName(value) {
// Handle string values and numeric values
if (typeof value === 'string') {
return value.toUpperCase();
}
const commitments = {
0: 'PROCESSED',
1: 'CONFIRMED',
2: 'FINALIZED'
};
return commitments[value] || `UNKNOWN(${value})`;
}
async shutdown() {
console.log('\n🛑 Shutting down Yellowstone gRPC client...');
this.stopPingInterval();
if (this.stream) {
try {
this.stream.end();
this.stream.destroy();
} catch (error) {
console.error('Error closing stream:', error.message);
}
}
// Yellowstone client doesn't need explicit closure like raw gRPC
console.log('✅ Yellowstone gRPC client shutdown complete');
}
}
// Main execution
async function main() {
const client = new SolanaYellowstoneClient();
try {
await client.initialize();
// Test connection with version check
await client.getVersion();
console.log('\n' + '='.repeat(60));
console.log('Starting Yellowstone gRPC subscription stream...');
console.log('='.repeat(60) + '\n');
// Start the subscription stream
await client.startSubscription();
// Start keepalive ping
client.startPingInterval();
// Handle graceful shutdown
process.on('SIGINT', async () => {
await client.shutdown();
process.exit(0);
});
// Keep process running
await new Promise(() => {});
} catch (error) {
console.error('Fatal error:', error);
process.exit(1);
}
}
main();
{
"name": "solana-rpc-demo",
"version": "1.0.0",
"type": "module",
"description": "Demo script for connecting to Solana RPC",
"main": "yellowstone-grpc-demo.js",
"scripts": {
"yellowstone": "node yellowstone-grpc-demo.js",
},
"dependencies": {
"@grpc/grpc-js": "^1.9.14",
"@grpc/proto-loader": "^0.7.10",
"@solana/web3.js": "^1.98.4",
"@triton-one/yellowstone-grpc": "^0.6.0",
"@witches-brew/spore": "0.1.0",
"dotenv": "^17.2.1",
"node-fetch": "^3.3.2"
},
"devDependencies": {
"bs58": "^6.0.0"
}
}
# These are available in your developer dashboard at https://www.hellomoon.io/dashboard
GRPC_ENDPOINT=<your node>
GRPC_XTOKEN=<your x-token>