🆔
ERC-165: Standard Interface Detection
ERC-165: Standard Interface Detection
なんなの?
スマートコントラクトが実装するインターフェイスを公開および検出するための標準メソッドを定義
= インターフェイス識別子を算出する方法を定義
なぜ必要なの?
対象のコントラクトがERC-20などのインターフェイスを実装しているか確認する手段がなかったため
どうやってインターフェイス識別子を取得するの?
インターフェイス内のすべての関数セレクタの排他的論理和(XOR)。
関数セレクタとは、関数の名前と引数をKeccak-256でハッシュにして最初の4バイトを取ったもの。
→ https://docs.soliditylang.org/en/v0.8.17/abi-spec.html?highlight=selector#function-selector
pragma solidity ^0.4.20;
interface Solidity101 {
function hello() external pure;
function world(int) external pure;
}
contract Selector {
function calculateSelector() public pure returns (bytes4) {
Solidity101 i;
return i.hello.selector ^ i.world.selector;
}
}
どうやって実装するの?
pragma solidity ^0.4.20;
interface ERC165 {
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
上のインターフェイスのインターフェイス識別子は
bytes4(keccak256('supportsInterface(bytes4)'));
で求めることができる。(関数が1つなのでこのような形だが、複数あればXORでつなげる)
結果は0x01ffc9a7
である。
詳細な定義
- 引数
interfaceID
が0x01ffc9a7
だったらtrue
を返す - 引数
interfaceID
が0xffffffff
だったらfalse
を返す - このインターフェイスを実装しているコントラクトだったら、
true
を返す - それ以外の場合
false
を返す - このメソッドの実行に使用するgasは30000以下にする必要がある
OpenZeppelinのEIP165の実装
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
type(I).interfaceId
は以下を返す
与えられたインターフェイスIのEIP-165インターフェイス識別子を含むbytes4値。この識別子は、インターフェイス自体で定義されたすべての関数セレクタのXORとして定義されます - 継承されたすべての関数を除く。
OpenZeppelinのEIP721の実装
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
参照
Discussion