本記事では最近見かけたERCについてethereum.orgとOpenZeppelin Docsの内容をまとめました。各ERCの大枠が把握できるように解説していきます。主に以下のような方に向けた内容になっています。
・ERC20やERC721を聞いた事があるけど実際どのような規格なのかソースコードを見ながら理解したい。
・初めて聞いたERCについて概要を押さえたい。
https://ethereum.org/ja/developers/docs/
https://docs.openzeppelin.com/
EIP/ERCとは
ERC20 Token Standard
ERC721 Non-Fungible Token Standard
ERC1155 Multi-Token Standard
Ethereum Improvement Proposal(イーサリアム改良提案)の略
イーサリアムの新しい機能やプロセスに関する提案を規定する標準規格
イーサリアムコミュニティ内の誰でも EIP を作成可能
EIPについている番号(EIP●●)は、EIP上で提出された順番を意味する
“EIPとは、Ethereum Improvement Proposal(イーサリアム改良提案)の略です。EIPは、イーサリアムコミュニティに情報を提供したり、イーサリアムやそのプロセス、環境に関する新しい機能を説明する設計文書です。EIPは、機能の簡潔な技術仕様と、その機能の根拠を提供する必要があります。EIP の作成者は、コミュニティ内のコンセンサスを形成し、反対意見を文書化する責任を負います。” (https://eips.ethereum.org/EIPS/eip-1より抜粋)

EIPはいくつかのカテゴリーがあり、そのうちの1つ
トークン規格などのコントラクト実装を含むアプリケーションレベルの標準規約
“トークン標準(EIP-20)、名前登録(EIP-137)、URIスキーム(EIP-681)、ライブラリ/パッケージ形式(EIP-190)、アカウント抽象化(EIP-4337)などの契約標準を含む、アプリケーションレベルの標準と規約です。” ( https://eips.ethereum.org/より抜粋)


独自トークンを発行するための規格
ERC-20 は Fungible Token の基準を導入しています。各 Token は他の Token と(種類や価値において)完全に同じになるような特性を備えています。例えば、ERC-20トークンはETHと同じように機能します。つまり、1トークンは他のすべてのトークンと常に等しいということです。
name
function name() public view returns (string)トークンの名前を返します。
symbol
function symbol() public view returns (string)トークンのシンボル(通常は名前の短縮形)を返します。
decimals
function decimals() public view returns (uint8)ユーザー表示に使用される小数の数を返します。例えば、小数点以下が2の場合、505枚のメダルの残高は5.05(505 / 10 ** 2)と表示されます。
トークンは通常、EtherとWeiの関係を模して、18の値を選択します。この関数がオーバーライドされない限り、ERC20はこの値を使用します。
この情報は表示のためだけに使用され、IERC20.balanceOfやIERC20.transferなどのコントラクトの演算には一切影響を及ぼしません。
totalSupply
function totalSupply() public view returns (uint256)存在するトークンの量を返します。
balanceOf
function balanceOf(address _owner) public view returns (uint256 balance)アカウントが所有するトークンの量を返します。
transfer
function transfer(address _to, uint256 _value) public returns (bool success)発信者のアカウントから
_valueの量だけトークンを_toに移動させる。操作が成功したかどうかを示す boolean 値を返します。
transfereventをemitします。//必要条件
_toをゼロアドレスにすることはできません。callerは、少なくとも
_valueの量は残高がなければなりません。
allowance
function allowance(address _owner, address _spender) public view returns (uint256 remaining)transferFromを通じて_ownerに代わって_spenderが使用することができるトークンの残数を返します。デフォルトでは0です。この値は、
approveやtransferFromが呼び出されると変化します。approve
function approve(address _spender, uint256 _value) public returns (bool success)呼び出し元のトークンに対する
_spenderが使用することができるトークンの量を_valueに設定します。操作が成功したかどうかを示す boolean 値を返します。
Approvaleventをemitします。//必要条件
_spenderをゼロアドレスにすることはできません。transferFrom
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)_valueの量のトークンを、allowanceを使って、_fromから_toに移動させる。その後、金額が発信者のallowanceから差し引かれます。操作が成功したかどうかを示す boolean 値を返します。
transfereventをemitします。//必要条件
_fromと_toをゼロアドレスにはできません。_fromは残高が_value以上であること。callerは
_fromのトークンに対して少なくとも_value以上のallowanceがなければならない。
Transfer
event Transfer(address indexed _from, address indexed _to, uint256 _value)_valueがあるアカウント_fromから別のアカウント_toへ移動したときにemitされる。_valueは0かもしれないことに注意。Approval
event Approval(address indexed _owner, address indexed _spender, uint256 _value)approveの呼び出しにより、ある_ownerが_spenderへのallowanceが設定されたときにemitされる。_valueは新しいallowanceである。

代替不可能トークン(Non-Fungible Token)を発行するための規格。
ERC-721はNFTの標準を導入しています。このタイプのトークンはユニークで、同じスマートコントラクトの他のトークンとは異なる価値を持つことができます。
すべてのNFTはtokenIdというuint256変数を持っています。 ERC-721コントラクトでは、コントラクトアドレスとuint256 tokenIdのペアはグローバルに一意でなければなりません。これによりtokenIdを入力として使用し、ゾンビ、武器、退屈な猿や子猫など、画像を出力することができます。
balanceOf
function balanceOf(address _owner) external view returns (uint256);_ownerのアカウントにあるトークンの数を返します。ownerOf
function ownerOf(uint256 _tokenId) external view returns (address);_tokenIdのトークンの所有者を返します。//必要条件
_tokenIdが存在すること。safeTransferFrom
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;_tokenIdトークンを_fromから_toへ安全に転送する。//必要条件
_fromをゼロアドレスにすることはできません。_toをゼロアドレスにすることはできません。_tokenIdトークンが存在し、_fromが所有していること。呼び出し元が
_fromでない場合、approveまたはsetApprovalForAllのいずれかによってこのトークンを移動することが承認されなければならない。_toがスマートコントラクトを参照している場合、安全な転送時に呼び出される IERC721Receiver.onERC721Received を実装する必要があります。
transfereventをemitします。transferFrom
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;非推奨! トークンのtransferには上記の
safeTransferFrom関数の使用を推奨します。ERC721にはsafeTransferFromとtransferFromがあり、safeTransferFromは受信側のコントラクトのonERC721Receivedメソッドが特定のマジックナンバーを返さない場合にthrowされます。これは、受信側のコントラクトがトークンを受信できることを確認し、トークンが永久に失われないようにするためのものです。
なぜトークンが失われる可能性のある
transferFrom関数があるかについて、EIP-721の著者の一人、Dieter Shirleyによると、「標準は常に単純な方がよい。要件が少なければ少ないほど、失敗するのが難しくなる。
transferFrom関数は、より柔軟性を高め、標準をできるだけシンプルに保つために残されている。」とのことです。approve
function approve(address _approved, uint256 _tokenId) external payable;_tokenIdを別のアカウントに転送する許可を与える。トークンが転送されると、承認はクリアされます。一度に承認できるアカウントは1つだけなので、ゼロアドレスを承認すると、それまでの承認はクリアされます。
//必要条件
トークンを所有しているか、承認されたオペレーターであること
_tokenIdが存在すること
Approvaleventをemitします。setApprovalForAll
function setApprovalForAll(address _operator, bool _approved) external;_operatorを呼び出し元のオペレーターとして承認または削除します。オペレータは、呼び出し元が所有する任意のトークンに対してtransferFromまたはsafeTransferFromを呼び出すことができます。//必要条件
_operatorがこの関数のcallerになることはできません。Approvaleventをemitします。getApproved
function getApproved(uint256 _tokenId) external view returns (address);_tokenIdトークン毎に応じてそれぞれで承認されたアカウントを返します。//必要条件
_tokenIdが存在することisApprovedForAll
function isApprovedForAll(address _owner, address _operator) external view returns (bool);_operatorが_ownerの全資産を管理することを許可されているかどうかを返します。
Transfer
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);_tokenIdトークンが_fromから_toに転送されるときに発行されます。Approval
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);_ownerが_tokenIdトークンの管理を_approvedアドレスに承認したときに発行されます。ApprovalForAll
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);_ownerが_operatorに全資産を管理させる、またはさせない(引数の_approvedで決定)ときに放出される。

