gRPC

Highly configurable real-time data streams.

Overview

Laserstream’s gRPC offering builds on a Yellowstone-based interface and enhances it with features like historical replay, multi-node failover, and a fully managed environment. You can connect either directly with @yellowstone-grpc or use the higher-level Helius Laserstream client for added benefits (auto-reconnect, subscription management, error handling, etc.).


Quickstart

1. Create a New Project

mkdir laserstream-grpc-demo
cd laserstream-grpc-demo
npm init -y

2. Install Dependencies

npm install helius-laserstream
npm install --save-dev typescript ts-node
npx tsc --init

3. Obtain Your API Key

Generate a key from the Helius Dashboard.

4. Create a Subscription Script

Create index.ts with the following:

import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      client: {
        accountInclude: ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {},
    slots: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    accountsDataSlice: [],
    // Optionally, you can replay missed data by specifying a fromSlot:
    // fromSlot: '224339000'
    // Note: Currently, you can only go back up to 3000 slots.
  };

// TODO: Replace the values below with your actual Laserstream API key and endpoint
const config: LaserstreamConfig = {
  apiKey: 'your-api-key',
  endpoint: 'your-endpoint',
}

  await subscribe(config, subscriptionRequest, async (data) => {
    
    console.log(data);

  }, async (error) => {
    console.error(error);
  });
}

main().catch(console.error);

5. Replace Your Endpoint and API Key

In index.ts, update the config object with the actual apiKey and endpoint from your Helius Dashboard:

const config: LaserstreamConfig = {
  apiKey: 'YOUR_ACTUAL_API_KEY',
  endpoint: 'YOUR_ACTUAL_ENDPOINT',
}

6. Run and View Results

npx ts-node index.ts

Whenever a confirmed token transaction involves TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA, you’ll see the data in your console.


Subscribe Request

In the subscribe request, you need to include the following:

commitment: Specifies the commitment level, which can be processed, confirmed, or finalized.

accountsDataSlice: An array of objects { offset: uint64, length: uint64 } that allows you to receive only the required data slices from accounts.

ping: An optional boolean. Some cloud providers (e.g., Cloudflare) close idle streams. To keep the connection alive, set this to true. The server will respond with a Pong message every 15 seconds, avoiding the need to resend filters.

  const subscriptionRequest: SubscribeRequest = {
    commitment: CommitmentLevel.CONFIRMED,
    accountsDataSlice: [],
    transactions: {},
    accounts: {},
    slots: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
  }

Next, you’ll need to specify the filters for the data you want to subscribe to, such as accounts, blocks, slots, or transactions.

Slots

filterByCommitment : By default, slots are sent for all commitment levels. With this filter, you can choose to receive only the selected commitment level.

interslotUpdates : Enables the subscription to receive updates for changes within a slot, not just at the beginning of new slots. This is useful for more granular, real-time slot data.

  slots: {
    // mySlotLabel is a user-defined name for slot updates
    mySlotLabel: {
      // filterByCommitment: true => Only broadcast slot updates at the specified subscribeRequest commitment
      filterByCommitment: true
      // interslotUpdates: true allows receiving updates for changes occurring within a slot, not just new slots.
      interslotUpdates: true
    }
  },
Accounts

account : Matches any public key from the provided array.

owner : The account owner's public key. Matches any public key from the provided array.

filters : Similar to the filters in getProgramAccounts. This is an array of dataSize and/or memcmp filters. Supported encoding includes bytes, base58, and base64.

