[ERC6785] NFTのユーティリティ情報をメタデータに記載する拡張機能の提案を理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、**ERC721**規格のNFTの具体的なユーティリティとその使用方法をメタデータに定義する仕組みを提案している**ERC6785**についてまとめていきます！

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

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

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

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

# 概要

この規格は**ERC721**トークンを拡張しています。
**ERC721**は、イーサリアムブロックチェーン上で非代替トークン（NFT）を発行するための標準規格です。
ここでの「**拡張機能**」とは、トークンが提供するユーティリティ（実用性や価値）を明確に定義し、その利用方法やアクセス方法を規定する追加のメタデータスキーマを意味しています。

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

https://chaldene.net/erc721

### ERC-721の基本
**ERC721**は、NFTを定義するためのスマートコントラクトのインターフェースです。
各**ERC721**トークンはユニークであり、異なる属性やメタデータを持つことができます。
これにより、芸術作品、コレクティブル、不動産など、デジタルまたは物理的な資産の所有権をブロックチェーン上で証明することが可能になります。

### メタデータスキーマの拡張
メタデータスキーマの拡張は、トークンのユーティリティをより詳細に記述するためのものです。
これには、トークンがゲーム内アイテム、イベントへのアクセス権、あるいは特定のサービスへのアクセス権を提供するなど、その使用法が含まれます。
拡張されたスキーマは、トークンの使用方法や利用できる機能についての情報を提供することで、ユーザーがトークンの真の価値を理解するのを助けます。

### 標準関数の定義
この文脈において「**標準関数**」とは、トークンのユーティリティを使用したり、アクセスしたりするために必要な関数（スマートコントラクト内のコードの断片）を指します。
これらの関数は、トークンのユーティリティにアクセスするための共通の方法を提供し、トークンの利用者がそれをどのように使用できるかを標準化します。

### 任意の拡張
ここで言及されている「**任意の拡張**」とは、**ERC721**規格の公式な部分ではなく、開発者が自由に採用することができる追加機能を指します。
つまり、この拡張をサポートすることは必須ではありませんが、トークンのユーティリティを明確にし、ユーザーエクスペリエンスを向上させるために推奨されます。

この拡張機能は、NFTの機能性と市場での活用可能性を高めることを目的としています。
トークンのユーティリティを詳細に定義することで、所有者や開発者にとって、より多くの価値を生み出しやすくなります。

# 動機

NFTのユーティリティについての情報をサードパーティのプラットフォームに頼ることは、詐欺、フィッシング、その他の形態の不正行為につながる可能性があるため、この仕様はそれを直接NFTのメタデータに組み込むことを提案しています。
これにより、NFTの利用価値についての透明性が向上し、クリエイターによるそのユーティリティの履行に対する責任が高まります。

提案されているメタデータ情報には以下が含まれます。

- **タイプのユーティリティ**
    - NFTが提供するユーティリティの種類（例：アクセス権、物理的な商品、デジタルコンテンツの利用権等）。
- **ユーティリティの説明**
    - ユーティリティの具体的な内容や提供する価値についての詳細。
- **ユーティリティの頻度と期間**
    - ユーティリティが提供される頻度（一度きり、定期的など）と、その利用可能期間。
- **ユーティリティの有効期限**
    - ユーティリティが利用できる最終期日。

この仕様により、NFT所有者は、所有するNFTが具体的にどのような価値を提供するのか、その使用方法、利用条件などをブロックチェーン上で直接確認することが可能になります。
これによって、サードパーティのプラットフォームを通じて情報を得る際に生じるリスクを避けることができます。

また、ユーティリティへのアクセス方法が時間と共に変化する可能性があるため、これらの変更の履歴を記録し、透明性を確保する必要があります。
これにより、NFTのユーティリティに関する情報が最新の状態に保たれ、所有者がいつでも確認できるようになります。

