Marketplace has launched, further enabling blockchain developers! Learn more

How to Get All Tokens Held by a Wallet in Solana

September 23, 2022

Overview

Hello readers! To kick off Solana Summer and the current whitelist meta, we thought it would be helpful to dig into all of the token accounts you and your users have using the getParsedProgramAccounts method. This tool is convenient for querying different programs on Solana, including the Solana SPL Token Account library. 

This guide will walk you through creating a simple script that will query Solana's mainnet and return all of the Token Accounts owned by that wallet and their account balances. 

Here is a video if you prefer to watch:

What You Will Need

Programs: smart contracts on Solana. In this example, we will use the SPL Token Program, which defines typical use cases for fungible and non-fungible tokens on Solana.
Program Filters: many on-chain program queries pull extensive data sets, so it is essential to narrow your search. We will use the GetProgramAccountsFilter type to help us narrow down our search. 

Set Up Your Environment

Create a new project directory and file, index.ts, in your terminal with:

set up your environment

Copy
mkdir sol-get-accounts
cd sol-get-accounts
echo > index.ts

Initialize your project: 

set up your environment

Copy
yarn init --yes

or

set up your environment

Copy
npm init --yes

Install Solana Web3 dependencies:

set up your environment

Copy
yarn add @solana/web3.js @solana/spl-token

or

set up your environment

Copy
npm install @solana/web3.js @solana/spl-token

Open index.ts in a code editor and add the following dependencies:

set up your environment

Copy
import { Connection, GetProgramAccountsFilter } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

Establish a Connection to Solana Mainnet

To build on Solana, you'll need an API endpoint to connect with the network. You're welcome to use public nodes or deploy and manage your own infrastructure, however, if you'd like 8x faster response times you can leave the heavy lifting to us. See why over 50% of projects on Solana choose QuickNode and sign up for a free, 7-day trial here.

Make sure to launch your node under the Solana Mainnet and copy the HTTP link:
Get Solana Mainnet Endpoint

set up your environment

Copy
const rpcEndpoint = 'https://example.solana-mainnet.quiknode.pro/000000/';
const solanaConnection = new Connection(rpcEndpoint);

Define the wallet that you want to query as a string:

set up your environment

Copy
const walletToQuery = 'YOUR_PUBLIC_KEY'; //example: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg

Great! We are ready to build our token query.

Create your Token Account Query

Create a new async function, getTokenAccounts and require a parameter of wallet and solanaConnection:

create your token account query

Copy
async function getTokenAccounts(wallet: string, solanaConnection: Connection) {
}

Establish filters

First, let's define our filters. The filters we will be using are: 
  • dataSize is a filter used to look for accounts of a specific size. For token accounts, this is a known quantity, 165.
  • memcmp, or "memory comparison" filter, is used to narrow our search within an account. Specifically, we will use offset to determine where in our account's 165 bytes to search (this is another known value for this Program: the owner's public key starts at 32) and bytes to set what we will be searching for: in this case, the users' wallet address. 
  • Source information about SPL token account data can be found here.

Inside getTokenAccounts, define a variable called filters.

create your token account query

Copy
    const filters:GetProgramAccountsFilter[] = [
        {
          dataSize: 165,    //size of account (bytes)
        },
        {
          memcmp: {
            offset: 32,     //location of our query in the account (bytes)
            bytes: wallet,  //our search criteria, a base58 encoded string
          }            
        }
     ];

This should reduce our query to look for only token accounts owned by our wallet. 

Get Program Accounts


Now call the getParsedProgramAccounts method passing in the SPL Token Program ID and our filters

create your token account query

Copy
    const accounts = await solanaConnection.getParsedProgramAccounts(
        TOKEN_PROGRAM_ID,   //SPL Token Program, new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
        {filters: filters}
    );

The previous call returns an array of all matching token accounts with the following structure: 

create your token account query

Copy
{
    pubkey: PublicKey,      //Token Account Public Key
    account: AccountInfo    //Object including information about our token account
}[]

You can log accounts.length to see how many token accounts the user has: 

create your token account query

