# [ERC7631] ERC20とERC721トークンが相互に影響し合う仕組みを理解しよう！

> この提案は、分割可能なERC20トークンと非分割可能なERC721トークンのコントラクトが相互に連携できるようにする方法について説明しています。具体的には、一方のコントラクトで行われたアクションがもう一方に反映されるようにするものです。

- URL: https://cardene.dev/articles/feef82cecbacf9a043bb
- 公開日: 2024-04-02
- 更新日: 2024-04-02
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、**ERC20**と**EREC721**のトークンが相互に影響し合い、柔軟にトークンの設計や運用ができる仕組みを提案している**ERC7631**についてまとめていきます！

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

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

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

この提案は、分割可能な**ERC20**トークンと非分割可能な**ERC721**トークンのコントラクトが相互に連携できるようにする方法について説明しています。
具体的には、一方のコントラクトで行われたアクションがもう一方に反映されるようにするものです。
ここで重要なのは、これら二つのトークンタイプの違いを理解することです。

#### ERC20トークンとは？
**ERC20**トークンは「**分割可能**」です。
つまり、トークンを分割して、小さな単位での取引が可能です。
例えば、1トークンを`0.1`トークンのように分けることができます。
これは、通貨や株のような資産を表すのに適しています。

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

https://chaldene.net/erc20

#### ERC721トークンとは？
一方で、**ERC721**トークンは「**非分割可能**」です。
これは、それぞれのトークンがユニークであり、分割できないことを意味します。
この性質は、デジタルアートやコレクティブルなど、一意性が重要なアイテムを表すのに適しています。

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

https://chaldene.net/erc721

#### 提案の内容
提案は、これら二つの異なるタイプのトークンコントラクトがどのように連携できるかについて定義します。
例えば、**ERC20**トークンの取引が行われた時に、それが**ERC721**トークンの何らかの変更を引き起こすことができます。
具体的には、**ERC20**トークンの取引が**ERC721**トークンの発行や送付に影響を与えるようなシステムです。

さらに、アカウントが**ERC20**から**ERC721**への同期中に、**ERC721**のミント（新規発行）や送付をスキップするかどうかを設定できるようにします。
これにより、ユーザーはより柔軟に両方のトークンタイプを管理できるようになります。

#### なぜこれが重要なのか？
このような連携機能は、デジタル資産の管理と取引をより柔軟にし、新しいタイプのアプリケーションやサービスの開発を促進する可能性があります。
例えば、**ERC20**トークンを使って**ERC721**のコレクティブルを購入するプラットフォームや、特定の**ERC20**トークンの所有者にだけ利用可能な**ERC721**ベースの報酬を提供するシステムなどが考えられます。

## 動機

このシステムでは、**ERC20**トークンの操作が**ERC721**トークンに自動的に影響を及ぼし、その逆も可能です。
これにより、特定の応用が可能になります。
例えば、「**ネイティブERC721の分割化**」が挙げられます。
これは、**ERC20**トークンを取得することで、そのバランスに応じた**ERC721**トークンが自動的に発行されるプロセスを意味します。

#### 二重性質トークンペアとは？
**分割可能なERC20トークン**と**非分割可能なERC721トークン**を組み合わせたものです。
一方のトークンで行われる操作（例えば、転送）が、もう一方のトークンに自動的に影響を及ぼすように設計されています。

#### 提案の目的
これらのトークンペアの機能を強化することです。
トークン間の関係を照会しやすくするために、**ERC20**および**ERC721**トークンに拡張インターフェースを提案します。
分散型取引所やNFTマーケットプレイスが、トークン間の関係を表示できるようにするなど、品質向上の改善を目指します。

#### カスタマイズ可能な設定
ユーザーは、**ERC20**から**ERC721**への同期時に、**ERC721**のミント（新規発行）や送付をスキップするかどうかを選択できます。

#### 応用例
**ERC20**トークンを使って特定の割合で**ERC721**トークンを自動的に得ることができるので、NFTの新しい形態の所有権や取引が可能になります。
例えば、あるアート作品のNFTを複数の人が共有する場合、それぞれの持ち分が**ERC20**トークンで表され、そのトークン量に応じてNFTの所有権が分配されます。

