# [ERC2535] 💎 ダイヤモンドパターンの仕組みを理解しよう！

> この規格では、アップグレーダブルなスマートコントラクトをより柔軟に管理する仕組みを提案しています。

- URL: https://cardene.dev/articles/51fc6fc998421c4d931a
- 公開日: 2023-08-23
- 更新日: 2023-08-23
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、アップグレーダブルなコントラクトの規格の1つである、ダイヤモンドパターンの提案をしている**ERC2535**についてまとめていきます！

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

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

## 概要

この規格では、アップグレーダブルなスマートコントラクトをより柔軟に管理する仕組みを提案しています。

:::message
コントラクトのアップグレードについては以下の記事を参考にしてください。
:::

https://chaldene.net/upgradable-contracts

https://speakerdeck.com/cardene/upgradable-contractnituitewakariyasukujie-shuo


この方法は「**ダイヤモンド**」と呼ばれています。
ダイヤモンドを使うことで、スマートコントラクトをデプロイした後でもコントラクトの機能をアップグレードしたり新たな機能を追加できます。
さらに、サイズ制限にも縛られずにコントラクトを拡張できる「**モジュール式スマートコントラクトシステム**」という特徴を持ちます。

![34.png](/images/qiita-b5bbd43e-18d2-42bd-e854-5fdfc90b8a6b.webp)

ダイヤモンドというのは、外部から呼び出せる関数を持ったコントラクトです。
関数の実際の処理は、ファセットと呼ばれる別のコントラクトによって提供されます。
このファセットはそれぞれが独立して存在し、内部の処理やライブラリ、状態変数を共有することができる仕組みです。

イメージとしては、ダイヤモンドが宝石の中心部分であり、その周りに複数の小さなファセットが取り付けられています。
各ファセットは異なる機能を提供し、必要に応じて追加したり交換したりできます。
これによって、スマートコントラクト全体の機能を簡単に管理・拡張できるのです。

![35.png](/images/qiita-249ea6e7-2fac-db49-2a84-d1b83dd75797.webp)

## 動機

#### 無制限なコントラクト機能の単一アドレス化
ダイヤモンドを利用する利点の1つは、コントラクトの機能を1つのアドレスで管理できることです。
それぞれの機能は各ファセットで管理されているため、ダイヤモンドにアクセスすることでそれぞれの機能にアクセスできます。
これにより、スマートコントラクトのデプロイ、テスト、他のスマートコントラクトやソフトウェア、ユーザーインターフェースとの統合がシンプルになります。

#### 24KBの最大コントラクトサイズを超える場合
もしスマートコントラクトが最大`24KB`の制限を超える場合、関連する機能を1つのコントラクト内または単一のコントラクトアドレスで保持するのが良い場合があります。
ダイヤモンドを使うことで、最大コントラクトサイズの制限に縛られずに機能を管理できます。

:::message
コントラクトにはサイズ制限があり、最大約`24`KBとなっています。
今回提案されている手法の場合、各機能を別コントラクトに切り出して読み込むことができるため、サイズ制限に対処できます。
:::

https://ethereum.org/ja/developers/tutorials/downsizing-contracts-to-fight-the-contract-size-limit/

#### コントラクトコードとデータの整理
複数の機能を持つコントラクトシステムを構築する場合、ダイヤモンドは異なる機能を分離して組み立て、必要に応じてデータを共有する手段を提供します。
これにより、ガスの効率を考慮しながら機能を組み合わせることができます。

#### 機能のアップグレード
アップグレード可能なダイヤモンドは、機能を追加、置換、削除するためにアップデートできます。
ダイヤモンドには最大コントラクトサイズの制限がないため、時間の経過とともに新たな機能を追加し続けることができます。
既存の機能を再デプロイすることなくアップグレードでき、一部の機能だけを変更することも可能です。

#### イミュータブルなダイヤモンド
イミュータブル（変更不可能）なダイヤモンドをデプロイしたり、アップグレード可能なダイヤモンドを後からイミュータブルにすることができます。
これによって、コントラクトの状態を保持しつつもアップグレードのリスクを軽減できます。

:::message
イミュータブルとは**変更不可能**なコントラクトのことです。
その反対がアップグレードできるコントラクトです。
:::

#### デプロイ済みコントラクトの再利用
新たなコントラクトをデプロイする代わりに、既存のオンチェーンコントラクトを使用してダイヤモンドを作成できます。
これによって、既存のコントラクトを再利用してカスタムのダイヤモンドを作成することができます。
これは、新たなスマートコントラクトプラットフォームやライブラリの構築に役立ちます。

:::message
既存のコントラクトを利用することで、他にも以下のようなメリットがあります。

**コスト削減**
コントラクトのデプロイにはガス費用がかかります。
既にデプロイされたコントラクトを再利用することで、新たにコントラクトをデプロイする時のガスを削減できます。

**時間短縮**
コントラクトのデプロイには時間がかかります。
既存のコントラクトを再利用することで、新たなコントラクトをゼロからデプロイする手間や時間を省くことができます。
特に、複数のダイヤモンドを作成する場合や、一般的な機能を提供するライブラリを利用する場合に効果的です。

**コード信頼性**
既存のコントラクトはすでにテストおよび運用されており、その信頼性が確立されています。
コントラクトの監査などがされていればより信頼性が強固になります。
再利用することで、これらのコントラクトが適切に動作することが保証されます。

**コントラクトの互換性**
既存のコントラクトは、すでに他のコントラクトやプロジェクトとの統合が行われている可能性があります。
このコントラクトを再利用することで、互換性のあるDappなどを簡単に作成できます。
:::

この規格は、**EIP1538** の改良版です。

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

### ファセットの共有
デプロイ済みのファセットは、複数のダイヤモンドで共有して利用できます。
以下の図では、同じファセットが異なるダイヤモンドで使用されている様子を示しています。

- Diamond1が**FacetA**を使用
- Diamond2が**FacetA**を使用
- Diamond1が**FacetB**を使用
- Diamond2が**FacetB**を使用
- Diamond1が**FacetA**と**FacetB**のデータを管理
- Diamond2が**FacetA**と**FacetB**のデータを管理

この仕組みにより、リソースの有効な共有が可能となっています。

![facetreuse.png](/images/qiita-ba95d82b-7614-3092-6bee-d6f8c882b031.webp)

### アップグレード可能なダイヤモンドと中央集権的なプライベートデータベース

アップグレード可能なダイヤモンドと中央集権的なプライベートデータベースの違いについて説明していきます。

