[ERC7204] コントラクトウォレットでの使用を想定したより安全で柔軟なトークン管理の仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、コントラクトウォレットでの利用を想定して、新たなトークンの`approve`と`transfer`の仕組みを提案している**ERC7204**についてまとめていきます！

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

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

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

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

# 概要

この提案は、トークン管理におけるコントラクトウォレットの活用を中心においています。
コントラクトウォレットはプログラム可能で、その特性を利用して資産管理をより適応性が高く、安全で、効率的なものにすることを目指しています。
具体的には、以下の機能を導入しています。

- **tokenTransfer**
    - トークンの送信を行う機能。
    - ユーザーはこの機能を使って、指定したアドレスにトークンを送ることができます。
- **tokenApprove**
    - 特定のアドレスが、ある量のトークンを代わりに送ることを許可する機能です。
    - これは、他人があなたのトークンを使う許可を与える時に使われます。
- **tokenApproveForAll**
    - 特定のアドレスが、あなたの全てのトークンを代わりに管理することを許可する機能です。
    - これは、複数のトークンを扱う時に便利です。
- **tokenIsApproveForAll**
    - あるアドレスが全てのトークンを代わりに管理する許可を持っているかどうかを確認する機能です。
- **tokenAllowance**
    - あるアドレスが、他のアドレスのトークンをどれだけ使えるか（許可されているか）を確認する機能です。

これらの機能は、トークンの取引や管理をより柔軟に制御することを可能にします。
例えば、あなたがあるサービスに対して支払いを許可したい場合、`tokenApprove`機能を使ってそのサービスのアドレスに対して特定量のトークンを使う許可を与えることができます。
また、`tokenTransfer`機能を使って、トークンを友人や他のウォレットに直接送ることもできます。

このように、スマートコントラクトウォレットを使ったアプローチは、トークンの管理をより効率的で安全なものにし、ユーザーがトークンを使う時の選択肢を広げることを目指しています。

# 動機

この提案は、コントラクトウォレットを用いたトークン資産管理の新しいアプローチを紹介しています。
主なポイントは以下の通りです。

### コントラクトウォレットとは

**EOAウォレット**と比較して、スマートコントラクトウォレットは状態（state）とコード（code）の保存が可能です。
これにより、ウォレットにプログラム可能性をもたらし、より柔軟な操作が実現します。
**アカウント抽象化（AA）**はコントラクトウォレットに関連する提案の1つで、抽象化されたアカウントを取り扱います。
このERCは**ERC4337**に基づく拡張や、ウォレットのプラグインとして機能する可能性があります。

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

https://qiita.com/cardene/items/8c97ca7c93c4557ebfc2

### 提案の目標

- **資産の自己管理**
    - トークン資産の承認（`approve`）や許可（`allowance`）を、トークン資産コントラクトではなくユーザーのコントラクトウォレット自体が設定・管理することで、既存の**ERC20**コントラクトのリスクを避けます。
- **機能の追加**
   - **tokenTransfer**
       - スマートウォレット自体または非スマートウォレットによるトランザクションを開始する時、許可された量を検証します。
   - **tokenApprove, tokenAllowance, tokenApproveForAll, tokenIsApproveForAll**
       - これらの関数を通じて、ユーザーのウォレットは単一または全てのトークン資産に対しての承認をサポートし、提供します。
- **バッチ操作**
    - ユーザーはバッチ承認やバッチ転送を選択できます。
- **フック関数の追加**
    - ユーザーは、`tokenTransfer`の前後にフック関数を追加することを選択でき、これによりプレイヤビリティが向上します。
- **tokenReceive関数の実装を選択可能**
    - ユーザーは、トークンの受け取り方をカスタマイズできます。

### 互換性

この提案は、**simpletoken ERC-X**をサポートし、**ERC20**は**ERC-X**と互換性があります。
これにより、市場に存在するすべての代替不可能トークンの管理が可能になります。

:::note info
### ERC-Xについて

**ERCx**は、Runtime Verificationによって提供されるサービスであり、ERCトークン（例：**ERC20**, **ERC721**, **ERC1155**など）の開発、テスト、準拠性チェック、およびセキュリティテストを行うためのツールを提供しています。
ERCxは、Ethereum Improvement Proposals（EIP）で記述された標準の要件を超え、セキュリティ監査員によって設計された重要なセキュリティプロパティを含んでいます。
このサービスは、スマートコントラクトの振る舞いに追加の信頼を与えるために、各標準（**ERC20**, **ERC4626**, **ERC721**, **ERC1155**）に対してカスタムセキュリティテストスイートを追加しています。
ERCxは、トークンの分析に関する構造化された詳細なレポートを生成し、トークンプロパティをカテゴリに整理して、それらが評価する内容とその重要性を反映しています。
:::

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

