如何检测以太坊地址是不是为 ERC20 代币合约?

Posted

技术标签:

【中文标题】如何检测以太坊地址是不是为 ERC20 代币合约?【英文标题】:How to detect if an Ethereum address is an ERC20 token contract?如何检测以太坊地址是否为 ERC20 代币合约? 【发布时间】:2018-01-03 23:23:33 【问题描述】:

如果我只从输入中得到一个以太坊地址,有没有办法找出它是否符合ERC20 令牌标准?

【问题讨论】:

请发布您已经尝试过的内容。这是打算在链上(在智能合约内)还是在链下(可能使用 web3js)工作? 【参考方案1】:

如果您询问的是链外,请使用以下功能:

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"         
    ];

像这样:

const contract = getContract(url, smartContractAddress);
const type = await getERCtype(contract);
console.log(type);

【讨论】:

【参考方案2】:

ERC165 解决了这个问题,但不幸的是,大多数 ERC20 实现不支持它(截至 2018 年 11 月,至少 OpenZeppelin doesn't)。这意味着您可以尝试调用supportsInterface 函数,但无论如何它都会恢复,您宁愿让事情复杂化。

不过,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)'))
 */

虽然不能保证所有实现都定义接口 ID,但考虑到社区从一开始就同意应用 ERC165 的事实,它在 ERC721 的情况下工作的可能性更高。如果下面查询的返回值为真,那么说明你有一个合规的合约,否则就恢复交易。

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

另外,手动检查给定方法的bytes4 的有用资源是4byte.directory

【讨论】:

【参考方案3】:

有很多可能的方法来实现这一点。一种可能的快速而肮脏的解决方案是通过调用以下命令来检查合约地址上是否存在 ERC20 函数:

eth.call(to:contractAddress, data:web3.sha3("balanceOf(address)"))

非 ERC20 将返回“空”0x 十六进制响应,而 ERC20 将为您提供 32 字节的 uint,在本例中为 0,但如果您在数据中提供地址,那么它将为您提供实际的地址该地址的代币余额。

这不是确定合约是否为 ERC20 的保证方法,因为其他合约可能会公开相同的功能,但它是一种快速简便的检查。您可以在totalSupply() 等上添加额外的电话以获得更多确认。

【讨论】:

我在想这里的 eth 是什么? @MrHash 我认为 OP 正在寻求一种可靠的方法。

以上是关于如何检测以太坊地址是不是为 ERC20 代币合约?的主要内容,如果未能解决你的问题,请参考以下文章

以太坊ERC20代币开发

以太坊私链部署erc20_usdt代币

以太坊 USDT-ERC20合约 注释版

以太坊 USDT-ERC20合约 注释版

第三方可以向以太坊区块链发送 ERC20 代币交易吗?

获取以太坊 ERC-20 代币信息的正确方法