edit) VM execution error was a bug on Web3, confirmed my code works fine.

I am trying to fetch random addresses from blockchain and trying to categorize them if it is an ERC20 contract address or not.

I've tried with web3.eth.call to check if the contract has a method totalSupply() but there was no success on that thing, with the single address it works fine however at the production stage it returns an odd (node:10722) UnhandledPromiseRejectionWarning: Error: Returned error: VM execution error.

Referring related documents or codes wouldn't help with me unless with web3 1.0.

Here is my code that doesn't work

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider(""));

var ABI = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}];

var myContract = new web3.eth.Contract(ABI, "0x085b0fdf115aa9e16ae1bddd396ce1f993c52220");

async function checkAddress() {
  var call = await web3.eth.call({ to: "0x085fb4f24031eaedbc2b611aa528f22343eb52db", data:web3.utils.sha3("totalSupply()")});
  if (call != '0x') {
    console.log('ERC20 token detected');
  } else {
    console.log('Not an ERC20 token address');
  • with the single address it works fine - what does that suppose to mean? Commented Mar 20, 2019 at 13:50
  • Side note: Not every contract which implements function totalSupply is an ERC20 contract. Commented Mar 20, 2019 at 13:51
  • @goodvibration Got it, however totalsupply is needed, Commented Mar 20, 2019 at 13:54
  • For "with the single address it works fine", single query with single address works fine, however multiple address query will always return an error Commented Mar 20, 2019 at 13:55
  • Why don't you share your multiple address query code then? If that is where the problem is, then we need to see it, don't you think? Also, be advised that you are calling checkAddress without awaiting for it to complete. It will work fine as long as you don't do anything else after that (which depends on this function-call). But if you do several things (for example, calling it multiple times), then you may possibly need to await for each function call to complete. Without seeing your code, it would be difficult to know for sure. Commented Mar 20, 2019 at 14:12

3 Answers 3


I think you should check a few conditions with different ABIs:

  1. Events Transfer(address,address,uint256) and Approval(address,address,uint256) should be emitted in case of any existing transactions to this smart contract

  2. Methods name(), symbol() could return bytes32 or string

  3. Method decimals() could return uint8 or uint256

  4. Method totalSupply() should return uint256

  5. Method balanceOf(address) should return uint256 for any argument

  • The deployed EVM code does not have any metadata associated with it. You do not know what functions code entry point exposes to the transactions. Commented Mar 22, 2019 at 11:09
  • Furthermore your points 1, 2 and 3 are a bit incorrect: those are not required by the standard. (Yes, the event signatures are required but the standard doesn't require you to actually emit them) Commented Mar 22, 2019 at 18:24
  • @LauriPeltonen my answer contains the most practical recommendations, do you agree?
    – k06a
    Commented Mar 23, 2019 at 19:18
  • 1
    @MikkoOhtamaa you should form those ABIs on your own.
    – k06a
    Commented Mar 23, 2019 at 19:22
  • 1
    @LauriPeltonen eips.ethereum.org/EIPS/eip-20 it is clearly stated in the standard that events MUST be fired on successful transfers and approvals. Commented Mar 24, 2019 at 0:39

This answer is not exactly for your web3 needs but more of a generic answer. I asked a very similar question some time ago here: How is a contract determined to be ERC20 compliant?

So, in the end, if the signatures are correct then it's considered an ERC20 contract. The actual implementation doesn't matter as long as the signatures are correct.

As for how to finding signatures from a deployed contract: as I see it you have two options:

1) Reverse-engineer the bytecode and try to find the signatures from there. This isn't necessarily possible or very easy: How can you decompile a smart contract?

2) Issue all the relevant transactions (calling each ERC20 function) to the contract and see if they go through. This basically requires that you guess the ABI, part by part (it's easy enough to guess if it's ERC20 contract).

  • And how to verify the signatures? Using call method or something else? Commented Mar 21, 2019 at 4:07
  • Can you share me a code so I can understand? Commented Mar 21, 2019 at 4:08
  • Edited my answer to issue your questions. But not, I don't have any ready code available. Commented Mar 21, 2019 at 4:26

If you want to use an API it's dead simple. Amberdata's /addresses/:hash/information endpoint returns of list of contract types like so...


curl --request GET \
  --url https://web3api.io/api/v1/addresses/0x06012c8cf97bead5deae237070f9587f8e7a266d/information \
  --header 'x-api-key: <x-api_key>'


  "status": 200,
  "title": "OK",
  "description": "Successful request",
  "payload": [
      "firstSeen": "2017-11-23T05:41:19.000Z",
      "type": "contract",
      "contractTypes": [
        "ERC721"      // <-- Here's what you are looking for
      "probability": 1,
      "network": {
        "name": "Ethereum",
        "network": "Mainnet",
        "slug": "ethereum-mainnet",
        "blockchainId": "1c9c969065fcd1cf",
        "link": "https://ethereum-mainnet.amberdata.io/addresses/0x06012c8cf97bead5deae237070f9587f8e7a266d"

This is the Cryptokitties address and as you can see it returns a contract type of ERC712.

If you have an API key (it's free) you can try it out here.

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.