Shyft
Start BuildingSupportWebsite
  • Welcome
    • πŸ‘‹Introducing Shyft
    • πŸ—οΈStart Building
  • Solana Infrastructure
    • 🚁Shyft RPCs
  • Yellowstone gRPC Network
    • Decoding gRPC Latency
    • ⚑gRPC Docs
      • Introduction
      • Authentication
      • Subscribe Requests
      • FAQ
      • Getting Started
        • Initializing the Yellowstone Client
        • Making a gRPC connection
        • Adding a Reconnection Mechanism
        • πŸ”₯Replaying Slots with Solana yellowstone gRPCs
        • Modifying your Subscribe Request
        • Closing a gRPC Connection
      • Subscribing to Transactions
        • All Transactions of an address
        • Subscribing to all transactions of a Liquidity Pool
        • Subscribing to all transactions of multiple addresses
        • Subscribing to all transactions of a Token
      • Subscribing to Accounts
        • Account Updates for a Program
        • Account Updates for an Address
        • Account updates using memcmp
      • Streaming Blocks & BlocksMeta
        • Streaming Block Updates
        • Subscribing to BlocksMeta
      • Modifying & Unsubscribing
  • Solana defi data
    • DeFI APIs
      • Get Pool By Address
      • Get Pools By Token Pair
      • Get All Pools for a Token
      • Get Liquidity Details of a Pool
  • Callbacks
    • ☎️What are Callbacks?
      • Transaction Callbacks
      • Account Callbacks
    • πŸ“”Callback APIs
      • Response Structure
      • List Callbacks
      • Register callback
      • Remove callback
      • πŸ”₯Pause a callback
      • πŸ”₯Resume a callback
      • Update Callbacks
      • Add Addresses
      • Remove addresses
  • Solana Super Indexers
    • 🌩️GraphQL APIs
      • Getting Started
      • Building Queries
      • Paginating Response
      • Applying Filters
      • Ordering and Sorting Data
    • πŸ“€Case Studies
      • Tensor
        • Get Active Listings of a Wallet
        • Get Active Bids of a Wallet
        • Get Active Listings of a Collection
        • Get all Bids of a Collection
        • Get all Pools of a Margin Account
        • Get all Pools by Owner
      • Raydium
        • Get Pool By Address
        • Get Pools By Token Address
        • Get Pools Created Between Time
        • Get Pool Burn Percentage
        • Get Liquidity Details of a Pool
        • Get Pool and OpenBook Market Info
        • Get Token Supply Percentage In Pool
      • Orca Whirlpool
        • Get Pool by Address
        • Get Pool by Token Address
        • Get Positions for a Pool
        • Get Positions for a Wallet
        • Get Liquidity Details of a Pool
      • Kamino
        • Get Borrow Details of a Wallet
        • Get Deposit Details of a Wallet
        • Get Reserve Details
      • Cross Marketplace Queries
        • Get active listings across marketplaces for a wallet
        • Get listings for a collection across marketplaces
        • Get floor price of a collection
      • Cross Defi Queries
        • Fetch Liquidity Pools for Token
      • Native Staking
        • Get Stakes for a Wallet
        • Get Stakes For Validator
      • Governance/Realms
        • Get DAO Token Owners
        • Get Proposals For Governing Mint
        • Get All Proposals For DAO
        • Get DAO Treasury Info
        • Get All Active Proposals For Wallet
      • Meteora
        • Get All LB Position Pairs
        • Get Position of a User Wallet
        • Get Pool by Token Addresses
        • Get All Deposits for a User
        • Get All Withdraws for a User
        • Get All Fees Claimed by a User
        • Get All User Positions and Deposits for a Pool
        • Get All User Positions and Withdrawals for a Pool
      • Fluxbeam
        • Get Pool by Address
        • Get Pool by Token Addresses
      • Drift
        • Get User account for Delegate
        • Get User accounts based on authority
        • Get User details based on Referrer
        • Get Borrow/Deposit Amount for an User
        • Get PrepPositions for an User Account
        • Getting OrderId and userOrderId
        • Get OpenOrders for a User Account
      • πŸ”₯Pumpswap
        • πŸ”₯Get Pool by Address
        • πŸ”₯Get Pool by Creator Address
        • πŸ”₯Get Pools by Token Addresses
      • Raydium Launchpad
        • Get Bonding Curve Details by Pool Address
        • Get All Pools for a Creator
        • Get Pools by Token Addresses
        • Get Migration details of a Pool
  • Solana APIs
    • API Reference
    • Transactions
      • Parsed Transaction Structure
      • Transaction APIs
        • History
        • Parse Signature
        • Parse Multiple Signatures
        • Send
        • Send Multiple
    • NFT
      • πŸ”₯Create Gasless
      • Create
      • Read All
      • Burn
      • πŸ”₯Burn Multiple NFTs V2
      • Update
      • πŸ”₯Create NFT from Metadata
      • πŸ”₯Read Wallet Nfts
      • πŸ”₯Read Selected NFTs
      • πŸ”₯Get NFT Owners
      • πŸ”₯Update NFT Metadata Uri
      • πŸ”₯Update V2
      • Search
      • Transfer
      • Transfer Multiple NFTs
      • Mint
      • Read
    • Wallet
      • Get Balance
      • Get Token Balance
      • Get All Tokens Balance
      • Get Portfolio
      • Resolve Address
      • Get All Domains
      • Get Stake Accounts
    • Fungible Tokens
      • Create
      • Mint
      • Burn
      • πŸ”₯Update
      • Get Token Info
      • Transfer
      • Airdrop
