# [ERC6093] ERC20・ERC721・ERC1155のカスタムエラーの提案を理解しよう！

> このEIP（Ethereum Improvement Proposal）は、Ethereum上で動作するトークンのスマートコントラクトに関する規格です。特に、ERC20、ERC721、ERC1155規格のトークンに関連しています。

- URL: https://cardene.dev/articles/ec266ece8e18c9c0d6f6
- 公開日: 2023-09-22
- 更新日: 2023-09-22
- トピック: Blockchain
- タグ: ethereum, solidity, ブロックチェーン, nft

## はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、**ERC20**、**ERC721**、**ERC1155**規格のトークンのカスタムエラーの実装を提案している規格である**ERC6093**についてまとめていきます！

:::message
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-6093

:::message alert
**6093**は現在（2023年9月17日）では「**Last Call**」段階です。
:::

## 概要

このEIP（Ethereum Improvement Proposal）は、Ethereum上で動作するトークンのスマートコントラクトに関する規格です。
特に、**ERC20**、**ERC721**、**ERC1155**規格のトークンに関連しています。

Ethereumアプリケーションやウォレットは、トランザクションが失敗した場合、ユーザーにエラーの詳細な情報を提供するために、エラーメッセージを表示します。
これまでは、エラーメッセージは簡単なテキストとして提供されていました。
しかし、最近のSolidity言語のバージョンでは、より詳細で特定のエラーに関連する情報を提供できる「**カスタムエラー**」と呼ばれる機能が導入されました。

このEIPは、トランザクションエラーの際にユーザーに対して、エラーの原因や詳細な情報を提供するための標準の提供を目的としています。
これにより、エラーメッセージがより構造化され、クライアントアプリケーションがエラー情報を解析しやすくなります。
ユーザーはトランザクションエラーに対してより理解しやすい情報を得ることができ、開発者もエラーメッセージをより効果的に処理できるようになります。

:::message
**ERC20**については以下を参考にしてください。
:::

https://chaldene.net/erc20

:::message
**ERC721**については以下を参考にしてください。
:::

https://chaldene.net/erc721

:::message
**ERC1155**については以下を参考にしてください。
:::

https://chaldene.net/erc1155

## 動機

Solidityのバージョン0.8.4では、カスタムエラーが導入されました。
これにより、トランザクションの失敗時にエラーをユーザーにより詳細かつわかりやすく表示できるようになりました。
カスタムエラーは、動的な情報（引数など）を含めることができ、ガスの効率も向上し、デプロイコストも低減されました。

:::message
エラーメッセージがより情報豊かで、トランザクションの処理が効率的になり、トランザクションの作成や実行にかかるコストも削減されました。
:::

ただし、このカスタムエラーの導入は、**ERC20**、**ERC721**、**ERC1155**などのトークン規格が既に完成していた時期に行われました。
そのため、これらの規格にはカスタムエラーの仕様が含まれていませんでした。

:::message
これらのトークンを使用するアプリケーションやスマートコントラクトは、エラーの表示においてカスタムエラーを利用できない状況でした。
:::

そこで、このEIPは標準化されたエラーを導入しました。
これにより、アプリケーションやテスト環境を問わず、ユーザーはより一貫性のあるエラーメッセージを期待できるようになります。
また、関連する情報や引数をエラーメッセージに含めることもできます。
これにより、リバート文字列をデプロイバイトコードに書き込む必要が減少し、コスト削減とユーザーエクスペリエンスの向上が実現されました。

## 仕様

このEIPは、特定の状況でプログラムの実装が発生させることができるエラーの一覧を定めています。
これらのエラーは、EIP内で述べられた理由に基づいて設計されました。

しかし、このEIPは注意すべき点があります。
それは、エラーが発生する状況で、プログラムが必ずしもエラーを起こすべきかどうかを指示していないことです。
つまり、これらのエラーが実際に発生した場合、プログラムは必ずしもエラーを報告しなければならないわけではありません。
エラーのハンドリング方法は、各実装者（スマートコントラクトの開発者など）に委ねられています。
ただし、対応するEIP（Ethereum Improvement Proposal）で明示的にリバートが求められている場合は別です。

さらに、エラーの引数（エラーに関連する情報）の名前は、**Parameter Glossary**で定義されており、これらの名前を正確に使用しなければなりません。
これにより、エラーメッセージの一貫性が保たれ、エラーの理解が容易になります。