この提案は、トークン間の相互作用をより柔軟にし、ブロックチェーン上での新しい経済活動やアプリケーションの形成を促進することを目指しています。

## 仕様

### 概要

「**二重性質トークンペア**」とは、**ERC20**のコントラクト（ベースコントラクト）と**ERC721**のコントラクト（ミラーコントラクト）の組み合わせで構成されています。

#### ERC-20コントラクト（基本契約）
**ERC20**コントラクトは、このトークンペアの「**基盤**」となる部分です。
分割可能なトークンであり、一般的には通貨やその他の資産のように扱われます。
このコントラクトは、資産の分割や交換を容易にするための標準的なルールと機能を提供します。

#### ERC721コントラクト（ミラーコントラクト）
**ERC721**コントラクトは、各トークンがユニークであり、分割不可能な性質を持つことを示す「**ミラー**」または反映された側です。
このコントラクトは、デジタルアート、コレクティブル、不動産など、一意性が重要なアイテムを表すのに適しています。
**ERC721**トークンは、所有権や希少価値が特定されたアイテムをデジタル世界で表現するために使用されます。

#### 二重性質トークンペアの動作原理
これら二つのコントラクトを組み合わせることで、トークンペアは「**二重性質**」を持ちます。
つまり、**ERC20**トークンの取引やバランスの変更が**ERC721**トークンに何らかの影響を与えることができ、逆もまた可能です。
例えば、特定の**ERC20**トークンを保有していることが、**ERC721**トークンの特定のアクション（例えば、新しいユニークトークンの発行や既存トークンの所有権変更）をトリガーする条件となる場合があります。

このように、ベースコントラクト（**ERC20**）とミラーコントラクト（**ERC721**）の間に設定された相互作用により、分割可能な資産と非分割可能な資産の間で新しい種類の関係が生まれます。
これにより、ブロックチェーン上での資産管理や取引の可能性が大きく広がります。

### ERC20拡張インターフェース

**ERC20**コントラクトは以下のインターフェースを実装する必要があります。

```ts
interface IERC7631Base {
    /// @dev Returns the address of the mirror ERC-721 contract.
    ///
    /// This method MAY revert or return the zero address
    /// to denote that a mirror ERC-721 contract has not been linked.
    ///
    /// If a non-zero address is returned, the returned address MUST
    /// implement `IERC7631Mirror` and its `baseERC20()` method MUST
    /// return the address of this contract.
    ///
    /// Once a non-zero address has been returned, this method
    /// MUST NOT revert and the returned value MUST NOT change.
    function mirrorERC721() external view returns (address);
}
```

このインターフェース `IERC7631Base` は、二重性質トークンペアにおける**ERC20**ベースコントラクトが使用するものです。
具体的には、**ERC20**トークン（ベースコントラクト）と紐付けられた**ERC721**トークン（ミラーコントラクト）間の関係を定義する方法を提供します。

#### `mirrorERC721()` 関数について
- **目的**
    - この関数は、紐付けられたミラーコントラクト（**ERC721**コントラクト）のアドレスを返します。
- **挙動**
  - **正常**
      - 非ゼロアドレスを返す場合、そのアドレスは `IERC7631Mirror` インターフェースを実装していなければならず、そのインターフェースの `baseERC20()` メソッドはこの**ERC20**コントラクトのアドレスを返す必要があります。
  - **異常**
    - ミラーコントラクト（**ERC721**コントラクト）がまだリンクされていない場合、この関数はゼロアドレスを返すか、あるいはリバート（エラーを発生）することがあります。
    - 一度非ゼロアドレスが返された後は、この関数はリバートしてはならず、返される値も変更してはなりません。

#### なぜ重要なのか？
このインターフェースは、**ERC20**と**ERC721**トークンの間の明確な関係を設定し、管理するための標準化された方法を提供します。
これにより、開発者は二重性質トークンペアをより簡単に実装し、利用者は**ERC20**トークンとそのミラーとなる**ERC721**トークン間の関係を確実に理解できるようになります。

