Overview

Account monitoring lets you track balance changes, data modifications, ownership transfers, and account creation/deletion events across Solana in real-time. This guide covers filtering strategies and implementation patterns for different use cases.
Prerequisites: This guide assumes you’ve completed the Yellowstone gRPC Quickstart and have a working stream setup.

Account Filtering Options

Monitor individual accounts by public keyUse this when you know exactly which accounts to watch:
const subscribeRequest: SubscribeRequest = {
  accounts: {
    accountSubscribe: {
      account: [
        "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC mint
        "So11111111111111111111111111111111111111112"   // Wrapped SOL
      ],
      owner: [],
      filters: []
    }
  },
  commitment: CommitmentLevel.CONFIRMED
};
Best for: Monitoring specific token mints, known wallets, or critical program accounts

Data Slicing

Optimize bandwidth by requesting only specific byte ranges from account data:
// Only get the balance portion of token accounts (bytes 64-72)
const subscribeRequest: SubscribeRequest = {
  accounts: {
    accountSubscribe: {
      owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
      filters: [{ dataSize: 165 }]
    }
  },
  accountsDataSlice: [
    { offset: 64, length: 8 } // Token balance (u64)
  ],
  commitment: CommitmentLevel.CONFIRMED
};

Practical Examples

Example 1: Monitor Large Token Holders

Track USDC accounts with significant balances:
import { StreamManager } from './stream-manager'; // From quickstart guide

async function monitorLargeUSDCHolders() {
  const streamManager = new StreamManager(
    "your-grpc-endpoint",
    "your-api-key",
    handleLargeHolderUpdate
  );

  const subscribeRequest: SubscribeRequest = {
    accounts: {
      accountSubscribe: {
        owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
        filters: [
          { dataSize: 165 }, // Token account size
          { 
            memcmp: { 
              offset: 0, 
              bytes: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC mint
            } 
          }
        ]
      }
    },
    accountsDataSlice: [
      { offset: 32, length: 32 }, // Owner
      { offset: 64, length: 8 }   // Balance
    ],
    commitment: CommitmentLevel.CONFIRMED
  };

  await streamManager.connect(subscribeRequest);
}

function handleLargeHolderUpdate(data: any): void {
  if (data.account) {
    const account = data.account.account;
    
    // Parse token account data
    if (account.data && account.data.length >= 8) {
      const balanceBuffer = Buffer.from(account.data.slice(64, 72), 'base64');
      const balance = balanceBuffer.readBigUInt64LE();
      const balanceInUSDC = Number(balance) / 1e6; // USDC has 6 decimals
      
      // Only log accounts with > 100,000 USDC
      if (balanceInUSDC > 100000) {
        console.log(`🐋 Large USDC Holder Update:`);
        console.log(`  Account: ${account.pubkey}`);
        console.log(`  Balance: ${balanceInUSDC.toLocaleString()} USDC`);
        console.log(`  Slot: ${data.account.slot}`);
      }
    }
  }
}

Example 2: Track Program Account Changes

Monitor all accounts owned by a specific program:
async function monitorProgramAccounts() {
  const PROGRAM_ID = "YourProgramId"; // Replace with actual program ID
  
  const streamManager = new StreamManager(
    "your-grpc-endpoint",
    "your-api-key",
    handleProgramAccountUpdate
  );

  const subscribeRequest: SubscribeRequest = {
    accounts: {
      accountSubscribe: {
        owner: [PROGRAM_ID],
        filters: []
      }
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  await streamManager.connect(subscribeRequest);
}

function handleProgramAccountUpdate(data: any): void {
  if (data.account) {
    const account = data.account.account;
    console.log(`📋 Program Account Update:`);
    console.log(`  Account: ${account.pubkey}`);
    console.log(`  Owner: ${account.owner}`);
    console.log(`  Lamports: ${account.lamports}`);
    console.log(`  Data Length: ${account.data?.length || 0} bytes`);
    console.log(`  Executable: ${account.executable}`);
    console.log(`  Rent Epoch: ${account.rentEpoch}`);
  }
}

Example 3: New Account Creation Monitoring

Track when new accounts are created:
async function monitorNewAccounts() {
  const streamManager = new StreamManager(
    "your-grpc-endpoint",
    "your-api-key",
    handleNewAccountCreation
  );

  const subscribeRequest: SubscribeRequest = {
    accounts: {
      accountSubscribe: {
        owner: ["11111111111111111111111111111111"], // System Program
        filters: []
      }
    },
    commitment: CommitmentLevel.CONFIRMED
  };

  await streamManager.connect(subscribeRequest);
}

function handleNewAccountCreation(data: any): void {
  if (data.account && data.account.account.lamports === 0) {
    // New account creation typically starts with 0 lamports
    const account = data.account.account;
    console.log(`🆕 New Account Created:`);
    console.log(`  Account: ${account.pubkey}`);
    console.log(`  Owner: ${account.owner}`);
    console.log(`  Slot: ${data.account.slot}`);
  }
}

Filter Logic Reference

Understanding how filters combine:

Performance Considerations

Bandwidth Optimization

Use data slicing to request only needed bytesApply strict filters to reduce unnecessary updatesChoose appropriate commitment levels for your use case

Scale Management

Start with specific accounts before using owner filtersMonitor subscription volume and adjust filters as neededImplement backpressure handling for high-volume streams

Error Handling

Common account monitoring errors and solutions:

Next Steps