8

The following code works for me to read Ether value from wallet:

var web3Instance =  new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

export async function readAccountEtherValue(address: string): Promise<number> {
    var balance = await web3Instance.eth.getBalance(address);
    return web3Instance.utils.fromWei(balance, "ether");
}

How can I read the values of all tokens from the wallet?

4 Answers 4

3

Token balances are not stored in a user's wallet. They are stored in the corresponding Token contract. Assuming the token you want to read the balance from is an ERC20 token, then you would have to instantiate the token contract and then call balanceOf(address) to get the address' balance. For example:

let token = await ERC20Basic.at(_tokenAddress);
let balance = await token.balanceOf(accounts[0]);
3
  • 1
    OMG that means I have to write a different code for each token in the entire world?
    – Alon
    Commented Dec 7, 2017 at 15:53
  • Not necessarily, tokens that are ERC20 compliant all follow the specification and have these common functions, for example balanceOf(). What you would need to do in order to read each one is just change the address of the token you want to get the balance of. You could write a function that loops through a list of token addresses and returns each one's balance for a particular user. Commented Dec 7, 2017 at 15:55
  • 1
    OK then how can I know which tokens implement ERC20, and how can I know all the existing tokens and know what's their interface? There are websites like etherscan.io that are able to read every existing token, even many tokens that are not listed on Coinmarketcap.
    – Alon
    Commented Dec 7, 2017 at 16:07
2

You could instead use the event Transfer to filter by that. You will probably need an almost full node:

const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));
const transferEventTopic = web3.sha3("Transfer(address,address,uint256)");
const myAddress = "0x0000000000000000000000003f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be";
const fromBlock = 4647513;
const myBalances = {};

const filter = web3.eth.filter({
        fromBlock: fromBlock,
        topics: [ transferEventTopic ]
    });

filter.watch((err, obj) => {
        if (err) {
            console.error(err);
        } else {
            if (typeof myBalances[obj.address] === "undefined") {
                myBalances[obj.address] = web3.toBigNumber(0);
            }
            let message = "Token " + obj.address;
            let changed = false;
            if (obj.topics[1] == myAddress) {
                changed = true;
                myBalances[obj.address] = myBalances[obj.address].minus(obj.data);
                message += ", Sent " + web3.toBigNumber(obj.data).toString(10);
            } else if (obj.topics[2] == myAddress) {
                changed = true;
                myBalances[obj.address] = myBalances[obj.address].plus(obj.data);
                message += ", Received " + web3.toBigNumber(obj.data).toString(10);
            }
            if (changed) {
                message += ", Balance " + myBalances[obj.address].toString(10);
                console.log(message);
            }
        }
    });

process.on('SIGINT', () => {
    console.log("Stop watching");
    filter.stopWatching(console.log);
    process.exit();
});

If you only want the events that denote "receive", then replace the topics as topics: [ transferEventTopic, null, myAddress ].

If you only want the events that denote "send", then replace it is topics: [ transferEventTopic, myAddress ].

4
  • Does that code iterate all the wallets in the entire world until it finds mine?
    – Alon
    Commented Dec 8, 2017 at 5:01
  • 1
    That code iterates all the events and filters for your wallet. So yes, heavy. To be faster and less heavy, use the 2 filters listed at the bottom. Commented Dec 8, 2017 at 13:08
  • Well it seems that maybe blockchain is not such a great architecture after all. While I assume your code is the formally correct answer, I seriously consider using a workaround, like reading from a website that has already calculated my token balances. How long do you think it's going to take a program to iterate all the blocks ever since 4647513, as your code does? (I'm not cynical, I'm asking seriously in order to make a decision)
    – Alon
    Commented Dec 10, 2017 at 3:23
  • That would take a sizeable fraction of an hour, I reckon. But this only needs be done once, for all balances. You are correct, blockchain cannot satisfy all your db needs, its needs external aggregators. The benefit you get from these Transfer events is the certainty they happened. Commented Dec 11, 2017 at 10:24
2

You can now use Amazon Managed Blockchain Query to easily retrieve a full list of token balances for a given EOA at finality (2 epochs on Ethereum) or from history (based on a timestamp). 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 = 'list-token-balances';

let dataArg = {
"ownerFilter": {"address":"<externally owned account address here"},
"tokenFilter":{"network":"ETHEREUM_MAINNET"}
}

//Run the query request.
queryRequest(methodArg, dataArg);

The response will follow this format, paginating results listing tokens (ERC20, native ETH, ERC721/1155 NFTs) for an EOA:

    {
   "nextToken": "string", // pagination
   "tokenBalances": [ 
      { 
         "atBlockchainInstant": { 
            "time": number //timestamp 
         },
         "balance": "string", // balance for a token as a string
         "lastUpdatedTime": { 
            "time": number // timestamp of when data was last updated
         },
         "ownerIdentifier": { 
            "address": "string" // EOA address
         },
         "tokenIdentifier": { 
            "contractAddress": "string", // contract address for token
            "network": "string", // network (e.g. Ethereum mainnet)
            "tokenId": "string" // token ID if it's an NFT
         }
      }
   ]
}

 
0

I just recently wrote a smart contract and library for this, and put it into an NPM package. You can find the package here: https://www.npmjs.com/package/eth-balance-checker

The code would look like this, but you should read the README for that package to make sure you know how it works:

import { getAddressBalances } from 'eth-balance-checker/lib/web3';

const address = '<your_address_here>';
const tokens = ['<token>', '<addresses>', '<here>'];
getAddressBalances(web3, address, tokens).then(balances => {
  console.log(balances); // { "0x0": "100", "0x456...": "200" }
});

You can find lists of tokens to use in your project in various places. MyCrypto has a pretty comprehensive list: https://github.com/MyCryptoHQ/MyCrypto/blob/develop/common/config/tokens/eth.json

1
  • needs maintenance, does not work anymore due to old libraries used.
    – sed
    Commented May 17, 2021 at 2:27

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.