#### 分散型自治組織（DAO）とアップグレード
アップグレード可能なダイヤモンドを使用すると、分散型自治組織（DAO）などの仕組みを介してコントラクトをアップグレードできます。
つまり、コミュニティの合意に基づいてコントラクトをアップグレードできるのできます。

##### Ethereumエコシステムとの連携
アップグレード可能なダイヤモンドは、Ethereumエコシステムとシームレスに連携できます。
これにより、他のスマートコントラクトやアプリケーションとの連携が容易で、複雑な機能を提供できます。

##### 透明性と検証可能な履歴
アップグレード可能なダイヤモンドでは、オープンなストレージデータと検証済みのソースコードを使用することで、コントラクトの信頼性や変更履歴に透明性を持たせます。
これにより、コントラクトの信頼性を証明することが可能です。

##### 透明性による問題の発見
オープンなデータベースを使用することで、問題や不正行為が発生した場合に早期に発見し対処できます。
透明性によって、問題が隠されることなくコミュニティ全体で監視できます。

##### セキュリティと専門家の監査
アップグレード可能なダイヤモンドの変更履歴をセキュリティやドメインの専門家が監査し、その信頼性を保証できます。
これによって、コードの安全性と信頼性を高めることができます。

##### イミュータブルなダイヤモンドへの変化
アップグレード可能なダイヤモンドは、後にイミュータブルで信頼性のある状態に変更することもできます。
これにより、安定した状態でコントラクトを維持し、改ざんを防ぐことができます。

アップグレード可能なダイヤモンドは、分散性と透明性を基にした改善と信頼性向上のメリットを提供します。
一方、中央集権的なプライベートデータベースは、これらの利点を持たない場合が多いです。

### ダイヤモンドのメリット

#### 1. 決まったアドレスで機能提供
ダイヤモンドは決まったアドレスで必要な機能を提供します。

:::message
通常、スマートコントラクトは特定のアドレスにデプロイされますが、そのアドレスは一度決まると変更することができません。
しかし、新たな機能の追加やアップグレードが必要な場合、従来のスマートコントラクトでは新たなアドレスで新しいコントラクトをデプロイする必要があります。

一方、ダイヤモンドは、一つの決まったアドレスに異なる機能や機能のバージョン（ファセット）を統合します。
これにより、ユーザーや他のコントラクトは常に同じアドレスを使用してダイヤモンドの機能にアクセスできます。
新たな機能を追加する場合でも、同じアドレスで新しいファセットを追加することで、アドレスの変更を避けることができます。

具体的な例で見てみましょう。
あなたがあるプロジェクトでスマートコントラクトを開発しており、そのコントラクトには複数の機能が含まれています。
従来のスマートコントラクトでは、新たな機能を追加するために新しいアドレスでコントラクトをデプロイする必要があります。
しかし、ダイヤモンドを使用すると、既存のアドレスに新しい機能を追加するだけで済みます。
これにより、ユーザーは常に同じアドレスを使用して、新たな機能にアクセスできるようになります。

簡単に言えば、ダイヤモンドは1つのアドレスで複数の機能を提供することで、アドレスの安定性と使いやすさを両立させる仕組みです。
:::

:::message
以下のアップグレーダブルなコントラクトについての記事が参考になります。
:::

https://chaldene.net/upgradable-contracts

[スマートコントラクトのアップグレードを理解しよう！](/articles/339d9fd83955cda55d14)

#### 2. 多機能の単一アドレス
ダイヤモンドは複数の独立したコントラクト（ファセット）の機能を1つのアドレスで統合します。
それぞれの機能は独立していて、内部関数やライブラリ、状態変数を共有できます。

#### 3. 単一アドレスからのイベント発行
ダイヤモンドの単一アドレスからイベントを発行することで、イベント処理が簡素化されます。

#### 4. 複数関数のアトミックな変更
ダイヤモンドは1つのトランザクションで複数の外部関数をアトミックに追加、置換、削除できます。

:::message
通常、スマートコントラクトのアップグレードは、新しいバージョンのコントラクトをデプロイし、旧バージョンからデータを移行するなどの手順が必要です。
しかし、このプロセスは複雑で、トランザクションが複数必要なこともあります。

ダイヤモンドは、このアップグレードプロセスを簡素化するための方法を提供します。
例えば、あるダイヤモンドに新たな機能を追加する場合、従来のスマートコントラクトでは新しいバージョンのコントラクトをデプロイし、そのアドレスを切り替える必要がありました。
しかし、ダイヤモンドを使用すると、1つのトランザクションで新しい機能をアトミックにダイヤモンドに統合することができます。

例えば、あなたが「**支払い**」と「**転送**」の2つの機能を持つダイヤモンドを持っているとします。
後から新たな機能「**バウンス**」を追加したい場合、ダイヤモンド内に「**バウンス**」機能を追加するトランザクションを1つだけ送信すれば良いです。
このトランザクションが処理される際、新しい機能がアトミックにダイヤモンドに追加されます。
これにより、新たな機能が追加されると同時に、他の機能に影響を与えることなく変更が行われます。

また、既存の機能を置換や削除する場合も同じです。
1つのトランザクションで機能の置換や削除を行うことができ、これによって複数のトランザクションを使用する必要がなくなります。

**アトミック**
アトミックな操作とは、その操作が一連のステップで構成され、その中でどれか1つのステップが失敗すると、他のすべてのステップも取り消されるという性質を指します。
このような操作は、すべてが成功するかすべてが失敗するかのどちらかで完了し、途中の状態は存在しません。

アトミックな操作は、データベースの一貫性やトランザクションの信頼性を確保するために重要です。
特に、スマートコントラクトにおいては、複数の操作が正確に順番通りに実行される必要があります。
アトミックな操作を使用することで、このような操作が確実に実行されることが保証されます。

ダイヤモンドのコンテキストで "**アトミックに複数の外部関数を追加、置換、削除する**" という表現を考えてみましょう。
これは、1つのトランザクション内で、複数の異なる操作（追加、置換、削除）を行うことを指しています。
このトランザクションがアトミックである場合、どれか1つの操作が失敗すると、他の操作も取り消されます。
つまり、すべての操作が正常に完了するか、どれも実行されないかのどちらかです。
このようなアトミックな操作は、データの整合性と信頼性を保つために非常に重要です。
:::

#### 5. 細かなアップグレード
ダイヤモンドは必要な部分だけを変更できるため、細かなアップグレードが可能です。

#### 6. 関数の制御
ダイヤモンドは関数の存在とタイミングを細かく制御できます。

:::message
具体的には、ダイヤモンドを構成する複数のファセットという独立したコントラクト群があります。
これらのファセットは、それぞれ異なる機能を提供します。
ダイヤモンドはこれらのファセットを組み合わせて構築されます。