### ERC20

#### ERC20InsufficientBalance

```javascript
event ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
```

**概要**

トークンの送信者の残高に関連するエラーを示すイベント。

**詳細**

トークンの送信者が必要な量のトークンを持っていない場合に発生します。
送信者の残高（`balance`）が必要な量（`needed`）よりも少ない場合に使用されます。

**パラメータ**
- `sender`
    - 送信者のアドレス。
- `balance`
    - 送信者の現在の残高。
- `needed`
    - 必要な残高。

---

#### ERC20InvalidSender

```javascript
event ERC20InvalidSender(address sender);
```

**概要**

トークン送信者に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの送信者が不正な場合に発生します。
例えば、ゼロアドレスからのトークン送信が許可されていない場合に使用されます。
ただし、承認操作や残高または承認の要件には使用すべきではありません。

**パラメータ**
- `sender`
    - 不正な送信者のアドレス。

---

#### ERC20InvalidReceiver

```javascript
event ERC20InvalidReceiver(address receiver);
```

**概要**

トークンの受け取りアドレスに関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの受け取りアドレスが不正な場合に発生します。
例えば、ゼロアドレスや互換性のないアドレス（例：コントラクトアドレス）へのトークン送信が許可されていない場合に使用されます。
ただし、承認操作には使用すべきではありません。

**パラメータ**
- `receiver`
    - 不正な受け取りアドレス。

---

#### ERC20InsufficientAllowance

```javascript
event ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
```

**概要**

トークンの承認額に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

このイベントは、トークンの送金時に、承認されたトークンの額（`allowance`）が必要な額（`needed`）よりも少ない場合に発行されます。

**パラメータ**
- `spender`
    - トークンを承認したアドレス。
- `allowance`
    - 承認されたトークンの額。
- `needed`
    - 必要な承認額。

---

#### ERC20InvalidApprover

```javascript
event ERC20InvalidApprover(address approver);
```

**概要**

トークン承認者に関連するエラーを示すイベント。
通常、トークンの承認操作時に使用されます。

**詳細**

トークンの承認者が不正な場合に発生します。
例えば、ゼロアドレスからの承認が許可されていない場合に使用されます。
ただし、トークン送金操作には使用すべきではありません。

**パラメータ**
- `approver`
    - 不正な承認者のアドレス。

---

#### ERC20InvalidSpender

```javascript
event ERC20InvalidSpender(address spender);
```

**概要**

トークンの承認対象者に関連するエラーを示すイベント。
通常、トークンの承認操作時に使用されます。

**詳細**

トークンの承認対象者が不正な場合に発生します。
例えば、ゼロアドレスやトークンの所有者自身への承認が許可されていない場合に使用されます。
ただし、トークン送金操作には使用すべきではありません。

**パラメータ**
- `spender`
    - 不正な承認対象者のアドレス。

---

### ERC721

#### ERC721InvalidOwner

```javascript
event ERC721InvalidOwner(address owner);
```

**概要**

特定のアドレスがトークンの所有者になれないことを示すイベント。
通常、トークンの所有者のクエリ時に使用されます。

**詳細**

特定のアドレスがトークンの所有者として認識されない場合に発行されます。
例えば、**ERC721**ではアドレス(`0`)が所有者として認識されないことがあり、その場合に使用されます。

**パラメータ**
- `owner`
    - 所有者として認識されないアドレス。

---

#### ERC721NonexistentToken

```javascript
event ERC721NonexistentToken(uint256 tokenId);
```

**概要**

所有者が存在しないトークンの`tokenId`を示すイベント。

**詳細**

存在しない（ミントされていないまたは燃やされた）トークンの`tokenId`が指定された場合に発行されます。

**パラメータ**
- `tokenId`
    - 存在しないトークンの`tokenId`。

---

#### ERC721IncorrectOwner

```javascript
event ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
```

**概要**

特定のトークンの所有権に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

特定のトークンの送信者（`sender`）がそのトークンの実際の所有者（`owner`）ではない場合に発行されます。
また、承認操作には使用すべきではありません。

**パラメータ**
- `sender`
    - トークンの送信者。
- `tokenId`
    - トークンの`tokenId`。
- `owner`
    - 実際の所有者。

---

#### ERC721InvalidSender

```javascript
event ERC721InvalidSender(address sender);
```

**概要**

