[ERC3754] NFTに実行権やアクセス権を付与する仕組みを理解しよう！

# はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

https://amzn.asia/d/gxvJ0Pw

今回は、**ERC721**形式のNFTを特定の機能を実行する権利やサブスクの利用権など使い方に焦点を当てている仕組みを提案している**ERC3754**についてまとめていきます！

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

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

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

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

# 概要

**ERC3754**では、NFTをアトミックな存在として扱い、その上に抽象的なレイヤーを重ねていく設計を提案しています。
つまり、NFTは単なるデジタル資産の所有権を示すだけでなく、「**権利**」や「**抽象的な所有**」などの概念を表現するための器として使うことが想定されています。

具体例として、NFTオプション（特定のNFTを購入する権利）、オラクルの利用権、バーチャルクーポン（例えば割引券やチケット）などが挙げられます。
これらの「権利」はNFTという形でトークン化されることで、流動性を持たせることが可能になります。

# 動機

これまでNFTは**ERC721**に基づいて、「**デジタルまたは物理的資産の所有**」を示す手段として普及してきました。
著名なNFTプロジェクトも、主に暗号資産やデジタルコレクティブルを対象にしています。

しかし、**ERC3754**が目指すのは資産型NFTとは異なり、「**抽象的な所有権**」を表現することに特化したNFTの形式です。
例えば以下のようなケースが想定されています。

- スマートコントラクトに対して特定の関数を呼び出す権利
- 特定の**ERC721**形式のNFTを購入する権利を持つオプションNFT
- オラクルが提供するデータフィードに対して、トークンを支払うことなく一定期間アクセスできる前払い型メンバーシップ

このように抽象的な権利をNFTとしてトークン化することで、オンチェーンのサブスクリプションビジネスモデルの実現が可能となります。

# 仕様

:::note info
仕様は**ERC721**と同じです。
使い方に焦点を当てている提案になります。
:::

## インターフェース

```js:IERC3754.sol
interface IERC3754 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function balanceOf(address owner) external view returns (uint256);
    function ownerOf(uint256 tokenId) external view returns (address);
    function approve(address to, uint256 tokenId) external;
    function getApproved(uint256 tokenId) external view returns (address);
    function setApprovalForAll(address operator, bool approved) external;
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    function transferFrom(address from, address to, uint256 tokenId) external;
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) external;
}
```

## イベント

### `Transfer`

```js
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
```

NFTの所有者が変更された時に発行されるイベント。
全ての`transferFrom`や`safeTransferFrom`によるトークンの移転操作によりこのイベントが発行されます。

**パラメータ**

* `from`
    * 送信元アドレス。
* `to`
    * 受信先アドレス。
* `tokenId`
    * 移転されたNFTの一意な識別子。

### `Approval`

```js
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
```

特定のNFTに対する承認が変更された時に発行されるイベント。
NFTの所有者が別のアドレスに対して特定の`tokenId`の操作権限を与えたときに発行されます。

**パラメータ**

* `owner`
    * トークンの所有者。
* `approved`
    * 承認されたアドレス。
* `tokenId`
    * 操作を許可されたNFTの識別子。

### `ApprovalForAll`

```js
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
```

全てのNFTに対する包括的な承認状態が変更された時に発行されるイベント。
あるアドレス（`operator`）が、所有者のすべてのNFTを操作できるように承認または解除されたときに発行されます。

**パラメータ**

* `owner`
    * 承認を出したNFTの所有者。
* `operator`
    * 操作を許可されたアドレス。
* `approved`
    * 承認されたかどうか（`true`なら承認された）。

## 関数

### `balanceOf`

```js
function balanceOf(address owner) external view returns (uint256);
```

アドレスが保有しているNFTの数を返す関数。
指定したアドレスが保有しているNFTの総数を取得します。
所有していない場合は0を返します。

**引数**

* `owner`
    * 残高を確認したいアドレス。

**戻り値**

* `uint256`
    * 保有しているNFTの数。

### `ownerOf`

```js
function ownerOf(uint256 tokenId) external view returns (address);
```

指定されたNFTの所有者アドレスを返す関数。
`tokenId`で識別されるNFTの現在の所有者を取得します。
存在しないトークンIDに対してはエラーになります。

**引数**

* `tokenId`
    * 所有者を確認したいNFTの識別子。

**戻り値**

* `address`
    * 指定されたNFTの所有者アドレス。

### `approve`

```js
function approve(address to, uint256 tokenId) external;
```

