[ERC7575] ERC4626を拡張してマルチアセット保管を可能にする仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、**ERC4626**を拡張して、より柔軟な資産管理と多様な資産の預入と引き出しを可能にする仕組みを提案している**ERC7575**についてまとめていきます！

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

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

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

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

# 概要

まず、**ERC4626**、**ERC20**、**ERC165**などの用語が出てくるのでこの説明からしていきます。

### ERC4626
**ERC4626**は、イーサリアムのスマートコントラクトで使われる標準の一つで、特に「**資産ヴォールト**」の仕組みを提案しています。
ヴォールトとは、ユーザーが仮想通貨などの資産を預け入れたり、引き出したりできるようにするための仕組みです。

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

https://qiita.com/cardene/items/99db4ee3074ab6c8c4e2

:::note info
**ERC4626**は、イーサリアムのブロックチェーン上で動作する資産ヴォールト（Vault）のための標準規格です。
ここでいう「**ヴォールト**」とは、ユーザーが仮想通貨やトークンなどのデジタル資産を預け入れることができるスマートコントラクトのことを指します。
この標準は、資産を預け入れたり引き出したりする時の一連の振る舞いやルールを定義することで、異なるプロジェクト間での資産管理の互換性と標準化を目指しています。

### 主な特徴と目的
- **標準化されたインターフェース**
    - **ERC4626**は、資産の預入れ、引き出し、資産に対する利息や報酬の計算など、資産ヴォールトが行う一般的な操作に対して統一されたインターフェースを提供します。
    - これにより、異なるヴォールト間でも互換性が生まれ、ユーザーや開発者がより簡単にこれらのシステムを理解し、利用できるようになります。

- **透明性の向上**
    - 規格に準拠することで、ヴォールト内の資産管理プロセスが標準化され、より透明性が高まります。
    - これは、投資家や利用者が自身の資産がどのように管理されているかをより容易に理解できることを意味します。

- **相互運用性**
    - 異なるプロジェクトやアプリケーション間での資産の移動や管理がスムーズに行われるようになります。
    - 例えば、**ERC4626**に準拠したヴォールトは、さまざまなDeFi（分散型金融）プラットフォームや投資戦略に容易に統合されることが可能です。

- **拡張性**
    - 基本的なインターフェースを提供しつつも、個々のヴォールトはその上で独自の機能やルールを実装することができます。
    - これにより、多様なニーズに応じたカスタマイズが可能になります。

### 使用例
- **投資ヴォールト**
    - ユーザーがトークンを預けると、それらのトークンを使ってさまざまな投資戦略を実行し、利益を生み出すようなヴォールト。
- **貯蓄アカウント**
    - 定期的に利息を生むような、貯蓄用のヴォールト。
- **流動性プール**
    - 特定のトークンペアに流動性を提供し、その報酬として手数料や他のインセンティブを得られるヴォールト。

**ERC4626**は、これらのヴォールトがより一貫した方法で資産を管理し、ユーザーに対して透明で信頼性の高いサービスを提供するための基盤を作ることを目的としています。
:::

### ERC20
**ERC20**は、イーサリアム上でのトークンの標準規格です。
多くのトークンがこの標準に従って作られており、トークンの発行や送信、残高の確認などの基本的な操作を定義しています。

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

https://chaldene.net/erc20

### ERC165
**ERC165**は、スマートコントラクトがどのインターフェースをサポートしているかを識別するための標準です。
これにより、あるコントラクトが特定の機能や規格をサポートしているかをプログラム的に確認できるようになります。

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

https://qiita.com/cardene/items/541184977a5cba51b759

### 多資産対応と新しい共有方法
ここで提案されている新しい標準は、**ERC4626**を拡張して、複数の資産や複数のエントリポイントをサポートするようにしています。
これは、1つのシェアトークンに対して、複数の異なる資産を預け入れることができるようにすることを意味します。
新しい共有方法を追加することで、**ERC20**トークンの依存関係を外部化し、ヴォールトが直接**ERC20**トークンを管理しなくてもよくなります。
これにより、実際には「**シェアトークン**」を持たないヴォールトも可能になります。
つまり、二つの異なる外部トークン間で変換を行うだけのシンプルなヴォールトが作れるということです。

### ERC165サポートの強制
この新しい標準では、すべてのヴォールトが**ERC165**をサポートすることが義務付けられます。
これは、ヴォールトがサポートする機能を識別しやすくするためのもので、より多様なヴォールトの統合と相互運用性を可能にします。