ERC20とERC721の各トークンを同じ形式で複数管理するための規格。 コントラクト内でトークンを定義・発行できるため、マルチトークンプラットフォームとして機能します。
ERC1155は、ゲーム・分散型アプリのプラットフォームを展開するenjin社のCTO、Witek Radomski氏により提案されました。 通常の暗号資産とNFTのハイブリッドのような規格で、ゲームアイテムの取引などを想定しています。
マルチトークン標準とは何ですか?
このアイデアはシンプルで、任意の数のFungibleおよびNon-fungibleトークンタイプを表現し制御できるスマートコントラクトインターフェースを作成しようとするものです。こうすることで、ERC-1155トークンはERC-20やERC-721トークンと同じ機能、さらには両方を同時に行うことができるようになるのです。そして何より、両規格の機能を向上させ、より効率的にし、ERC-20とERC-721規格の明らかな実装ミスを修正することができるのです。
Batch 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に発信者トークンを転送する許可を与えるか、取り消す。ApprovalForAlleventをemitする。//必要条件
_operatorはcallerであってはならない。isApprovedForAll(address _owner, address _operator)_operatorが_ownerのトークンの転送を承認された場合、true を返します。Receive Hook
function 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とは何か
ERC20
ERC721
ERC1155
について説明しました。各ERCについて文章の説明だけでなくコードレベルまで見ることでどのように動作するかがイメージできれば嬉しいです。

