4

I'm using to get the balance of a single token/contract address within my wallet address.

If I have an array of tokens eg

[
    "0x2a9718deff471f3bb91fa0eceab14154f150a385",
    "0xad90c05bc51672eedfee36e58b3ff1a78bbc146d",
    "0x33a3d962955a3862c8093d1273344719f03ca17c",
    "0x85102c0062aa918cb9e26d94a284aafca602df13"
]

Is there a possibility to pass that array into a single call that retrieves the balance for each? Or would we need to iterate through the list one by one?

3 Answers 3

4

You cannot do this through regular JSONRPC calls, but it is possible to limit the number of calls needed by using a smart contract. You can use the library eth-scan to do this for you. Simply pass in the array of addresses, and it will fetch the balance for each token through the eth-scan smart contract.

By default, the library will do a single call for every 1,000 tokens, but this is configurable.

For example:

import { getTokensBalance } from '@mycrypto/eth-scan';
import Web3 from 'web3';

// Get a Web3 provider from somewhere
const web3 = new Web3;

const address = "0x....";
const tokens = [
  // ...
];

// `eth-scan` can use a Web3 provider, but Ethers.js, HTTP URLs and EIP-1193 providers
// (e.g., `window.ethereum`) are also supported
getTokensBalance(web3, address, tokens)
  .then(console.log)
  .catch(console.error);

Disclaimer: I am the author of eth-scan.

2
  • This sounds great, I'll give it a shot when I'm back at pc. Would this work for binance smart chain bep 20 tokens too? Great work on that btw
    – Gangrel
    May 1, 2021 at 12:16
  • 1
    The contract is currently not deployed on BSC, but assuming BSC is compatible with EVM smart contracts, it should work as well if the contract was deployed.
    – Morten
    May 1, 2021 at 12:21
1

You can use multicall to batch several call results to a single RPC call.

0

While you can use multicall to batch several RPC calls, you can also use Amazon Managed Blockchain Query to easily retrieve token balances for a batch of EOAs at finality (2 epochs on Ethereum) or from history (based on a timestamp). Specifically, you can use the BatchGetTokenBalance API. I've included some sample Node.js code to show you how to do this.

To run the sample code, the following prerequisites apply:

You must have node version manager (nvm) and Node.js installed on your machine. You can find installation instruction for your OS here.

Use the node --version command and confirm that you are using Node version 14 or higher. If required, you can use the nvm install 14 command, followed by the nvm use 14 command to install version 14. NOTE: Node 14, 15, 16 are now at end of life.

The environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must contain the credentials that are associated with the AWS account and user with IAM permissions to access Amazon Managed Blockchain Query.

    const axios = require('axios').default;
    const SHA256 = require('@aws-crypto/sha256-js').Sha256
    const defaultProvider = require('@aws-sdk/credential-provider-node').defaultProvider
    const HttpRequest = require('@aws-sdk/protocol-http').HttpRequest
    const SignatureV4 = require('@aws-sdk/signature-v4').SignatureV4
    
    // define a signer object with AWS service name, credentials, and region
    const signer = new SignatureV4({
      credentials: defaultProvider(),
      service: 'managedblockchain-query',
      region: 'us-east-1',
      sha256: SHA256,
    });
    
    const queryRequest = async (path, data) => {
      //query endpoint
      let queryEndpoint = `https://managedblockchain-query.us-east-1.amazonaws.com/${path}`;
      
      // parse the URL into its component parts (e.g. host, path)
      const url = new URL(queryEndpoint);
      
      // create an HTTP Request object
      const req = new HttpRequest({
        hostname: url.hostname.toString(),
        path: url.pathname.toString(),
        body: JSON.stringify(data),
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Accept-Encoding': 'gzip',
          host: url.hostname,
        }
      });
    
      
      // use AWS SignatureV4 utility to sign the request, extract headers and body
      const signedRequest = await signer.sign(req, { signingDate: new Date() });
      
      try {
        //make the request using axios
        const response = await axios({...signedRequest, url: queryEndpoint, data: data})
    
        console.log(response.data)
      } catch (error) {
        console.error('Something went wrong: ', error)
        throw error
      } 
    
     
    }
    
    
    let methodArg = 'batch-get-token-balance';
    
    let dataArg = {
    "getTokenBalanceInputs": [
        {
            "ownerIdentifier":{
                "address":"0x2a9718deff471f3bb91fa0eceab14154f150a385"
            },
            "tokenIdentifier":{
                "network":"ETHEREUM_MAINNET",
                "tokenId":"eth"
            }           
        },
        {
            "ownerIdentifier":{
                "address":"0xad90c05bc51672eedfee36e58b3ff1a78bbc146d"
            },
            "tokenIdentifier":{
                "network":"ETHEREUM_MAINNET",
                "tokenId":"eth"
            }           
        },
         {
            "ownerIdentifier":{
                "address":"0x33a3d962955a3862c8093d1273344719f03ca17c"
            },
            "tokenIdentifier":{
                "network":"ETHEREUM_MAINNET",
                "tokenId":"eth"
            }           
        },
        {
            "ownerIdentifier":{
                "address":"0x85102c0062aa918cb9e26d94a284aafca602df13"
            },
            "tokenIdentifier":{
                "network":"ETHEREUM_MAINNET",
                "tokenId":"eth"
            }           
        }
    ]
}
    
    //Run the query request.
    queryRequest(methodArg, dataArg);

While I showed how to get the ETH balance of each of the addresses you provided, you can also use this API to request balances for tokens (e.g. ERC20, ERC721, ERC1155) by defining an object in the request body array with the following syntax:

{
            "ownerIdentifier":{
                "address":"<externally owned address here>"
            },
            "tokenIdentifier":{
                "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", //USDC contract address, for example
                "network":"ETHEREUM_MAINNET"
            }           
}

The response will follow this format, paginating results listing tokens (ERC20, native ETH, ERC721/1155 NFTs) for a list of token balances requested:

{
    "errors": [],
    "tokenBalances": [
        {
            "atBlockchainInstant": {
                "time": 1.69645255E9
            },
            "balance": "12798225245872899819",
            "lastUpdatedTime": {
                "time": 1.644268594E9
            },
            "ownerIdentifier": {
                "address": "0x2a9718deff471f3bb91fa0eceab14154f150a385"
            },
            "tokenIdentifier": {
                "network": "ETHEREUM_MAINNET",
                "tokenId": "eth"
            }
        },
        {
            "atBlockchainInstant": {
                "time": 1.69645255E9
            },
            "balance": "16000000000000000",
            "lastUpdatedTime": {
                "time": 1.619206298E9
            },
            "ownerIdentifier": {
                "address": "0xad90c05bc51672eedfee36e58b3ff1a78bbc146d"
            },
            "tokenIdentifier": {
                "network": "ETHEREUM_MAINNET",
                "tokenId": "eth"
            }
        },
        {
            "atBlockchainInstant": {
                "time": 1.69645255E9
            },
            "balance": "254939146214820996",
            "lastUpdatedTime": {
                "time": 1.634617233E9
            },
            "ownerIdentifier": {
                "address": "0x33a3d962955a3862c8093d1273344719f03ca17c"
            },
            "tokenIdentifier": {
                "network": "ETHEREUM_MAINNET",
                "tokenId": "eth"
            }
        },
        {
            "atBlockchainInstant": {
                "time": 1.69645255E9
            },
            "balance": "122981200000000000",
            "lastUpdatedTime": {
                "time": 1.619653947E9
            },
            "ownerIdentifier": {
                "address": "0x85102c0062aa918cb9e26d94a284aafca602df13"
            },
            "tokenIdentifier": {
                "network": "ETHEREUM_MAINNET",
                "tokenId": "eth"
            }
        }
    ]
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.