1

As the title states I would like to get all wallets that hold a particular token by providing the token's address. I believe in more accurate terms I would like to get all token accounts with a non-zero balance related to a particular mint account via mint address. These token accounts should provide me the wallet addresses and the balances in each wallet which is what I'm ultimately after. I'll be using it to take a snapshot of all token holders at a given datetime.

Base setup:

  1. Attempting to do this with a local Javascript Node application.
  2. Using Quicknode as my RPC provider.
  3. Using the solana-web3.js V2.0.0 library to interact with the RPC provider.

Current code:

interface TokenAccountInfo { account: { data: { parsed: { info: { owner: string; tokenAmount: { uiAmount: number; }; }; }; }; }; } export class SolanaService { private rpc: ReturnType<typeof createSolanaRpc>; constructor(endpoint: string) { this.rpc = createSolanaRpc(endpoint); } async getTokenHolders(tokenMintAddress: string): Promise<Map<string, number>> { const tokenAddress = address(tokenMintAddress); const tokenHolders = new Map<string, number>(); const tokenProgramId = address('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); const TOKEN_ACC_SIZE = 165; const datasizeFilter: GetProgramAccountsDatasizeFilter = { // Filter to only accounts with length 165, which is the fixed length that token accounts have. This way we get rid of accounts that are owned by the token program but aren't token accounts dataSize: TOKEN_ACC_SIZE as unknown as bigint } const memoryComparisonFilter: GetProgramAccountsMemcmpFilter = { memcmp: { offset: 0 as unknown as bigint, // Filter by mint address bytes: tokenMintAddress, encoding: "base64" } } // Fetch all token accounts by mint address const tokenAccounts = await this.rpc.getProgramAccounts( tokenProgramId, { filters: [ datasizeFilter, memoryComparisonFilter] } ).send(); console.log('Token accounts response:', tokenAccounts); // Iterate over each token account and sum the balances (tokenAccounts.values as unknown as TokenAccountInfo[]).forEach((accountInfo) => { const accountData = accountInfo.account.data.parsed.info; const walletAddress = accountData.owner; const tokenAmount = accountData.tokenAmount.uiAmount; console.log(`Processing account: ${walletAddress}, amount: ${tokenAmount}`); if (tokenHolders.has(walletAddress)) { tokenHolders.set(walletAddress, tokenHolders.get(walletAddress)! + tokenAmount); } else { tokenHolders.set(walletAddress, tokenAmount); } }); console.log('Final token holders:', tokenHolders); return tokenHolders; } } 

I am currently attempting to do this using the getProgramAccounts endpoint and applying the appropriate filters to get back the token accounts. This idea was derived from the following posts:

  1. What is the best way to get all token holders and their balances by mint address?
  2. Get all token holders of a token (mint)

However it looks like this functionality may have been deprecated and when doing so I get the following error:

SolanaError: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA excluded from account secondary indexes; this RPC method unavailable for key

It looks as if the token program ID (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA) is no longer an accepted value for this endpoint.

Could someone please provide me the correct means of achieving this query?

Edit* I am aware that Helius has an endpoint specifically for this and a SDK to call it but I am using QuickNode as my RPC provider. I would like to implement this using the solana-web3.js library and Solana standard endpoints.

2 Answers 2

2

The error occurs because getProgramAccounts no longer supports querying the Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA) due to Solana's updates. Instead, you can use Helius RPC, which provides the getTokenAccounts endpoint specifically for fetching token holders.

Helpful Links:

1

I personally use the getTokenAccount method from helius like so

let page = 1; let allOwners = new Set<TokenHolder>(); while (true) { const response = await fetch( `https://mainnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ jsonrpc: "2.0", method: "getTokenAccounts", id: "421", params: { page: page, limit: 1000, mint: token, }, }), } ); const data = await response.json(); if (!data.result || data.result.token_accounts.length === 0) { break; } data.result.token_accounts.forEach((account: any) => { allOwners.add({ amount: account.amount, address: account.owner, } as TokenHolder); }); page++; } return Array.from(allOwners); 
9
  • and how do you find all the tokens that one account has ? how you find their mints? Commented Jan 27 at 9:49
  • if I'm understanding your question right, you should be able to get that calling solana.com/docs/rpc/http/gettokenaccountsbyowner Commented Jan 27 at 22:26
  • Hi Riki. The call above gives information about the amount only for the specified token. I need to first get all tokens that the user owns because I don't know them. If I knew that user had Pepe token and had the pepe mint the call above would be useful. I wan to get all tokens and their balances for a wallet/address when I have no other info Commented Jan 29 at 10:36
  • Seems like helius is offering this docs.helius.dev/compression-and-das-api/… but I wonder if solana is offering that natively as well Commented Jan 29 at 10:37
  • There was a misunderstanding. I want to get all tokens that my wallet has ? Not the other way around get all wallets having X token (myDog token) Commented Jan 29 at 18:26

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.