:::note info
この新しい標準は、より柔軟な資産管理を可能にし、様々な資産やトークン間での変換を容易にし、ヴォールトの機能をより明確に識別できるようにすることを目的としています。
:::

# 動機

**ERC4626**は、「**ヴォールト**」のための標準ですが、すべてのユースケースをカバーしているわけではありません。

### ERC4626の制約
**ERC4626**は基本的に、ヴォールトが**ERC20**トークン標準に準拠することを要求しています。
これは、ヴォールト内の資産を代表するトークンが、**ERC20**として振る舞う必要があるということです。

### 複数資産や複数エントリーポイントのヴォールト
しかし、実際には「**複数の資産**」を扱うヴォールトや「**複数のエントリーポイント**」を持つヴォールトが存在します。
例えば、流動性プロバイダー（LP）トークンを扱うヴォールトなどがこれにあたります。
LPトークンは、ユーザーが流動性プールに資産を提供することで得られるトークンで、そのプール内の資産の一部を表しています。

### ERC4626との非互換性
このようなヴォールトは、複数の異なるタイプの資産を預かるか、または特定の複雑な操作（例えば、特定の資産ペアに対する流動性の提供など）を通じてエントリーポイントを提供します。
これらのケースでは、ヴォールトが単一の**ERC20**トークンによってその振る舞いを完全に表現することが難しくなることがあります。

**ERC4626**はこれらの複雑なヴォールトにとって扱いにくい、あるいは準拠できない可能性があります。
これは、**ERC4626**が設計された時の基本的な前提が、ヴォールトが単一の資産タイプのみを扱う、比較的シンプルなケースに基づいているためです。

:::note info
**ERC4626**の現在の構造では、複数の資産を扱ったり、より複雑な流動性プロバイダートークンなどをサポートするようなヴォールトのニーズに対応できない場合があります。
これは、そのようなヴォールトが**ERC20**トークンの枠組みに収まりにくい、特殊なケースであるためです。
:::

# 仕様

## 定義

### ERC4626の既存の定義
**ERC4626**は、イーサリアムのブロックチェーン上で動作する資産ヴォールトのための標準規格です。
ヴォールトとは、ユーザーがデジタル資産（トークン）を預け入れたり引き出したりできるスマートコントラクトのことを指します。
**ERC4626**では、これらの操作に関する一連の標準的なインターフェースとルールが定義されています。

### マルチアセットヴォールト（Multi-Asset Vaults）
「**マルチアセットヴォールト**」とは、複数の異なる資産（トークン）を預け入れることができるヴォールト、または複数の異なる方法（エントリーポイント）で資産を預け入れることができるヴォールトを指します。
従来のヴォールトが一種類のトークンのみを対象としていたのに対し、マルチアセットヴォールトはより複雑な資産管理や多様な投資戦略を実現することができます。

### パイプ（Pipe）
「**パイプ**」とは、あるトークンを別のトークンに変換するためのコンバーター（変換器）を指します。
この変換は一方向（単方向）の場合もあれば、双方向の場合もあります。
パイプを使用することで、ユーザーは自分が持っているトークンを、ヴォールトが受け入れ可能な別のトークンに変換し、その後、変換されたトークンをヴォールトに預け入れることができます。
この機能は、ヴォールトの利便性を高めると同時に、より多様な資産を扱うことが可能になります。

:::note info
これらの用語は**ERC4626**ヴォールトの機能拡張を指しており、ユーザーが異なる種類の資産を柔軟に管理できるようにするためのものです。
マルチアセットヴォールトにより、ユーザーは複数のトークンを一つのヴォールト内で管理できるようになり、パイプを通じてトークンの変換が簡単に行えるようになります。
:::

## メソッド

あるスマートコントラクト（ヴォールト）のメソッド（関数）`share`に関する説明です。
このメソッドは、ヴォールトに資産を預け入れた時に受け取る「**シェア**」の表現について定義しています。
具体的には、ヴォールト内のシェアをどのように扱うかについてのルールが述べられています。

### `share`メソッドの役割
`share`メソッドは、ヴォールトの**ERC20**トークン表現、つまりヴォールトのシェアを示すトークンのアドレスを返します。
これにより、ヴォールトに資産を預けることで得られるシェアがどのトークンであるかを知ることができます。