関数の制御に関して、以下のようなケースを考えてみましょう。

**関数の存在と実行タイミングの制御**
ダイヤモンド内の特定のファセットには、必要な機能を提供する関数が実装されています。
ダイヤモンドの管理者は、どのファセットがどの関数を提供するかを制御できます。
また、特定のタイミングで特定の関数を有効にしたり無効にしたりすることも可能です。

**機能の追加と削除**
ダイヤモンドは、新しいファセットを追加することで新しい機能を導入できます。
同様に、不要な機能を持つファセットを削除することで、ダイヤモンド内の機能を制御できます。

**タイミングに合わせた関数の有効化・無効化**
特定のイベントや条件が発生した際に、特定の関数を一時的に有効化または無効化することができます。
これにより、必要に応じて特定の機能を利用可能にしたり制限したりできます。

**機能の組み合わせ**
ダイヤモンドのファセットは独立しており、異なる機能を提供します。
ダイヤモンドの管理者は、これらのファセットを組み合わせて、必要な機能を持つダイヤモンドを構築できます。

ダイヤモンドを使用することで、必要な機能を持ちつつ、それらの機能の存在と実行タイミングを柔軟に制御できるため、アプリケーションのニーズに合わせたカスタマイズが可能です。
:::

#### 7. DAOやガバナンスでのアップグレード
ダイヤモンドは分散自治組織（DAO）やマルチシグコントラクトを介してアップグレードできます。

:::message
#### 分散自治組織（DAO）を介したアップグレード

例えば、あるプロジェクトがダイヤモンドを使用してスマートコントラクトを構築しています。
プロジェクトコミュニティは、新しい機能を追加したりバグを修正したりするためにダイヤモンドをアップグレードしたいと考えています。
ここで、分散自治組織（DAO）が登場します。

1. **投票と決定**
プロジェクトの参加者は、DAOのプラットフォームを通じてアップグレード提案を行います。
提案内容には、新しい機能の追加や変更内容が含まれます。

2. **コミュニティの合意**
DAOの参加者は提案に対して投票を行い、その提案が受け入れられるかどうかを決定します。
過半数の賛成が得られた場合、提案は受け入れられます。

3. **アップグレード実行**
提案が承認されたら、DAOはダイヤモンドのアップグレードトランザクションを実行します。
これにより、新しい機能が追加されたり既存の機能が変更されたりします。

#### マルチシグコントラクトを介したアップグレード

別の例として、プロジェクトチームがダイヤモンドを使用して特定のサービスを提供しています。
チームは、サービスの改善やセキュリティの向上を目指して、ダイヤモンドのアップグレードを行いたいと考えています。
ここで、マルチシグコントラクトが役立ちます。

1. **マルチシグコントラクトの設定**
プロジェクトチームは、複数のキーホルダーが合意してアップグレードを行うためのマルチシグコントラクトを設定します。

2. **アップグレード提案**
チームはアップグレードの提案を作成し、マルチシグコントラクトによる承認プロセスを開始します。
提案には、変更内容やアップグレードの理由が含まれます。

3. **キーホルダーの承認**
マルチシグコントラクトのキーホルダーたちは提案を検討し、アップグレードの必要性や影響を評価します。
必要な数のキーホルダーが提案に同意することで、アップグレードが承認されます。

4. **アップグレード実行**
承認が得られた場合、マルチシグコントラクトはアップグレードトランザクションを発行し、ダイヤモンドの新しいバージョンがデプロイされます。

これらの例から分かるように、分散自治組織（DAO）やマルチシグコントラクトを通じて、プロジェクトコミュニティやチームがダイヤモンドのアップグレードを合意し、実行することが可能です。
:::

#### 8. 変更を示すイベント
ダイヤモンドは関数の変更を示すイベントを提供します。

#### 9. 変更履歴の表示
ダイヤモンドの変更履歴を表示することで、信頼性を向上させます。

#### 10. 現在の状態の表示
ダイヤモンドの現在のファセットと関数を確認できます。

#### 11. 信頼性のあるダイヤモンド
ダイヤモンドは後からイミュータブルにすることができます。

#### 12. コントラクトサイズの制限克服
ダイヤモンドはコントラクトサイズ制限を克服し、任意のサイズを持つことができます。

#### 13. 機能の分割と統合
異なるファセットに機能を分割し、ダイヤモンドで統合できます。

#### 14. 既存コントラクトの再利用
既存のコントラクトからダイヤモンドを作成できます。

#### 15. コードの整理
ダイヤモンドとファセットを使用してコードを整理できます。

#### 16. 大規模なモジュール化
大規模なダイヤモンドでもモジュール化されており、効率的な管理が可能です。

#### 17. ガス節約
複数のコントラクトを1つにまとめてガスを節約できます。

:::message
通常、複数のコントラクトを操作する場合、それぞれのコントラクトとのやり取りにはガスがかかります。
しかし、これらのコントラクトを1つのダイヤモンドに統合すると、1つのトランザクション内で複数のコントラクトを操作できます。
つまり、コントラクト間のやり取りにかかるガスコストが削減されるのです。

ダイヤモンド内のコントラクトは、同じコントラクト内であるため、内部関数や状態変数を直接アクセスすることができます。
これにより、コントラクト間のデータのやり取りや状態の変更が効率的に行えます。
その結果、1つのトランザクションで複数のコントラクトを操作する際のガスコストが削減され、トランザクションの実行コストが低減されます。

具体例として、複数のコントラクトを個別に呼び出す場合と、それらを1つのダイヤモンド内でまとめて呼び出す場合を考えてみましょう。
個別に呼び出す場合は、それぞれの呼び出しにガスがかかりますが、ダイヤモンド内でまとめて呼び出す場合は、1つのトランザクション内で済むため、ガスコストが削減されることが期待されます。
:::

#### 18. 外部関数の最適化
ファセット間で内部関数を共有し、ガスを節約できます。

#### 19. 特定の用途の最適化
ガス最適化された外部関数を作成してガスを節約できます。

#### 20. ツールとユーザーインターフェース向け
ダイヤモンドはツールとユーザーインターフェースの開発に適しています。

これにより、ダイヤモンドはスマートコントラクトの設計と開発を効果的にサポートします。

## 仕様

### 条件

#### ダイヤモンド（Diamond）
ダイヤモンドは、まるで宝石のような名前ですが、ここではスマートコントラクトを指します。
このコントラクトは、自身の内部に複数の「**ファセット**」と呼ばれる部分コントラクトを持ち、必要に応じてそれらのファセットを呼び出します。
ダイヤモンド自体はテータを持ち、コントラクトストレージに保存されます。