この仕様の実装は、NFT市場における信頼性と透明性を高め、ユーザーが自分のNFTに関連するユーティリティの詳細を正確に理解し、それを安心して利用できるようにすることを目的としています。

# 仕様

**ERC6785**に準拠するすべてのコントラクトは、以下に定義されたインタフェースを実装する必要があります。

## インターフェース

```ts
// @title NFT Utility description
///  Note: the EIP-165 identifier for this interface is ed231d73

interface IERC6785 {

    // Logged when the utility description URL of an NFT is changed
    /// @notice Emitted when the utilityURL of an NFT is changed
    /// The empty string for `utilityUri` indicates that there is no utility associated
    event UpdateUtility(uint256 indexed tokenId, string utilityUri);

    /// @notice set the new utilityUri - remember the date it was set on
    /// @dev The empty string indicates there is no utility
    /// Throws if `tokenId` is not valid NFT
    /// @param utilityUri  The new utility description of the NFT
    /// 4a048176
    function setUtilityUri(uint256 tokenId, string utilityUri) external;

    /// @notice Get the utilityUri of an NFT
    /// @dev The empty string for `utilityUri` indicates that there is no utility associated
    /// @param tokenId The NFT to get the user address for
    /// @return The utility uri for this NFT
    /// 5e470cbc
    function utilityUriOf(uint256 tokenId) external view returns (string memory);

    /// @notice Get the changes made to utilityUri
    /// @param tokenId The NFT to get the user address for
    /// @return The history of changes to `utilityUri` for this NFT
    /// f96090b9
    function utilityHistoryOf(uint256 tokenId) external view returns (string[] memory);
}
```

### `setUtilityUri`

```javascript
function setUtilityUri(uint256 tokenId, string utilityUri) external;
```

**概要**

NFTのユーティリティ記述のURLを新しく設定する関数。

**詳細**

この関数は、特定のNFTのユーティリティに関する情報を提供するURLを設定または更新します。
設定された日付も記録されるべきです。
空文字列が指定された場合、そのNFTにはユーティリティが関連付けられていないことを示します。
無効な`tokenId`が与えられた場合にはエラーを投げます。

**引数**

- `tokenId`
    - 設定または更新するNFTのID。
- `utilityUri`
    - NFTのユーティリティに関する情報を提供する新しいURL。

---

### `utilityUriOf`

```javascript
function utilityUriOf(uint256 tokenId) external view returns (string memory);
```

**概要**

指定されたNFTのユーティリティURLを取得する関数。

**詳細**

この関数は、指定されたNFTのユーティリティに関する情報を提供するURLを返します。
URLが設定されていない場合は空文字列が返されます。
これにより、NFTの所有者や利用者がそのNFTが提供するユーティリティについての情報にアクセスできます。

**引数**

- `tokenId`
    - ユーティリティURLを取得したいNFTのID。

**戻り値**

- `string memory`
    - 指定されたNFTのユーティリティURL。

---

### `utilityHistoryOf`

```javascript
function utilityHistoryOf(uint256 tokenId) external view returns (string[] memory);
```

**概要**

指定されたNFTのユーティリティURLの変更履歴を取得する関数。

**詳細**

この関数は、指定されたNFTに関して設定または更新されたユーティリティURLの履歴を配列形式で返します。
これにより、NFTのユーティリティに関する情報の変更を時間を追って確認することが可能になります。

**引数**

- `tokenId`
    - ユーティリティURLの履歴を取得したいNFTのID。

**戻り値**

- `string[] memory`
    - 指定されたNFTのユーティリティURLの変更履歴。

---

### `UpdateUtility`

```javascript
event UpdateUtility(uint256 indexed tokenId, string utilityUri);
```

**概要**

NFTのユーティリティURLが変更された時に記録されるイベント。

**詳細**

このイベントは、特定のNFTのユーティリティURLが新しく設定または更新された時に発行されます。
`utilityUri`が空文字列の場合、それはNFTにユーティリティが関連付けられていないことを意味します。
このイベントを通じて、NFTのユーティリティに関する情報の変更を追跡できます。

