Overview
This guide covers how to track wallet balances (native SOL + SPL tokens) across thousands of wallets — typical for market-making operations where you have many wallets trading different tokens on Solana. There are 3 approaches, each suited to different use cases:
Recommendation for MM wallets: Use webhooks to get notified of every transfer in/out of your wallets, then call the portfolio API to refresh the full balance when needed.
Approach 1: Webhooks (Recommended for MM)
Webhooks let you receive push notifications every time tokens move in or out of your wallets. You tracktransfer events filtered to your wallet addresses.
Full runnable script:
src/create-webhooks.tsStep 1: Create a Transfer Webhook
Step 2: Receive Transfer Events on Your Server
Every time a transfer happens involving your wallets, Mobula POSTs a payload like this:Step 3: Build Your Webhook Server
Full runnable server with health check & balance query endpoints:
src/server.tsStep 4: Also Track Swap Events (Optional)
If your MM wallets are actively trading, you can also track swap events to see trades:Approach 2: Portfolio API (Polling)
For on-demand balance checks or to initialize/reconcile your balance tracking, use the Portfolio API.Full runnable script with batch polling & rate limiting:
src/poll-balances.tsSingle Wallet Balance
Full Portfolio with USD Values
Batch Polling for Thousands of Wallets
Approach 3: WebSocket Balance Stream
For persistent, real-time balance feeds with the lowest latency.Full runnable script with auto-reconnect:
src/ws-stream.tsSubscribe to Balance Updates
Scaling to Thousands of Wallets
All scaling scripts are in the wallet-balance-tracker repo:
src/create-webhooks.ts— auto-partitions wallets across webhookssrc/update-webhooks.ts— add/remove wallets dynamicallysrc/poll-balances.ts— batch polling with rate limiting
Architecture
1. Partition Wallets Across Multiple Webhooks
Each webhook supports ~450 wallets (1,000 filter ops limit, 2 per wallet). Thecreate-webhooks.ts script handles this automatically:
2. Add/Remove Wallets Dynamically
When you spin up new MM wallets or retire old ones, update the webhook filter withupdate-webhooks.ts:
PATCH /api/1/webhook:
3. Initialize Balances on Startup
Before relying on webhooks for deltas, fetch current balances for all wallets using the batch poller:4. Periodic Reconciliation
Webhooks can occasionally miss events (network issues, dead webhook recovery). Run periodic reconciliation by re-polling a random subset:Recommended Production Setup
- Initialize: Poll all wallets on startup (
bun run poll-balances) - Track: Webhooks push transfer events in real-time (
bun run server) - Reconcile: Every 5 min, re-poll a random subset of wallets
- Store: Use Redis or a database instead of in-memory maps
- Monitor: Track webhook delivery failures via the list webhooks endpoint
Quick Reference
API Endpoints
Transfer Event Fields for Filtering
Filter Operators
Solana-Specific Notes
- Native SOL address:
So11111111111111111111111111111111111111112(Wrapped SOL mint) - Chain ID:
solana:solana - SOL decimals: 9 (1 SOL = 1,000,000,000 lamports)
- USDC decimals: 6
- Webhook event delivery is batched (up to 10 events per POST, 2-second debounce)
- Failed deliveries are retried every 10 minutes for up to 7 days
Repo Scripts
GitHub Repo
Ready-to-run code example
Webhook Getting Started
Webhook basics
Filter Reference
Full filter documentation
Transfer Data Model
Transfer event fields
Mobula SDK
TypeScript SDK
Support
Telegram support