Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if an Ethereum address is an ERC20 token contract?

If I only get an Ethereum address from the input, is there a way to find out whether it matches the ERC20 token standard?

like image 902
kaichen Avatar asked Jul 28 '17 03:07

kaichen


People also ask

How do you check if an address is ERC20?

To view your ETH or ERC-20 address, navigate and select the Deposit Ether Directly tab. Then click on View Account to see and copy your address. You can now paste the Ethereum address on airdrop portals requesting an ERC-20 address to receive free tokens.

Is Ethereum address ERC20?

One of the most significant smart contract standards on Ethereum is known as ERC-20, which has emerged as the technical standard used for all smart contracts on the Ethereum blockchain for fungible token implementations.

How do you find out if an Ethereum address is a contract?

Each Ethereum address has a code field associated with it. If the address is not a smart contract, this field would be empty. If the extcodesize checks the code size of the address is zero, then the address is a regular one. If it finds the code size greater than zero, it is a smart contract.


2 Answers

ERC165 tackles this problem, but, unfortunately, most ERC20 implementations don't support it (as of Nov 2018, at least OpenZeppelin doesn't). This means that you could try calling the supportsInterface function, but it would revert anyway and you'd rather complicate things.

Nevertheless, here's how it's defined in ERC721:

bytes4 private constant _InterfaceId_ERC721 = 0x80ac58cd;
/*
 * 0x80ac58cd ===
 *   bytes4(keccak256('balanceOf(address)')) ^
 *   bytes4(keccak256('ownerOf(uint256)')) ^
 *   bytes4(keccak256('approve(address,uint256)')) ^
 *   bytes4(keccak256('getApproved(uint256)')) ^
 *   bytes4(keccak256('setApprovalForAll(address,bool)')) ^
 *   bytes4(keccak256('isApprovedForAll(address,address)')) ^
 *   bytes4(keccak256('transferFrom(address,address,uint256)')) ^
 *   bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
 *   bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
 */

Although it's not guaranteed for all implementations to define the interface id, there's a higher chance it will work in the case of ERC721, given the fact the community agreed on applying ERC165 right from the get-go. If the return value of the query below is true, then it means you have a compliant contract, otherwise just revert the transaction.

// you can call this in your contracts
IERC721(contractAddress).supportsInterface(0x80ac58cd)

Also, a useful resource for manually checking the bytes4 of a given method is 4byte.directory

like image 144
Paul Razvan Berg Avatar answered Sep 27 '22 22:09

Paul Razvan Berg


If you are asking about off-chain, so use these functions:

getContract(url, smartContractAddress){
    const Web3Eth = require('web3-eth');

    const abi_ = this.getABI();
    const web3Eth = new Web3Eth(Web3Eth.givenProvider || url);
    return new web3Eth.Contract(abi_, smartContractAddress);
}

async getERCtype(contract){
    const is721 = await contract.methods.supportsInterface('0x80ac58cd').call();
    if(is721){
        return "ERC721";
    }
    const is1155 = await contract.methods.supportsInterface('0xd9b67a26').call();
    if(is1155){
        return "ERC1155";
    }
    return undefined;
}

getABI(){
    return [         
        {"constant":true,"inputs": [
                {"internalType":"bytes4","name": "","type": "bytes4"}],
            "name": "supportsInterface",
            "outputs": [{"internalType":"bool","name": "","type": "bool"}],
            "payable": false,"stateMutability":"view","type": "function"}         
    ];
}

like this:

const contract = getContract(url, smartContractAddress);
const type = await getERCtype(contract);
console.log(type);
like image 29
Silvio Guedes Avatar answered Sep 27 '22 22:09

Silvio Guedes