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

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

3
请发布您已经尝试过的内容。这是打算在链上(智能合约内部)还是链下(可能使用web3js)工作? - William Entriken
4个回答

8

ERC165 解决了这个问题,但是很不幸,大多数 ERC20 实现都不支持它(至少在 2018 年 11 月之前,OpenZeppelin 不支持)。这意味着您可以尝试调用 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,但在ERC721的情况下,有更高的机会能够成功,因为社区一开始就同意应用ERC165。如果以下查询的返回值为true,则意味着您拥有符合要求的合约,否则请撤销交易。

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

此外,一个有用的资源可以手动检查给定方法的bytes4,请访问4byte.directory

5
如果你询问的是离线交易(off-chain),那么请使用以下函数:
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);

3

有很多实现这个目标的可能性。其中一种可能的简单粗暴的解决方案是通过调用以下内容检查合约地址上是否存在ERC20函数:

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

非ERC20代币将返回 'null' 0x,而ERC20代币将返回32字节的uint,在此情况下为0,但如果您在数据中提供地址,则它将为您提供该地址的实际代币余额。

这不是确定合约是否为ERC20的保证方式,因为其他合约可能会公开相同的函数,但这是一种快速简便的检查方法。您可以添加其他调用例如 totalSupply() 等等以获得更多确认。


1
我在思考这里的eth是什么? - Szymon Roziewski
2
@MrHash 我认为原帖的作者是在问如何在Solidity中实现这一点。 - Paul Razvan Berg

0

问题陈述为:给定一个以太坊地址,这是一个以太坊合约地址还是外部拥有账户地址?

首先,您必须确定此地址是合约地址还是外部拥有账户地址。如何确定以太坊地址是否为合约地址

如果它是一个合约地址,那么您只能获取存储在区块链中的字节码。现在,您需要反向工程字节码以获取合约函数,但这几乎是不可能的。有一些反编译器,但它们不能完美地从字节码创建合约代码。

ERC165仅检查当前合约签名是否支持给定的接口ID。由于您只有以太坊地址,在这个问题中这并没有帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接