https://chaldene.net/erc721

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

https://chaldene.net/erc1155

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

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

:::note info
この提案は、コントラクトウォレットを通じて、トークン資産の管理と承認をより安全で柔軟に行う新しい方法を提供します。
ユーザーは自分のウォレットをカスタマイズして、資産の管理を自己の手で行うことが可能になります。これにより、既存の**ERC20**トークンの一部のリスクを回避し、トークン取引の機能を拡張することが目指されています。
:::

# 仕様

この規格に準拠するコントラクトは、**ERC165**インターフェイスを実装する必要があります。

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

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

```ts
/// @title ERC-7204 
/// @dev See https://eips.ethereum.org/EIPS/eip-7204
/// @dev Note: the ERC-165 identifier for this interface is 0xf73edcda
pragma solidity ^0.8.20;

interface IERC7204 /* is ERC165 */ {

    /**
     * @notice Used to notify listeners that owner has granted approval to the user to manage assets tokens.
     * @param asset Address of the token
     * @param owner Address of the account that has granted the approval for token‘s assets
     * @param spender Address of the spender
     * @param value The amount allowed to spend
     */
    event TokenApproval(
        address indexed asset,
        address indexed owner, 
        address indexed spender, 
        uint256 value
    );

    /**
     * @notice Used to notify listeners that owner has granted approval to the spender to manage all token .
     * @param asset Address of the token
     * @param owner Address of the account that has granted the approval for token‘s assets
     * @param approved approve all token
     */
    event TokenApprovalForAll(
        address indexed owner, 
        address indexed spender,
        bool approved
    );

    /**
     * @notice Approve token
     * @dev Allows spender address to withdraw from your account multiple times, up to the value amount.
     * @dev If this function is called again it overwrites the current allowance with value.
     * @dev Emits an {TokenApproval} event.
     * @param asset Address of the token
     * @param spender Address of the spender
     * @param value The amount allowed to spend
     * @return success The bool value returns whether the approve is successful
     */
    function tokenApprove(address asset, address spender, uint256 value) 
        external 
        returns (bool success);

    /**
     * @notice read token allowance value
     * @param asset Address of the token
     * @param spender Address of the spender
     * @return remaining The asset amount which spender is still allowed to withdraw from owner.
     */
    function tokenAllowance(address asset, address spender) 
        external
        view
        returns (uint256 remaining);

    /**
     * @notice Approve all token
     * @dev Allows spender address to withdraw from your wallet all token.
     * @dev Emits an {TokenApprovalForAll} event.
     * @param spender Address of the spender
     * @param approved Approved all tokens
     * @return success The bool value returns whether the approve is successful
     */
    function tokenApproveForAll(address spender, bool approved) 
        external 
        returns (bool success);

    /**
     * @notice read spender approved value
     * @param spender Address of the spender
     * @return approved Whether to approved spender all tokens
     */
    function tokenIsApproveForAll(address spender) 
        external
        view
        returns (bool approved);

    /**
     * @notice Transfer token
     * @dev must call asset.transfer() inside the function
     * @dev If the caller is not wallet self, must verify the allowance and update the allowance value
     * @param asset Address of the token
     * @param to Address of the receive
     * @param value The transaction amount
     * @return success The bool value returns whether the transfer is successful
     */
    function tokenTransfer(address asset, address to, uint256 value) 
        external 
        returns (bool success); 
}
```

### `tokenApprove`

```javascript
function tokenApprove(address asset, address spender, uint256 value) 
    external 
    returns (bool success);
```

**概要**

特定のトークンについて、指定されたアドレスが一定量までのトークンを使用できるように承認する関数。

**詳細**

`tokenApprove`関数は、特定のアセット（トークン）に対して、指定された`spender`（使用者）が許可された`value`（量）までトークンを引き出すことを可能にします。
この関数が再度呼び出されると、現在の許可額が新しい`value`で上書きされます。
この操作は`TokenApproval`イベントを発火させます。

**引数**

- `asset`
    - 承認されるトークンのアドレス。
- `spender`
    - トークンを使用することが許可されるアドレス。
- `value`
    - `spender`が使用できるトークンの量。

**戻り値**

- `success`
    - 承認が成功したかどうかを示す`bool`値。

### `tokenAllowance`

```javascript
function tokenAllowance(address asset, address spender) 
    external
    view
    returns (uint256 remaining);
```

**概要**

特定のトークンに対する使用者の許可された残量を確認する関数。

**詳細**

`tokenAllowance`関数は、`spender`（使用者）が`asset`（トークン）から引き出すことができる残りの許可量を返します。
これにより、使用者がどの程度のトークンをまだ使用できるかを把握することができます。

