The account model context
Skip this section if you’re familiar with Solana accounts and their structure.
- Data: The actual bytes storing program state, token balances, or other information
- Owner: The program that controls this account and can modify its data
- Lamports: The account’s SOL balance for rent exemption
- Executable: Whether this account contains program code
Basic account subscription
Let’s start with a simple example that subscribes to changes in token accounts. This script will notify you whenever token balances change:BKMHWYLAX4un3HUbR7a3u9jPmzCiLNa4mSj1RiX11eWF.
This account has:
- 2,039,280 lamports (~0.002 SOL balance - this is the rent-exempt amount for this token account)
- Owner program
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA(this is the SPL Token program) - Transaction signature
5C9Hr5nG2j8eQz6inxPmfyjbYdmXddzUDyR1iQgEnjYQ3RNvuP4Zzc8t1enLNy7Rk8KNCtQPEQztENYWxkt9GaVDshowing which specific transaction caused this account to change - Slot 352366983 indicating when this update occurred on the blockchain
- Data field containing 165 bytes of account data encoded as base58
Understanding account filtering with datasize
The data field is crucial - it contains the actual token account structure. Let’s use this understanding for smart account filtering.Why use datasize filtering?
To understand why we need filtering, let’s first understand what token accounts actually are. For every token a wallet holds, there’s a separate account on-chain. If your wallet holds 3 different tokens (USDC, BONK, and SOL), you actually have 1 wallet account (your main SOL account) plus 3 token accounts (one for each token type). Each token account is exactly 165 bytes and stores: which token it holds (mint address), who owns it (your wallet address), and how much of that token it contains (amount). The Token Program owns millions of accounts on Solana, but not all of them are what we think of as “token accounts” holding user balances. Here’s what happens with and without filtering: Without filtering - The flood:- Token accounts (165 bytes) - User balances: millions of accounts
- Mint accounts (82 bytes) - Token definitions: hundreds of thousands of accounts
- Multisig accounts (355 bytes) - Shared wallet controls: tens of thousands of accounts
- Associated Token Program accounts (various sizes) - millions of accounts
- Without filtering: Millions of account updates (mint creations, multisig changes, etc.)
- With datasize filtering: Only token balance changes
Where does 165 bytes come from?
This isn’t magic - it comes from the SPL Token program’s account structure. Looking at the source code, we can see theAccount struct defines exactly 165 bytes:
- Mint accounts (82 bytes)
- Multisig accounts (355 bytes)
- Associated token account program accounts
- Other token-related accounts with different sizes
Decoding the account structure
Now that we understand why we filtered for 165 bytes, let’s decode what’s inside our example account:- Bytes 0-31: Mint address (which token this account holds)
- Bytes 32-63: Owner address (who owns this token account)
- Bytes 64-71: Token amount (how many tokens are in the account)
- Bytes 72-164: Additional metadata (delegate, state, close authority, etc.)
Combining filters: datasize + memcmp for laser precision
Now that we know the mint address lives at bytes 0-31, we can get even more specific. Let’s say we only want to monitor USDC token accounts. We can combine ourdatasize filter with a memcmp filter to target the exact mint address:
- Owner filter: “Give me accounts owned by Token Program” (millions of accounts)
- Datasize filter: “But only 165-byte standard token accounts” (hundreds of thousands)
- Memcmp filter: “And only those holding USDC” (thousands)
Reading USDC account updates: Who, How Much, Where?
Now let’s see what these filtered updates actually contain. Let’s create a USDC-specific monitor that answers the key questions when a token account changes:- Who owns this token account?
- How much USDC does it now contain?
- Where (which specific account) changed?
- When did this change happen?
- What transaction caused the change?
bs58.encode() function to convert binary Buffer objects to readable strings.
Complete filtering reference
Beyond the basicowner, datasize, and memcmp filters we’ve used, account subscriptions support additional filtering options to further narrow your results:
Specific account filtering
Monitor exact accounts by their public keys:Combined filtering strategies
The power comes from combining multiple filter types. Here’s the mental model:- Cast a wide net with
owner- “Give me all accounts managed by this program” - Filter by structure with
datasize- “But only accounts of this specific type” - Target specific data with
memcmp- “And only those containing this specific information” - Monitor known accounts with
account- “Or just watch these exact accounts I care about”
Understanding the bigger picture
Think of account subscriptions as watching a live feed of database changes. Solana’s state is essentially a massive key-value store where each account is an entry. When programs execute, they modify these accounts. Your subscription lets you watch specific entries change in real-time. The filtering system works like database indexes - you’re not just watching “all changes” but rather “changes to accounts that match these criteria.” This makes it possible to build responsive applications that react immediately to relevant on-chain events without overwhelming your system with irrelevant data.Applying this pattern to other programs
The approach we’ve learned works for any Solana program. Here’s the general pattern:- Research the account structure - Check the program’s source code or documentation
- Start with owner filtering - Target the program that manages the accounts
- Apply structural filters - Use account size, data patterns, or other characteristics to narrow down to specific account types
- Add targeted filters - Focus on specific accounts, states, or data values that matter to your application