第4节:ERC165(识别合约类型)
概述
在opensea中,我们能够知道一个NFT的具体协议类型,即这个collection到底是ERC721还是ERC1155,
而之所以能够判断出NFT的协议类型,是因为标准的NFT的代码都会遵循一个标准,即EIP-165。
EIP-165接口定义
EIP165提供了一种检测智能合约类型的方法,在实现上它只定义了一个接口,同时也明确了计算interfaceId的规则:对该协议(如NFT721)的所有接口selector的hash值做^运算(异或,XOR,^),再取前四字节作为interfaceId。
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
EIP165协议的interfaceId为0x01ffc9a7,计算公式:
0x01ffc9a7=bytes4(keccak256(supportsInterface.selector))
NFT721的interfaceid
// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface ERC721 /* is ERC165 */ {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
NFT721的interfaceId为:0x80ac58cd,计算公式为:
0x80ac58cd=bytes4(keccak256(ERC721.Transfer.selector)^keccak256(ERC721.Approval.selector) ^ ··· ^keccak256(ERC721.isApprovedForAll.selector))
当我们想判断一个合约的类型是否为NFT721时,只需检查一下supportsInterface(0x80ac58cd)
是否返回true即可。
NFT721Meta的interfaceId
// Note: the ERC-165 identifier for this interface is 0x5b5e139f.
interface ERC721Metadata /* is ERC721 */ {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) external view returns (string);
}
NFT721Meta的interfaceId为:0x5b5e139f,计算公式为:
0x5b5e139f=bytes4(keccak256(ERC721Metadata.name.selector)^keccak256(ERC721Metadata.symbol.selector)^keccak256(ERC721Metadata.tokenURI.selector))
在NFT721中实现supportsInterface
下面这个接口是NFT721中的标准实现
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
// 0x80ac58cd
interfaceId == type(IERC721).interfaceId ||
// 0x5b5e139f
interfaceId == type(IERC721Metadata).interfaceId ||
// 0x01ffc9a7
super.supportsInterface(interfaceId);
}
总结
- 当想检查一个NFT721是否实现了EIP165标准时,只需要查询:supportsInterface(0x01ffc9a7)的返回值即可,true表示支持,false表示不支持;
- 同样的道理:0x5b5e139f返回true表示支持IERC721Metadata,0x80ac58cd返回true表示为标准NFT721协议。