**引数**

- `tokenId`
    - ユーティリティURLが更新されたNFTのID。
- `utilityUri`
    - 新しいユーティリティURL。


NFT（非代替トークン）に関するユーティリティ情報を管理するためのコントラクトのインターフェースについて説明してきました。
ここでのユーティリティとは、NFTが提供する追加の価値や機能のことを指します。
この指針に従うことで、NFTの利用価値を明確にし、その情報をブロックチェーン上で透明に管理することが目指されています。

### 関数の実装に関する指針

- **`view` と `pure` の使用**
    - `view`として定義されている関数は、状態を変更しない読み取り専用の関数ですが、`pure`または`view`として実装することが許可されています。
    - `pure`関数は、コントラクトの状態を読み取らず、与えられた引数のみから結果を計算します。
- **`setUtilityUri` のアクセス修飾子**
    - `setUtilityUri`関数は、`public`または`external`として実装できます。
    - `external`修飾子は、コントラクト外部からのみアクセス可能な関数に使用され、`public`はコントラクト内外からアクセス可能です。
    - さらに、`utilityUri`の設定は、ユーティリティを提供する当事者（NFTのクリエイターまたは他者）に限定されるべきです。

### イベントとメソッドに関する指針

- **`UpdateUtility`**
    - `setUtilityUri`関数が呼び出された時、またはトークンのユーティリティがバッチ更新など他の方法で変更された時には、必ず`UpdateUtility`イベントを発行する必要があります。
    - これにより、NFTのユーティリティ情報の変更を透明に追跡できます。
- **`utilityHistoryOf`**
    - このメソッドは、`setUtilityUri`を通じても、バルク更新など他の手段を通じても、`tokenId`の`utilityUri`に行われたすべての変更を反映する必要があります。
    - これにより、NFTのユーティリティ情報の完全な履歴を提供します。
- **`supportsInterface`**
    - このメソッドは、与えられたインターフェイス識別子がサポートされているかどうかを示すために使用されます。
    - このコントラクトは、`ed231d73`が渡された場合に`true`を返す必要があります。
    - これにより、コントラクトが特定の機能をサポートしていることを示すことができます。

### メタデータスキーマに関する指針

- **メタデータの適合性**
    - オリジナルのメタデータは、“ERC-6785 Metadata with utilities JSON Schema”に準拠しているべきです。
    - これは、“ERC-721 Metadata JSON Schema”を基にした互換性のある拡張であり、NFTが提供するユーティリティに関する情報を含むように設計されています。

これらの指針に従うことで、NFTのユーティリティ情報を透明かつ一貫性のある方法で管理し、NFTの所有者や利用者にとって価値のある情報を提供することが可能になります。

### ユーティリティJSONスキーマによる**ERC6785**メタデータ

```json
{
  "title": "Asset Metadata",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Identifies the asset to which this NFT represents"
    },
    "description": {
      "type": "string",
      "description": "Describes the asset to which this NFT represents"
    },
    "image": {
      "type": "string",
      "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
    },
    "utilities": {
      "type": "object",
      "required": [
        "type",
        "description",
        "t&c"
      ],
      "properties": {
        "type": {
          "type": "string",
          "description": "Describes what type of utility this is"
        },
        "description": {
          "type": "string",
          "description": "A brief description of the utility"
        },
        "properties": {
          "type": "array",
          "description": "An array of possible properties describing the utility, defined as key-value pairs",
          "items": {
            "type": "object"
          }
        },
        "expiry": {
          "type": "number",
          "description": "The period of time for the validity of the utility, since the minting of the NFT. Expressed in seconds"
        },
        "t&c": {
          "type": "string",
          "description": ""
        }
      }
    }
  }
}
```