トークン送信者に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの送信者が不正な場合に発行されます。
例えば、ゼロアドレスからのトークン送信が許可されていない場合に使用されます。
ただし、承認操作や所有権または承認の要件には使用すべきではありません。

**パラメータ**
- `sender`
    - 不正な送信者のアドレス。

---

#### ERC721InvalidReceiver

```javascript
event ERC721InvalidReceiver(address receiver);
```

**概要**

トークンの受け取りアドレスに関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの受け取りアドレスが不正な場合に発行されます。
例えば、ゼロアドレスや**ERC721**非対応のコントラクトアドレスへのトークン送信が許可されていない場合に使用されます。
また、これらのコントラクトがトークン受け入れの`onERC721Received`で無効な応答を返す場合にも使用されます。
ただし、承認操作には使用すべきではありません。

**パラメータ**
- `receiver`
    - 不正な受け取りアドレス。

---

#### ERC721InsufficientApproval

```javascript
event ERC721InsufficientApproval(address operator, uint256 tokenId);
```

**概要**

特定のオペレーターの承認に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの送金時に、トークンの所有者とオペレーターの間で十分な承認が行われていない場合に発行されます。
具体的には、`tokenId`の所有者と`operator`の間で`isApprovedForAll(owner, operator)`が`false`であり、`getApproved(tokenId)`が`operator`を返さない場合に使用されます。

**パラメータ**
- `operator`
    - 承認エラーが発生したオペレーターのアドレス。