If all fields are empty, all accounts are broadcasted. Otherwise:

  • Fields operate as a logical AND.

  • Values within arrays act as a logical OR (except within filters, which operate as a logical AND)

  accounts: {
    // tokenAccounts is a user-defined label for the "accounts" subscription
    tokenAccounts: {
      // Matches any of these public keys (logical OR)
      account: ["9SHQTA66Ekh7ZgMnKWsjxXk6DwXku8przs45E8bcEe38"],
      // Matches owners that are any of these public keys
      owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
      // Filters - all must match (AND logic)
      filters: [
        { dataSize: 165 },
        {
          memcmp: {
            offset: 0,
            data: { base58: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
          }
        }
      ]
    }
  },
Transaction

vote: Enable or disable the broadcast of vote transactions.

failed : Enable or disable the broadcast of failed transactions.

signature: Broadcast only transactions matching the specified signature.

accountInclude: Filter transactions that involve any account from the provided list.

accountExclude: Exclude transactions that involve any account from the provided list (opposite of accountInclude).

accountRequired: Filter transactions that involve all accounts from the provided list (all accounts must be used).

If all fields are left empty, all transactions are broadcasted. Otherwise:

  • Fields operate as a logical AND.

  • Values within arrays are treated as a logical OR.

  transactions: {
    // myTxSubscription is a user-defined label for transaction filters
    myTxSubscription: {
      vote: false,
      failed: false,
      signature: "",
      // Transaction must include at least one of these public keys (OR)
      accountInclude: ["86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"],
      // Exclude if it matches any of these
      accountExclude: [],
      // Require all accounts in this array (AND)
      accountRequired: []
    }
  },
Block

accountInclude: Filters transactions and accounts that involve any account from the provided list.

includeTransactions: Includes all transactions in the broadcast.

includeAccounts: Includes all account updates in the broadcast.

includeEntries: Includes all entries in the broadcast.

  blocks: {
    // myBlockLabel is a user-defined label for block subscription
    myBlockLabel: {
      // Only broadcast blocks referencing these accounts
      accountInclude: ["86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"],
      includeTransactions: true,
      includeAccounts: false,
      includeEntries: false
    }
  },
Blocks Meta

This functions similarly to Blocks but excludes transactions, accounts, and entries. Currently, no filters are available for block metadata—all messages are broadcasted by default.

  blocksMeta: {
    blockmetadata: {}
  },
Entries

Currently, there are no filters available for entries; all entries are broadcasted.

  entry: {
    entrySubscribe: {}
  },

Code Examples

Subscribing to Slot Updates
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {},
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {},
    slots: {
      slot: { filterByCommitment: true },
    },
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    accountsDataSlice: [],
  }


 const config: LaserstreamConfig = {
    apiKey: 'your-api-key',
    endpoint: 'your-endpoint',
  }

  await subscribe(config, subscriptionRequest, async (data) => {
    console.log(data);
  }, async (error) => {
    console.error(error);
  });
}

main().catch(console.error);
Subscribing to Account Updates
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
    const subscribeRequest: SubscribeRequest = {
        accounts: {
            accountSubscribe: {
                account: ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"], // USDC mint account
                owner: [],
                filters: []
            }
        },
        accountsDataSlice: [],
        commitment: CommitmentLevel.CONFIRMED,
        slots: {},
        transactions: {},
        transactionsStatus: {},
        blocks: {},
        blocksMeta: {},
        entry: {}
    };


 const config: LaserstreamConfig = {
    apiKey: 'your-api-key',
    endpoint: 'your-endpoint',
  }

  await subscribe(config, subscriptionRequest, async (data) => {
    console.log(data);
  }, async (error) => {
    console.error(error);
  });
}

main().catch(console.error);
Subscribing to Transaction Updates
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
  const subscriptionRequest: SubscribeRequest = {
    transactions: {
      client: {
        accountInclude: ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'],
        accountExclude: [],
        accountRequired: [],
        vote: false,
        failed: false
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {},
    slots: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    accountsDataSlice: [],
  };

 const config: LaserstreamConfig = {
    apiKey: 'your-api-key',
    endpoint: 'your-endpoint',
  }

  await subscribe(config, subscriptionRequest, async (data) => {
    console.log(data);
  }, async (error) => {
    console.error(error);
  });
}

main().catch(console.error);
Subscribing to Blocks
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
    const subscriptionRequest: SubscribeRequest = {
        entry: {},
        accounts: {},
        accountsDataSlice: [],
        slots: {},
        blocks: {
            blocks: {
                accountInclude: []
            }
        },
        blocksMeta: {},
        transactions: {},
        transactionsStatus: {},
        commitment: CommitmentLevel.CONFIRMED,
    };

 const config: LaserstreamConfig = {
    apiKey: 'your-api-key',
    endpoint: 'your-endpoint',
  }

  await subscribe(config, subscriptionRequest, async (data) => {
    console.log(data);
  }, async (error) => {
    console.error(error);
  });
}

main().catch(console.error);
Subscribing to Block Metadata
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
    const subscriptionRequest: SubscribeRequest = {
        entry: {},
        accounts: {},
        accountsDataSlice: [],
        slots: {},
        blocks: {},
        blocksMeta: {
            blockmetadata: {}
        },
        transactions: {},
        transactionsStatus: {},
        commitment: CommitmentLevel.CONFIRMED,
    };


    const config: LaserstreamConfig = {
        apiKey: 'your-api-key',
        endpoint: 'your-endpoint',
    }

    await subscribe(config, subscriptionRequest, async (data) => {
        console.log(data);
    }, async (error) => {
        console.error(error);
    });
}

main().catch(console.error);
Subscribing to Entries
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream'

async function main() {
    const subscriptionRequest: SubscribeRequest = {
        entry: {
            entrySubscribe: {}  // Subscribe to all entries
        },
        accounts: {},
        accountsDataSlice: [],
        slots: {},
        blocks: {},
        blocksMeta: {},
        transactions: {},
        transactionsStatus: {},
        commitment: CommitmentLevel.CONFIRMED,
    };


    const config: LaserstreamConfig = {
        apiKey: 'your-api-key',
        endpoint: 'your-endpoint',
    }

    await subscribe(config, subscriptionRequest, async (data) => {
        console.log(data);
    }, async (error) => {
        console.error(error);
    });
}

main().catch(console.error);

Last updated

Was this helpful?