#### ファセット（Facet）
ファセットは、ダイヤモンドの一部であるスマートコントラクトやSolidityライブラリです。
ファセットは、外部関数を提供します。
ダイヤモンドには複数のファセットを組み合わせて使うことができ、それぞれのファセットが独立して機能します。
ファセット自体はデータを持たず、ダイヤモンドのコントラクトストレージに保存されます。

#### ルーペファセット（Loupe Facet）
ルーペファセットは、ファセットの一種で、`introspection`関数を提供します。
`introspection`関数は、コントラクトの内部状態や情報を調べるための情報を提供します。

#### イミュータブルな関数（Immutable Function）
イミュータブルな関数は、ダイヤモンド内で変更ができない関数を指します。
これは、外部から置き換えたり削除したりできない関数であり、ダイヤモンドの一部として確定された機能です。

#### マッピング（Mapping）
この文脈では、マッピングとは2つの要素の関連付けを指します。
具体的な実装に依存せず、関連性を示す一般的な概念です。

#### コントラクト（Contract）
ここでは、スマートコントラクトやSolidityライブラリの総称を指します。

この解説で関数が「**`internal`（内部）関数**」か「**`external`（外部）関数**」かわからない場合、それは「**`external`（外部）関数**」として判断します。
また、この文脈では`external`（外部）関数に関する情報は`public`（公開）関数にも適用されます。

### 概要

**ダイヤモンドの概要**
ダイヤモンドは、委任呼び出し（`delegatecall`）を用いて、その中にある「**ファセット**」と呼ばれる部分コントラクトの関数を呼び出します。

**宝石業界の比喩:**
宝石業界では、ダイヤモンドは切削されてファセットが作られ、その結果形成されます。
同様に、スマートコントラクト内のダイヤモンドも、ファセット内にある関数を追加、置換、削除することで形成されるのです。

この比喩を通じて、スマートコントラクトのダイヤモンドとファセットの関係を理解しやすくなります。

### インターフェイスの実装メモ

**インターフェースの実装についての注意**
ダイヤモンドは、特定のインターフェースを実装する方法として、2つの選択肢があります。
1つは、ダイヤモンド自体にインターフェースを直接結びつける方法です（**contract Contract is Interface**）。
もう1つは、ダイヤモンドのファセットに関数を追加することで、インターフェースを実装する方法です。
この提案の文脈では、どちらの方法でもインターフェースを実装することが許容されています。

### フォールバック関数

ダイヤモンドの外部関数が呼び出される際には、そのダイヤモンドのフォールバック関数が自動的に実行されます。
このフォールバック関数は、呼び出しデータの先頭にある`4`バイトの関数セレクタ（呼び出す関数を識別するためのもの）に基づいて、どのファセットに含まれる関数を実行するかを判断します。
そして、その選ばれたファセットの中の関数を、`delegatecall`を通じて実行します。

ダイヤモンドのフォールバック関数と`delegatecall`によって、ダイヤモンドは、まるでそのダイヤモンド自体がその関数を持っているかのように、ファセット内の関数を実行できるのです。
この際、`msg.sender`（トランザクションの送信者）や`msg.value`（トランザクションの送金額）は変更されず、ダイヤモンドのストレージだけが読み書きされます。

具体的な例を考えてみましょう。
例えば、あるダイヤモンドが3つのファセットを持っており、それぞれのファセットには異なる関数が実装されています。
外部からダイヤモンドの関数を呼び出すと、フォールバック関数が関数セレクタに基づいて適切なファセットを選び、そのファセット内の関数を実行します。
この仕組みによって、ダイヤモンドは柔軟に機能を追加、置換、削除できる上に、外部からの呼び出しに対してもスムーズに対応することができるのです。

この仕組みによって、スマートコントラクトの設計とアップグレードが効果的に行えるようになります。

:::message
`delegatecall`と`delegatecall`を使用した時の動作については、以下の記事が参考になります。
:::

https://chaldene.net/solidity-delegatecall

https://chaldene.net/upgradable-contracts

[スマートコントラクトのアップグレードを理解しよう！](/articles/339d9fd83955cda55d14)

```javascript
// Find facet for function that is called and execute the
// function if a facet is found and return any value.
fallback() external payable {
  // get facet from function selector
  address facet = selectorTofacet[msg.sig];
  require(facet != address(0));
  // Execute external function from facet using delegatecall and return any value.
  assembly {
    // copy function selector and any arguments
    calldatacopy(0, 0, calldatasize())
    // execute function call using the facet
    let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
    // get any return value
    returndatacopy(0, 0, returndatasize())
    // return any return value or error back to the caller
    switch result
      case 0 {revert(0, returndatasize())}
      default {return (0, returndatasize())}
  }
}
```

以下の図はダイヤモンドの構造を説明しています。

![DiamondDiagram.png](/images/qiita-c31bfa1d-1abb-07b1-b879-a5a800c042fe.webp)

:::message
先ほど説明したように、FacetA~Cが存在しています、
各Facet内には1~7の関数が定義されていて、Diamond内にはその情報が格納されています。
呼び出された関数の関数セレクターを確認して、一致する関数を呼び出すという構成になっています。
:::

:::message
**関数セレクター**
関数セレクターとは、関数名をハッシュ化した先頭`4`バイトを使用して関数を識別するものです。
ではなぜ関数名のハッシュ値を全て使わずに先頭`4`バイトのみを使用しているのでしょうか？
これは単純にガス代節約のためです。
詳しくは以下の記事を参考にしてください。
:::

https://rootbabu.medium.com/function-selector-solidity-day26-573bbeec8186

### ストレージ

もちろんです。以下に再度、上記の内容を簡潔に説明します。

**ストレージ:**

ダイヤモンドやプロキシコントラクトのために、Solidityのデフォルトのストレージ配置システムでは対応できない状態変数やストレージの配置が必要です。
具体的な配置方法はこの提案では定義されていませんが、後の提案で定義される可能性があります。
ダイヤモンドに適したストレージ配置パターンの例として、**Diamond Storage**や**AppStorage**などがあります。

:::message
**Diamond Storage**
**Diamond Storage**は、ダイヤモンドのストレージを効果的に管理するための一般的なパターンです。
このパターンでは、各ファセットが特定のストレージ領域を使用するように設計されます。
ダイヤモンド全体のストレージ領域が適切に分割され、各ファセットが自身のデータを保持できるようになります。
これにより、ファセット同士のデータの干渉を防ぎつつ、ダイヤモンド全体でのデータ共有が可能となります。