- `tokenId
    - 関連するトークンの`tokenId`。

---

#### ERC721InvalidApprover

```javascript
event ERC721InvalidApprover(address approver);
```

**概要**

特定のトークンの承認者に関連するエラーを示すイベント。
通常、トークンの承認操作時に使用されます。

**詳細**

トークンの承認者が不正な場合に発行されます。
例えば、ゼロアドレスからの承認が許可されていない場合に使用されます。
ただし、トークンの送金操作には使用すべきではありません。

**パラメータ**
- `approver`
    - 不正な承認者のアドレス。

---

#### ERC721InvalidOperator

```javascript
event ERC721InvalidOperator(address operator);
```

**概要**

特定のオペレーターの承認に関連するエラーを示すアドレス。
通常、トークンの承認操作時に使用されます。

**詳細**

特定のオペレーターが不正な場合に発行されます。
具体的には、承認されるトークンの所有者であるべきではないゼロアドレスへの承認が試みられた場合に使用されます。
また、トークンの送金操作には使用すべきではありません。

**パラメータ**
- `operator`
    - 不正なオペレーターのアドレス。

---

### ERC1155

#### ERC1155InsufficientBalance

```javascript
event ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
```

**概要**

トークンの送信者の現在の残高に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの送信者が特定のトークン（`tokenId`）に対して必要な額よりも残高が不足している場合に発行されます。

**パラメータ**
- `sender`
    - トークンの送信者のアドレス。
- `balance`
    - 送信者の現在の残高。
- `needed`
    - 必要な残高。
- `tokenId`
    - 関連するトークンの`tokenId`。

---

#### ERC1155InvalidSender

```javascript
event ERC1155InvalidSender(address sender);
```

**概要**

トークンの送信者に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの送信者が不正な場合に発行されます。
例えば、ゼロアドレスからのトークン送信が許可されていない場合に使用されます。
ただし、承認操作や残高または承認の要件には使用すべきではありません。

**パラメータ**
- `sender`
    - 不正な送信者のアドレス。

---

#### ERC1155InvalidReceiver

```javascript
event ERC1155InvalidReceiver(address receiver);
```

**概要**

トークンの受け取りアドレスに関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの受け取りアドレスが不正な場合に発行されます。
例えば、ゼロアドレスや**ERC1155**非対応のコントラクトアドレスへのトークン送信が許可されていない場合に使用されます。
また、これらのコントラクトがトークン受け入れの`onERC1155Received`で無効な応答を返す場合にも使用されます。
ただし、承認操作には使用すべきではありません。

**パラメータ**
- `receiver`
    - 不正な受け取りアドレス。

---

#### ERC1155MissingApprovalForAll

```javascript
event ERC1155MissingApprovalForAll(address operator, address owner);
```

**概要**

特定のオペレーターの承認に関連するエラーを示すイベント。
通常、トークンの送金時に使用されます。

**詳細**

トークンの送金時に、トークンの所有者（`owner`）とオペレーター（`operator`）の間で適切な承認が行われていない場合に発行されます。
具体的には、`tokenId`の所有者と`operator`の間で`isApprovedForAll(owner, operator)`が`false`である場合に使用されます。

**パラメータ**
- `operator`
    - 承認エラーが発生したオペレーターのアドレス。
- `owner`
    - トークンの所有者のアドレス。

---

#### ERC1155InvalidApprover

```javascript
event ERC1155InvalidApprover(address approver);
```

**概要**

特定のトークンの承認者に関連するエラーを示すイベント。
通常、トークンの承認操作時に使用されます。

**詳細**

トークンの承認者が不正な場合に発行されます。
例えば、ゼロアドレスからの承認が許可されていない場合に使用されます。
ただし、トークンの送金操作には使用すべきではありません。

**パラメータ**
- `approver`
    - 不正な承認者のアドレス。

---

#### ERC1155InvalidOperator

```javascript
event ERC1155InvalidOperator(address operator);
```

**概要**

特定のオペレーターの承認に関連するエラーを示すイベント。
通常、トークンの承認操作時に使用されます。

**詳細**

特定のオペレーターが不正な場合に発行されます。
具体的には、承認されるトークンの所有者であるべきではないゼロアドレスへの承認が試みられた場合に使用されます。
また、トークンの送金操作には使用すべきではありません。

**パラメータ**
- `operator`
    - 不正なオペレーターのアドレス。

---

#### ERC1155InvalidArrayLength

```javascript
event ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
```

**概要**

`safeBatchTransferFrom`操作における`ids`と`values`の配列の長さの不一致を示すイベント。
通常、バッチ送信時に使用されます。

**詳細**

このイベントは、`ids`（トークンID）と`values`（数量）の配列の長さが一致しない場合に発行されます。
バッチ送信操作において、`ids`の数と`values`の数は対応していなければなりません。

**パラメータ**
- `idsLength`
    - `ids`の配列の長さ。
- `valuesLength`
    - `values`の配列の長さ。

---

### 用語集

| パラメータ名 | 説明 |
| ------------ | ---- |
| sender       | トークンの送信元のアドレス。 |
| balance      | インタラクションするアカウントの現在の残高。 |
| needed       | アクションを実行するために必要な最小額。 |
| receiver     | トークンが送信されるアドレス。 |
| spender      | トークンの所有者でなくてもトークンを操作できる可能性のあるアドレス。 |
| allowance    | スペンダーが操作を許可されているトークンの数量。 |
| approver     | 承認操作を開始するアドレス。 |
| tokenId      | トークンの識別番号。 |
| owner        | トークンの現在の所有者のアドレス。 |
| operator     | `spender`と同じ。 |
| Length       | パラメータに関連する配列の長さ。 |

### エラーの追加

このEIPに新しいエラーを追加する場合、または実装固有のエラー（拡張など）を導入する場合、一貫性を保つためには、EIPの理論的な背景として説明されているガイドラインに従うことが重要です。

:::message
エラーメッセージの内容や構造、命名規則などについて、EIP内で提供されている指針に従うことが推奨されます。
:::

これを実行することで、新しいエラーコードや実装固有のエラーが、既存のエラーコードと整合性を持ち、開発者やユーザーがエラーメッセージを予測しやすく、理解しやすい形で受け取ることができます。

:::message
エラー処理がより一貫性のあるものとなり、エコシステム全体の品質と予測可能性が向上します。
:::

## 補足

トークンエラーの標準化における主な目的は、エラーが発生した時にそのエラーの文脈を提供し、エラーメッセージを理解しやすくすることです。
また、エラーメッセージ内で意味のある引数を適切に使用することも重要です。
なぜなら、エラーメッセージが長大にならず、かつコードのサイズを小さく保つことができるからです。

このため、トークンエラーの名前は、各トークンで実行できる標準的なアクションと、そのアクションに関連する主題に基づいた基本的な文法構造に従って設計されています。

:::message
エラー名自体がエラーの文脈や理由を示す役割を果たします。
エラー名は、エラーが発生したアクションと主題に関連付けられ、エラーメッセージをより明確にし、理解しやすくするために使用されます。
:::

このアプローチにより、エラーメッセージが一貫性を持ち、トークン操作中に何が問題となったのかが開発者やユーザーにとって容易に理解できるようになります。
同時に、エラーメッセージの長さやコードの複雑さを最小限に抑えることができます。


### アクションと対象

トークンエラーの設計において、重要なのはエラーが何に関連しているのか、つまりエラーの文脈を提供し、エラーメッセージが意味を持つ引数を適度に使用することです。
これにより、コードサイズを制御しながらもエラーに関する情報を十分に伝えることができます。

この目標に基づいて、エラーの名前はトークンで実行できる基本的なアクションと、それに関与する対象に基づいて設計されています。

具体的には、以下の2つのアクションがトークン操作において重要です。

#### Transfer（転送）
送信者が受け取りアドレスにトークンを移動する操作。
トークンは交換可能な残高（**fungible balance**）であるか、非交換可能なトークンIDであるかのどちらかです。

#### Approval（承認）
承認者がオペレーターに対してあらゆる形式の承認を与える操作。

これらのアクションと関連する対象を考慮することで、トークン操作において何が問題となる可能性があるかを包括的に捉えています。
したがって、エラーメッセージは、アクションの実行中にどの対象が失敗したかを特定し、エラープレフィックスを付けることで構築されます。

また、特定のトークン規格で対象の呼称が異なる場合でも、エラーの名前はそのトークン規格に合わせて統一されるべきです。

### エラープレフィックス

エラーには、具体的なエラー状況を明示するために、エラープレフィックス（エラーの接頭辞）が付けられます。
開発者は、エラープレフィックスを、なぜエラーが発生したのかを示すものと考えることができます。

エラープレフィックスには、一般的な不正確さを示す「**Invalid**」のような一般的なものから、「**Insufficient**」のような数量に関連する具体的なものまで、さまざまな種類があります。

たとえば、「**Invalid**」プレフィックスは、一般的なエラーを表し、何かが正しくないことを指します。
一方、「**Insufficient**」プレフィックスは、数量に関連するエラーを示し、不足していることを指します。
エラープレフィックスを使用することで、エラーメッセージがなぜエラーが発生したのかを理解しやすくなり、開発者やユーザーが問題を迅速に特定できるようになります。

### ドメイン

各トークンのエラーは、そのトークンの種類やドメインに応じて、引数が異なることがあります。
しかし、同じ名前のエラーが異なる引数で複数存在する場合、Solidityコンパイラはエラーを検出し、`DeclarationError`というエラーを発生させます。

例えば、以下のような状況です。

```solidity
InsufficientApproval(address spender, uint256 allowance, uint256 needed);
InsufficientApproval(address operator, uint256 tokenId);
```

上記のように、同じ名前のエラー「`InsufficientApproval`」が異なる引数を持つ場合、コンパイラはエラーとして扱います。

この問題を回避するために、各エラーの名前にはトークンの種類やドメインを示すプレフィックスが提案されています。
このプレフィックスは、ERC規格の名前とそれに対応する番号を組み合わせて表現されます。

例えば、以下のようになります。

```solidity
ERC20InsufficientApproval(address spender, uint256 allowance, uint256 needed);
ERC721InsufficientApproval(address operator, uint256 tokenId);
```

このように、ドメインプレフィックスを使用することで、トークンのドメインに応じてエラーを区別し、エラーの名前の衝突を回避することができます。

### 引数

トークンエラーの引数の選択は、エラーの文脈を提供するために非常に重要です。
引数の選択は、次の順序に従うべきです。

#### 誰がエラーに関与しているか
これはエラーが発生した主体を示します。
例えば、エラーが特定のアドレス（例：`address sender`）に関連している場合、そのアドレスを引数として含めます。

#### 何が失敗したか
これは具体的に何が問題であるかを示します。
例えば、トークンの承認額（例：`uint256 allowance`）が不足している場合、その承認額を引数として含めます。

#### なぜ失敗したか、追加の引数で表現される理由
エラーがなぜ発生したのかを説明するために、追加の引数が必要な場合があります。
例えば、特定の操作が失敗した理由として、必要なトークンの量（例：`uint256 needed`）を追加の引数として含めます。

この順序を守ることにより、エラーメッセージが明確で理解しやすくなり、開発者やユーザーがエラーの文脈を把握しやすくなります。
ただし、すべての引数が必要なわけではなく、トークンによっては`tokenId`が必要な場合があります。
`tokenId`は通常、追加情報としてエラーメッセージの最後に含めることが提案されています。

### エラー文法ルール

ここまでの情報を元に、エラー名の構築は以下の文法に従います。

```bash
<Domain><ErrorPrefix><Subject>(<Arguments>);
```

#### Domain（トークンの種類）
トークンの種類を示します。
一般的には**ERC20**、**ERC721**、**ERC1155**が使用されますが、他のトークン規格も考慮される場合があります。
この部分には、特定のトークン規格の名前が入ります。

#### ErrorPrefix（エラーのプレフィックス）
エラーの種類や原因を示すプレフィックスです。
一般的には「**Invalid**」（不正確さを示す）や「**Insufficient**」（不足を示す）が使用されますが、状況に応じて別のプレフィックスが適用されることもあります。

#### Subject（主題）**
エラーが関連する主題や関係者を示します。
一般的な主題には「`Sender`」（送信者）、「`Receiver`」（受信者）、 「`Balance`」（残高）、 「`Approver`」（承認者）、 「`Operator`」（オペレーター）、 「`Approval`」（承認）などがあります。
ただし、トークン規格によっては、この対象に関する命名規則が異なる場合があるため、その規格に合わせて調整する必要があります。

#### Arguments（引数）
引数はエラーに関する詳細情報を提供し、エラーがなぜ発生したのかを説明します。
これらの引数は、通常、「**Who**」（誰が関与しているか）、 「**What**」（何が失敗したか）、 「**Why**」（なぜ失敗したか）の順序に従って構築されます。
引数はエラーの特定の状況に応じて異なる情報を含むことがあります。

## 後方互換性

デプロイされたトークンの多くは、以前の実装で「`revert strings`」を主に使用しており、カスタムエラーを使うのではなく「`require`」を利用しています。
また、Solidityのバージョン0.8.4以降で新たにデプロイされたトークンも、一般的には「`revert strings`」を使用した実装を継承しています。

このEIPは、既存のアップグレード不可能なトークンに対しては強制的に適用できません。
しかし、これらのトークンは一般的には似たような規則に従っており、ドメインの追加や削除、異なるエラープレフィックスの使用、類似の主題の追加など、細かい変更が加えられています。

一方、アップグレード可能なコントラクトは、このEIPを実装するためにアップグレードできる可能性があります。

このEIPに準拠したトークンをサポートする実装者やDApp開発者は、このEIPに準拠しないコントラクトが発生させる異なるエラー、および従来の「`revert strings`」に対しても対応する必要があります。

:::message
このEIPに従わないコントラクトが発生させるエラーにも柔軟に対応できるようにする必要があります。
:::

## 参考実装

```javascript
pragma solidity ^0.8.4;