**ERC20**コントラクトは、以下のインターフェイスを実装することも可能です。

```ts
interface IERC7631BaseNFTSkippable {
    /// @dev Emitted when the skip NFT status of `owner` is changed by
    /// any mechanism.
    ///
    /// This initial skip NFT status for `owner` can be dynamically chosen to
    /// be true or false, but any changes to it MUST emit this event.
    event SkipNFTSet(address indexed owner, bool status);

    /// @dev Returns true if ERC-721 mints and transfers to `owner` SHOULD be
    /// skipped during ERC-20 to ERC-721 synchronization. Otherwise false.
    /// 
    /// This method MAY revert
    /// (e.g. contract not initialized, method not supported).
    ///
    /// If this method reverts:
    /// - Interacting code SHOULD interpret `setSkipNFT` functionality as
    ///   unavailable (and hide any functionality to call `setSkipNFT`).
    /// - The skip NFT status for `owner` SHOULD be interpreted as undefined.
    ///
    /// Once a true or false value has been returned for a given `owner`,
    /// this method MUST NOT revert for the given `owner`.
    function getSkipNFT(address owner) external view returns (bool);

    /// @dev Sets the caller's skip NFT status.
    ///
    /// This method MAY revert
    /// (e.g. insufficient permissions, method not supported).
    ///
    /// Emits a {SkipNFTSet} event.
    function setSkipNFT(bool status) external;
}
```

`IERC7631BaseNFTSkippable` インターフェースは、**ERC20**と**ERC721**トークン間の同期中に、特定のオーナー向けに**ERC721**トークンのミント（新規発行）や送付をスキップするオプションを提供するための機能を定義しています。
これにより、ユーザーは自分のニーズに応じて、**ERC721**の自動発行または送付を回避する設定が可能になります。

#### 機能とイベント
- **`SkipNFTSet` イベント**
    - オーナーのNFTスキップステータスが変更された時に発生します。
    - このイベントは、ステータスが真（`true`）または偽（`false`）に変更されるたびに発行される必要があります。

- **`getSkipNFT(address owner)` 関数**
    - 特定のオーナーに対して**ERC721**トークンのミントや送付をスキップするかどうかのステータスを返します。
    - この関数は、ステータスが定義されていない場合やサポートされていない機能に対しては、`revert`（エラーを発生）する可能性があります。
    - しかし、一度オーナーに対してステータスが設定された後は、そのオーナーに対してこの関数が`revert`することはありません。

- **`setSkipNFT(bool status)` 関数**
    - 呼び出し元のオーナーのNFTスキップステータスを設定します。
    - この関数が成功すると、`SkipNFTSet` イベントが発行されます。
    - 権限が不足している場合や、このメソッドがサポートされていない場合には、この関数はリバートする可能性があります。

#### なぜ重要なのか？
このインターフェースを通じて、ユーザーは自分自身のプリファレンスに基づいて**ERC721**トークンの自動ミントや送付を管理することができます。
例えば、あるユーザーが**ERC20**トークンと**ERC721**トークン間の同期を望まない場合や、特定の条件下でのみミントや送付を許可したい場合に、この機能を活用することができます。
このような柔軟性は、ユーザーがブロックチェーン上の資産をより細かくコントロールできるようにするため、特にデジタルアセットの分野で有用です。

### ERC721拡張インターフェース

**ERC721**コントラクトは以下のインタフェースを実装する必要があります。

```ts
interface IERC7631Mirror {
    /// @dev Returns the address of the base ERC-20 contract.
    ///
    /// This method MAY revert or return the zero address
    /// to denote that a base ERC-20 contract has not been linked.
    ///
    /// If a non-zero address is returned, the returned address MUST
    /// implement `IERC7631Base` and its `mirrorERC721()` method MUST
    /// return the address of this contract.
    ///
    /// Once a non-zero address has been returned, this method
    /// MUST NOT revert and the returned value MUST NOT change.
    function baseERC20() external view returns (address);
}
```

