# 気になるERCまとめ(1/3)

By [Eisuke Kawasaki](https://paragraph.com/@0xeisuke) · 2022-11-21

---

はじめに
----

本記事では最近見かけたERCについてethereum.orgとOpenZeppelin Docsの内容をまとめました。各ERCの大枠が把握できるように解説していきます。主に以下のような方に向けた内容になっています。

・ERC20やERC721を聞いた事があるけど実際どのような規格なのかソースコードを見ながら理解したい。

・初めて聞いたERCについて概要を押さえたい。

[https://ethereum.org/ja/developers/docs/](https://ethereum.org/ja/developers/docs/)

[https://docs.openzeppelin.com/](https://docs.openzeppelin.com/)

目次
--

*   EIP/ERCとは
    
*   ERC20 Token Standard
    
*   ERC721 Non-Fungible Token Standard
    
*   ERC1155 Multi-Token Standard
    

EIP/ERCとは
---------

### EIPとは

*   Ethereum Improvement Proposal（イーサリアム改良提案）の略
    
*   **イーサリアムの新しい機能やプロセスに関する提案を規定する標準規格**
    
*   イーサリアムコミュニティ内の誰でも EIP を作成可能
    
*   [EIP](https://eips.ethereum.org/) を書くためのガイドラインは [EIP-1](https://eips.ethereum.org/EIPS/eip-1)に記載されている
    
*   EIPについている番号（EIP●●）は、EIP上で提出された順番を意味する
    
    > “EIPとは、Ethereum Improvement Proposal（イーサリアム改良提案）の略です。EIPは、イーサリアムコミュニティに情報を提供したり、イーサリアムやそのプロセス、環境に関する新しい機能を説明する設計文書です。EIPは、機能の簡潔な技術仕様と、その機能の根拠を提供する必要があります。EIP の作成者は、コミュニティ内のコンセンサスを形成し、反対意見を文書化する責任を負います。” ([https://eips.ethereum.org/EIPS/eip-1](https://eips.ethereum.org/EIPS/eip-1)より抜粋)
    

![提出されたEIPがコミュニティ内で承認されると正式なEIPとして採択され、Ethereumの次回アップデート時に実装される(詳しくはEIP-1を参照)](https://storage.googleapis.com/papyrus_images/b3b8e5a88e0be892bc509aabb07a57d0e8f3fe269e1c08a399368ae9fcc52416.png)

提出されたEIPがコミュニティ内で承認されると正式なEIPとして採択され、Ethereumの次回アップデート時に実装される(詳しくはEIP-1を参照)

### ERCとは

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

### 今回解説するERC

![ERC20 / 721 / 1155 について解説します。](https://storage.googleapis.com/papyrus_images/3525aee284cb638f559dec569ee46f3fee336f597efcdea046b811c3027ba0dc.png)

ERC20 / 721 / 1155 について解説します。

ERC20 Token Standard
--------------------

![ERC-20 イーサリアム上で通貨としてのトークンを発行するための標準規格](https://storage.googleapis.com/papyrus_images/8c7134eb4de50f1382492838efa3f65809195e446e9589f4af9252bf56db8666.png)

ERC-20 イーサリアム上で通貨としてのトークンを発行するための標準規格

### 概要

*   **独自トークン**を発行するための規格
    
    > ERC-20 は Fungible Token の基準を導入しています。**各 Token は他の Token と（種類や価値において）完全に同じになるような特性**を備えています。例えば、ERC-20トークンはETHと同じように機能します。つまり、1トークンは他のすべてのトークンと常に等しいということです。
    

### Functions

*   **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 値を返します。
    
    `transfer` eventを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 値を返します。
    
    `Approval` eventをemitします。
    
    > //必要条件 `_spender`をゼロアドレスにすることはできません。
    
*   **transferFrom**
    
        function 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`がなければならない。
    >     
    

### Events

*   **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`である。
    

ERC721 Non-Fungible Token Standard
----------------------------------

![ERC-721 トークンに様々な情報を付け加えることにより唯一無二の価値を持ったトークンを発行するための標準規格](https://storage.googleapis.com/papyrus_images/ba552a0f787f6f710e7c0cad70484a4113ac0ba3635ef84e572be7e7bf365b99.png)

ERC-721 トークンに様々な情報を付け加えることにより唯一無二の価値を持ったトークンを発行するための標準規格

### 概要

*   **代替不可能トークン**(Non-Fungible Token)を発行するための規格。
    
    > ERC-721は**NFTの標準を導入**しています。このタイプのトークンはユニークで、**同じスマートコントラクトの他のトークンとは異なる価値を持つ**ことができます。
    > 
    > すべてのNFTはtokenIdというuint256変数を持っています。 ERC-721コントラクトでは、**コントラクトアドレス**とuint256 **tokenId**のペアは**グローバルに一意**でなければなりません。これによりtokenIdを入力として使用し、ゾンビ、武器、退屈な猿や子猫など、画像を出力することができます。
    

### Functions

*   **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](https://docs.openzeppelin.com/contracts/4.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-) を実装する必要があります。
    >     
    
    `transfer` eventをemitします。
    
*   **transferFrom**
    
        function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
        
    
    **非推奨！** トークンのtransferには上記の`safeTransferFrom`関数の使用を推奨します。
    
    ERC721にはsafeTransferFromとtransferFromがあり、safeTransferFromは受信側のコントラクトの[onERC721Received](https://docs.openzeppelin.com/contracts/4.x/api/token/erc721#IERC721Receiver-onERC721Received-address-address-uint256-bytes-)メソッドが特定のマジックナンバーを返さない場合にthrowされます。これは、受信側のコントラクトがトークンを受信できることを確認し、トークンが永久に失われないようにするためのものです。
    
    > なぜトークンが失われる可能性のある`transferFrom`関数があるかについて、EIP-721の著者の一人、Dieter Shirleyによると、
    > 
    > 「標準は常に単純な方がよい。要件が少なければ少ないほど、失敗するのが難しくなる。`transferFrom`関数は、より柔軟性を高め、標準をできるだけシンプルに保つために残されている。」とのことです。
    
*   **approve**
    
        function approve(address _approved, uint256 _tokenId) external payable;
        
    
    `_tokenId`を別のアカウントに転送する許可を与える。トークンが転送されると、承認はクリアされます。
    
    一度に承認できるアカウントは1つだけなので、ゼロアドレスを承認すると、それまでの承認はクリアされます。
    
    > //必要条件
    > 
    > *   トークンを所有しているか、承認されたオペレーターであること
    >     
    > *   `_tokenId`が存在すること
    >     
    
    `Approval` eventをemitします。
    
*   **setApprovalForAll**
    
        function setApprovalForAll(address _operator, bool _approved) external;
        
    
    `_operator`を呼び出し元のオペレーターとして承認または削除します。オペレータは、呼び出し元が所有する任意のトークンに対して`transferFrom`または`safeTransferFrom`を呼び出すことができます。
    
    > //必要条件
    > 
    > `_operator`がこの関数のcallerになることはできません。
    
    `Approval` eventを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`の全資産を管理することを許可されているかどうかを返します。
    

### Events

*   **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`で決定）ときに放出される。
    

ERC1155 Multi-Token Standard
----------------------------

![ERC-1155 1つのコントラクトで複数のトークンを扱うことができる標準規格](https://storage.googleapis.com/papyrus_images/b4686b08cd09407aa09a64faa2aeb586a75488af8041952a9220d3833b933dc7.png)

ERC-1155 1つのコントラクトで複数のトークンを扱うことができる標準規格

### 概要

*   ERC20とERC721の各トークンを**同じ形式で複数管理**するための規格。 コントラクト内でトークンを定義・発行できるため、マルチトークンプラットフォームとして機能します。
    
*   ERC1155は、ゲーム・分散型アプリのプラットフォームを展開するenjin社のCTO、Witek Radomski氏により提案されました。 **通常の暗号資産とNFTのハイブリッドのような規格**で、ゲームアイテムの取引などを想定しています。
    
    > マルチトークン標準とは何ですか？
    

このアイデアはシンプルで、任意の数のFungibleおよびNon-fungibleトークンタイプを表現し制御できるスマートコントラクトインターフェースを作成しようとするものです。こうすることで、ERC-1155トークンはERC-20やERC-721トークンと同じ機能、さらには両方を同時に行うことができるようになるのです。そして何より、両規格の機能を向上させ、より効率的にし、ERC-20とERC-721規格の明らかな実装ミスを修正することができるのです。

### Functions & Features

*   **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](https://docs.openzeppelin.com/contracts/4.x/api/token/erc1155#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-)を実装し、受理マジック値を返す必要がある。
>     

*   **Batch Balance**
    
    **１回のコールで複数の残高を取得できます**。引数として所有者の配列に続いて、トークン 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 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について文章の説明だけでなくコードレベルまで見ることでどのように動作するかがイメージできれば嬉しいです。

[Subscribe](null)

---

*Originally published on [Eisuke Kawasaki](https://paragraph.com/@0xeisuke/erc-1-3)*