**AppStorage**
**AppStorage**もダイヤモンドのストレージ管理をサポートするパターンの1つです。
**AppStorage**では、ファセットが個別のアプリケーション固有のストレージ領域を使用するように設計されます。
各ファセットは自身のアプリケーションに関連するデータを保持し、ダイヤモンド全体でのデータの共有と同時にアプリケーション間のデータの隔離を実現します。

これらのストレージパターンは、ダイヤモンドのファセットが効果的にデータを管理し、コードの整理とモジュール化を支援するために使用されます。
どちらのパターンも、ダイヤモンドの設計に合わせてカスタマイズできる柔軟性を提供します。
:::

ファセットは、同じストレージ位置で同じ構造体を使用することで、状態変数を共有できます。
また、同じコントラクトを継承したり、同じライブラリを使用することで、内部関数やライブラリを共有できます。
これにより、ファセットは独立したユニットでありながら、状態と機能を共有できます。

以下の図は、各ファセットが独自のデータと共有されるデータを持つ構造を示しています。

![diamondstorage1.png](/images/qiita-8d7271ef-f319-ad25-330c-b983e42e9d26.webp)

この図では、すべてのデータはダイヤモンドのストレージに保存されていますが、異なるファセットは異なるデータへのアクセス権を持っています。

具体的には次のようになっています。

- ファセットAだけが**DataA**にアクセスできます。
- ファセットBだけが**DataB**にアクセスできます。
- ダイヤモンド自体のコードだけが**DataD**にアクセスできます。
- ファセットAとファセットBは**DataAB**へのアクセスを共有します。
- ダイヤモンド自体のコードとファセットA、ファセットBは**DataABD**へのアクセスを共有します。

この仕組みによって、ファセット同士でデータを共有しながらも、それぞれが独立して機能するダイヤモンドの設計が可能となります。

### ファセットSolidityライブラリ

スマートコントラクトやデプロイされたSolidityライブラリは、ダイヤモンドのファセットとして活用することができます。

ただし、少なくとも1つ以上の外部関数を持つSolidityライブラリのみが、ブロックチェーンにデプロイされてダイヤモンドのファセットとなることができます。

一方で、内部関数だけを含むSolidityライブラリはブロックチェーンにデプロイできず、ダイヤモンドのファセットにもなれません。
その代わり、内部関数を含むSolidityライブラリは、それを利用するファセットやコントラクトのバイトコード内に組み込まれます。
この仕組みによって、内部関数を共有することが可能となります。
ただし、内部関数だけを持つSolidityライブラリはダイヤモンドのファセットとして使用することはできません。

Solidityライブラリファセットには、ファセットとしての特性がいくつかあります。

- 削除することはできません。
    - 永続的にダイヤモンドの一部として存在します。
- データを保持しません。
    - つまり、コントラクトストレージを利用することはありません。
- 構文的に、**Diamond Storage**の外で状態変数を宣言することができません。

Solidityライブラリは、ダイヤモンドのファセットとして利用する際に、内部関数の共有やコードの再利用をサポートする有用なツールです。

### 関数の追加・置換・削除

#### IDiamond インターフェース
ダイヤモンドを使用するすべてのスマートコントラクトは、`IDiamond`インターフェースを実装する必要があります。
これにより、ダイヤモンドの特定の機能や方法にアクセスできるようになります。

##### ダイヤモンドのデプロイ時
ダイヤモンドがデプロイされる際、そのダイヤモンドに含まれるイミュータブルな関数（変更不可の関数）や外部関数が、`DiamondCut`イベント内で通知されます。
これにより、ダイヤモンドがどのような関数を持つかが透明になります。

##### 関数の追加・置換・削除時
ダイヤモンドの外部関数が追加されたり、既存の関数が置換されたり、関数が削除されたりする際、`DiamondCut`イベントが必ず発生します。
これは、ダイヤモンドのアップグレードや関数の変更が行われるたびに適用されます。
つまり、ダイヤモンド内の機能を変更する際には、その変更が`DiamondCut`イベントを通じて公開されることになります。

これにより、ダイヤモンドの変更履歴やアップグレード情報が透明になり、信頼性が向上します。
ダイヤモンド内の関数がいつどのように変更されたかを追跡できるため、ユーザーや開発者はダイヤモンドの進化を追うことができます。

```javascript
interface IDiamond {
    enum FacetCutAction {Add, Replace, Remove}
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}
```

##### FacetCutAction

ダイヤモンド内で関数を変更する時のアクションを示す列挙型。

- `ADD`（追加）= `0`
- `Replace`（置換）= `1`
- `Remove`（削除）= `2`

##### FacetCut

ダイヤモンド内の関数変更に関する情報を格納する構造体。

- `facetAddress`
    - 関数を追加、置換、削除する対象のファセット（スマートコントラクトやライブラリ）のアドレス。
- `action`
    - 実行するアクション（追加、置換、削除）を示す。
- `functionSelectors`
    - 関数セレクタ（関数の一意の識別子）の配列。

##### DiamondCut

ダイヤモンド内での関数の追加、置換、削除が行われるときに発行されるイベント。
ダイヤモンドに対するすべての機能変更を記録します。

- `_diamondCut`
    - 関数の変更情報を持つ`FacetCut`構造体の配列。
- `_init`
    - 初期化コードのアドレス。
- `_calldata`
    - 呼び出しデータ。

####  IDiamondCutインターフェース

##### ダイヤモンド内の関数セレクタとファセットアドレスのマッピング

ダイヤモンドは、関数セレクタ（関数の一意の識別子）とファセットアドレスのマッピングを内部に持っています。
関数の追加、置換、削除は、このマッピングを変更することで行われます。

##### IDiamondCutインターフェースの実装

ダイヤモンドは、デプロイ後に関数セレクタのマッピングを変更する場合、`IDiamondCut`インターフェースを実装する必要があります。
このインターフェースにより、関数のセレクタとアドレスのマッピングの変更が管理されます。

##### diamondCut関数の役割

`diamondCut`関数は、1つのトランザクション内で、複数のファセットから複数の関数を同時に追加、置換、削除する役割を持ちます。
複数の変更を1つのトランザクション内ですべて実行することで、複数トランザクションを跨いだアップグレードによるデータの破損を防ぐことができます。

:::message
関連する他の変更も同時に適用することができ、一貫性のある状態を保つことが可能です。
:::

##### diamondCutの目的

`diamondCut`関数は、相互運用性を実現するために指定されています。
ダイヤモンドのツール、ソフトウェア、ユーザーインターフェースは、標準の`diamondCut`関数を期待し、利用すべきです。
これにより、異なるツールやアプリケーション間でダイヤモンドの操作が一貫して行えるようになります。

