How to get the token balances of a Solana address with JavaScript

In this tutorial, we are going to learn how to get the balance of all the tokens that a Solana address holds using JavaScript and the @solana/web3.js library.

In this tutorial, we are going to learn how to get the balance of all the tokens that a Solana address holds using JavaScript and the @solana/web3.js library.

To get the all the balances of all the tokens that an address has at once, you'll also need to install the @solana/spl-token library:

npm install @solana/spl-token

You can also install it with Yarn.

Now, here is the code to do fetch the token balances of an address:

import { clusterApiUrl, Connection, PublicKey } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';


const fetchBalances = async () => {
  const connection = new Connection(clusterApiUrl('devnet'));
  
  const ownerAddress = 'GX6nkQgcXy4xDyuSH9MKjG9nq5KN5ntE3ZUUHSqUrcC8'
  const ownerPublicKey = new PublicKey(ownerAddress)


  // Fetch the balance of a single token
  
  const tokenPublicKey = new PublicKey('4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU');
  const balance = await connection.getParsedTokenAccountsByOwner(
    ownerPublicKey,
    {
      mint: tokenPublicKey,
    }
  );


  // Fetch all token balances
  
  const balances = await connection.getParsedTokenAccountsByOwner(
    ownerPublicKey,
    {
      programId: TOKEN_PROGRAM_ID,
    }
  );

  console.log(balances, balance);
  return { balances, balance }
};

Let's dive into the code!

Connecting to the Solana blockchain

First, we need a connection to the blockchain to interact with it. To do that, you can either create a Connection object:

import { clusterApiUrl, Connection } from '@solana/web3.js';

// You can also pass "mainnet-beta" to connect to the Mainnet
// or pass "testnet" to connect to the Testnet

const connection = new Connection(clusterApiUrl('devnet'));

Or, if you use React, you can use the useConnection hook:

import { useConnection } from '@solana/wallet-adapter-react';

// In your component:
const { connection } = useConnection()

Preparing the variables we need to get the token balances

Next, we need to create a PublicKey object from the address that you want to get the balances for:

import { PublicKey } from '@solana/web3.js';


// ... In your code:

const ownerAddress = 'GX6nkQgcXy4xDyuSH9MKjG9nq5KN5ntE3ZUUHSqUrcC8'
const ownerPublicKey = new PublicKey(ownerAddress)

If you're using React and you allow users to connect their wallet to your app, you can just use the useWallet hook:

import { useWallet } from '@solana/wallet-adapter-react';

// ... In your component:

const { publicKey: ownerPublicKey } = useWallet()

If you're getting the balance of a specific token, you'll also need to create a PublicKey object from the token address:

import { PublicKey } from '@solana/web3.js';

const tokenPublicKey = new PublicKey(tokenAddress);

You can find the address of the token's contract on the page of that token on any Solana block explorer website like solscan.io or https://explorer.solana.com/.

On explorer.solana.com, you can find that address by searching your token name in the search bar and then you get the address here:

In the example above, I used the USDC token on the Devnet so the address of that token is 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU on the devnet.

How to get the token balances of an address

To get the token balances of an address, we are going to use the getParsedTokenAccountsByOwner function of the Solana Web3.js library.

That function takes in 2 parameters:

  1. The address of which you want to get the balances for It needs to be a PublicKey object.
  2. An object containing information about the token(s) you want to get the balances of.

For the second parameters, you can either pass an object with:

  • a mint property containing a PublicKey object, created from the token address of the token to get the balance of.
  • a programId property containing the token program of the tokens to get the balances of. You can pass either pass the TOKEN_PROGRAM_ID or the TOKEN_2022_PROGRAM_ID that you can import from '@solana/spl-token'

So to get the balance of a specific token, you would use that function like this:

const tokenPublicKey = new PublicKey('4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU');

const balance = await connection.getParsedTokenAccountsByOwner(
  fromPublicKey,
  {
    mint: tokenPublicKey,
  }
);

And if you want to get the balances of all the tokens that an address has, you would call it that way:

const balances = await connection.getParsedTokenAccountsByOwner(
  fromPublicKey,
  {
    programId: TOKEN_PROGRAM_ID,
  }
);

This function returns a pretty complex object with a lot of properties. The most straightforward way to get the balance, without having to convert it to the right unit or format it, is to use the uiAmount property:

const tokenBalance = balance.value[0]?.account.data.parsed.info.tokenAmount.uiAmount;

This will return a string containing the token balance in the right unit and format.

Keep in mind that token balances use 6 decimals so if you don't use that property, the token balance you will get will need to be divided by 10^6 to be in the correct unit so I recommend using the uiAmount to avoid any computation.

And you can also get the address of the token using the mint property:

const tokenAddress = balance.value[0]?.account.data.parsed.info.mint

Here is a complete example of what the getParsedTokenAccountsByOwner function returns:

{
    "context": {
        "apiVersion": "1.13.3",
        "slot": 174961389
    },
    "value": [
        {
            "account": {
                "data": {
                    "parsed": {
                        "info": {
                            "isNative": false,
                            "mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
                            "owner": "GX6nkQgcXy4xDyuSH9MKjG9nq5KN5ntE3ZUUHSqUrcC8",
                            "state": "initialized",
                            "tokenAmount": {
                                "amount": "990000000",
                                "decimals": 6,
                                "uiAmount": 990,
                                "uiAmountString": "990"
                            }
                        },
                        "type": "account"
                    },
                    "program": "spl-token",
                    "space": 165
                },
                "executable": false,
                "lamports": 2039280,
                "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                "rentEpoch": 0
            },
            "pubkey": "AqNjCUp2ZFf4oQvibNYhhVksN5Q7M1FGoB5kbwVJfnnN"
        },
        {
            "account": {
                "data": {
                    "parsed": {
                        "info": {
                            "isNative": false,
                            "mint": "Brqze44MbTjnSZReQQ87TaTdcWgbxVPYuZ8VMz93Ak8k",
                            "owner": "GX6nkQgcXy4xDyuSH9MKjG9nq5KN5ntE3ZUUHSqUrcC8",
                            "state": "initialized",
                            "tokenAmount": {
                                "amount": "100000000000",
                                "decimals": 9,
                                "uiAmount": 100,
                                "uiAmountString": "100"
                            }
                        },
                        "type": "account"
                    },
                    "program": "spl-token",
                    "space": 165
                },
                "executable": false,
                "lamports": 2039280,
                "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                "rentEpoch": 0
            },
            "pubkey": "Cvq5nDUM2x6YoC2hjUEQ49iDRg6p2AtaQhpFGmpB92B4"
        }
    ]
}

If you pass a specific token in the parameters, the value property will have a single object inside of it and if you fetched all the balances of all the tokens an address holds, there will be an object for each token.

If the address holds no tokens, the value property will be an empty array.

As you can see, the problem with that function is that you won't get much information about the token itself apart from its address.

When writing this article, there is no way to fetch information about a token using the libraries we used above.

To address that issue, you can create a JSON file that maps token addresses to token information (name, decimals and everything you want). Then, when you fetch the balances, you can use that JSON object to get information about a token using the address that is in the mint property.

And that's it! 🎉

Thanks for reading this article!