Skip to main content
gRPC subscribers provide the lowest latency and highest throughput for account updates using Yellowstone or Laser gRPC streaming infrastructure. They are ideal for high-frequency trading and applications requiring maximum performance.

Overview

gRPC subscribers extend WebSocket subscribers with gRPC streaming capabilities:
  • Yellowstone gRPC - Geyser plugin-based streaming
  • Laser gRPC - High-performance streaming service
  • Lower latency than WebSocket subscriptions
  • Higher throughput than polling
  • Requires dedicated gRPC infrastructure

GrpcConfigs

Configuration for gRPC connections.

Yellowstone Configuration

type YellowstoneGrpcConfigs = {
  client?: 'yellowstone';
  endpoint: string;
  token: string;
  commitmentLevel?: CommitmentLevel;
  enableReconnect?: boolean;
  channelOptions?: ConstructorParameters<typeof Client>[2];
};
client
'yellowstone'
Client type (defaults to yellowstone if not specified)
endpoint
string
required
gRPC endpoint URL (e.g., ‘https://grpc.example.com:443’)
token
string
required
Authentication token for the gRPC service
commitmentLevel
CommitmentLevel
Commitment level for updates (PROCESSED, CONFIRMED, or FINALIZED)
enableReconnect
boolean
default:"false"
Whether to enable automatic reconnection on connection loss
channelOptions
object
gRPC channel options for advanced configuration

Laser Configuration

type LaserGrpcConfigs = {
  client: 'laser';
  endpoint: string;
  token: string;
  commitmentLevel?: CommitmentLevel;
  enableReconnect?: boolean;
  channelOptions?: LaserstreamConfig['channelOptions'];
};
client
'laser'
required
Must be ‘laser’ for Laser gRPC client

Example Configurations

// Yellowstone configuration
const yellowstoneConfig: GrpcConfigs = {
  client: 'yellowstone',
  endpoint: 'https://grpc.mainnet.yellowstone.com:443',
  token: 'your-auth-token',
  commitmentLevel: CommitmentLevel.CONFIRMED,
  enableReconnect: true,
};

// Laser configuration
const laserConfig: GrpcConfigs = {
  client: 'laser',
  endpoint: 'https://laser.drift.com:443',
  token: 'your-auth-token',
  commitmentLevel: CommitmentLevel.CONFIRMED,
  enableReconnect: true,
};

grpcUserAccountSubscriber

Subscribe to user account updates via gRPC.

Constructor

new grpcUserAccountSubscriber(
  grpcConfigs: GrpcConfigs,
  program: Program,
  userAccountPublicKey: PublicKey,
  resubOpts?: ResubOpts
)
grpcConfigs
GrpcConfigs
required
gRPC connection configuration
program
Program
required
Anchor program instance for the Drift protocol
userAccountPublicKey
PublicKey
required
Public key of the user account to subscribe to
resubOpts
ResubOpts
Options for automatic resubscription

Example Usage

import { 
  grpcUserAccountSubscriber,
  CommitmentLevel 
} from '@drift-labs/sdk';
import { Program } from '@coral-xyz/anchor';
import { PublicKey } from '@solana/web3.js';

// Configure gRPC connection
const grpcConfig = {
  endpoint: 'https://grpc.mainnet.drift.com:443',
  token: 'your-auth-token',
  commitmentLevel: CommitmentLevel.CONFIRMED,
  enableReconnect: true,
};

// Create gRPC subscriber
const userPubkey = new PublicKey('...');
const subscriber = new grpcUserAccountSubscriber(
  grpcConfig,
  program,
  userPubkey,
  {
    resubTimeoutMs: 30_000,
    logResubMessages: true,
  }
);

// Listen for updates
subscriber.eventEmitter.on('userAccountUpdate', (userAccount) => {
  console.log('User account updated via gRPC:', userAccount);
  console.log('Total positions:', userAccount.perpPositions.length);
});

subscriber.eventEmitter.on('error', (error) => {
  console.error('gRPC subscription error:', error);
});

// Subscribe
await subscriber.subscribe();

// Get current data
const { data: userAccount, slot } = subscriber.getUserAccountAndSlot();
console.log('Current user account at slot', slot);

// Cleanup
await subscriber.unsubscribe();

grpcDriftClientAccountSubscriber

Subscribe to Drift protocol accounts (state, markets, oracles) via gRPC.

Constructor

new grpcDriftClientAccountSubscriber(
  grpcConfigs: GrpcConfigs,
  program: Program,
  perpMarketIndexes: number[],
  spotMarketIndexes: number[],
  oracleInfos: OracleInfo[],
  shouldFindAllMarketsAndOracles: boolean,
  delistedMarketSetting: DelistedMarketSetting,
  resubOpts?: ResubOpts
)
grpcConfigs
GrpcConfigs
required
gRPC connection configuration
program
Program
required
Anchor program instance for the Drift protocol
perpMarketIndexes
number[]
required
Array of perpetual market indexes to subscribe to
spotMarketIndexes
number[]
required
Array of spot market indexes to subscribe to
oracleInfos
OracleInfo[]
required
Array of oracle information to subscribe to
shouldFindAllMarketsAndOracles
boolean
required
Whether to automatically discover and subscribe to all markets
delistedMarketSetting
DelistedMarketSetting
required
How to handle delisted markets
resubOpts
ResubOpts
Options for automatic resubscription

Example Usage

import { 
  grpcDriftClientAccountSubscriber,
  DelistedMarketSetting,
  CommitmentLevel 
} from '@drift-labs/sdk';

// Configure gRPC connection
const grpcConfig = {
  client: 'yellowstone' as const,
  endpoint: 'https://grpc.mainnet.yellowstone.com:443',
  token: 'your-auth-token',
  commitmentLevel: CommitmentLevel.CONFIRMED,
  enableReconnect: true,
};

// Create gRPC subscriber for all markets
const driftSubscriber = new grpcDriftClientAccountSubscriber(
  grpcConfig,
  program,
  [], // perpMarketIndexes - will be auto-discovered
  [], // spotMarketIndexes - will be auto-discovered
  [], // oracleInfos - will be auto-discovered
  true, // shouldFindAllMarketsAndOracles
  DelistedMarketSetting.Discard,
  {
    resubTimeoutMs: 30_000,
    logResubMessages: true,
  }
);

// Listen for events
driftSubscriber.eventEmitter.on('stateAccountUpdate', (state) => {
  console.log('State updated via gRPC:', state);
});

driftSubscriber.eventEmitter.on('perpMarketAccountUpdate', (market) => {
  console.log('Perp market updated:', market.marketIndex);
  console.log('Market price:', market.amm.historicalOracleData.lastOraclePrice);
});

driftSubscriber.eventEmitter.on('spotMarketAccountUpdate', (market) => {
  console.log('Spot market updated:', market.marketIndex);
});

driftSubscriber.eventEmitter.on('oraclePriceUpdate', (pubkey, source, data) => {
  console.log('Oracle update via gRPC:', {
    price: data.price.toString(),
    slot: data.slot.toString(),
    confidence: data.confidence.toString(),
  });
});

// Subscribe to all accounts
await driftSubscriber.subscribe();

// Get state account
const { data: state } = driftSubscriber.getStateAccountAndSlot();
console.log('Exchange status:', state.exchangeStatus);

// Get specific market
const solPerpMarket = driftSubscriber.getMarketAccountAndSlot(0);
if (solPerpMarket) {
  console.log('SOL-PERP funding rate:', solPerpMarket.data.amm.lastFundingRate);
}

// Dynamically add a market
await driftSubscriber.addPerpMarket(5);

// Cleanup
await driftSubscriber.unsubscribe();

grpcAccountSubscriber

Generic gRPC account subscriber for any account type.

Creating a Subscriber

const subscriber = await grpcAccountSubscriber.create<AccountType>(
  grpcConfigs: GrpcConfigs,
  accountName: string,
  program: Program,
  accountPublicKey: PublicKey,
  decodeBuffer?: (buffer: Buffer) => AccountType,
  resubOpts?: ResubOpts,
  clientProp?: Client
)
grpcConfigs
GrpcConfigs
required
gRPC connection configuration
accountName
string
required
Name of the account type (e.g., ‘state’, ‘market’)
program
Program
required
Anchor program instance
accountPublicKey
PublicKey
required
Public key of the account to subscribe to
decodeBuffer
(buffer: Buffer) => AccountType
Optional custom buffer decoder function
resubOpts
ResubOpts
Options for automatic resubscription
clientProp
Client
Optional pre-configured gRPC client to reuse

Example Usage

import { grpcAccountSubscriber } from '@drift-labs/sdk';
import { PublicKey } from '@solana/web3.js';

// Create gRPC subscriber for state account
const statePublicKey = await getDriftStateAccountPublicKey(program.programId);

const stateSubscriber = await grpcAccountSubscriber.create<StateAccount>(
  {
    endpoint: 'https://grpc.mainnet.drift.com:443',
    token: 'your-auth-token',
    commitmentLevel: CommitmentLevel.CONFIRMED,
  },
  'state',
  program,
  statePublicKey
);

// Subscribe with callback
await stateSubscriber.subscribe((state: StateAccount) => {
  console.log('State account updated:', state);
  console.log('Exchange paused:', state.exchangePaused);
});

// Get current data
const { data: state, slot } = stateSubscriber.dataAndSlot;
console.log('State at slot', slot, ':', state);

// Cleanup
await stateSubscriber.unsubscribe();

Other gRPC Subscribers

The SDK provides gRPC subscribers for various account types:

grpcUserStatsAccountSubscriber

import { grpcUserStatsAccountSubscriber } from '@drift-labs/sdk';

const statsSubscriber = new grpcUserStatsAccountSubscriber(
  grpcConfig,
  program,
  userStatsPublicKey
);

await statsSubscriber.subscribe();

grpcInsuranceFundStakeAccountSubscriber

import { grpcInsuranceFundStakeAccountSubscriber } from '@drift-labs/sdk';

const stakeSubscriber = new grpcInsuranceFundStakeAccountSubscriber(
  grpcConfig,
  program,
  stakeAccountPublicKey
);

await stakeSubscriber.subscribe();

Performance Characteristics

Latency Comparison

MethodTypical LatencyUse Case
gRPC10-50msHigh-frequency trading
WebSocket50-200msReal-time applications
Polling500-5000msBackground monitoring

Throughput

gRPC subscribers can handle:
  • 1000+ updates per second
  • Multiple concurrent account streams
  • Lower overhead than WebSocket subscriptions

Resource Usage

  • Network: Lower bandwidth than polling
  • CPU: Moderate (protocol buffer decoding)
  • Memory: Similar to WebSocket subscribers

Connection Management

Automatic Reconnection

Enable automatic reconnection on connection loss:
const grpcConfig = {
  endpoint: 'https://grpc.example.com:443',
  token: 'your-token',
  enableReconnect: true, // Enable auto-reconnect
  commitmentLevel: CommitmentLevel.CONFIRMED,
};

Manual Reconnection

Handle reconnection manually:
subscriber.eventEmitter.on('error', async (error) => {
  console.error('Connection lost:', error);
  
  // Wait before reconnecting
  await new Promise(resolve => setTimeout(resolve, 5000));
  
  // Resubscribe
  try {
    await subscriber.unsubscribe();
    await subscriber.subscribe();
    console.log('Reconnected successfully');
  } catch (err) {
    console.error('Reconnection failed:', err);
  }
});

Best Practices

  1. Use connection pooling - Reuse gRPC clients across multiple subscribers
  2. Enable reconnection - Set enableReconnect: true for production
  3. Monitor connection health - Listen to error events
  4. Choose appropriate commitment - Use CONFIRMED for balance of speed and safety
  5. Handle backpressure - Process updates quickly to avoid buffer overflow
  6. Secure credentials - Store gRPC tokens securely

Advantages Over WebSocket

  • Lower latency - Direct streaming from validator
  • Higher throughput - More efficient protocol
  • Better error handling - Built-in reconnection
  • Type safety - Protocol buffer schemas
  • Multiplexing - Multiple streams over single connection

Infrastructure Requirements

Running Your Own gRPC Server

To run your own Yellowstone gRPC server:
  1. Set up a Solana validator with Geyser plugin
  2. Install and configure Yellowstone gRPC plugin
  3. Configure authentication tokens
  4. Set up SSL/TLS certificates
  5. Configure firewall and network access

Using Hosted Services

Alternatively, use hosted gRPC services:
  • Triton - Managed Yellowstone gRPC infrastructure
  • Helius - gRPC streaming service
  • Custom providers - Various RPC providers offer gRPC endpoints

Troubleshooting

Connection Errors

// Check endpoint and token
if (error.message.includes('authentication')) {
  console.error('Invalid token or endpoint');
}

// Check network connectivity
if (error.message.includes('connection')) {
  console.error('Cannot reach gRPC endpoint');
}

Slow Updates

// Monitor update latency
let lastUpdate = Date.now();

subscriber.eventEmitter.on('update', () => {
  const latency = Date.now() - lastUpdate;
  if (latency > 1000) {
    console.warn('High update latency:', latency, 'ms');
  }
  lastUpdate = Date.now();
});

Memory Leaks

// Always unsubscribe when done
try {
  // Use subscriber
  await subscriber.subscribe();
  // ... do work ...
} finally {
  // Cleanup
  await subscriber.unsubscribe();
}

Build docs developers (and LLMs) love