`IERC7631Mirror` インターフェースは、**ERC721**トークン（ミラーコントラクト）が、それと連携する**ERC20ト**ークン（ベースコントラクト）に関する情報を提供するために使用されます。
具体的には、**ERC721**トークンコントラクトが、自身に紐づく**ERC20**コントラクトのアドレスを返す機能を定義しています。

#### `baseERC20()` 関数について
- **目的**
    - この関数は、関連付けられているベースコントラクト（**ERC20**コントラクト）のアドレスを返します。
- **挙動**
  - **正常**
      - 非ゼロアドレスが返される場合、そのアドレスは `IERC7631Base` インターフェースを実装していなければならず、`mirrorERC721()` メソッドはこの**ERC721**コントラクトのアドレスを返さなければなりません。
  - **異常**
    - 基本**ERC20**コントラクトがまだリンクされていない場合、この関数はゼロアドレスを返すか、`revert`（エラーを発生）することがあります。
    - 一度非ゼロアドレスが返された後は、このメソッドはリバートすることなく、返される値は変更されないことが保証されます。

#### なぜ重要なのか？
このインターフェースを通じて、**ERC721**コントラクト（ミラーコントラクト）は、それ自身がどの**ERC20**コントラクト（ベースコントラクト）と関連付けられているかを明確に示すことができます。
これにより、開発者やユーザーは**ERC20**と**ERC721**トークン間の関連を容易に識別し、管理することが可能になります。
また、**ERC721**と**ERC20**間の連携機能を実装する時の信頼性と互換性が向上します。

## 補足

このテキストは、二重性質トークンペアに関する提案の理由や実装の検出、NFTのスキッピング、実装規約、およびリンキングメカニズムについて説明しています。

### 実装検出
#### `mirrorERC721` と `baseERC20` メソッド
これらは非ゼロアドレスを返すことで、**ERC20**と**ERC721**コントラクトがそれぞれ必要なインターフェースを実装していることを示します。
そのため、**ERC165**（インターフェース検出標準）は必要ありません。

:::message
**ERC165**については以下の記事を参考にしてください。
:::

[\[ERC165\] コントラクトが特定のインターフェースをサポートしているか確認する仕組みを理解しよう！](/articles/541184977a5cba51b759)

#### `getSkipNFT` と `setSkipNFT` メソッド
これらのメソッドは`revert`する可能性がありますが、SolidityやVyperでコンパイルされたコントラクトは未定義のメソッドへの呼び出しで自動的に`revert`するため、これらのメソッドの明示的な定義がない場合でも `IERC7631BaseNFTSkippable` に準拠しているとみなされます。

### NFTのスキッピング
#### デフォルトの挙動
`getSkipNFT` は、オーナーがスマートコントラクトである場合にデフォルトで `true` を返すというパターンが有用です。
これにより、**ERC20**の`transfer`があるたびに**ERC721**トークンが自動的にミントされることをデフォルトで回避でき、**ERC20**の流動性プールが不必要に**ERC721**トークンを受け取ることを避けられます。

### 実装規約
#### ベースコントラクトとミラーコントラクト
**ERC20**コントラクトは慣例によりベースコントラクトとされ、**ERC721**トークンのバランスを**ERC20**のバランスから便利に導出できます。
しかし、必要に応じてほとんどのロジックを**ERC721**コントラクトに実装することも可能です。

#### トークン同期ロジックのカバー外
提案はトークン同期ロジックを扱っていません。
これは、様々な実装パターンや新しい使用例（例えば、自動的にリベースされるトークンなど）に柔軟性を持たせるためです。

### リンキングメカニズム
#### リンキングプロセスの省略
リンキングプロセスは柔軟性を持たせるために省略されています。
開発者は任意のメカニズム（例えば、コンストラクター内でのリンキング、initilizerを使用する、または二つのコントラクト上のカスタム管理者専用の公開メソッドを通じてのリンキングなど）を使用できます。
唯一の制限は、一度確立されたペアリングが不変である必要があることです（インデックス作成ロジックを単純化するため）。

