4

I am currently using Solana's onLogs method to monitor transactions for multiple wallets in real-time. The implementation involves subscribing to multiple wallet addresses and handling transaction events as they occur. However, I have encountered an issue where some transactions are being missed during monitoring.

Here are some key details about the implementation:

I am using the onLogs method from the Solana Web3.js library and QuickNode($39) Each wallet address is subscribed to individually, with a slight delay between each subscription to avoid overwhelming the connection. I have implemented mechanisms to avoid duplicate processing of transactions and to log all received events. Despite this setup, I am observing inconsistent behavior where some transactions for subscribed wallets do not trigger the onLogs callback. This issue occurs sporadically—sometimes transactions are detected, but other times they are not. I have also ensured that:

The WebSocket connection is stable and retries are handled in case of disconnections. There are no overlapping or duplicate subscriptions for the same wallet. The RPC endpoint being used (QuickNode) is functioning properly. This inconsistency is critical for my application, which requires real-time monitoring without missing any transactions. I am looking for insights into:

Potential reasons why onLogs might miss transactions for certain wallets. Whether there are known limitations or caveats with onLogs when monitoring a large number of wallets. Alternative approaches to ensure all transactions are captured in real-time. Any guidance, suggestions, or shared experiences with similar issues would be greatly appreciated!

async onModuleInit() {
    try {
      const rpcUrl = this.configService.get<string>('TEST_QUICK_NODE_URL');
      const wssrpcUrl = this.configService.get<string>(
        'TEST_QUICK_NODE_WSS_URL',
      );
      this.connection = new Connection(rpcUrl, {
        wsEndpoint: wssrpcUrl,
      });
      const wallets = await this.walletService.listWallets();
      this.walletAddresses = wallets.map((wallet) => ({
        id: parseInt(wallet.id, 10),
        address: new PublicKey(wallet.address),
        important: wallet.important,
      }));
      Logger.log('Successfully loaded wallet addresses from the database.');
      await this.monitorWallets();
    } catch (error) {
      Logger.error('Failed to initialize wallet monitoring:', error);
    }
  }

  private async monitorWallets() {
    for (const walletAddress of this.walletAddresses) {
      try {
        const subscriptionId = this.connection.onLogs(
          walletAddress.address,
          async (logInfo) => {
            await this.handleAccountChange(logInfo.signature, walletAddress);
          },
          'confirmed',
        );

        this.subscriptions.set(walletAddress.id, subscriptionId);

        Logger.log(
          `Successfully subscribed to wallet ID ${walletAddress.id} with Subscription ID ${subscriptionId}`,
        );

        await new Promise((resolve) => setTimeout(resolve, 100));
      } catch (error) {
        Logger.error(
          `Failed to subscribe to wallet ID ${walletAddress.id}: ${error.message}`,
        );

        setTimeout(() => {
          Logger.warn(
            `Retrying subscription for wallet ID ${walletAddress.id}`,
          );
          this.monitorWallets();
        }, 5000);
      }
    }
  }

1 Answer 1

3

I suggest you try Chainstack too.

Overall, I don't think anyone has a perfect solution, especially given how fast and finicky Solana is.

That said, having worked with this issue for quite some time in different solutions, I'll dump my experience and hope it helps. Especially since you mentioned you are open to alternative approaches.

First of all, Solana web3.js onLogs is the logsSubscribe method under the hood. (Making it clear just in case for others too).

Option 1: Redundant event listener

If you want to stick to logsSubscribe, you can try building a redundant event listener that uses jiggles nodes, not just one. I don't have a Solana example at hand, but for an idea of how to do one, have a look here at a version on Ethereum. The issue is not exclusive to Solana as you can see. Same logic would work on Solana.

Option 2: blockSubscribe

You can also try using blockSubscribe and see if you get better results.

But also be aware of the following issues (they are for logsSubscribe & blockSubscribe, but also I'm pretty sure both are relevant to both—the mechanics is the same):

Also check out this script that I used to listen to the pump.fun events (although it's in Python) using blockSubscribe: pump.fun listener script.

Hope this helps and you'll be able to assemble that works for your case specifically!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.