I'm trying to fetch the balance of a token for a given address using web3 and truffle console, but the problem is that it always returns a 0 hex string (i.e. '0x0000000000000000000000000000000000000000000000000000000000000000')

The token I'm using is: 0x607F4C5BB672230e8672085532f7e901544a7375

The address I'm using to check the balance is: 0x7c195D981AbFdC3DDecd2ca0Fed0958430488e34 (not mine, just a random address). I can verify at the moment of running the commands that the balance in this address is about 49.100 tokens in Etherscan.

First of all, I create a fork of the current blockchain state using ganache-cli

Then I open the truffle console and input the following commands

let token = '0x607F4C5BB672230e8672085532f7e901544a7375'
let target = '0x7c195D981AbFdC3DDecd2ca0Fed0958430488e34'
let balance_function = web3.utils.sha3('balanceOf(address)').substring(0,10)
let calldata = {to:token,data:balance_function + target.substring(2)}
let result = web3.eth.call(calldata)

This results in a balance of 0 from the target address, but still cant figure out why. Strange thing is that if I do the same process to get for intance the totalSupply() it works just fine.

Could it be that creating a fork of the current state with ganache-cli doesn't copy the state of ERC20 token balances?


The problem is that the address has to be padded to 32 bytes with zero bytes (64 hex digits), since addresses are 20 bytes (40 hex digits) you have to add 24 zero digits.

let token = '0x607F4C5BB672230e8672085532f7e901544a7375'
let target = '0x7c195D981AbFdC3DDecd2ca0Fed0958430488e34'
let balance_function = web3.utils.sha3('balanceOf(address)').substring(0,10)
let padding = '000000000000000000000000'
let calldata = {to:token,data:balance_function + padding + target.substring(2)}
let result = web3.eth.call(calldata)

Calldata has to have a length of 74 characters (including the initial '0x').

  • Thanks a lot! I have one more question regarding this, do only addresses need to be padded? Or also If I pass a uint256 for instance in hex also should be padded to 32 bytes? Are there any exceptions for the parameters passed in the calldata, or does each one of the parameters need to be represented by 32 bytes? Thanks again!
    – Hiperfly
    Jun 4 at 8:14
  • 1
    @Hiperfly For simple types like uintXXX, bytesYY they have to be padded to 32 bytes, for dynamic types like string, array, struct is more complicated in that case is better to create the ABI file. For the details of the spec see the solidity documentation docs.soliditylang.org/en/v0.8.4/abi-spec.html.
    – Ismael
    Jun 4 at 14:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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