ERC6551(Token Bound Accounts)とは何か?
ERC6551のコンセプト
NFTがオンチェーン資産(NFTやFT)を保有することができる。
ERC6551のコンセプトイメージ
ブロックチェーンにおけるID(DID)を、walletではなく、NFTにするべきである。
つまり、walletがNFTを保有する構造ではなく、NFTがwalletを保有する構造になっている。
ERC6551の技術的な構造
EIP6551の提案には以下のような図解があります。
それを元に自分の理解のイメージ図を以下にまとめてました。
主な登場人物は4人です。
①NFT
ERC6551はERC721AのようなERC721を継承した別テンプレートではなく、ERC721に対して後から拡張可能な、装備品のようなイメージだと考えています。そのため、現状存在する全てのERC721に対して、ERC6551を装備(拡張)することができます。
②Proxy Contract(Token Bound Accounts)
Proxy ContractというのはTBAのアカウントだけを持つ、最小限のスマートコントラクトです。ほとんどの実装部分は、Implement Contract側が担うことで、TBAの発行コストを最小限にしています。
③Implement Contract
Implement Contractというのは、TBA(Token Bound Accounts)における実行部分のコントラクトである。基本的にはここの部分がERC6551における自由部分であり、それぞれのERC721においてカスタマイズできる部分です。
④Registry
NFTからProxy Contractを紐付け、Proxy ContractとImplement Contractを紐づけるコントラクトです。ユーザーはTBAを作りたいNFTの情報を、Registerに入力することで、TBAを作成することができます。
実際に触ってみる
実際に「ERC6551を作成して触ってみたい!」という人は、ユウキさんのnoteがわかりやすく解説してあるのでおすすめです。
上記のnoteと以下のgithubを参考にして、コードを確認していきます。
Registry
import "@openzeppelin/contracts/utils/Create2.sol";
import "./interfaces/IERC6551Registry.sol";
contract ERC6551Registry is IERC6551Registry {
error InitializationFailed();
function createAccount(
address implementation,
uint256 chainId,
address tokenContract,
uint256 tokenId,
uint256 salt,
bytes calldata initData
) external returns (address) {
// ...
}
function account(
address implementation,
uint256 chainId,
address tokenContract,
uint256 tokenId,
uint256 salt
) external view returns (address) {
// ...
}
}
implamentationが少しわかりづらいですが、実際の実行コントラクトのアドレスになります。
Implement Contract
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./interfaces/IERC6551Account.sol";
import "./lib/MinimalReceiver.sol";
import "./lib/ERC6551AccountLib.sol";
contract ERC6551Account is IERC165, IERC1271, IERC6551Account {
uint256 public nonce;
receive() external payable {}
function executeCall(
address to,
uint256 value,
bytes calldata data
) external payable returns (bytes memory result) {
// ...
}
function token()
external
view
returns (
uint256,
address,
uint256
)
{
return ERC6551AccountLib.token();
}
function owner() public view returns (address) {
// 所有者のアドレスを返す
}
function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
return (interfaceId == type(IERC165).interfaceId ||
interfaceId == type(IERC6551Account).interfaceId);
}
function isValidSignature(bytes32 hash, bytes memory signature)
external
view
returns (bytes4 magicValue)
{
// そのユーザーが署名可能かを返す
}
}
全体感
ERC721が普及してきたことで、ERC6551のようなERC721を前提に装備(拡張)するような規格が生まれてきたと感じる。ただし、誰でも比較的自由に拡張することができるため、画面としてどのように見えるようにするのかは難しいと感じる。ちなみにOpenseaはこんな感じ。
左のNFT画像の左上に新たなアイコンが表示される
TBAに入っているアセットが一覧で表示される
Discussion