JS
Quick Start
Code Example
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const bs58 = require('bs58');
// Load proto file
const PROTO_PATH = __dirname + '/proto/geyser.proto';
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
const geyserProto = grpc.loadPackageDefinition(packageDefinition).geyser;
// Create gRPC client with SSL credentials and metadata
function createGeyserClient(host, token) {
// Use system's root certificates for SSL verification
// No need to specify certificate paths explicitly
const sslCreds = grpc.credentials.createSsl();
// Create metadata with x-token
const metadata = new grpc.Metadata();
metadata.add('x-token', token);
return {
client: new geyserProto.Geyser(host, sslCreds),
metadata
};
}
// Abstract method to build subscription request
function buildSubscribeRequest(config) {
const request = {};
// Add account subscription if enabled
if (config.subscribeAccounts) {
const { filterKey, owners, accounts, filters, nonemptyTxnSignature } = config.accountParams;
request.accounts = {
[filterKey]: {
owner: owners,
account: accounts,
filters: filters,
nonempty_txn_signature: nonemptyTxnSignature
}
};
}
// Add block subscription if enabled
if (config.subscribeBlocks) {
const { filterKey, includeTransactions, includeAccounts, includeEntries, accountInclude } = config.blockParams;
request.blocks = {
[filterKey]: {
account_include: accountInclude,
include_transactions: includeTransactions,
include_accounts: includeAccounts,
include_entries: includeEntries
}
};
}
// Add transaction subscription if enabled
if (config.subscribeTransactions) {
const { filterKey, vote, failed, accountInclude, accountExclude, accountRequired, signature } = config.transactionParams;
request.transactions = {
[filterKey]: {
vote: vote,
failed: failed,
account_include: accountInclude,
account_exclude: accountExclude,
account_required: accountRequired,
signature: signature
}
};
}
// Add common parameters
request.commitment = config.commitment;
return request;
}
// Handle incoming updates
function handleUpdate(update) {
switch (update.update_oneof) {
case 'account':
console.log(`\nAccount update (slot: ${update.account.slot})`);
console.log(`Account pubkey: ${bs58.encode(update.account.account.pubkey)}`);
console.log(`Owner: ${bs58.encode(update.account.account.owner)}`);
console.log(`Lamports: ${update.account.account.lamports}`);
break;
case 'block':
console.log(`\nBlock update (slot: ${update.block.slot})`);
console.log(`Blockhash: ${update.block.blockhash}`);
console.log(`Transaction count: ${update.block.transactions.length}`);
break;
case 'transaction':
console.log(`\nTransaction update (slot: ${update.transaction.slot})`);
console.log(`Signature: ${bs58.encode(update.transaction.transaction.signature)}`);
console.log(`Is vote: ${update.transaction.transaction.is_vote}`);
break;
default:
console.log('\nUnknown update type');
}
}
// Main subscription logic
async function subscribeToGeyser() {
// Subscription configuration
const subscribeConfig = {
// Common configuration
commitment: 'CONFIRMED', // Commitment level: PROCESSED/CONFIRMED/FINALIZED
// Account subscription configuration
subscribeAccounts: false, // Whether to subscribe to accounts
accountParams: {
filterKey: 'account-filter-1',
owners: ['11111111111111111111111111111111'], // System program owner
accounts: [], // Specific accounts to subscribe to (empty for all matching)
filters: [], // Additional filters (e.g., memcmp, datasize)
nonemptyTxnSignature: false // Whether to include only updates with transaction signatures
},
// Block subscription configuration
subscribeBlocks: false, // Whether to subscribe to blocks
blockParams: {
filterKey: 'block-filter-1',
accountInclude: [], // Include blocks involving these accounts (empty for all)
includeTransactions: true, // Whether to include transactions in blocks
includeAccounts: false, // Whether to include account updates in blocks
includeEntries: false // Whether to include entries in blocks
},
// Transaction subscription configuration
subscribeTransactions: true, // Whether to subscribe to transactions
transactionParams: {
filterKey: 'tx-filter-1',
vote: false, // Whether to include only vote transactions
failed: false, // Whether to include only failed transactions
accountInclude: [], // Include transactions involving these accounts
accountExclude: [], // Exclude transactions involving these accounts
accountRequired: [], // Transactions must involve these accounts
signature: null // Specific transaction signature (empty for all matching)
}
};
// Client configuration
const clientConfig = {
host: 'geyserstream-tokyo.blockrazor.xyz:443', // gRPC server address
token: '' // auth token
};
// Create client with SSL credentials
const { client, metadata } = createGeyserClient(
clientConfig.host,
clientConfig.token
);
// Build subscription request
const subscribeRequest = buildSubscribeRequest(subscribeConfig);
console.log('Sending subscription request:', JSON.stringify(subscribeRequest, null, 2));
// Establish stream and send request
const stream = client.Subscribe(metadata);
stream.on('data', (update) => handleUpdate(update));
stream.on('error', (err) => console.error('Stream error:', err));
stream.on('end', () => console.log('Stream ended'));
stream.write(subscribeRequest);
// Handle process exit
process.on('SIGINT', () => {
console.log('Closing subscription...');
stream.end();
process.exit(0);
});
}
// Start subscription
subscribeToGeyser().catch(console.error);Last updated