**引数**

- `asset`
    - 対象となるトークンのアドレス。
- `spender`
    - 使用者のアドレス。

**戻り値**

- `remaining`
    - 使用者がまだ引き出すことができるトークンの量。

### `tokenApproveForAll`

```javascript
function tokenApproveForAll(address spender, bool approved) 
    external 
    returns (bool success);
```

**概要**

すべてのトークンに対して、指定されたアドレスが使用を承認されるか設定する関数。

**詳細**

`tokenApproveForAll`関数は、指定された`spender`（使用者）に、コントラクトのすべてのトークンを使用する許可を与えるかどうかを`approved`（承認）するために使用されます。
この操作は`TokenApprovalForAll`イベントを発火させます。

**引数**

- `spender`
    - トークンの使用が許可されるアドレス。
- `approved`
    - すべてのトークンに対する使用を承認するかどうかの`bool`値。

**戻り値**

- `success`
		- 承認が成功したかどうかを示す`bool`値。

### `tokenIsApproveForAll`

```javascript
function tokenIsApproveForAll(address spender) 
    external
    view
    returns (bool approved);
```

**概要**

指定されたアドレスがすべてのトークンの使用を承認されているか確認する関数。

**詳細**

`tokenIsApproveForAll`関数は、`spender`（使用者）がコントラクトのすべてのトークンを使用することが承認されているかどうかを確認するために使用されます。
これにより、特定のアドレスが全トークンの使用を許可されているかを判断できます。

**引数**

- `spender`
    - 使用者のアドレス。

**戻り値**

- `approved`
    - すべてのトークンに対する使用が承認されているかどうかの`bool`値。

### `tokenTransfer`

```javascript
function tokenTransfer(address asset, address to, uint256 value) 
    external 
    returns (bool success);
```

**概要**

トークンを指定されたアドレスに転送する関数。

**詳細**

`tokenTransfer`関数は、`asset`（トークン）を`to`（受取人）に転送するために使用されます。
この関数を呼び出す時、コントラクトは内部で`asset.transfer()`を呼び出す必要があります。
呼び出し元がウォレット自身ではない場合、許可された量を検証し、許可量を更新する必要があります。

**引数**

- `asset`
    - 転送されるトークンのアドレス。
- `to`
    - トークンを受け取るアドレス。
- `value`
    - 転送するトークンの量。

**戻り値**

- `success`
    - 転送が成功したかどうかを示す`bool`値。

# 補足

### 改良された承認メカニズム

**現行と提案の違い**
現存する**ERC20**トークンシステムでは、外部所有アカウント（EOA）がトークンコントラクトと直接やりとりして承認します。
提案された新しい`tokenApprove`と`tokenApproveForAll`関数は、ウォレットコントラクト内でのトークン使用に対してより正確な制御を可能にし、従来の方法を大きく改善します。

**セキュリティの向上**
このメカニズムは、トークンの過剰承認のようなリスクを軽減します。
承認の制御をユーザーのスマートコントラクトウォレットに移すことで、これを実現します。

**プログラム可能性**
ユーザーは、条件付きや時間限定の承認など、進化した承認戦略を設定する権限を得ます。`tokenApproveForAll`関数は特に、すべてのトークンに対するユニバーサルな設定を可能にします。
これは従来の**ERC20**トークンでは不可能でした。

### 最適化された転送プロセス

**効率性とセキュリティ**
`tokenTransfer`関数は、トークン転送プロセスを合理化し、トランザクションをより効率的かつ安全にします。

**柔軟性**
`transfer`の前後にカスタムロジック（フック）を組み込むことを可能にし、追加のセキュリティチェックやユーザーのニーズに合わせた特定のアクションを可能にします。

### バッチ操作のサポート

**効率性の増大**
ユーザーは複数の承認または`transfer`操作を同時に処理でき、トランザクションの効率を大幅に向上させることができます。

**ユーザーエクスペリエンスの向上**
多数の資産を管理することを簡素化し、大量のポートフォリオを持つユーザーの全体的な経験を改善します。

これらの技術的改善は、ユーザーが自身のトークン資産をより精密に、効率的に、そして安全に管理できるようにすることを目指しています。

# 互換性

このERCは**ERC4337**の拡張として使用でき、**ERC4337**と互換性があります。

# 引用

Xiang (@wenzhenxiang), Ben77 (@ben2077), Mingshi S. (@newnewsms), "ERC-7204: Contract wallet management token [DRAFT]," Ethereum Improvement Proposals, no. 7204, June 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7204.

# 最後に

今回は「コントラクトウォレットでの利用を想定して、新たなトークンの`approve`と`transfer`の仕組みを提案している**ERC7204**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.substack.com/

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