# 気になるERCまとめ(1/3) **Published by:** [Eisuke Kawasaki](https://paragraph.com/@0xeisuke/) **Published on:** 2022-11-21 **URL:** https://paragraph.com/@0xeisuke/erc-1-3 ## Content はじめに本記事では最近見かけたERCについてethereum.orgとOpenZeppelin Docsの内容をまとめました。各ERCの大枠が把握できるように解説していきます。主に以下のような方に向けた内容になっています。 ・ERC20やERC721を聞いた事があるけど実際どのような規格なのかソースコードを見ながら理解したい。 ・初めて聞いたERCについて概要を押さえたい。 https://ethereum.org/ja/developers/docs/ https://docs.openzeppelin.com/目次EIP/ERCとはERC20 Token StandardERC721 Non-Fungible Token StandardERC1155 Multi-Token StandardEIP/ERCとはEIPとはEthereum Improvement Proposal(イーサリアム改良提案)の略イーサリアムの新しい機能やプロセスに関する提案を規定する標準規格イーサリアムコミュニティ内の誰でも EIP を作成可能EIP を書くためのガイドラインは EIP-1に記載されているEIPについている番号(EIP●●)は、EIP上で提出された順番を意味する“EIPとは、Ethereum Improvement Proposal(イーサリアム改良提案)の略です。EIPは、イーサリアムコミュニティに情報を提供したり、イーサリアムやそのプロセス、環境に関する新しい機能を説明する設計文書です。EIPは、機能の簡潔な技術仕様と、その機能の根拠を提供する必要があります。EIP の作成者は、コミュニティ内のコンセンサスを形成し、反対意見を文書化する責任を負います。” (https://eips.ethereum.org/EIPS/eip-1より抜粋)提出されたEIPがコミュニティ内で承認されると正式なEIPとして採択され、Ethereumの次回アップデート時に実装される(詳しくはEIP-1を参照)ERCとはEIPはいくつかのカテゴリーがあり、そのうちの1つトークン規格などのコントラクト実装を含むアプリケーションレベルの標準規約“トークン標準(EIP-20)、名前登録(EIP-137)、URIスキーム(EIP-681)、ライブラリ/パッケージ形式(EIP-190)、アカウント抽象化(EIP-4337)などの契約標準を含む、アプリケーションレベルの標準と規約です。” ( https://eips.ethereum.org/より抜粋)今回解説するERCERC20 / 721 / 1155 について解説します。ERC20 Token StandardERC-20 イーサリアム上で通貨としてのトークンを発行するための標準規格概要独自トークンを発行するための規格ERC-20 は Fungible Token の基準を導入しています。各 Token は他の Token と(種類や価値において)完全に同じになるような特性を備えています。例えば、ERC-20トークンはETHと同じように機能します。つまり、1トークンは他のすべてのトークンと常に等しいということです。Functionsnamefunction name() public view returns (string) トークンの名前を返します。symbolfunction symbol() public view returns (string) トークンのシンボル(通常は名前の短縮形)を返します。decimalsfunction decimals() public view returns (uint8) ユーザー表示に使用される小数の数を返します。例えば、小数点以下が2の場合、505枚のメダルの残高は5.05(505 / 10 ** 2)と表示されます。 トークンは通常、EtherとWeiの関係を模して、18の値を選択します。この関数がオーバーライドされない限り、ERC20はこの値を使用します。 この情報は表示のためだけに使用され、IERC20.balanceOfやIERC20.transferなどのコントラクトの演算には一切影響を及ぼしません。totalSupplyfunction totalSupply() public view returns (uint256) 存在するトークンの量を返します。balanceOffunction balanceOf(address _owner) public view returns (uint256 balance) アカウントが所有するトークンの量を返します。transferfunction transfer(address _to, uint256 _value) public returns (bool success) 発信者のアカウントから_valueの量だけトークンを_toに移動させる。 操作が成功したかどうかを示す boolean 値を返します。 transfer eventをemitします。//必要条件_toをゼロアドレスにすることはできません。callerは、少なくとも_valueの量は残高がなければなりません。allowancefunction allowance(address _owner, address _spender) public view returns (uint256 remaining) transferFromを通じて_ownerに代わって_spenderが使用することができるトークンの残数を返します。デフォルトでは0です。 この値は、approveやtransferFromが呼び出されると変化します。approvefunction approve(address _spender, uint256 _value) public returns (bool success) 呼び出し元のトークンに対する_spenderが使用することができるトークンの量を_valueに設定します。 操作が成功したかどうかを示す boolean 値を返します。 Approval eventをemitします。//必要条件 _spenderをゼロアドレスにすることはできません。transferFromfunction transferFrom(address _from, address _to, uint256 _value) public returns (bool success) _valueの量のトークンを、allowanceを使って、_fromから_toに移動させる。その後、金額が発信者のallowanceから差し引かれます。 操作が成功したかどうかを示す boolean 値を返します。 transfer eventをemitします。//必要条件_fromと_toをゼロアドレスにはできません。_fromは残高が_value以上であること。callerは_fromのトークンに対して少なくとも_value以上のallowanceがなければならない。EventsTransferevent Transfer(address indexed _from, address indexed _to, uint256 _value) _valueがあるアカウント_fromから別のアカウント_toへ移動したときにemitされる。 _valueは0かもしれないことに注意。Approvalevent Approval(address indexed _owner, address indexed _spender, uint256 _value) approveの呼び出しにより、ある_ownerが_spenderへのallowanceが設定されたときにemitされる。 _valueは新しいallowanceである。ERC721 Non-Fungible Token StandardERC-721 トークンに様々な情報を付け加えることにより唯一無二の価値を持ったトークンを発行するための標準規格概要代替不可能トークン(Non-Fungible Token)を発行するための規格。ERC-721はNFTの標準を導入しています。このタイプのトークンはユニークで、同じスマートコントラクトの他のトークンとは異なる価値を持つことができます。 すべてのNFTはtokenIdというuint256変数を持っています。 ERC-721コントラクトでは、コントラクトアドレスとuint256 tokenIdのペアはグローバルに一意でなければなりません。これによりtokenIdを入力として使用し、ゾンビ、武器、退屈な猿や子猫など、画像を出力することができます。FunctionsbalanceOffunction balanceOf(address _owner) external view returns (uint256); _ownerのアカウントにあるトークンの数を返します。ownerOffunction ownerOf(uint256 _tokenId) external view returns (address); _tokenId のトークンの所有者を返します。//必要条件 _tokenId が存在すること。safeTransferFromfunction safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable; _tokenId トークンを _from から _to へ安全に転送する。//必要条件_fromをゼロアドレスにすることはできません。_toをゼロアドレスにすることはできません。_tokenId トークンが存在し、_from が所有していること。呼び出し元が_fromでない場合、approveまたはsetApprovalForAllのいずれかによってこのトークンを移動することが承認されなければならない。_to がスマートコントラクトを参照している場合、安全な転送時に呼び出される IERC721Receiver.onERC721Received を実装する必要があります。transfer eventをemitします。transferFromfunction transferFrom(address _from, address _to, uint256 _tokenId) external payable; 非推奨! トークンのtransferには上記のsafeTransferFrom関数の使用を推奨します。 ERC721にはsafeTransferFromとtransferFromがあり、safeTransferFromは受信側のコントラクトのonERC721Receivedメソッドが特定のマジックナンバーを返さない場合にthrowされます。これは、受信側のコントラクトがトークンを受信できることを確認し、トークンが永久に失われないようにするためのものです。なぜトークンが失われる可能性のあるtransferFrom関数があるかについて、EIP-721の著者の一人、Dieter Shirleyによると、 「標準は常に単純な方がよい。要件が少なければ少ないほど、失敗するのが難しくなる。transferFrom関数は、より柔軟性を高め、標準をできるだけシンプルに保つために残されている。」とのことです。approvefunction approve(address _approved, uint256 _tokenId) external payable; _tokenIdを別のアカウントに転送する許可を与える。トークンが転送されると、承認はクリアされます。 一度に承認できるアカウントは1つだけなので、ゼロアドレスを承認すると、それまでの承認はクリアされます。//必要条件トークンを所有しているか、承認されたオペレーターであること_tokenIdが存在することApproval eventをemitします。setApprovalForAllfunction setApprovalForAll(address _operator, bool _approved) external; _operatorを呼び出し元のオペレーターとして承認または削除します。オペレータは、呼び出し元が所有する任意のトークンに対してtransferFromまたはsafeTransferFromを呼び出すことができます。//必要条件 _operatorがこの関数のcallerになることはできません。Approval eventをemitします。getApprovedfunction getApproved(uint256 _tokenId) external view returns (address); _tokenId トークン毎に応じてそれぞれで承認されたアカウントを返します。//必要条件 _tokenIdが存在することisApprovedForAllfunction isApprovedForAll(address _owner, address _operator) external view returns (bool); _operator が_ownerの全資産を管理することを許可されているかどうかを返します。EventsTransferevent Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); _tokenIdトークンが_fromから_toに転送されるときに発行されます。Approvalevent Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); _ownerが_tokenIdトークンの管理を_approvedアドレスに承認したときに発行されます。ApprovalForAllevent ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); _ownerが_operatorに全資産を管理させる、またはさせない(引数の_approvedで決定)ときに放出される。ERC1155 Multi-Token StandardERC-1155 1つのコントラクトで複数のトークンを扱うことができる標準規格概要ERC20とERC721の各トークンを同じ形式で複数管理するための規格。 コントラクト内でトークンを定義・発行できるため、マルチトークンプラットフォームとして機能します。ERC1155は、ゲーム・分散型アプリのプラットフォームを展開するenjin社のCTO、Witek Radomski氏により提案されました。 通常の暗号資産とNFTのハイブリッドのような規格で、ゲームアイテムの取引などを想定しています。マルチトークン標準とは何ですか?このアイデアはシンプルで、任意の数のFungibleおよびNon-fungibleトークンタイプを表現し制御できるスマートコントラクトインターフェースを作成しようとするものです。こうすることで、ERC-1155トークンはERC-20やERC-721トークンと同じ機能、さらには両方を同時に行うことができるようになるのです。そして何より、両規格の機能を向上させ、より効率的にし、ERC-20とERC-721規格の明らかな実装ミスを修正することができるのです。Functions & FeaturesBatch Transfers 一括転送は通常の ERC-20 転送と非常によく似た動作をします。通常のERC-20のtransferFrom関数を見てみましょう。// ERC-20 function transferFrom(address from, address to, uint256 value) external returns (bool); // ERC-1155 function safeBatchTransferFrom( address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data ) external; ERC-1155の唯一の違いは、値を配列で渡すことと、idの配列も渡すことです。例えば、id=[3, 6, 13] と values=[100, 200, 5] の場合、転送の結果は以下のようになります。 idが3のトークンを100個、_fromから_toに転送します。 idが6のトークンを200個、_fromから_toに転送します。idが13のトークンを5個、_fromから_toに転送します。 ERC-1155では、transferFromのみで、transferはありません。通常の転送のように使うには、_fromのアドレスを関数を呼び出しているアドレスに設定しましょう。以下safeBatchTransferFrom関数についてもう少し詳しく見てみます。safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] _values, bytes data) TransferBatch イベントを発行する。//必要条件idsとamountsの配列の長さは同じ長さでなければならない。toがスマートコントラクトを参照する場合、IERC1155Receiver.onERC1155BatchReceivedを実装し、受理マジック値を返す必要がある。Batch Balance 1回のコールで複数の残高を取得できます。引数として所有者の配列に続いて、トークン ID の配列を渡します。// ERC-20 function balanceOf(address owner) external view returns (uint256); // ERC-1155 function balanceOfBatch( address[] calldata _owners, uint256[] calldata _ids ) external view returns (uint256[] memory); たとえば、_ids=[3, 6, 13] と _owners=[0xbeef..., 0x1337..., 0x1111...] が与えられた場合、返り値は次のようになります。[ balanceOf(0xbeef...), balanceOf(0x1337...), balanceOf(0x1111...) ] 以下balanceOfBatch関数についてもう少し詳しく見てみます。balanceOfBatch(address[] _owners, uint256[] _ids) _owners配列に含まれるowner毎に所有するトークンの量を返します。//必要条件 _ownersと_idsの配列の長さは同じ長さでなければならない。Batch Approval ApprovalはERC-20とは若干異なります。特定の金額を承認するのではなく、setApprovalForAllでオペレータを承認または非承認に設定します。 現在のステータスの読み取りはisApprovedForAllで行うことができます。見ての通り、All or Nothingです。何個のトークンを承認するか、どのトークン・クラスを承認するかさえも定義することはできません。 これは意図的にシンプルになるように設計されています。1つのアドレスに対して、すべてを承認することしかできません。// ERC-1155 function setApprovalForAll( address _operator, bool _approved ) external; function isApprovedForAll( address _owner, address _operator ) external view returns (bool); setApprovalForAll関数とisApprovedForAll関数についてより詳しく見ていきましょう。setApprovalForAll(address _operator, bool _approved) 承認された内容に従って、_operatorに発信者トークンを転送する許可を与えるか、取り消す。 ApprovalForAll eventをemitする。//必要条件 _operatorはcallerであってはならない。isApprovedForAll(address _owner, address _operator) _operatorが_ownerのトークンの転送を承認された場合、true を返します。Receive Hookfunction onERC1155BatchReceived( address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data ) external returns(bytes4); EIP-165のサポートを考えると、ERC-1155はスマートコントラクトのための受信フックのみをサポートしています。フック関数は、次のように与えられるマジックで定義されたbytes4値を返す必要があります。bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)")) **受信側のコントラクトがこの値を返すと、そのコントラクトが転送を受け入れ、ERC-1155トークンの処理方法を知っていると見なされます。**これで、コントラクトの中でトークンが動かなくなることはありません。NFT Support 供給が1つだけの場合、トークンは基本的にNFT(non-fungible token)となります。また、ERC-721の標準として、メタデータのURLを定義することができます。このURLはクライアントが読み取り、変更することができますので、こちらをご参照ください。Safe Transfer Rule これまでの説明で、すでにいくつかの安全な転送ルールについて触れてきました。しかし、今回はその中でも最も重要なルールについて見ていきましょう。callerは、_fromアドレスのトークンを使用することを承認されるか、callerが_fromと等しくなければならない。転送コールは、以下の場合に戻す必要があります。 1, _toアドレスがゼロアドレス 2, _idsの配列の長さは_valuesの配列の長さと異なる 3, _idsのトークン保有者の残高が、受信者に送信された_valuesの各金額を下回っている場合 4, その他のエラーが発生した場合まとめ「気になるERCまとめ」第一回となる今回はEIP/ERCとは何かERC20ERC721ERC1155について説明しました。各ERCについて文章の説明だけでなくコードレベルまで見ることでどのように動作するかがイメージできれば嬉しいです。Subscribe ## Publication Information - [Eisuke Kawasaki](https://paragraph.com/@0xeisuke/): Publication homepage - [All Posts](https://paragraph.com/@0xeisuke/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@0xeisuke): Subscribe to updates - [Twitter](https://twitter.com/0xEisuke): Follow on Twitter