EthereumのERC1820 Pseudo-introspection Registry Contract(擬似説明を行うレジストリコントラクト)について説明します。
このEIPはERC | Ethereum Improvement Proposals においてファイナライズされた提案であり、ERCとして正式登録されています。
ERC1820の公式定義はこちらで、
こちらに基づいて説明を書いていきます。
何をするコントラクトか
ERC1820はあるアドレスと実装内容の説明マッピングを管理することができます。例えば、ERC20トークンはそれ自体にトークン名などを設定していますが、コントラクトの中身を見るまでERC20であるかどうかの説明はわかりません。 このコントラクトでは、アドレスがERC20であるか、ERC721であるかなどを管理しておくことでアドレスの説明を閲覧できます。
またこれ自体は特殊なERCで、
ERC20などと違って、Ethereumブロックチェーン内に1個しかコントラクトを持ちません。なぜなら、Ethereumブロックチェーン内で説明を保存する共通の台帳コントラクトという位置付けだからです。
そのため、ERCにデプロイするためのhexが固定されており、アドレスも固定です。
アドレスとそのインターフェースを管理するinterfacesマッピング
ERC1820コントラクトには、アドレスとインターフェースの組み合わせを管理するマッピングを持っています。
基本的にはERC1820内の以下マッピングを更新していきます。
(このマッピングを設定するアドレス:
(インターフェースの名付けをする文字列(bytes32型):定義インターフェースが実装されているコントラクトアドレス)
)
というマッピング定義です。
/// @notice mapping from addresses and interface hashes to their implementers. mapping(address => mapping(bytes32 => address)) internal interfaces;
ERC1820でinterfaceに関連する関数は以下で、setやgetなどがありますね。
function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) { function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external { function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) {
addressの管理権限を設定するmanagersマッピング
ERC1820ではmanagersというマッピングも設定できます。managersは、interfacesに登録するアドレスの管理アドレスを設定できます。managerに設定されているアドレスは、manager管理下のアドレスについてinterfacesに登録できます。
managersマッピングは以下で、(対象アドレス:managerアドレス)のマッピングです。
/// @notice mapping from addresses to their manager. mapping(address => address) internal managers;
managersマッピングに関連する関数は以下になります。
function setManager(address _addr, address _newManager) external { function getManager(address _addr) public view returns(address) {
どのように呼び出されるか、ERC1400の実装からみてみる
ConsenSysのセキュリティトークン実装であるERC1400ではこのERC1820コントラクトが使われています。ERC1820を呼び出す実装をERC1820Clientコントラクトとして実装しています。
Client実装から、ERC1400.solのコンストラクタでERC1820の関数を呼び出しています。こちらでは"ERC1400Token"をインターフェースのラベル付け文字列として使っています。
// ERC1400.solのコンストラクタ。setInterfaceImplementationで呼び出している constructor( string memory name, string memory symbol, uint256 granularity, address[] memory controllers, address certificateSigner, bytes32[] memory defaultPartitions ) public ERC1400Partition(name, symbol, granularity, controllers, certificateSigner, defaultPartitions) { // "ERC1400Token"というラベルとこのSTのアドレスを引数にしている setInterfaceImplementation("ERC1400Token", address(this)); _isControllable = true; _isIssuable = true; } /// Base client to interact with the registry. contract ERC1820Client { // 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24はERC1820のアドレス ERC1820Registry constant ERC1820REGISTRY = ERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); // interfacesを登録する関数 function setInterfaceImplementation(string memory _interfaceLabel, address _implementation) internal { bytes32 interfaceHash = keccak256(abi.encodePacked(_interfaceLabel)); ERC1820REGISTRY.setInterfaceImplementer(address(this), interfaceHash, _implementation); } // 登録済interfacesにアクセスするための関数 function interfaceAddr(address addr, string memory _interfaceLabel) internal view returns(address) { bytes32 interfaceHash = keccak256(abi.encodePacked(_interfaceLabel)); // 引数のラベルをkeccak256ハッシュ化 return ERC1820REGISTRY.getInterfaceImplementer(addr, interfaceHash); } // address(this)- ここではERC1400アドレスのmanagerを設定する function delegateManagement(address _newManager) internal { ERC1820REGISTRY.setManager(address(this), _newManager); } }
まとめ
ERC 1820は、対象のアドレスに求める関数たちが実装されているかを確認できるレジストリとして利用できるコントラクトです。ConsensysにおけるERC1400のコンストラクタでの使い方のように、デプロイ時に登録しておくことでアドレスの説明をみることができます。
ERC165という同種のインターフェースを確認する規格もあるのですが、こちらとの互換性を保つためにERC165のための関数もERC1820には定義されています。ERC165は @y_nakajo さんのブログが詳しいです。
ContractのInterface検出機能の提案ERC-165とERC-820を調べてみた - アルゴリズムとかオーダーとか
また、ERC1820の仕組みをENSのようなドメインサービスとの組み合わせも考えられるかもしれません。ノートで書いているエンジニアがブロックチェーンを見るマガジンにENSを書いていただいたのでよければこちらもご覧ください。
エンジニアがブロックチェーンを見るマガジンもよろしくお願いします