Powered by GitBook
On this page

Was this helpful?

  1. Yellowstone gRPC Network
  2. gRPC Docs
  3. Getting Started

Replaying Slots with Solana yellowstone gRPCs

Start streaming data from a specific slot when establishing a new gRPC connection or reconnecting

PreviousAdding a Reconnection MechanismNextModifying your Subscribe Request

Last updated 4 hours ago

Was this helpful?

Reconnect mechanisms are important for production applications β€” we don’t want to miss any data due to temporary network issues. But sometimes, reconnecting alone isn’t enough. We also need to replay data from a specific slot, especially if a stream drops during critical updates. Yellowstone gRPC supports this via the fromSlot field in the subscription request. By storing the last received slot and including it in the next subscription, you can ensure your stream resumes from where it left off β€” without missing a single block or transaction.

At any given time, the earliest available slot for replay is approximately 150 slots older than the current slot.

The example below illustrates how you can replay from a specific slot upon disconnection. You can paste this code in Replit to see it in action, or simply run the Repl .

import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
import { SubscribeRequest } from "@triton-one/yellowstone-grpc/dist/types/grpc/geyser";
import base58 from "bs58";

const GRPC_URL = "https://grpc.ams.shyft.to"; //enter your grpc url here
const X_TOKEN = ""; //enter your grpc access token here
const MAX_RETRY_WITH_LAST_SLOT = 30;
const RETRY_DELAY_MS = 1000;
const ADDRESS_TO_STREAM_FROM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";

type StreamResult = {
  lastSlot?: string;
  hasRcvdMSg: boolean;
};

async function handleStream(
  client: Client,
  args: SubscribeRequest,
  lastSlot?: string,
): Promise<StreamResult> {
  const stream = await client.subscribe();
  let hasRcvdMSg = false;

  return new Promise((resolve, reject) => {
    stream.on("data", (data) => {
      const tx = data.transaction?.transaction?.transaction;
      if (tx?.signatures?.[0]) {
        const sig = base58.encode(tx.signatures[0]);
        console.log("Got tx:", sig);
        lastSlot = data.transaction.slot;
        hasRcvdMSg = true;
      }
    });

    stream.on("error", (err) => {
      stream.end();
      reject({ error: err, lastSlot, hasRcvdMSg });
    });

    const finalize = () => resolve({ lastSlot, hasRcvdMSg });
    stream.on("end", finalize);
    stream.on("close", finalize);

    stream.write(args, (err: any) => {
      if (err) reject({ error: err, lastSlot, hasRcvdMSg });
    });
  });
}

async function subscribeCommand(client: Client, args: SubscribeRequest) {
  let lastSlot: string | undefined;
  let retryCount = 0;

  while (true) {
    try {
      // checks if the stream is starting from a specific slot
      if (args.fromSlot) {
        console.log("Starting stream from slot", args.fromSlot);
      }
      // starts the stream from lastSlot if value is present
      const result = await handleStream(client, args, lastSlot);
      lastSlot = result.lastSlot;
      if (result.hasRcvdMSg) retryCount = 0;
    } catch (err: any) {
      console.error(
        `Stream error, retrying in ${RETRY_DELAY_MS / 1000} second...`,
      );
      //in case the stream is interrupted, it waits for a while before retrying
      await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));

      lastSlot = err.lastSlot;
      if (err.hasRcvdMSg) retryCount = 0;

      if (lastSlot && retryCount < MAX_RETRY_WITH_LAST_SLOT) {
        console.log(
          `#${retryCount} retrying with last slot ${lastSlot}, remaining retries ${
            MAX_RETRY_WITH_LAST_SLOT - retryCount
          }`,
        );
        // sets the fromSlot to the last slot received before the stream was interrupted, if it exists
        args.fromSlot = lastSlot;
        retryCount++;
      } else {
        //when there is no last slot available, it starts the stream from the latest slot
        console.log("Retrying from latest slot (no last slot available)");
        delete args.fromSlot;
        retryCount = 0;
        lastSlot = undefined;
      }
    }
  }
}

const client = new Client(GRPC_URL, X_TOKEN, {
  "grpc.keepalive_permit_without_calls": 1,
  "grpc.keepalive_time_ms": 10000,
  "grpc.keepalive_timeout_ms": 1000,
  "grpc.default_compression_algorithm": 2,
});

const req: SubscribeRequest = {
  accounts: {},
  slots: {},
  transactions: {
    pumpFun: {
      vote: false,
      failed: false,
      accountInclude: [ADDRESS_TO_STREAM_FROM],
      accountExclude: [],
      accountRequired: [],
    },
  },
  transactionsStatus: {},
  blocks: {},
  blocksMeta: {},
  entry: {},
  accountsDataSlice: [],
  commitment: CommitmentLevel.CONFIRMED,
};

subscribeCommand(client, req);

The above example implements a robust mechanism to reconnect to the gRPC stream and replay from the last known slot to avoid missing any data.

  • Reconnection: If the stream encounters an error (like a network drop), the stream automatically retries after waiting a short time (denoted by theRETRY_DELAY_MS variable). This loop ensures the stream keeps trying to reconnect without manual restart.

  • Replay from Last Slot: Before each retry, the app checks if it previously received any transaction data. If so, it stores the latest slot number (lastSlot). When reconnecting, it includes this lastSlot in the fromSlot field of the SubscribeRequest, telling Yellowstone gRPC to resume streaming from that exact slot, not from the current blockchain tip.

The complete code of implementing a reconnection mechanism is available on and .

⚑
πŸ”₯
code here
GitHub
Replit here