/// @title Standard ERC20 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-20
///  https://eips.ethereum.org/EIPS/eip-6093
interface ERC20Errors {
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
    error ERC20InvalidSender(address sender);
    error ERC20InvalidReceiver(address receiver);
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
    error ERC20InvalidApprover(address approver);
    error ERC20InvalidSpender(address spender);
}

/// @title Standard ERC721 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  https://eips.ethereum.org/EIPS/eip-6093
interface ERC721Errors {
    error ERC721InvalidOwner(address owner);
    error ERC721NonexistentToken(uint256 tokenId);
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
    error ERC721InvalidSender(address sender);
    error ERC721InvalidReceiver(address receiver);
    error ERC721InsufficientApproval(address operator, uint256 tokenId);
    error ERC721InvalidApprover(address approver);
    error ERC721InvalidOperator(address operator);
}

/// @title Standard ERC1155 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
///  https://eips.ethereum.org/EIPS/eip-6093
interface ERC1155Errors {
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
    error ERC1155InvalidSender(address sender);
    error ERC1155InvalidReceiver(address receiver);
    error ERC1155MissingApprovalForAll(address operator, address owner)
    error ERC1155InvalidApprover(address approver);
    error ERC1155InvalidOperator(address operator);
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
```

## セキュリティ考慮事項

指定されたエラーに関して、既知のシグネチャハッシュの衝突はありません。

このEIPを実装するためにアップグレードされたトークンは、`revert strings`に依存する他のシステムの前提条件を壊す可能性があります。

## 引用

Ernesto García (@ernestognw), Francisco Giordano (@frangio), Hadrien Croubois (@Amxx), "ERC-6093: Custom errors for commonly-used tokens [DRAFT]," Ethereum Improvement Proposals, no. 6093, December 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6093.

## 最後に

今回は「**ERC20**、**ERC721**、**ERC1155**規格のトークンのカスタムエラーの実装を提案している規格である**ERC6093**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58