特定のNFTに対する操作を別のアドレスに許可する関数。
所有者または全体の承認者が、指定したNFTに対して`to`アドレスに操作権限を付与します。
1つのNFTに対して1つのアドレスしか承認できません。

**引数**

* `to`
    * 操作を許可するアドレス。
* `tokenId`
    * 対象となるNFTの識別子。

### `getApproved`

```js
function getApproved(uint256 tokenId) external view returns (address);
```

指定されたNFTに対して承認されているアドレスを取得する関数。
ある`tokenId`に対して現在操作を許可されているアドレスを返します。
誰にも承認されていなければゼロアドレスを返します。

**引数**

* `tokenId`
    * 操作権限を確認するNFTの識別子。

**戻り値**

* `address`
    * 承認されているアドレス。

### `setApprovalForAll`

```js
function setApprovalForAll(address operator, bool approved) external;
```

全てのNFTに対して包括的な操作権限を付与または削除する関数。
所有者は、自分が保有するすべてのNFTを、`operator`が操作できるようにするかどうかを設定できます。

**引数**

* `operator`
    * 操作権限を設定するアドレス。
* `approved`
    * `true`で承認、`false`で解除。

### `isApprovedForAll`

```js
function isApprovedForAll(address owner, address operator) external view returns (bool);
```

指定されたアドレスが全NFTの操作を許可されているかを確認する関数。
`operator`が`owner`のすべてのNFTを操作できるかどうかを返します。

**引数**

* `owner`
    * NFTの所有者。
* `operator`
    * 操作権限を確認するアドレス。

**戻り値**

* `bool`
    * 操作権限があるかどうか。

### `transferFrom`

```js
function transferFrom(address from, address to, uint256 tokenId) external;
```

指定したNFTを別のアドレスに転送する関数。
`from`が所有している`tokenId`を`to`に転送します。
呼び出し元は所有者か承認されたアドレスでなければなりません。

**引数**

* `from`
    * NFTの現在の所有者。
* `to`
    * 転送先のアドレス。
* `tokenId`
    * 転送するNFTの識別子。

### `safeTransferFrom`

```javascript
function safeTransferFrom(address from, address to, uint256 tokenId) external;
```

NFTを安全に転送する関数。
NFTを転送する時、受信先がコントラクトである場合に正しく受け取れるかを確認してから転送します。
失敗時は処理を巻き戻します。

**引数**

* `from`
    * 現在の所有者。
* `to`
    * 受信先アドレス。
* `tokenId`
    * 転送するNFTの識別子。

### `safeTransferFrom`

```javascript
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) external;
```

データ付きでNFTを安全に転送する関数。
`_data`パラメータを受け取れるよう拡張された`safeTransferFrom`関数です。
追加のデータを送信先に渡せます。

**引数**

* `from`
    * 現在の所有者。
* `to`
    * 受信先アドレス。
* `tokenId`
    * 転送するNFTの識別子。
* `_data`
    * 任意のデータ（バイト列）。

# 補足

**ERC3754**で定義されるNFTは、**ERC721**によって広く普及した「**デジタル資産の所有権**」を表現するNFTとは異なり、「**抽象的な所有権**」を表現することを目的としています。
抽象的な所有権とは、具体的な物理的・デジタルな資産ではなく、ある種の権利や機能の利用権などを指します。

この目的を実現するために、**ERC3754**ではNFTの上に抽象的なユーティリティ（利用機能）を重ねて設計・実装することを推奨しています。
こうしたNFTの所有者は、該当するトークンに紐づけられた「**機能を実行する権利**」を有することになります。
そして、その権利を他者に譲渡する（トークンを移転する）ことで、実質的にその権利自体の譲渡も可能になります。

さらに、**ERC721**との違いを明確にするために、この標準ではURI（メタデータ）に関するデータフィールドや関数は除外されています。
これは、この標準が資産情報の表示やコレクティブルの性質よりも、「**実行権やアクセス権**」といった抽象的な権利の管理と移転を重視しているためです。

# セキュリティ

**ERC721**からセキュリティが強化されており、トークンを発行する時にはURIを渡す必要がありません。
これにより、URIの取り扱いに関するエラーを回避できます。

# 引用

Simon Tian (@simontianx), "ERC-3754: A Vanilla Non-Fungible Token Standard [DRAFT]," Ethereum Improvement Proposals, no. 3754, August 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3754.














# 最後に

今回は「**ERC721**形式のNFTを特定の機能を実行する権利やサブスクの利用権など使い方に焦点を当てている仕組みを提案している**ERC3754**」についてまとめてきました！
いかがだったでしょうか？

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