### シェアの扱い
`share`がヴォールト自体のアドレスを返す場合もあります。
これは、ヴォールト自身がシェアのトークン表現として機能することを意味します。
もし`share`がヴォールト外の外部トークン（つまり、`share != address(this)`）を返す場合、以下のルールが適用されます。
    - **エントリー関数**（資産をヴォールトに預ける関数）は、受取人のシェアの残高を増やさなければなりません（`share.balanceOf(receiver) += shares`）。
    - **エグジット関数**（ヴォールトから資産を引き出す関数）は、所有者のシェアの残高を減らさなければなりません（`share.balanceOf(owner) -= shares`）。
このメソッドは、操作が失敗した場合でもリバート（エラーによる処理の中断）してはなりません。

### `share`メソッドの構造

```yaml
- name: share
  type: function
  stateMutability: view

  inputs: []
  outputs:
    - name: shareTokenAddress
      type: address
```

- **関数名**
    - `share`
- **タイプ**
    - 関数
- **状態の変更可能性**
    - `view`（この関数が状態を変更せず、外部から読み取り可能であることを意味します）
- **入力**
    - なし
- **出力** 
  - **名前**
      - `shareTokenAddress`
  - **タイプ**
      - `address`（シェアを表す**ERC20**トークンのアドレス）

このメソッドは、ヴォールトに関連するシェアの取り扱い方を定義することで、ユーザーが資産を預け入れたり引き出したりする時の透明性と予測可能性を高めるのに役立ちます。

## Multi-Asset Vaults

「**マルチアセットヴォールト**」は、複数の資産（トークン）を1つのヴォールト内で管理し、それらを代表する1つのシェアトークンを共有するという概念に基づいています。
ここでいう「**エントリーポイント**」とは、ヴォールトに資産を預け入れるための異なる方法やアクセスポイントを指します。
それぞれのエントリーポイントは異なる資産トークンで表されることがあります。

### マルチアセットヴォールトの特徴
#### 単一のシェアトークン
マルチアセットヴォールトは、ヴォールト内のさまざまな資産に関わらず、1つのシェアトークンでユーザーの持分を表します。
つまり、ユーザーがヴォールトに異なる種類の資産を預けても、得られるシェアトークンは同じです。

#### 複数のエントリーポイント
これらのヴォールトは、異なる種類の資産トークンで表される複数のエントリーポイントを提供します。
これにより、ユーザーは好みの資産を使ってヴォールトに参加することができます。

### 実装要件
#### `share`メソッドの実装
マルチアセットヴォールトは、各エントリーポイントで`share`メソッドを実装しなければなりません。
これは、ユーザーがどのエントリーポイントを通じて資産を預ける場合でも、その持分が正確に計算され、適切なシェアトークンが発行されることを保証します。

#### ERC20ではないエントリーポイント
エントリーポイントは**ERC20**トークンであるべきではありません。
これは、ヴォールトへの資産の預け入れや引き出しの方法が、通常の**ERC20**トークンの送信や受信とは異なる特殊な操作を必要とするためです。
エントリーポイントは、資産の預け入れや引き出しに特化した機能を提供し、それぞれ異なる資産タイプに対応します。

:::note info
マルチアセットヴォールトはユーザーに対し、複数の資産を使って1つのヴォールトに参加する柔軟性を提供します。
そして、ヴォールト内でのユーザーの持分は、複数の資産に関わらず、単一のシェアトークンで統一的に管理されます。
このアプローチにより、異なる資産を扱いながらも、ヴォールトの管理とユーザー体験の両方をシンプルに保つことが可能になります。
:::

## パイプ

「**パイプ**」とは、マルチアセットヴォールトの文脈で使用される概念であり、資産（トークン）とヴォールトのシェアトークンの間の変換を行うためのメカニズムを指します。
ここでの「**シェア**」とは、ユーザーがヴォールトに資産を預け入れた時に得られる、ヴォールト内の持分を表すトークンです。
パイプを通じて、ユーザーは自分の持っている**ERC20**トークンをヴォールトのシェアトークンに変換することができます。
また、この変換はヴォールトの外部で行われます。

### パイプの特性

#### 単一資産とシェアの変換
パイプは、ユーザーが持つ特定の単一の資産（**ERC20**トークン）を、ヴォールトのシェアトークンに変換します。
逆の変換も可能ですが、これはパイプの方向性に依存します。

#### 方向性
パイプには「**単方向（unidirectional）**」と「**双方向（bidirectional）**」の二つのタイプがあります。