上記のJSONスキーマは、NFT（非代替トークン）が表す資産のメタデータを記述するためのものです。
このスキーマは、NFTがどのような資産を代表しているのか、またその資産に関連するユーティリティ（追加の価値や機能）についての情報を含む構造を定義しています。

##＃# 資産メタデータのプロパティ

- **name**
  - **型**
      - `string`
  - **説明**
      - このNFTが表す資産を識別します。
- **description**
  - **型**
      - `string`
  - **説明**
      - このNFTが表す資産について説明します。
- **image**
  - **型**
      - `string`
  - **説明**
      - このNFTが表す資産を表現する画像へのURIです。
      - MIMEタイプが`image/*`であるリソースを指します。
      - 画像は320ピクセルから1080ピクセルの幅で、アスペクト比は1.91:1から4:5の範囲であることが推奨されます。

###＃ ユーティリティに関するプロパティ

- **utilities**
  - **型**
      - `object`
  - **必須項目**
      - `type`, `description`, `t&c`
  - **プロパティ**
    - **type**
      - **型**
          - `string`
      - **説明**
          - ユーティリティのタイプを説明します。
    - **description**
      - **型**
          - `string`
      - **説明**
          - ユーティリティの簡単な説明です。
    - **properties**
      - **型**
          - `array`
      - **説明**
          - ユーティリティを記述する可能性のあるプロパティの配列です。
          - キーと値のペアとして定義されます。
      - **アイテム**: 
        - **型**
            - `object`
    - **expiry**
      - **型**
          - `number`
      - **説明**
          - ユーティリティの有効期間です。
          - NFTのミンティングからの時間を秒単位で表します。
    - **t&c**
      - **型**
          - `string`
      - **説明**
          - ユーティリティに適用される利用規約です。

このスキーマは、NFTのオーナーに対して、NFTが代表する資産とその資産に付随するユーティリティに関する透明かつ包括的な情報を提供することを目的としています。
これにより、NFTの利用価値やその条件についての理解が深まり、NFT市場の透明性と信頼性の向上に寄与することが期待されます。

# 補足

NFT（非代替トークン）に関連付けられたユーティリティ情報（`utilityUri`）を管理するための柔軟性と透明性の必要性について言及しています。
具体的には、NFTのユーティリティ情報が、外部のツールやプラットフォームに依存する場合があるため、それらが利用不可能またはアクセス不能になった時に、クリエイターが`utilityUri`を修正できる能力が必要であると述べています。
このような状況に対応することで、NFTのユーティリティ情報を最新の状態に保ち、利用者に正確な情報を提供することができます。

### ユーティリティ情報の修正

NFTのユーティリティ情報（`utilityUri`）は、NFTが提供する特定の価値や機能に関する詳細を含むURLです。
このURLが外部のツールやプラットフォームに依存している場合、そのサービスの継続性に問題が生じたときに情報を更新する柔軟性が必要になります。
例えば、外部サービスが閉鎖された場合や、情報をホストしているウェブサイトがダウンした場合などです。
このような状況でクリエイターが`utilityUri`を迅速に修正できることは、NFTの価値を維持し、所有者に対して正確な情報を提供する上で重要です。

### 透明性の確保

`utilityHistoryOf`メソッドを用いることで、NFTの`utilityUri`が時間とともにどのように変化してきたかを明確にすることができます。
これにより、NFTのユーティリティ情報の変更履歴を追跡し、その変更がいつ、なぜ行われたのかを所有者や潜在的な購入者が確認できるようになります。
透明性の高い情報提供は、信頼性を向上させ、ユーザーの理解を深める助けとなります。

### 例：ビデオコールの権利を提供するNFT

クリエイターがビデオコールというユーティリティを提供するNFTを販売する場合、そのNFTのメタデータは、この特典の詳細を説明する内容を含むことになります。
しかし、ビデオコールを実施するプラットフォームが変更されたり、使用されるツールに関する情報が更新されたりする必要がある場合、`utilityUri`を適宜修正する必要があります。
このように`utilityUri`を更新することで、NFTの所有者は常に最新の情報にアクセスでき、提供されるユーティリティを適切に利用できるようになります。