`diamondCut`関数を通じて、関数セレクタとファセットアドレスのマッピングの変更が管理され、ダイヤモンドのアップグレードや操作がシンプルかつ安全に行えるようになります。

```javascript
interface IDiamondCut is IDiamond {
    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;
}
```

##### diamondCut

ダイヤモンドのアップグレードや変更を行う関数。
1つのトランザクション内で複数のファセットから複数の関数を変更し、安全かつ効率的なダイヤモンドのアップグレードや操作を行うことができます。

- `_diamondCut`
    - ファセットのアドレスと関数セレクタ（関数の一意の識別子）の情報を含む配列。
    - この配列には、追加、置換、削除する関数の情報が含まれます。
- `_init`
    - `_calldata`を実行するためのコントラクトまたはファセットのアドレス。
    - このアドレス上で`_calldata`に含まれる関数が実行されます。
- `_calldata`
    - 関数セレクタと引数を含む関数呼び出しのデータ。
    - `_init`上で`_calldata`に含まれる関数が`_delegatecall`を用いて実行されます。


##### _diamondCut引数とFacetCut構造体

`_diamondCut`引数は、`FacetCut`構造体の配列です。
各`FacetCut`構造体には、ファセットのアドレスと、ダイヤモンド内で更新される関数セレクタ（関数の一意の識別子）の配列が含まれます。

**各`FacetCut`構造体について**

- `Add`の場合、関数セレクタマッピングを追加します。
    - もし既に別のファセットにマップされている関数セレクタがある場合は`revert`します。
- `Replace`の場合、関数セレクタマッピングを置換します。
    - ただし、既に同じファセットにマップされているか、未設定の場合は`revert`します。
- `Remove`の場合、関数セレクタマッピングを削除します。
    - ただし、以前に未設定の場合は`revert`します。
- イミュータブルな関数を置換または削除しようとする試みは、必ず`revert`します。

##### _calldataの実行

関数の追加/置換/削除後、`_calldata`引数は`_init`上で`delegatecall`を使って実行されます。
これにより、関数の追加、置換、削除後の初期化やデータのセットアップ、不要なデータの削除が行われます。

もし`_init`が`address(0)`であれば、`_calldata`の実行はスキップされます。
この場合、`_calldata`は0バイトまたはカスタム情報を含むことができます。

`_diamondCut`と`_calldata`を使用することで、ダイヤモンド内の関数の変更が安全かつ効率的に行えるようになります。

#### ファセットとファンクションの検査

##### ルーペ（Loupe）とIDiamondLoupeインターフェース

ルーペは、ダイヤモンドを拡大して見るために使用される小さな拡大鏡です。

##### IDiamondLoupeインターフェースの実装

ダイヤモンドは、ファセットと関数を調査できるようにするために、`IDiamondLoupe`インターフェースを実装する必要があります。
このインターフェースにより、ダイヤモンド内の構造や関数を詳しく調べることができます。

このように、`IDiamondLoupe`インターフェースは、ダイヤモンドの内部を拡大して確認するための道具として機能します。

####  IDiamondLoupeインターフェース

```javascript
// A loupe is a small magnifying glass used to look at diamonds.
// These functions look at diamonds
interface IDiamondLoupe {
    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses() external view returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
}
```

##### Facet

**概要**
ファセットのアドレスとそのファセットがサポートする関数セレクタ（関数の一意の識別子）の一覧を保持する構造体。

**パラメータ**
- `facetAddress`
    - ファセットのアドレス。
- `functionSelectors`
    - ファセットがサポートする関数セレクタの配列。

#### facets

**概要**
すべてのファセットのアドレスとそれらのファセットがサポートする関数セレクタを取得する関数。

**引数**
なし

**戻り値**
- `facets_`
    - Facet構造体の配列。
    - 各構造体はファセットのアドレスとそのファセットがサポートする関数セレクタの一覧を持ちます。

#### facetFunctionSelectors

**概要**
特定のファセットがサポートする関数セレクタの一覧を取得する関数。

**引数**
- `_facet`
    - ファセットのアドレス。

**戻り値**
- `facetFunctionSelectors_`
    - `bytes4`の配列。
    - 指定されたファセットがサポートする関数セレクタの一覧です。

#### facetAddresses

**概要**
ダイヤモンド内で使用されているすべてのファセットのアドレスを取得する関数。

**引数**
なし

**戻り値**
- `facetAddresses_`
    - アドレスの配列。
    - ダイヤモンド内で使用されているファセットのアドレスです。

#### facetAddress

**概要**
指定された関数セレクタをサポートするファセットのアドレスを取得する関数。

**引数**
- `_functionSelector`
    - 関数セレクタ（`bytes4`）。

**戻り値**
- `facetAddress_`
    - ファセットのアドレス。
    - 指定された関数セレクタをサポートするファセットが見つからない場合は、`address(0)`が返されます。

**リファレンス実装の確認**
リファレンス実装を確認することで、具体的なコードや方法を参考にしながら、`IDiamondLoupe`インターフェースがどのように実装されるかを理解することができます。
これにより、自分のプロジェクトに適用する際に役立つ情報を得ることができます。

**ルーペ関数の利用**
ルーペ関数は、ユーザーインターフェースソフトウェア内で利用されることがあります。
ユーザーインターフェースは、ユーザーに対してダイヤモンドの情報をわかりやすく表示し、ダイヤモンドの構造や機能を視覚化するためにこれらの関数を呼び出します。
これにより、ユーザーはダイヤモンドの機能や特性について理解しやすくなります。

**ルーペ関数の利用範囲**
ルーペ関数は、デプロイメント機能やアップグレード機能など、ダイヤモンドの運用や管理に関わるさまざまなソフトウェア内で使用されます。
例えば、ダイヤモンドをアップグレードする際に、どのファセットがどの関数セレクタをサポートしているかを確認するためにこれらの関数を利用することができます。
また、テスト時にも関数セレクタやファセットの情報を取得して、テストケースを設計する際の参考にすることができます。

これにより、ダイヤモンドの操作や管理がよりスムーズに行えるようになり、ダイヤモンドの機能を最大限に活用するための支援が提供されます。

### 実装ポイント

#### ダイヤモンドの要件
- ダイヤモンドは、フォールバック関数と`0`個以上のイミュータブルな関数を含む必要があります。
    - これらの関数は、ダイヤモンド内で直接定義されます。
- ダイヤモンドは、関数セレクタ（関数の一意の識別子）をファセットと関連付けます。
    - これにより、ダイヤモンドの関数がどのファセットに属するかが管理されます。