#### 単方向パイプ
資産からシェアへの変換のみをサポートします。
これは、主に資産の預け入れに使用されます。

#### 双方向パイプ
資産からシェアへの変換と、その逆の変換の両方をサポートします。
これにより、ユーザーはヴォールトに資産を預けるだけでなく、シェアを資産に戻す操作も行うことができます。

### 単方向パイプの操作
単方向パイプは、「**預け入れ（deposit）**」や「**発行（mint）**」といったエントリー関数のみを実装します。
これらの関数は、ユーザーが持っている資産をヴォールトのシェアトークンに変換するために使用されます。

#### 預け入れ（deposit）
ユーザーが持っている資産をパイプに送り、それに応じた量のシェアトークンを受け取る操作です。

#### 発行（mint）
特定の条件下で、ユーザーの資産を基に新たにシェアトークンを生成する操作です。

パイプの概念を通じて、ヴォールトとユーザーの資産間の柔軟な変換が可能になり、より複雑な資産管理戦略やユーザー体験の向上が実現されます。

## ERC165サポート

**ERC7575**を実装するスマートコントラクトが、**ERC165**標準にも対応する必要があります。

### ERC-165
**ERC165**は、スマートコントラクトが特定のインターフェイスをサポートしているかどうかを検出するための標準です。
これにより、スマートコントラクトが特定の機能や規格に準拠しているかを外部から確認できるようになります。

### ERC165の`supportsInterface`関数
この関数は、スマートコントラクトが特定のインターフェースをサポートしているかどうかを確認するために使用されます。
関数には`interfaceID`という引数があり、これにはチェックしたいインターフェースの識別子が渡されます。
関数は、そのインターフェースがサポートされている場合は`true`を、そうでない場合は`false`を返します。

### ERC7575との関連
**ERC7575**を実装するスマートコントラクトは、`supportsInterface`関数を実装し、`0x2f0a18c5`という特定の`interfaceID`が渡されたときに`true`を返す必要があります。
これは、**ERC7575**がこの特定のインターフェース識別子に対応していることを意味します。
つまり、この機能を通じて、外部のエンティティ（他のコントラクトやユーザー）は、スマートコントラクトが**ERC7575**をサポートしているかをプログラム的に確認できるようになります。

## Share-to-Vault lookup

ある**ERC20&&トークン（ここでは「**シェア**」と呼ばれています）が特定の資産に対するヴォールトのアドレスを返すために、`vault`という名前の関数を実装する必要があります。

### `vault`関数の役割
この関数は、特定の資産（`asset`）に関連付けられたヴォールトのアドレスを返します。
言い換えると、ユーザーが持っているシェアトークンがどのヴォールトに対応しているのかを知るための方法を提供します。

### 関数の仕様
- **関数名**
    - `vault`
- **タイプ**
    - 関数
- **状態変更の可能性**
    - `view`（この関数がブロックチェーンの状態を変更しないことを示し、外部から読み取り可能であることを意味します）

### 入力
- **資産のアドレス**（`asset`）
    - この入力は、ユーザーがヴォールトのアドレスを知りたい特定の資産のアドレスです。

### 出力
- **ヴォールトのアドレス**（`vault`）
    - この出力は、指定された資産に対してユーザーのシェアが存在するヴォールトのアドレスです。

### 使用例
想定される一般的な使用例としては、ユーザーが自分のシェアトークンがどのヴォールトに関連しているのかを知りたい場合に、この関数を呼び出します。
例えば、ユーザーが複数のヴォールトに資産を預けており、各ヴォールトから得られるシェアトークンを持っている場合、各シェアトークンがどのヴォールトに属しているのかを簡単に特定することができます。

このように、`vault`関数はユーザーにとって有用な情報を提供し、異なるヴォールト間での資産管理をより簡単にし、システムの透明性を高めることが期待されます。

```yaml
- name: vault
  type: function
  stateMutability: view

  inputs: 
    - name: asset
      type: address
    
  outputs:
    - name: vault
      type: address
```

# 補足

この規格は、既存の**ERC4626**ヴォールトに簡単に適用できる柔軟性を持たせつつ、新しいユースケースをサポートするための柔軟性を提供します。

