初めに
2015年、イーサリアムネットワークが公開され、脱中心化されたネットワーク上で新しい可能性の世界が現れました。「スマートコントラクト」を実行することができる「イーサリアム仮想マシン(EVM)」は既存の金融環境を大きく変化させるゲームチェンジャーでした。結果的に、独自通貨から不動産資産まで様々な資産のデジタル化は、資産に対して誰でも便利で効率的に投資することができるようになりました!
今回はイーサリアムで資産をデジタル化する、3つ(ERC-20 / ERC-721 / ERC-1155)の規格についてご紹介しようと思います!
ERC20
登場の背景
「スマートコントラクト」の登場でユーザーは通貨のように使われる特別なコントラクトを作れるようになりました。その中でネットワーク上に様々な独自通貨が公開されましたが、結果的に「統一されていないインタフェース」のせいで、ネットワーク上の多様な通貨を追跡・取引することが難しかったです。その理由で「ERC20」という規格が作成されました。
ERC20の登場は仮想通貨のインタフェースを標準化して、様々なプロトコルと仮想通貨ウォレットでトークンをスムーズに統合しました。その結果MakerDAO、UniSwapのような分散型金融(DeFi)が活性化されました。
ERC20の特徴
ERC-20トークンはアカウントに保管されません。トークンはコントラクト内部にだけ存在しています。これはルール(例えば、名前、シンボル)を具体的に明示して、ユーザーアカウントに相応するリストをイーサリアムアドレスに保管します。
代替可能トークン(Fungible Token)
「代替可能」とは商品や資産が他の資産に代替できる可能性を表す言葉です。角トークの価値は他のトークンと正確に同じです。その結果、ステーブルコイン(Stablecoin)、ガバナンストークン(Governance Token)のようなERC20トークンを応用した様々なトークンが登場しました。
ERC20のインタフェース
interface IERC20 {
// totalSupply():コントラクトが保有しているトークンの全体保有量を返します。
function totalSupply() external view returns (uint256);
// balanceOf():accountが保有しているトークンの保有量を返します。
function balanceOf(address account) external view returns (uint256);
// transfer():recipientにamountほどのトークンを転送します。
function transfer(address recipient, uint256 amount) external returns (bool);
// allowance():spenderにownerのトークンを出金する権限を付与します。
function allowance(address owner, address spender) external view returns (uint256);
// approve():残高から引き出せるトークンの数量を制限します。
function approve(address spender, uint256 amount) external returns (bool);
// transferFrom():senderのトークンをrecipientにamountほどのトークンを転送します。
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
詳細の実装はGitHubで確認できます。
ERC721
では、ERC20については理解できましたので、今からは「ERC721」について調べてみましょう!
登場の背景
ERC20は様々な資産の中でイーサリアムネットワークで使用される通貨の規格を定義しました。しかし、すべての資産が通貨で表現されることはできません。芸術品、不動産、音楽アルバム、契約書など、その自体が唯一性と固有性を持つ資産もあります。このような特徴を「非代替性(Non-Fungible)」、ブロックチェーン上で発行・流通するデジタル資産を「NFT:非代替性トークン」と呼ばれています。結果的に、ERC721はイーサリアムネットワークで発行する「NFT:非代替性トークン」の規格で、ERC20以外の資産をデジタル化するために作られました。
ERC721の特徴
それではNFTトークンは正確に何を表す言葉でしょうか?簡単です。それだけで価値のある何でもNFTで作成できます。不動産、契約書、芸術品、さらには皆さんの思い出が詰まった写真もできます。このような特徴のため、二つのNFTトークンは価値の面で同じではありません。
非代替性トークン(NFT : Non-Fungible Token)
ERC-721トークンはERC-20トークンとは逆に、「非代替性」という特徴を持っています。簡単に言うと、ERC-721で発行されるトークンは、すべてそれぞれ異なる価値を持っているということです。
例えば、2人のサッカー選手を表す2つのNFTを考えてみてください。一番目は「リオネル・メッシ」で、2番目は「クリスティアーノ・ロナウド」です。ここで、二人の選手の価値は異なり、互いに代替しきれないということがわかります。
所有権証明
NFTはデジタルコンテンツまたはデジタル資産に対する所有権証明の役割をします。 NFTは購入、販売、取引できる特定デジタル資産を表す固有のデジタルトークンです。 デジタルアーティストは自分が生産する作品の価値が販売期間中に維持され、今後発生するロイヤリティも保障されます。
ERC721のインタフェース
ERC-721は、各トークンの唯一性、固有性を保証するために、uint256タイプの_tokenId
を付与しています。 また、付与された_tokenId
に基づき、イーサリアムネットワーク上でERC-721トークンを交換できるように次のようなインターフェースを提供しています。
interface ERC721 /* is ERC165 */ {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
しかし、上記のインタフェースで不十分な場合もあります。トークンが実際に「何を示すのか」、「どんな資産とつながったのか」といったメタデータが必要な場合もあります。そのためERC-721はメタデータのために次のような選択的なインタフェースを提案しています。
interface ERC721Metadata /* is ERC721 */ {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) external view returns (string);
}
また、これまで発行されたトークン数や全体のトークン保有者が何人なのかといった、トークンの状態を列挙するための選択的インタフェースも提案しています。
interface ERC721Enumerable /* is ERC721 */ {
function totalSupply() external view returns (uint256);
function tokenByIndex(uint256 _index) external view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
詳細の実装はGitHubで確認できます。
ERC1155(Multi-Token Standard)
最後に、ERC-1155について調べてみましょう!
ERC1155の特徴
ERC1155は様々なトークンの規格を一つのスマートコントラクトに結合したものです。ですので、代替可能トークン、非代替性トークン、さらにはSFT(Semi-Fungible)も同一の規格を使用して生成することができます。また、1つのスマートコントラクトで無限のトークンを管理することができです。さらにERC1155は、g既存のERC20とERC721にはなかった機能を採用して、以下のような特徴を持っています。
複数のトークン
単一のスマートコントラクトでファンジブルとNFTの両方を定義し、設定することができます。
ガスの節約
新しいトークンを鋳造する際のガス料金を最大90%カットすることができます。
一括転送とアトミックスワップ
複数のトークンを一度に送信することができます。また、任意の量のトークンのアトミック・スワップを可能にします。
ERC1155のインタフェース
ERC1155は既存のトークンとは異なる特徴を持っています。TransferBatch()
関数で、uint256[] _ids, uint256[] _values
で配列のパラーメータをもらって一括で転送することができます。
interface IERC1155 /* is ERC165 */ {
event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value);
event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values);
event URI(string _value, uint256 indexed _id);
function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
function balanceOf(address _owner, uint256 _id) external view returns (uint256);
function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
また、ERC-721の標準で使われたメタデータURLを定義できます。
interface ERC1155Metadata_URI {
function uri(uint256 _id) external view returns (string memory);
}
最後に、IERC1155Receiver
で一つまたは複数のERC1155トークンタイプの受信を処理します。
interface ERC1155TokenReceiver {
function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4);
function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4);
}
詳細の実装はGitHubで確認できます。