:::message
#### リンキングプロセスの柔軟性
「**リンキング**」とは、二つの異なる種類のトークン（この場合は**ERC20**と**ERC721**）を互いに関連付けるプロセスのことです。
この関連付けにより、一方のトークンの動きがもう一方に影響を与えるようになります。
ただし、具体的にどのようにこれらのトークンを関連付けるかは、あえて詳細に定められていません。
これは、開発者が自由に最適な方法を選べるようにするためです。

#### リンキングの方法
開発者は、トークンを関連付けるためにさまざまな技術的アプローチを取ることができます。
いくつかの一般的な方法は以下の通りです。

- **コンストラクター内でのリンキング**
    - トークンコントラクトが作成される時に、他方のトークンコントラクトのアドレスを設定します。
- **イニシャライザを使用する**
    - コントラクトが初期化される時に、関連付けを設定します。
    - これは、アップグレード可能なコントラクトなど特定の状況で有用です。
- **カスタム管理者専用の公開メソッドを通じてのリンキング**
    - コントラクトがデプロイされた後、管理者だけが特定の関数を呼び出してトークンを関連付けることができます。

#### リンキングの不変性
リンキングされた一度確立された関係は、変更不可能である必要があります。
これは、トークン間の関連を追跡しやすくするため、またシステムの安全性を保つために重要です。
一度設定されたリンキングは後から変更できないようにすることで、データの一貫性や予測可能性を高めることができます。

この柔軟性は、さまざまなプロジェクトや用途に合わせて最適なリンキング方法を選択できるようにするために設けられています。
同時に、リンキングの不変性により、システム全体の安定性と信頼性を保つことが目指されています。
:::

## セキュリティ

### 同期アクセスガード

#### 問題
二重性質トークンペア間の同期ロジックは外部からアクセス可能ですが、不適切なアクセス管理が行われているとセキュリティリスクが生じます。

#### 対策
同期メソッドは、他方のコントラクトのみが呼び出しを許可されるように厳格に制御する必要があります。
これにより、無関係な第三者による不正な操作を防ぎます。

### レアNFTのスナイピング
#### 問題
異なる希少性レベルを持つ**ERC721**トークンを提供するコレクションでは、メタデータをスクレイピングしてゲーミングすることで、希少なNFTを不正に取得されるリスクがあります。

#### 対策
**ERC721**トークンのメタデータは、同じアカウントによって一定期間保持された後にのみ公開されるよう要求することが推奨されます。
これにより、メタデータの不正な利用を防ぐことができます。

### ガス切れによるサービス拒否（DoS）

#### 問題
**ERC20**トークンの送付が自動的に**ERC721**トークンのミント、`transfer`、またはバーンを引き起こすと、通常の**ERC20**トークン`transfer`のO(1)ガスコストに対して、O(n)ガスコストが発生する可能性があります。
これは、大量の**ERC721**トークン操作によりガス切れを引き起こし、サービス拒否（DoS）問題につながる可能性があります。

#### 対策
**ERC721**トークンIDの選択ロジックを含む同期ロジックは、**ERC721**に関連するガスコストを考慮して設計する必要があります。
これにより、ガス切れによるサービス拒否（DoS）問題を防ぐことができます。

これらのセキュリティ上の考慮事項は、安全な二重性質トークンペアの実装と運用を保証するために重要です。
開発者はこれらのリスクを理解し、適切な対策を講じることが求められます。

## 引用

vectorized (@vectorized), Thomas (@0xth0mas), Quit (@quitcrypto), Michael Amadi (@AmadiMichael), cygaar (@cygaar), Harrison (@pop-punk), "ERC-7631: Dual Nature Token Pair [DRAFT]," Ethereum Improvement Proposals, no. 7631, February 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7631.

## 最後に

今回は「**ERC20**と**EREC721**のトークンが相互に影響し合い、柔軟にトークンの設計や運用ができる仕組みを提案している**ERC7631**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
