How to get all tokens by wallet address
Asked Answered
V

3

17

I am trying to pull a list of token contracts held by a wallet address, similar to how bscscan does, except programmatically. bscscan.com/apis does not have an endpoint, and web3js seems to only report the ETH balance.

This is possible to achieve, since bscscan reports the list and many token trackers ( such as farmfol.io ) also seem to pull that information. I am just not finding the correct methodology

Voyage answered 22/6, 2021 at 14:27 Comment(0)
V
28

ERC-20 (and ERC-20-like such as TRC-20, BEP-20, etc.) token balance of each address is stored in the contract of the token.

Blockchain explorers scan each transaction for Transfer() events and if the emitter is a token contract, they update the token balances in their separate DB. The balance of all tokens per each address (from this separate DB) is then displayed as the token balance on the address detail page.

Etherscan and BSCScan currently don't provide an API that would return the token balances per address.

In order to get all ERC-20 token balances of an address, the easiest solution (apart from finding an API that returns the data) is to loop through all token contracts (or just the tokens that you're interested in), and call their balanceOf(address) function.

const tokenAddresses = [
    '0x123',
    '0x456',
];
const myAddress = '0x789';

for (let tokenAddress of tokenAddresses) {
    const contract = new web3.eth.Contract(erc20AbiJson, tokenAddress);
    const tokenBalance = await contract.methods.balanceOf(myAddress).call();
}
Verenaverene answered 22/6, 2021 at 15:3 Comment(2)
Hi there. Thanks for your answer. Looking at your code I am wondering if in addition of all erc20 token addresses, you will also need their respective abis to make this work. Correct? Please clarify that for me if you can. Thanks againScrubland
@Scrubland In this case, you just need the ABI of the balanceOf() function, which is the same for all token contracts (assuming they all follow the ERC20 standard), because you're only calling this function... If you wanted to call other functions, you'd need to add them to the ABI as well.Verenaverene
G
1

You can call

https://api.bscscan.com/api?module=account&action=tokentx&address=0x7bb89460599dbf32ee3aa50798bbceae2a5f7f6a&page=1&offset=5&startblock=0&endblock=999999999&sort=asc&apikey=YourApiKeyToken

and parse the result. All your tokens you ever touched will be here.

BSCScan Reference

Giralda answered 23/3, 2022 at 17:47 Comment(0)
C
1

There are a few different ways you can pull a wallet's token balances.

  1. Index the entire blockchain since genesis, track all ERC-20 contracts in its txn history and compute token balances of wallets. Obviously would not recommend it -- it takes a lot of dev work and time.

  2. Use a Token API. Dev tools like Alchemy and Moralis have free ones.

In the case of Alchemy, use the "alchemy_getTokenBalances" endpoint. Detailed tutorial HERE, or just follow the steps below.

Prior to running the script

When querying the token balance for a user, you should have a couple of key parameters on hand:

OwnerAddress: This is the blockchain address that owns the tokens in question. Note that this is not the contract address of the token itself. tokenContractAddress: An array of contract addresses of all the tokens you want the balances for. Or if you specify the string erc20 it will include the entire set of erc20 tokens that the address has ever held.

The below instructions are for after you've set up an Alchemy account (it's free):

Method 1 (easiest): Use the Alchemy SDK + "alchemy_getTokenBalances" endpoint.

Run the below commands in the command line

// Setup: npm install alchemy-sdk
import { Alchemy, Network } from "alchemy-sdk";

const config = {
  apiKey: "<-- ALCHEMY APP API KEY -->",
  network: Network.ETH_MAINNET,
};
const alchemy = new Alchemy(config);

//Feel free to switch this wallet address with another address
const ownerAddress = "0x00000000219ab540356cbb839cbe05303d7705fa";

//The below token contract address corresponds to USDT
const tokenContractAddresses = ["0xdAC17F958D2ee523a2206206994597C13D831ec7"];

const data = await alchemy.core.getTokenBalances(
  ownerAddress,
  tokenContractAddresses
);

console.log("Token balance for Address");
console.log(data);

Method 2: Use Node-Fetch

import fetch from 'node-fetch';

// Replace with your Alchemy API key:
const apiKey = "demo";
const fetchURL = `https://eth-mainnet.g.alchemy.com/v2/${apiKey}`;

// Replace with the wallet address you want to query:
const ownerAddr = "0x00000000219ab540356cbb839cbe05303d7705fa";
/* 
Replace with the token contract address you want to query:
The below address Corresponds to USDT
*/
const tokenAddr = "0xdAC17F958D2ee523a2206206994597C13D831ec7";

var raw = JSON.stringify({
  "jsonrpc": "2.0",
  "method": "alchemy_getTokenBalances",
  "headers": {
    "Content-Type": "application/json"
  },
  "params": [
    `${ownerAddr}`,
    [
      `${tokenAddr}`,
    ]
  ],
  "id": 42
});

var requestOptions = {
  method: 'POST',
  body: raw,
  redirect: 'follow'
};

var data;

/*
** Fetching the token Balance with Alchemy's getTokenBalances API
*/
await fetch(fetchURL, requestOptions)
  .then(response => response.json())
  .then(response => {
    //This line converts the tokenBalance values from hex to decimal
    response["result"]["tokenBalances"][0]["tokenBalance"] = parseInt(response["result"]["tokenBalances"][0]["tokenBalance"], 16);
    data = response.result;
    console.log("Response Object for getTokenBalances\n", data)
  })
  .catch(error => console.log('error', error));
Candice answered 3/3, 2023 at 5:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.