How to Monitor Solana Accounts with WebSocket and Web3.js 2.0

·

Solana Web3.js 2.0 represents a major update to the JavaScript library used for interacting with the Solana blockchain. Among its many enhancements, it introduces a more powerful WebSocket subscription system for monitoring on-chain events. This guide explains how to use the new subscription system for tracking account balance changes, emphasizing improvements in type safety, modern asynchronous iteration, and error handling mechanisms.

Overview of Solana Web3.js 2.0

The latest version of Solana’s JavaScript library brings significant upgrades for developers. The most notable improvements include:

These features make it easier to build reliable and maintainable applications that interact with the Solana blockchain in real time.

Setting Up Your Development Environment

Before diving into the implementation, ensure you have the necessary tools and dependencies installed.

Prerequisites

Step-by-Step Setup

  1. Create a new project directory:
    Open your terminal and run:

    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

    For development dependencies, install TypeScript and related packages:

    npm install --save-dev typescript ts-node @types/node
  4. Configure TypeScript:
    Generate a tsconfig.json file:

    tsc --init

    Update the configuration with the following settings:

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

Building an Account Monitor

With the environment ready, you can now create a script to monitor Solana account changes.

Import Dependencies

Create a new file named app.ts and add the following imports:

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

Define Constants

Add constants for the WebSocket provider URL, Lamports per SOL, and the account address to monitor:

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

Note: Replace the WebSocket URL with your actual endpoint. For Solana development, a reliable API endpoint is essential.

Helper Function for Formatting

Include a function to convert Lamports to SOL for display:

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

Interface for Tracking Arguments

Define an interface to structure the arguments for the tracking function:

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

Account Tracking Function

Implement the core function to monitor account changes:

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(`Detected account change at slot ${slot.toLocaleString()}. New balance: ${lamportsToSolString(currentLamports)} (${sign}${lamportsToSolString(Math.abs(delta))})`);
        lastLamports = currentLamports;
      }
    } catch (error) {
      throw error;
    }
  } catch (error) {
    throw error;
  }
}

This function sets up a subscription to account notifications, processes each update, and logs balance changes in a user-friendly format.

Entry Point and Execution

Add the main function to execute the tracker:

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();

Run the script using:

ts-node app.ts

The monitor will start tracking balance changes and display outputs like:

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

Billing and Optimization Tips

WebSocket methods are billed based on the number of responses received, not the number of subscriptions created. For example, if you receive 100 responses from an accountNotifications subscription, your account will be charged 2,000 credits (20 credits per response × 100 responses).

To optimize usage and avoid unnecessary costs:

👉 Explore real-time monitoring tools

Alternative Solutions for Real-Time Data

QuickNode offers multiple tools for accessing real-time Solana data:

Each tool has unique strengths, so choose based on your project’s requirements for scalability, filtering, and integration.

Frequently Asked Questions

What is Solana Web3.js 2.0?
Solana Web3.js 2.0 is the latest version of the JavaScript library for interacting with the Solana blockchain. It introduces improved type safety, modern asynchronous patterns, and better error handling.

How do I set up a WebSocket subscription?
Use the accountNotifications method from the RpcSubscriptions class, providing an account address and commitment level. The method returns an async iterable for processing notifications.

Can I monitor multiple accounts simultaneously?
Yes, you can create multiple subscriptions by calling the accountNotifications method for each account. Ensure proper resource management to avoid excessive billing.

What is AbortController used for?
AbortController allows you to cancel asynchronous operations, such as WebSocket subscriptions, when they are no longer needed, helping manage resources and costs.

How are WebSocket requests billed?
Billing is based on the number of responses received. Each response consumes a fixed number of API credits, so optimizing filters and unsubscribing promptly can reduce costs.

Are there alternatives to WebSockets for real-time data?
Yes, alternatives include gRPC plugins and managed streams, which offer additional features like historical data support and built-in filtering for complex applications.

Conclusion

Solana Web3.js 2.0 provides a robust, type-safe approach to handling WebSocket subscriptions. Its modern API simplifies subscription management, error handling, and resource cleanup, making it easier to build reliable applications for monitoring blockchain events. By leveraging these tools, developers can create efficient and maintainable solutions for real-time data tracking on Solana.

For further learning, explore the official Solana Web3.js documentation and community resources to deepen your understanding of blockchain development.