📑

【Solidity】ERC165を読んでみる

2022/11/17に公開

ERC721で継承されているERC165とは何者か?と気になったのでコントラクトを読んでみました。
その結果を備忘録を兼ねて記事にまとめています。

ERC721

ERC165が継承されているのが確認できます。

ERC721.sol
pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {

ERC165

https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/utils/introspection

コードが短いので、全文を載せておきます。
まずはInterfaceを定義しているIERC165.solを見てみます。

以下はコメントをDeepLで翻訳したものです。
要は、コントラクトでサポートしているInterfaceを他者から問い合わせ可能にする規格のようです。

ERC165 規格のインターフェースで、以下のように定義されています。 https://eips.ethereum.org/EIPS/eip-165[EIP].
実装者はコントラクトインターフェースのサポートを宣言することができ、そのインターフェイスを他者({ERC165Checker})が照会することができる。
実装者はコントラクトインターフェースのサポートを宣言することができ、それを他者({ERC165Checker})が問い合わせることができる。
実装については、{ERC165}を参照。

このコントラクトが interfaceId で定義されたインターフェースを実装している場合、true を返します。
定義されたインターフェイスを実装しているかどうかを返します。
これらのIDがどのように作成されるかについては、対応する EIP セクション を参照してください。
この関数呼び出しは、30,000ガス未満でなければなりません。

IERC165.sol
pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
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);
}

次にERC165.solを見ていきます。
supportsInterface関数はvirtualのため、overrideして使用します。

自分で新たなInterfaceを作成して継承した場合は、overrideして追加していきます。

{IERC165} インターフェースの実装です。
ERC165 を実装したいコントラクトは、このコントラクトを継承して {supportsInterface} をオーバーライドし、サポートされる追加インターフェース ID をチェックする必要があります。
サポートされる追加インターフェース ID をチェックする。例えば...(コード省略)
あるいは、{ERC165Storage}はより使いやすいですが、より高価な実装を提供しています。

ERC165.sol
pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

overrideする場合はこのように書きます。

SampleContract.sol
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
}

Discussion