# ERC165使用方法 **Published by:** [xyyme.eth](https://paragraph.com/@xyyme/) **Published on:** 2022-03-11 **URL:** https://paragraph.com/@xyyme/erc165 ## Content 了解过 NFT 合约的同学应该注意到,每个 NFT 合约都实现了 supportsInterface 方法,但是每个合约中的具体方法实现又不尽相同,那么在实际开发过程中,究竟应该怎么实现这个方法呢,这篇文章就来讲讲这个内容ERC165的具体内容这里就不再多说了,不了解的同学可以 Google 一下首先我们需要知道计算一个接口的 interfaceId 都有几种方法。 假设对于如下接口:interface IExample { function foo() external view returns (uint); function bar() external view returns (bool); function baz() external view returns (bytes32); } 那么可以这样计算它的 interfaceId使用硬编码函数签名计算(不推荐,容易出错且麻烦)function calcInterfaceId1() public view returns (bytes4) { return bytes4(keccak256("foo()")) ^ bytes4(keccak256("bar()")) ^ bytes4(keccak256("baz()")); } 使用方法 selector 计算(不推荐,不过在 0.6.7 之前的版本要用这个)function calcInterfaceId2() public view returns (bytes4) { IExample i; return i.foo.selector ^ i.bar.selector ^ i.baz.selector; } 直接使用 type 关键词(推荐,0.6.7版本及之后支持)function calcInterfaceId3() public view returns (bytes4) { return type(IExample).interfaceId; } 这三种方法都可以用来计算 interfaceId,结果相同,都是 0x9bb235aa。 接下来,我们看看实际开发中都是怎么实现 supportsInterface 方法的。 来看几个例子:同时继承与实现包含 IERC165 的合约(ERC721)和接口(IERC2981)Invisible Friends → 代码// 合约继承了 ERC721,实现了 IERC2981接口 contract InvisibleFriends is ERC721, IERC2981, Ownable, ReentrancyGuard { } // override 后面包括 ERC721 和 IERC2981 的最上层基类 IERC165 function supportsInterface(bytes4 interfaceId) public view override(ERC721, IERC165) returns (bool) { // 需要显式声明 IERC2981 return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); } 合约实现的基类中,ERC721 和 IERC2981 中都包括 IERC165,因此需要显式重写 supportsInterface 方法。override后面的括号需要包含 ERC721,由于 IERC2981 是接口,因此要包含 IERC2981 的最上层基类 IERC165,同时需要在方法实现中显示声明 IERC2981 接口本身。同时继承多个包含 IERC165接口的合约(ERC721,ERC721Enumerable)mfers → 代码// 合约继承了 ERC721,ERC721Enumerable contract mfers is ERC721, ERC721Enumerable, Ownable { } // override 后面包括 ERC721 和 ERC721Enumerable function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { // 无需显式声明接口 return super.supportsInterface(interfaceId); } 合约实现的基类中,ERC721 和 ERC721Enumerable 中都包括 IERC165。因此需要显式重写 supportsInterface 方法。而由于两者均非接口,因此直接在 override 后面声明。在方法实现中无需显式声明。只继承一个包含 IERC165 接口的合约(ERC721A)Tasty Bones → 代码// 合约继承了 ERC721 contract TastyBones is Ownable, ERC721A, ReentrancyGuard { } // 没有显式实现 supportsInterface 方法 合约实现的基类中,只有 ERC721A 一个合约包括 IERC165 接口,因此合约的最终实现无需显式实现 supportsInterface 方法。 这三个合约基本上代表了几种具体实现方式,总结一下:如果合约继承的基类中只有一个合约包含 IERC165,即没有冲突,那么无需显式实现如果基类中存在 IERC165 冲突,且均非接口,需要显式实现,override 之后需要包括这些基类名,方法实现中无需显式包括合约如果基类中存在 IERC165 冲突,且存在接口,需要显式实现,override 之后需要包括合约以及接口的最上层基类 IERC165,方法实现中需要显式包括继承的接口参考ERC-165: Standard Interface DetectionCreates a standard method to publish and detect what interfaces a smart contract implements.https://eips.ethereum.org ## Publication Information - [xyyme.eth](https://paragraph.com/@xyyme/): Publication homepage - [All Posts](https://paragraph.com/@xyyme/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@xyyme): Subscribe to updates - [Twitter](https://twitter.com/xyymeeth): Follow on Twitter