### ERC20依存性の外部化
この提案では、シェア（ヴォールトの持分を表すトークン）がヴォールト自体のアドレスとは異なる場合（`share != address(this)`）を許容しています。
これにより、ヴォールトはシェアの**ERC20**機能を管理する外部コントラクトを持つことができます。
このアプローチは、特にマルチアセットヴォールトの場合に有効で、各ヴォールトが自身を**ERC20**として振る舞う必要がある場合の混乱を避けることができます。
これは、統合者やフロントエンドにとっての混乱を減少させる効果があります。

### 新しいタイプのヴォールトの創出
さらに、このアプローチにより、パイプと呼ばれる新しいタイプのヴォールトが可能になります。
パイプは、二つの外部**ERC20**トークン間の変換を容易にします。これらのパイプは単方向（例えば、資産からシェアへの変換のみをサポートする）または双方向（エントリーとエグジットの両方のフローをサポートする）である可能性があります。

### シェアからヴォールトへのルックアップ
「`vault`」メソッドの導入により、特定の資産に対するシェアを持つヴォールトを簡単に検索できます。
これにより、マルチアセットヴォールトの統合が容易になります。
このメソッドはオプショナルであり、既存のデプロイ済みのコントラクトがシェアとして機能する場合に後方互換性を維持します。

:::note info
この提案は、ヴォールトとそのシェアの管理をより柔軟にし、新しいユースケースをサポートするための方法を提供します。
これにより、既存のヴォールトを維持しつつ、新しい形式のヴォールトを作成することが可能になり、エコシステム全体の革新と成長を促進することができます。
:::

# 互換性

**ERC4626**と**ERC7575**の互換性に関するこの説明は、既存の**ERC4626**ヴォールト（資産を預け入れるためのスマートコントラクト）を、新しい**ERC7575**標準に準拠させるための簡単な手順を提案しています。

### ERC7575への互換性
**ERC7575**は、既存の**ERC4626**ヴォールトに新しい機能や拡張性をもたらす新しい標準です。
特に「**シェア**」メソッドを追加することが推奨されています。

### 「シェア」メソッドの追加
「`share`」メソッドをヴォールトに追加することで、そのヴォールトのアドレスを返す機能が提供されます。
これは、**ERC7575**の要件を満たすためのものであり、このメソッドを通じて、ヴォールトが自身のアドレス情報を外部に公開することができます。
既存の**ERC4626**ヴォールトは、新しい標準に対応するために必要な最小限の変更で**ERC7575**に準拠することができます。

# セキュリティ

**ERC20**標準に準拠していないヴォールトが、所有者が`msg.sender`（トランザクションを発行したアドレス）ではない場合の引き出し（**redeem**）フローをサポートする時の注意点について述べています。


### セキュリティ上の問題点
ヴォールトとシェアが別のコントラクトである場合、**ERC20**の承認フローだけでは引き出しフローを適切にサポートできない可能性があります。
これは、ヴォールトがシェアトークンの`transfer`を直接承認できないため、所有者が`msg.sender`でない引き出しリクエストを正しく処理することが難しいからです。

### 解決策：ERC2771を使用した`transfer`
この問題を解決するための提案として、**ERC2771**を使用してヴォールトをシェアトークンの「**Trusted Forwarder**」として設定する方法があります。
**ERC2771**は、メタトランザクション（ユーザーがガス代を支払わずにトランザクションを送信できる仕組み）をサポートするための標準です。
この標準を使うと、ヴォールトがシェアトークンに対する操作を代行し、`msg.sender`が実際のトークンの所有者でなくても、所有者に代わってトークンの転送や引き出しなどの操作を行うことができるようになります。

:::note info
**ERC20**に準拠していないヴォールトは、所有者が操作を直接行わない引き出しフローをサポートする時に注意が必要です。
**ERC2771**を利用することで、これらのヴォールトがシェアトークンの信頼された`transfer`元アドレスとして機能し、セキュリティリスクを軽減しながら便利な引き出しフローを提供できるようになります。
:::

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

https://qiita.com/cardene/items/e84f53471b7a79240f33

# 引用

Jeroen Offerijns (@hieronx), Alina Sinelnikova (@ilinzweilin), Vikram Arun (@vikramarun), Joey Santoro (@joeysantoro), Farhaan Ali (@0xfarhaan), "ERC-7575: Multi-Asset ERC-4626 Vaults [DRAFT]," Ethereum Improvement Proposals, no. 7575, December 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7575.

# 最後に

今回は「**ERC4626**を拡張して、より柔軟な資産管理と多様な資産の預入と引き出しを可能にする仕組みを提案している**ERC7575**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下の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