- ダイヤモンド上で関数が呼び出されると、まず「**イミュータブル関数**」であるかどうかをチェックします。
    - もしイミュータブル関数であれば、直ちにその関数が実行されます。
    - イミュータブル関数でない場合、ダイヤモンドのフォールバック関数が実行されます。
    - このフォールバック関数は、呼び出された関数に関連付けられたファセットを見つけ、`delegatecall`を使用して関数を実行します。
    - もし関数のファセットが存在しない場合、オプションでデフォルト関数が実行されることもあります。
    - さらに、関数のファセットもデフォルト関数も処理できるメカニズムが存在しない場合は、実行が`revert`（無効化して元に戻す）されます。
- 関数が追加、置換、削除されるたびに、`DiamondCut`イベントが発生して変更が記録されます。
    - これにより、関数の追加や変更が透明かつ追跡可能になります。
- ダイヤモンドは`DiamondLoupe`インターフェースを実装する必要があります。
    - これにより、ダイヤモンドのファセットや関数に関する情報を取得できるようになります。

#### イミュータブルな関数
- イミュータブルな関数は、`DiamondCut`イベント内に新しい関数として記録されます。
- また、ルーペ関数は、イミュータブルな関数に関する情報を提供します。
- イミュータブルな関数のファセットアドレスは、ダイヤモンドのアドレスそのものです。
- イミュータブルな関数を削除または置換しようとすると必ず`revert`されます。

#### 追加できる実装
- **EIP165**の`supportsInterface`を実装することができます。
- この実装により、ダイヤモンドが特定のインターフェースをサポートしているかどうかを判別できるようになります。
- 例えば、`diamondCut`関数を持つダイヤモンドは、`IDiamondCut.diamondCut.selector`というインターフェースIDをサポートしていることが示されます。
- 同様に、ダイヤモンドルーペインターフェース用のインターフェースIDも判別できます。
- これにより、ダイヤモンドの機能が他のコントラクトやツールとの連携に対応することができます。

これらの実装により、ダイヤモンドの機能や操作が明確に定義され、運用や管理がスムーズに行えるようになります。
また、ユーザーインターフェースやテスト、アップグレード機能などの実装においても利用される、柔軟で堅牢なアーキテクチャが提供されます。

## 補足

### 関数セレクタの利用
ユーザーインターフェースソフトウェアは、ダイヤモンドから関数セレクタとファセットアドレスを取得して、ダイヤモンドがどのような関数を持っているかを表示するために使用できます。
これにより、ユーザーはダイヤモンドの機能を理解し、操作できるようになります。

### ガスに関する考慮事項
`delegatecall`を使用して関数を実行するのにガスのオーバーヘッドがありますが、以下の方法で緩和できます。

- ダイヤモンドにはサイズ制限がないため、特定の使用ケースに合わせてガス節約の関数を追加できます。
    - たとえば、**EIP721**標準を実装し、バッチ転送関数をダイヤモンド内に追加してガスを削減し、バッチ転送を便利に行えるようにできます。
- 一部のコントラクトアーキテクチャでは、1つのトランザクション内で複数のコントラクトを呼び出す必要があります。
    - これらのコントラクトを1つのダイヤモンドにまとめることで、コントラクトの呼び出しとコントラクトストレージへのアクセスを効率的に行えます。
- ファセットには少数の外部関数が含まれることがあり、関数の数が少ないファセットを呼び出す際のガスコストが低くなります。
    - 多くの関数を持つファセットを呼び出す場合はガスの消費が多くなります。
- Solidityの最適化設定を高くすると、生成されるバイトコードが増えますが、ファセットが実行される際のガス消費量が少なくなります。

### 関数のバージョン情報の取得
ダイヤモンド内の関数のバージョン情報を知りたい場合、ソフトウェアやユーザーはその関数のファセットアドレスを取得することができます。
これは、`IDiamondLoupe`インターフェース内の`facetAddress`関数を呼び出すことで行います。
この関数は、関数セレクタを引数として受け取り、その関数が実装されているファセットアドレスを返します。

### デフォルト関数の設定
Solidityでは、コントラクト内に存在しない関数が呼び出された場合、特定の機能を実行するためのフォールバック関数を提供しています。
同様の機能をダイヤモンド内でもオプションで実装することができます。
これをデフォルト関数と呼び、ダイヤモンド内に存在しない関数が呼び出された際に実行される関数です。

デフォルト関数は、様々な方法で実装することができますが、この標準では具体的な実装方法は定められていません。
つまり、ダイヤモンド内でどのようにデフォルト関数を設定するかは、開発者に任されています。

### ルーペ関数とDiamondCutイベント

通常のコントラクトの場合、その検証済みのソースコードを見ることで、どのような関数がコントラクトに存在するかがわかります。

しかし、ダイヤモンドの検証済みのソースコードには、どのような関数が存在するかの情報は含まれていません。
そのため、ダイヤモンドでは異なるアプローチが必要です。

ダイヤモンドは、ルーペ関数と呼ばれる4つの標準関数を持っており、これらの関数を使用して、ダイヤモンドがどのような関数を持っているかを示すことができます。

ルーペ関数は、以下のような目的で利用されます。

- ダイヤモンドが使用しているすべての関数を表示するために利用されます。
- Etherscanなどのサービスやファイルをクエリして、ダイヤモンドが使用しているすべてのソースコードを取得し表示するために利用されます。
- Etherscanなどのサービスやファイルをクエリして、ダイヤモンドのABI情報を取得するために利用されます。
- ダイヤモンドに関数の追加、置換、削除を行うトランザクションが成功したかをテストや検証するために利用されます。
- ダイヤモンドの関数を呼び出す前に、ダイヤモンドがどのような関数を持っているかを確認するために利用されます。
- ツールやプログラミングライブラリがダイヤモンドをデプロイやアップグレードする際に利用されます。
- ユーザーインターフェースがダイヤモンドに関する情報を表示し、ユーザーがダイヤモンド上の関数を呼び出すために利用されます。

これにより、ダイヤモンドの関数情報を取得し、操作するための手段が提供され、ユーザーインターフェースや開発ツール、ライブラリの有用性が向上します。

ダイヤモンドは、透明性を提供する別の方法をサポートしており、ダイヤモンド上で行われるすべてのアップグレードの履歴を記録します。
これは、`DiamondCut`イベントを通じて実現されます。
このイベントは、ダイヤモンドに関数が追加、置換、削除される際に記録するために使用されます。

これにより、ダイヤモンドの変更履歴を簡単に追跡できるようになります。
アップグレードや変更の過程が透明になるため、ダイヤモンドの変更に対する信頼性が向上します。
また、この履歴情報は、ダイヤモンドの運用やセキュリティの評価にも役立ちます。