このアプローチにより、NFTのクリエイターは外部依存性に柔軟に対応できるだけでなく、NFT所有者に対して透明性と信頼性の高い情報を提供することが可能になります。

```json
{
  "name": "...",
  "description": "...",
  "image": "...",
  "utilities": {
    "type": "Video call",
    "description": "I will enter a private video call with whoever owns the NFT",
    "properties": [
      {
        "sessions": 2
      },
      {
        "duration": 30
      },
      {
        "time_unit": "minutes"
      }
    ],
    "expiry": 1.577e+7,
    "t&c": "https://...."
  }
}
```

NFTが提供する特定のユーティリティ（この例ではビデオコールへのアクセス権）の詳細情報にアクセスする方法について説明しています。
このプロセスは、NFTの所有者が彼らが所有するNFTに関連付けられた`getUtilityUri`メソッドによって返されるURIを介して行われます。
ここで、URIとは、ビデオコールに参加するために必要な情報（日時、アクセス方法など）を提供するウェブリソースのアドレスです。
さらに、ビデオコールの詳細へのアクセスが、そのNFTを所有しているウォレットによる認証を条件とする場合があります。
これにより、ユーティリティへのアクセスが正当な所有者に限定されることを保証します。

### ユーティリティアクセスのプロセス

1. **ユーティリティURIの取得**
    - NFTの所有者は、`getUtilityUri`メソッドを使用して、ビデオコールに関する詳細情報を提供するURIを取得します。
    - このURIは、ビデオコールのセッションにアクセスするために必要な情報を含むウェブページを指します。

2. **認証プロセス**
    - ビデオコールの詳細情報へのアクセスがNFTの所有者に制限されている場合、所有者は自分がそのNFTの正当な所有者であることを証明するために、所有しているウォレットによる認証を行う必要があります。
    - これにより、非所有者がユーティリティへアクセスすることを防ぎます。

3. **ユーティリティの状態情報**
    - URIには、ビデオコールセッションの現在の状態に関する情報も含まれていることがあります。
    - 例えば、利用可能なセッションの回数、ビデオコールのスケジュール、予約の方法などがこれに該当します。

### セキュリティと利便性

この方法により、ユーティリティへのアクセスをNFTの所有者に限定することができ、セキュリティを確保しつつ、所有者が簡単にユーティリティを利用できるようになります。
また、ユーティリティの状態に関する情報をリアルタイムで提供することで、所有者がユーティリティの利用計画を立てやすくなります。
このプロセスは、ブロックチェーンとNFTの透明性と不変性を活用しつつ、デジタルアセットが提供する価値を最大化するための一例です。

# 互換性

NFTにユーティリティ情報を追加するための方法や標準を定義しており、このアプローチは他の**ERC721**に関連する標準によって使用されているメソッド名とは重複していません。
つまり、この標準を採用しても、既存の**ERC721**トークンの動作に影響を与えずに、追加の機能や情報を提供できるということです。

# テスト

以下のテストコードが格納されています。

https://eips.ethereum.org/assets/eip-6785/test/ERC6785.test.js

# 実装

以下に実装コードが格納されています。

https://eips.ethereum.org/assets/eip-6785/contracts/ERC6785.sol

# セキュリティ

この規格の実装に直接関係するセキュリティ上の考慮事項はありません。

# 引用

Otniel Nicola (@OT-kthd), Bogdan Popa (@BogdanKTHD), "ERC-6785: ERC-721 Utilities Information Extension [DRAFT]," Ethereum Improvement Proposals, no. 6785, March 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6785.

# 最後に

今回は「**ERC721**規格のNFTの具体的なユーティリティとその使用方法をメタデータに定義する仕組みを提案している**ERC6785**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

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