Copy
console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}.`);

Parse the Results

Build a simple forEach loop to iterate through our results and log our results. Inside your getTokenAccounts function add:

create your token account query

Copy
    accounts.forEach((account, i) => {
        //Parse the account data
        const parsedAccountInfo:any = account.account.data;
        const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
        const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
        //Log results
        console.log(`Token Account No. ${i + 1}: ${account.pubkey.toString()}`);
        console.log(`--Token Mint: ${mintAddress}`);
        console.log(`--Token Balance: ${tokenBalance}`);
    });

Run Your Code

Finally, call getTokenAccounts(walletToQuery,solanaConnection). Your final script should look like this:

run your code

Copy
import { Connection, GetProgramAccountsFilter } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

const rpcEndpoint = 'https://example.solana-mainnet.quiknode.pro/000000/';
const solanaConnection = new Connection(rpcEndpoint);

const walletToQuery = 'YOUR_PUBLIC_KEY'; //example: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg

async function getTokenAccounts(wallet: string, solanaConnection: Connection) {
    const filters:GetProgramAccountsFilter[] = [
        {
          dataSize: 165,    //size of account (bytes)
        },
        {
          memcmp: {
            offset: 32,     //location of our query in the account (bytes)
            bytes: wallet,  //our search criteria, a base58 encoded string
          },            
        }];
    const accounts = await solanaConnection.getParsedProgramAccounts(
        TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
        {filters: filters}
    );
    console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}.`);
    accounts.forEach((account, i) => {
        //Parse the account data
        const parsedAccountInfo:any = account.account.data;
        const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
        const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
        //Log results
        console.log(`Token Account No. ${i + 1}: ${account.pubkey.toString()}`);
        console.log(`--Token Mint: ${mintAddress}`);
        console.log(`--Token Balance: ${tokenBalance}`);
    });
}
getTokenAccounts(walletToQuery,solanaConnection);

Run ts-node index.ts and you should see a log like this in your terminal: 

Sample Output: Token Log in Terminal

Bonus: Add More Filters

Having fun? Want to try more filters? Say, for example, you want to see if a wallet contains tokens of a particular mint. You could include that filter in your forEach loop above, but you might consider adding it to your filters variable in your original query to reduce the search time. Here's how to do it. 
In your definitions at the top of your application, add a mint address to search, for example: 

bonus add more filters

Copy
    const MINT_TO_SEARCH = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; //USDC Mint Address

Now back in our getTokenAccounts function, add an additional filter to filters looking for MINT_TO_SEARCH at byte position 0 (known location of the mint public key in this program): 

bonus add more filters

Copy
    const filters:GetProgramAccountsFilter[] = [
        {
          dataSize: 165,    //size of account (bytes)
        },
        {
          memcmp: {
            offset: 32,     //location of our query in the account (bytes)
            bytes: wallet,  //our search criteria, a base58 encoded string
          },            
        },
        //Add this search parameter
        {
            memcmp: {
            offset: 0, //number of bytes
            bytes: MINT_TO_SEARCH, //base58 encoded string
            },
        }];

Rerun your code, and you should see the results are now limited to just the mint you searched for: 

Sample Output: Single Mint Search Results

Conclusion

And you're done! You should now understand how to query a wallet for all of its token accounts and have a solid foundation that will enable you to query other Solana Programs in the future. 
Find this useful? Check out some of our other Solana tutorials here.Subscribe to our newsletter for more articles and guides on Solana. Feel free to reach out to us via Twitter if you have any feedback. You can always chat with us on our Discord community server, featuring some of the coolest developers you'll ever meet :)

Related articles 33

Como crear un NFT en SOLANA
Published: Dec 27, 2021
Updated: Sep 23, 2022

¡Hola querido lector! Bienvenidos a una nueva guía de Solana.Solana es una blockchain que promete mucho a la hora de intentar resolver los problemas de escalabilidad que...

Continue reading
How to Get Transaction Logs on Solana
Published: Jun 24, 2022
Updated: Oct 27, 2022

Ever need to pull all the transactions associated with a Wallet? Want to see all of the mint transactions associated with a Candy Machine? Or maybe see transaction history of an NFT? Solana's...

Continue reading
How to Transfer SPL Tokens on Solana
Published: Sep 23, 2022
Updated: Sep 23, 2022

Sending Solana Program Library (SPL) Tokens is a critical mechanism for Solana development. Whether you are airdropping whitelist tokens to your community, bulk sending NFTs to another wallet,...

Continue reading
How to Mint an NFT on Solana
Published: Aug 27, 2021
Updated: Sep 23, 2022

Updated at: April 10, 2022Welcome to another QuickNode guide on Solana - the up-and-coming blockchain that seeks to solve the scalability issues of Ethereum. We will be walking through...

Continue reading
How to Send Bulk Transactions on Solana
Published: Aug 31, 2022
Updated: Oct 3, 2022

Are you running a batch process that has many transactions? Perhaps an airdrop to your community's NFT holders or a token distribution to early users of your dApp. Solana transaction...

Continue reading
Solana Fundamentals Reference Guide
Published: Oct 27, 2022
Updated: Oct 27, 2022

The Solana blockchain is a powerful tool, delivering thousands of transactions per second with almost no-cost transaction fees. If you are new to Web3 or have developed on EVM-based...

Continue reading