### ファセット間で関数共有

異なるファセットで定義された関数を呼び出す必要が生じた場合、以下の方法を使ってその処理を行うことができます。

#### 1. 内部関数コードのコピー
1つのファセット内で定義された内部関数コードを、別のファセットにコピーする方法です。
これにより、関数の実装が複数のファセットで共有されますが、コードの重複が発生する可能性があります。

#### 2. 共通コントラクトの継承
共通の内部関数を含むコントラクトを作成し、複数のファセットがそのコントラクトを継承する方法です。
これにより、関数のコードは一箇所にまとめられますが、継承の階層が深くなる可能性があります。

#### 3. Solidityライブラリの使用
共通の内部関数をSolidityライブラリに配置し、必要なファセット内でそのライブラリを使用する方法です。
これにより、関数のコードがライブラリに集約され、ファセット間で共有されます。

#### 4. 別ファセットの関数の安全呼び出し
別のファセットで定義された外部関数を、安全な方法で呼び出すことができます。
この際、ファセットのアドレスを指定して関数を呼び出すことで、別のファセットの関数を利用できます。

#### 5. delegatecallの使用
別のファセットで定義された外部関数を、ガス効率の良い方法で呼び出すことができます。
`delegatecall`を使用すると、他のコントラクトのコードをそのまま実行できます。

```javascript
DiamondStorage storage ds = diamondStorage();
bytes4 functionSelector = bytes4(keccak256("myFunction(uint256)"));
// get facet address of function
address facet = ds.selectorToFacet[functionSelector];
bytes memory myFunctionCall = abi.encodeWithSelector(functionSelector, 4);
(bool success, bytes memory result) = address(facet).delegatecall(myFunctionCall);
```

#### 6. 内部関数のバージョン作成
別のファセットで定義された外部関数の代わりに、その関数の内部バージョンを作成することもできます。
必要なファセット内で内部関数を追加することで、関数をファセット内で共有できます。

### ファセットは再利用可能で合成可能

ファセットは、非常に柔軟な方法で機能を再利用し、組み合わせることができる重要な概念です。

#### 1. 再利用性の高いファセット
ファセットは一度デプロイされると、異なるダイヤモンド間で再利用できます。
これにより、同じ機能を複数のダイヤモンドで再利用し、開発コストとデプロイコストを節約できます。

#### 2. 異なるファセットの組み合わせ
異なるファセットを組み合わせることで、異なるダイヤモンドに異なる機能を提供することができます。
これは、ダイヤモンドごとに適切な機能セットを組み合わせてカスタマイズできることを意味します。

#### 3. 再利用可能なファセットセットの作成
特定の機能を持つファセットセットを作成し、これを異なるダイヤモンド間で再利用できます。
これにより、新しいダイヤモンドを展開する際に、既存のファセットを再利用することができ、時間とコストを節約できます。

#### 4. ファセットの組み合わせ
ファセットは他のファセットと組み合わせて使用することができます。
これにより、異なるファセット同士の連携や統合が可能になります。
また、一部のファセットは特定の組み合わせでは使用できないように制御することもできます。

#### 5. 関数シグネチャ
関数シグネチャを使用することで関数の特定を行うことができます。
同じシグネチャを持つ外部関数を同じダイヤモンドに同時に追加することはできません。
これにより、関数の一意性とダイヤモンド内での正確な関数の識別が保証されます。

#### 6. ファセットの関数選択
ダイヤモンドには、ファセット内の関数の一部のみを追加できます。
必要な機能だけを選んで追加することができるため、余計な機能を持たせずにダイヤモンドを構築できます。

## 後方互換性

この標準は、アップグレード可能なダイヤモンドを将来の標準や機能と互換性があるものにします。
なぜなら、新しい関数を追加したり、既存の関数を置換したり、削除したりできるからです。
新しい機能や要件が導入されても、ダイヤモンドのアップグレードによってこれに適応させることができます。

## 参考実装

以下に実装をまとめています。

https://github.com/cardene777/base-code/blob/develop/contract/contracts/ERC2535/

引用: https://eips.ethereum.org/EIPS/eip-2535

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

### 所有権と認証
**⚠️注記**
ダイヤモンドの所有権や認証の設計と実装は、この標準の一部ではありません。
この標準やリファレンス実装で提供される例は、実際の実装方法の一例です。

この提案には、さまざまな認証や所有権のスキームを作成することができます。
認証スキームは非常にシンプルなものから複雑なものまで、細かい制御から荒い制御まで可能です。
この提案はその方法を制限しません。
たとえば、所有権/認証は、1つのアカウントアドレスが関数の追加/置換/削除の権限を持つだけであることもあります。
または、分散型自治組織が特定の関数のみを追加/置換/削除する権限を持つことも考えられます。

コンセンサス機能も実装できます。
複数の異なる人々が変更を承認するために`diamondCut`関数を呼び出す承認関数などが考えられます。
これらはあくまで例です。

ダイヤモンドの所有権、制御、認証に関する標準と実装の開発が奨励されています。

### diamondCutによる任意の実行
`diamondCut`関数は、ダイヤモンドのストレージへのアクセスを通じて任意の実行が可能です（`delegatecall`を介して）。
この関数へのアクセスは慎重に制限される必要があります。

### selfdestructの使用禁止
**facet**内での`selfdestruct`の使用は強く推奨されません。
誤用するとダイヤモンドや**facet**が削除される可能性があります。

### 関数セレクタの衝突
関数セレクタの衝突は、2つの異なる関数シグネチャが同じ`4`バイトハッシュにハッシュ化される場合に発生します
これにより、新しい関数を追加しようとしたのに既存の関数が置換されてしまう`unintended consequence`が生じます。
適切に実装された`diamondCut`関数では、すでに存在する関数セレクタを追加することを防ぐため、このシナリオは発生しません。

### 透明性
ダイヤモンドは、1つ以上の関数が追加、置換、削除されるたびにイベントを発行します。
すべてのソースコードは検証可能です。
これにより、人々やソフトウェアがコントラクトの変更を監視することができます。
もしダイヤモンドに不正な関数が追加された場合、それは確認できます。

セキュリティおよびドメインの専門家は、ダイヤモンドの変更履歴をレビューして不正な履歴を検出することができます。

## 引用

Nick Mudge (@mudgen), "ERC-2535: Diamonds, Multi-Facet Proxy," Ethereum Improvement Proposals, no. 2535, February 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2535.

## 最後に

今回は「アップグレーダブルなコントラクトの規格の1つである、ダイヤモンドパターンの提案をしている**ERC2535**」についてまとめてきました！
いかがだったでしょうか？

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

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