Solana gRPC Streaming API
AllenHark provides high-performance Solana gRPC streaming powered by the Yellowstone Geyser plugin. Stream real-time account updates, transactions, blocks, and slot notifications directly from the validator with sub-millisecond latency — significantly faster than WebSocket or polling-based alternatives.
Why gRPC Over WebSocket
| Feature | AllenHark gRPC | Standard WebSocket |
|---|---|---|
| Protocol | HTTP/2 multiplexed streams | Single TCP connection |
| Latency | Sub-millisecond (Geyser plugin) | 50–500 ms (RPC polling) |
| Filtering | Server-side (only matching data sent) | Client-side (all data sent, filter locally) |
| Throughput | Millions of updates/sec | Limited by connection |
| Backpressure | Built-in flow control | Manual handling |
| Data Source | Direct from validator (Geyser) | Processed via RPC layer |
gRPC is the preferred protocol for HFT bots, MEV searchers, arbitrage systems, snipers, real-time analytics, and any application where latency is critical.
Getting Started
1. Get Your Endpoint
Join our Discord to request gRPC access. Your server IP will be whitelisted for direct connection — no API keys needed.
2. Install Dependencies
Node.js
1npm install @grpc/grpc-js @grpc/proto-loaderRust
Add to Cargo.toml:
1[dependencies]
2yellowstone-grpc-client = "6.0.0"
3yellowstone-grpc-proto = "6.0.0"
4tokio = { version = "1.0", features = ["full"] }
5tonic = "0.12"
6futures = "0.3"3. Get the Proto File
Download the Yellowstone Geyser proto definition:
1curl -o geyser.proto https://raw.githubusercontent.com/rpcpool/yellowstone-grpc/master/yellowstone-grpc-proto/proto/geyser.proto4. Connect and Subscribe
Node.js
1const grpc = require('@grpc/grpc-js');
2const protoLoader = require('@grpc/proto-loader');
3
4const packageDef = protoLoader.loadSync('geyser.proto', {
5 keepCase: true, longs: String, enums: String, defaults: true, oneofs: true
6});
7const proto = grpc.loadPackageDefinition(packageDef).geyser;
8const client = new proto.Geyser('[IP_ADDRESS]:[PORT]', grpc.credentials.createInsecure());
9
10const stream = client.subscribe(new grpc.Metadata());
11
12stream.on('data', (update) => {
13 if (update.account) {
14 console.log('Account update:', update.account.account.pubkey);
15 } else if (update.transaction) {
16 console.log('Transaction:', update.transaction.transaction.signature);
17 } else if (update.slot) {
18 console.log('Slot:', update.slot.slot);
19 }
20});
21
22stream.on('error', (err) => {
23 console.error('Stream error:', err.message);
24 // Implement reconnection logic here
25});
26
27// Subscribe to all slot updates and Raydium program accounts
28stream.write({
29 accounts: {
30 raydium: {
31 account: [],
32 owner: ['675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'],
33 filters: []
34 }
35 },
36 slots: { slots: {} },
37 transactions: {},
38 blocks: {},
39 blocksMeta: {},
40 commitment: 1, // Processed
41 entry: {},
42 accountsDataSlice: [],
43 ping: null
44});Rust
1use yellowstone_grpc_client::GeyserGrpcClient;
2use yellowstone_grpc_proto::prelude::*;
3use std::collections::HashMap;
4use futures::StreamExt;
5
6#[tokio::main]
7async fn main() -> anyhow::Result<()> {
8 let mut client = GeyserGrpcClient::build_from_uri("http://[IP_ADDRESS]:[PORT]")
9 .connect()
10 .await?;
11
12 // Subscribe to Raydium program accounts and all slots
13 let mut accounts = HashMap::new();
14 accounts.insert("raydium".to_string(), SubscribeRequestFilterAccounts {
15 account: vec![],
16 owner: vec!["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8".to_string()],
17 filters: vec![],
18 nonempty_txn_signature: None,
19 });
20
21 let mut slots = HashMap::new();
22 slots.insert("slots".to_string(), SubscribeRequestFilterSlots {
23 filter_by_commitment: None,
24 interleave_updates: None,
25 });
26
27 let request = SubscribeRequest {
28 accounts,
29 slots,
30 transactions: HashMap::new(),
31 blocks: HashMap::new(),
32 blocks_meta: HashMap::new(),
33 commitment: Some(CommitmentLevel::Processed as i32),
34 entry: HashMap::new(),
35 accounts_data_slice: vec![],
36 ping: None,
37 from_slot: None,
38 transactions_status: HashMap::new(),
39 };
40
41 let (_, mut stream) = client.subscribe_with_request(Some(request)).await?;
42
43 while let Some(msg) = stream.next().await {
44 match msg?.update_oneof {
45 Some(UpdateOneof::Account(account)) => {
46 println!("Account update: {:?}", account);
47 }
48 Some(UpdateOneof::Slot(slot)) => {
49 println!("Slot: {}", slot.slot);
50 }
51 _ => {}
52 }
53 }
54
55 Ok(())
56}API Reference
Unary Methods (Request/Response)
Standard request-response methods available alongside streaming:
| Method | Description |
|---|---|
| GetLatestBlockhash | Returns the latest blockhash for transaction signing |
| GetBlockHeight | Returns the current block height |
| GetSlot | Returns the current slot |
| GetBlock | Returns full block data for a given slot |
| GetTransaction | Returns transaction details by signature |
| GetVersion | Returns the Geyser plugin version |
| GetGenesisHash | Returns the genesis hash |
| GetFeeForMessage | Returns the fee for a given message |
| IsBlockhashValid | Checks if a blockhash is still valid |
| Subscribe | Opens a bidirectional streaming subscription |
Subscription Filters
The Subscribe method accepts filters for different data types. Each filter type streams specific on-chain data in real-time:
| Subscription | Description | Common Use Case |
|---|---|---|
| Accounts | Real-time account state changes | Token balances, program state, wallet monitoring |
| Transactions | Individual transactions as they're processed | DEX trade monitoring, copy trading, MEV |
| TransactionStatus | Transaction confirmation status updates | Confirmation tracking without full tx data |
| Blocks | Complete block data including all transactions | Block explorers, full indexing |
| BlockMeta | Block metadata without transaction details | Slot monitoring, block timing |
| Slots | Slot progression notifications | Leader tracking, timing synchronization |
| Entries | Ledger entry data | Advanced analytics, validator monitoring |
| Programs | Program deployment and upgrade events | Protocol monitoring, security alerts |
Common Patterns
Monitor a DEX Pool (e.g., Raydium AMM)
1stream.write({
2 accounts: {
3 pool: {
4 account: ['POOL_ACCOUNT_PUBKEY'],
5 owner: [],
6 filters: []
7 }
8 },
9 slots: {},
10 transactions: {},
11 blocks: {},
12 blocksMeta: {},
13 commitment: 1,
14 entry: {}
15});Track All Transactions for a Program
1stream.write({
2 accounts: {},
3 slots: {},
4 transactions: {
5 pumpfun: {
6 vote: false,
7 failed: false,
8 account_include: ['6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'],
9 account_exclude: [],
10 account_required: []
11 }
12 },
13 blocks: {},
14 blocksMeta: {},
15 commitment: 1,
16 entry: {}
17});Watch Multiple Wallets
1stream.write({
2 accounts: {
3 wallets: {
4 account: [
5 'WALLET_PUBKEY_1',
6 'WALLET_PUBKEY_2',
7 'WALLET_PUBKEY_3'
8 ],
9 owner: [],
10 filters: []
11 }
12 },
13 slots: {},
14 transactions: {},
15 blocks: {},
16 blocksMeta: {},
17 commitment: 1,
18 entry: {}
19});Performance Tips
- Use server-side filters — only subscribe to accounts and programs you need. Every filter reduces bandwidth and processing on your end.
- Process updates asynchronously — use worker threads or async channels to avoid blocking the stream reader.
- Implement reconnection logic — gRPC streams can disconnect. Always handle errors and reconnect automatically.
- Use
processedcommitment — for lowest latency, subscribe atprocessedlevel. Useconfirmedonly if you need higher certainty. - Batch state updates — if you receive many account updates per second, batch them before writing to storage.
Error Handling and Reconnection
1function connectWithRetry() {
2 const stream = client.subscribe(new grpc.Metadata());
3
4 stream.on('data', handleUpdate);
5
6 stream.on('error', (err) => {
7 console.error('Stream error:', err.message);
8 setTimeout(connectWithRetry, 1000); // Reconnect after 1 second
9 });
10
11 stream.on('end', () => {
12 console.log('Stream ended, reconnecting...');
13 setTimeout(connectWithRetry, 1000);
14 });
15
16 // Send subscription request
17 stream.write(subscriptionRequest);
18}
19
20connectWithRetry();Support
- Discord: discord.gg/JpzS72MAKG
- Website: allenhark.com
- Yellowstone gRPC Repo: github.com/rpcpool/yellowstone-grpc