Monitor Solana Accounts with WebSockets and Solana Web3.js 2.0

·

Introduction

Solana Web3.js 2.0 represents a significant upgrade to the JavaScript library for interacting with the Solana blockchain. This update introduces a more robust WebSocket subscription system for monitoring on-chain events, offering enhanced type safety and error handling. This guide provides a step-by-step approach to implementing account monitoring using the new subscription system, enabling developers to track real-time changes on the Solana network efficiently.

Key Improvements in Web3.js 2.0

The updated subscription system in Solana Web3.js 2.0 brings several notable enhancements:

Setting Up the Development Environment

Prerequisites

Step-by-Step Setup

  1. Create a new project directory:

    mkdir solana-subscriptions-v2 && cd solana-subscriptions-v2
  2. Initialize a new npm project:

    npm init -y
  3. Install required dependencies:

    npm install @solana/web3.js@2
    npm install --save-dev typescript ts-node @types/node
  4. Configure TypeScript:
    Create a tsconfig.json file with the following settings:

    {
      "compilerOptions": {
        "module": "NodeNext",
        "moduleResolution": "NodeNext",
        "noEmit": true,
        "target": "ESNext"
      }
    }

Implementing Account Monitoring

Create the Main Application File

Create a new file named app.ts and open it in your code editor.

Import Dependencies

Add the following imports to app.ts:

import {
  createSolanaRpcSubscriptions,
  RpcSubscriptions,
  SolanaRpcSubscriptionsApi,
  address,
  Address
} from '@solana/web3.js';

Define Constants

Add these constants below your imports:

const WSS_PROVIDER_URL = 'wss://your-quicknode-endpoint.example';
const LAMPORTS_PER_SOL = 1_000_000_000;
const PUMP_FUN_FEE_ACCOUNT = address("CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM");

Replace the placeholder WebSocket URL with your actual QuickNode endpoint. The example uses the Pump.fun fee account, but you can substitute any Solana account address.

Helper Function for Formatting

Add this utility function to convert lamports to SOL:

const lamportsToSolString = (lamports: number, includeUnit = true): string => {
  const solAmount = lamports / LAMPORTS_PER_SOL;
  return `${solAmount.toLocaleString('en-US', {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  })} ${includeUnit ? 'SOL' : ''}`;
};

Define Interface for Tracking Arguments

Create an interface to define the parameters for the tracking function:

interface TrackAccountArgs {
  rpcSubscriptions: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
  accountAddress: Address;
  abortSignal: AbortSignal;
}

Implement Account Tracking Function

Add the following function to handle account monitoring:

async function trackAccount({ rpcSubscriptions, accountAddress, abortSignal }: TrackAccountArgs) {
  let lastLamports: number | null = null;
  try {
    const accountNotifications = await rpcSubscriptions
      .accountNotifications(accountAddress, { commitment: 'confirmed' })
      .subscribe({ abortSignal });
    try {
      for await (const notification of accountNotifications) {
        const { slot } = notification.context;
        const currentLamports = Number(notification.value.lamports);
        const delta = lastLamports !== null ? currentLamports - lastLamports : 0;
        const sign = delta > 0 ? '+' : delta < 0 ? '-' : ' ';
        console.log(`Account change detected at slot ${slot.toLocaleString()}. New balance: ${lamportsToSolString(currentLamports)} (${sign}${lamportsToSolString(Math.abs(delta))})`);
        lastLamports = currentLamports;
      }
    } catch (error) {
      throw error;
    }
  } catch (error) {
    throw error;
  }
}

Create Main Function

Add the entry point function to execute your tracking:

async function main() {
  console.log(`💊 Tracking Pump.fun fee account: ${PUMP_FUN_FEE_ACCOUNT} 💊`);
  const rpcSubscriptions = createSolanaRpcSubscriptions(WSS_PROVIDER_URL);
  const abortController = new AbortController();
  try {
    await trackAccount({
      rpcSubscriptions,
      accountAddress: PUMP_FUN_FEE_ACCOUNT,
      abortSignal: abortController.signal
    });
  } catch (e) {
    console.log('Subscription error', e);
  } finally {
    abortController.abort();
  }
}
main();

Running the Monitoring Script

Execute the script using ts-node:

ts-node app.ts

The monitor will begin tracking changes to the specified account and display balance changes in the following format:

Account change detected at slot 301,428,932. New balance: 265,598.16 SOL (+0.14 SOL)

Billing Considerations and Optimization

WebSocket methods are billed based on the number of responses received rather than the number of subscriptions created. Each response from an accountNotifications subscription costs 20 API credits. To optimize your usage and avoid unnecessary costs:

👉 View real-time monitoring tools

Alternative Real-Time Data Solutions

QuickNode offers several solutions for obtaining real-time Solana data:

Each option has distinct advantages depending on your specific use case and technical requirements.

Frequently Asked Questions

What is Solana Web3.js 2.0?

Solana Web3.js 2.0 is a major update to the JavaScript library for interacting with the Solana blockchain. It introduces improved type safety, modern asynchronous iteration patterns, and better error handling for WebSocket subscriptions and other blockchain interactions.

How does account monitoring work with WebSockets?

Account monitoring through WebSockets establishes a persistent connection to a Solana node. When changes occur to the specified account (such as balance changes), the node pushes notifications to the client in real-time, allowing immediate response to on-chain activity.

What commitment level should I use for monitoring?

The 'confirmed' commitment level provides a balance between speed and reliability, ensuring that changes are recorded by the cluster before notifications are sent. For applications requiring maximum certainty, 'finalized' may be more appropriate, though it may introduce slight delays.

Can I monitor multiple accounts simultaneously?

Yes, you can create multiple subscriptions to monitor different accounts. However, be mindful of API credit usage as each response from each subscription incurs separate costs.

How do I handle disconnections and reconnections?

The new Web3.js 2.0 API provides improved error handling that can help detect disconnections. Implementing reconnection logic with exponential backoff is recommended for production applications to maintain reliable monitoring.

What are the rate limits for WebSocket subscriptions?

Rate limits vary by provider and subscription plan. Check with your RPC provider for specific limitations on the number of subscriptions and messages per connection.

Conclusion

Solana Web3.js 2.0 provides a more robust, type-safe approach to handling WebSocket subscriptions for Solana blockchain monitoring. The new API simplifies subscription management, error handling, and resource cleanup, enabling developers to create more reliable and maintainable applications for tracking on-chain events.

👉 Explore more monitoring strategies

The enhanced subscription system represents a significant step forward in developer experience for Solana ecosystem projects. By following the implementation outlined in this guide, developers can efficiently monitor account changes and respond to real-time blockchain events with confidence.