[ERC5639] より安全で便利な権限委譲の仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、より安全で便利な署名操作を実行するための権限委譲を提案している規格である**ERC5639**についてまとめていきます！

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

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

:::note warn
**5639**は現在（2023年10月20日）では「**Review**」段階です。
:::

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

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

# 概要

このEIPは、提案されたプロトコルとABI（アプリケーションバイナリインターフェース）の詳細を説明しています。
このプロトコルとABIの定義により、1つまたは複数のデリゲートウォレットをボールトウォレットにリンクする機能が提供され、リンクされたデリゲートウォレットは、ボールトウォレットの制御と資産の所有権を証明することができるようになります。

**Delegation Registry**コントラクトは、デリゲートウォレットとボールトウォレットをリンクし、そのリンクを証明するためのルールを提供します。

デリゲートウォレットは、他のウォレット（通常は個人のウォレット）がボールトウォレットを代理で操作するための権限を持つことができます。
これにより、ボールトウォレットの所有者は、信頼できるデリゲートに対して特定の操作権限を付与することができます。

このプロトコルの目的は、ボールトウォレットの所有者がセキュリティとアクセス管理を向上させ、他のウォレットとのやり取りを容易にすることです。

:::note info
**Delegation Registry**はスマートコントラクトであり、デリゲートウォレットとボールトウォレットをリンクし、デリゲートの操作権限を証明するためのルールを提供します。
これにより、セキュリティとアクセス管理が向上し、やり取りが容易になります。
:::

# 動機

Ethereumの生態系において、第三者のアプリケーションに資産の所有権を証明することは一般的です。
ユーザーは、特定の操作を行う前に、自分が誰であるかを証明するためにデータのペイロードに署名することがよくあります。
しかし、この方法は安全性に問題があり、また不便な場合があります。

例えば以下のような状況です。

- OpenSeaでプロフィールを編集するには、ウォレットでメッセージに署名する必要があります。
- NFTの閲覧制限コンテンツにアクセスするには、NFTを所有するウォレットでメッセージに署名して所有権を証明する必要があります。
- 特定のイベントにアクセスするには、必要なNFTを所有するウォレットでメッセージに署名して所有権を証明する必要があります。
- エアドロップを受け取るには、資格のあるウォレットでスマートコントラクトとやり取りする必要があります。
- NFTの所有権を証明するには、そのNFTを所有するウォレットで特定のデータに署名する必要があります。

これらの例では、ユーザーはウォレットそのものを使用してアプリケーションやスマートコントラクトとやり取りしなければなりません。
これは不便であり、これらの操作は読み取り専用であるべきですが、実際には書き込みアクセス権を持つウォレットで署名や対話を行う必要があるため、セキュリティ上の懸念があります。

代わりに、特定のウォレットを複数承認し、そのウォレットが特定のウォレットの代理で認証できるようにする仕組みが必要です。

## 既存の方法と問題点

残念ながら、ユーザーが誤って悪意のあるデータに署名する事例が多く見受けられます。
その結果、ほとんどの場合、デリゲートアドレスに関連する資産の損失が発生してしまいます。

さらに、多くのユーザーは自分の資産の大部分を「**コールドストレージ**」に保管しています。
**コールドストレージ**はセキュリティ向上するにもかかわらず、これらのウォレットへのアクセス障壁が高まる傾向があります。

:::note info

障壁が高まる理由は、コールドストレージのセキュリティが向上する反面、アクセス性が制限されることに起因します。具体的な理由は以下の通りです。

#### オフライン保管
コールドストレージはオフラインで資産を保管するため、ネットワークに接続されていない状態が一般的です。
これにより、インターネット経由での攻撃やハッキングから保護されますが、ウォレットにアクセスするためにはオンラインにする必要があり、手動で切り替える必要があります。

#### 物理的なアクセス
コールドストレージのウォレットは通常、物理的なデバイス（ハードウェアウォレットや紙ウォレット）に保存されます。
そのため、ウォレットにアクセスするには物理的にそのデバイスにアクセスする必要があります。
これは、ユーザーがデバイスを安全に保管し、必要なときに取り出す手間を要します。

#### 署名プロセスの手動化
コールドストレージからのトランザクション署名や操作は通常、手動で行われます。
これには署名者がトランザクションデータをデバイスから取得し、署名してから再びデバイスに戻す手順が含まれます。
この手動プロセスは便利さを損ない、誤操作や遅延の原因となります。

#### セキュリティ設定の厳格化
コールドストレージのユーザーは、高いセキュリティ標準を維持する必要があります。
これにはバックアップの取得、デバイスの暗号化、アクセスコードの保護、定期的なソフトウェアの更新などが含まれます。
これらの手順はセキュリティを向上させますが、同時にアクセスを難しくする要因ともなります。

コールドストレージのセキュリティ向上にはコストとアクセスの制約が伴うため、ユーザーはセキュリティと便益のバランスを取る必要があります。
:::

## [提案]デリゲーションレジストリの使用

この提案は、ボールトウォレットがデリゲートウォレットに対して、ウォレット、コントラクト、またはトークンのレベルで権限を付与できる仕組みを提供することを目指しています。
これにより、より安全かつ便利な方法で署名と認証を行い、1つまたは複数のセカンダリウォレットを介してボールトウォレットへの「**読み取り専用**」アクセスを可能にします。

この提案には、以下の2つの主要な利点があります。
まず第一に、ユーザーは悪意のある署名操作をよりアクセスしやすいウォレット（ホットウォレット）に委託することにより、セキュリティを向上させることができます。
これにより、重要な操作を安全に実行できます。
第二に、ユーザーは、署名操作に頻繁に使用されないウォレットに対しては、意図したセキュリティの前提条件を維持しながら、より便利にアクセスできます。

:::note info
この提案は、ユーザーにセキュアで柔軟な方法を提供し、ウォレットの権限管理を向上させることを目指しています。
:::

### dAppとの対話セキュリティの向上
多くのdAppsでは、ウォレットの制御権を証明してアクセスする必要があります。
現在の方法では、この証明を行うためにウォレット自体を使用する必要があります。
しかし、これはセキュリティのリスクを伴います。
悪意のあるdAppsやフィッシングサイトによって、ウォレットの資産が悪意のあるデータに署名させられ、危険にさらされる可能性があります。

そのため、セカンダリウォレットを使用することで、このリスクを軽減できます。
悪意のある対話はセカンダリウォレットに制限され、価値がないかほとんど価値のない資産を含むように設定できます。

### 複数のデバイスでのアクセスセキュリティの向上
非ハードウェアウォレットを複数のデバイスで使用するには、各デバイスにシードフレーズをインポートする必要があります。
新しいデバイスにシードフレーズを入力するたびに、ウォレットのセキュリティが危険にさらされるリスクが増加します。
なぜなら、シードフレーズを知っているデバイスの数が増えるためです。

その代わりに、各デバイスには固有のウォレットを持たせ、それをメインウォレットの承認済みセカンダリウォレットとして使用できます。
デバイス固有のウォレットが侵害されたり紛失した場合でも、単に承認を取り消して認証を無効にすることができます。

さらに、ウォレットの認証を連鎖させることも可能で、セカンダリウォレットが1つまたは複数のサードウォレットを承認し、それらのサードウォレットがセカンダリアドレスだけでなくルートメインアドレスの署名権を持つようにできます。
これにより、チームごとに独自の署名者を持つことができ、メインウォレットはルートステムから権限を剥奪することで、全体を無効にできます。

### 利便性の向上
多くの人々は最高のセキュリティを求めてハードウェアウォレットを使用しています。
しかし、これは不便な場合があります。
なぜなら、既存のウォレットの問題点で述べたように、常にハードウェアウォレットを持ち歩くには不便だからです。

代わりに、非ハードウェアウォレットを認証用途（モバイルデバイスなど）に承認すれば、ハードウェアウォレットを手元に持たなくても、ほとんどのdAppを利用できます。

# 仕様

- `vault`（ボールト）
    - ボールトは、認証や資産の所有権を証明しようとしているアドレスを指します。
    - つまり、ユーザーが保護している重要なアドレスやウォレットです。
- `delegate`（デリゲート）
    - デリゲートは、ボールトの代わりに署名を行うために使用したいアドレスです。
    - ボールトの操作を代理で行う権限を持つウォレットやアドレスを指します。

**Delegation Registry（デリゲーション レジストリ）**は、`IDelegationRegistry`インターフェースを実装する必要があります。
このインターフェースは、デリゲーション関連の機能や設定を提供するための規格やルールを定義します。
デリゲーション レジストリは、ボールトとデリゲートの関係を設定し、管理するために使用されます。
つまり、どのデリゲートがどのボールトを代理で操作できるかを制御するための仕組みを提供します。

```javascript
/**
 * @title An immutable registry contract to be deployed as a standalone primitive
 * @dev New project launches can read previous cold wallet -> hot wallet delegations
 * from here and integrate those permissions into their flow
 */
interface IDelegationRegistry {
    /// @notice Delegation type
    enum DelegationType {
        NONE,
        ALL,
        CONTRACT,
        TOKEN
    }

    /// @notice Info about a single delegation, used for onchain enumeration
    struct DelegationInfo {
        DelegationType type_;
        address vault;
        address delegate;
        address contract_;
        uint256 tokenId;
    }

    /// @notice Info about a single contract-level delegation
    struct ContractDelegation {
        address contract_;
        address delegate;
    }

    /// @notice Info about a single token-level delegation
    struct TokenDelegation {
        address contract_;
        uint256 tokenId;
        address delegate;
    }

    /// @notice Emitted when a user delegates their entire wallet
    event DelegateForAll(address vault, address delegate, bool value);

    /// @notice Emitted when a user delegates a specific contract
    event DelegateForContract(address vault, address delegate, address contract_, bool value);

    /// @notice Emitted when a user delegates a specific token
    event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value);

    /// @notice Emitted when a user revokes all delegations
    event RevokeAllDelegates(address vault);

    /// @notice Emitted when a user revoes all delegations for a given delegate
    event RevokeDelegate(address vault, address delegate);

    /**
     * -----------  WRITE -----------
     */

    /**
     * @notice Allow the delegate to act on your behalf for all contracts
     * @param delegate The hotwallet to act on your behalf
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForAll(address delegate, bool value) external;

    /**
     * @notice Allow the delegate to act on your behalf for a specific contract
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForContract(address delegate, address contract_, bool value) external;

    /**
     * @notice Allow the delegate to act on your behalf for a specific token
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param tokenId The token id for the token you're delegating
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external;

    /**
     * @notice Revoke all delegates
     */
    function revokeAllDelegates() external;

    /**
     * @notice Revoke a specific delegate for all their permissions
     * @param delegate The hotwallet to revoke
     */
    function revokeDelegate(address delegate) external;

    /**
     * @notice Remove yourself as a delegate for a specific vault
     * @param vault The vault which delegated to the msg.sender, and should be removed
     */
    function revokeSelf(address vault) external;

    /**
     * -----------  READ -----------
     */

    /**
     * @notice Returns all active delegations a given delegate is able to claim on behalf of
     * @param delegate The delegate that you would like to retrieve delegations for
     * @return info Array of DelegationInfo structs
     */
    function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory);

    /**
     * @notice Returns an array of wallet-level delegates for a given vault
     * @param vault The cold wallet who issued the delegation
     * @return addresses Array of wallet-level delegates for a given vault
     */
    function getDelegatesForAll(address vault) external view returns (address[] memory);

    /**
     * @notice Returns an array of contract-level delegates for a given vault and contract
     * @param vault The cold wallet who issued the delegation
     * @param contract_ The address for the contract you're delegating
     * @return addresses Array of contract-level delegates for a given vault and contract
     */
    function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory);

    /**
     * @notice Returns an array of contract-level delegates for a given vault's token
     * @param vault The cold wallet who issued the delegation
     * @param contract_ The address for the contract holding the token
     * @param tokenId The token id for the token you're delegating
     * @return addresses Array of contract-level delegates for a given vault's token
     */
    function getDelegatesForToken(address vault, address contract_, uint256 tokenId)
        external
        view
        returns (address[] memory);

    /**
     * @notice Returns all contract-level delegations for a given vault
     * @param vault The cold wallet who issued the delegations
     * @return delegations Array of ContractDelegation structs
     */
    function getContractLevelDelegations(address vault)
        external
        view
        returns (ContractDelegation[] memory delegations);

    /**
     * @notice Returns all token-level delegations for a given vault
     * @param vault The cold wallet who issued the delegations
     * @return delegations Array of TokenDelegation structs
     */
    function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations);

    /**
     * @notice Returns true if the address is delegated to act on the entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForAll(address delegate, address vault) external view returns (bool);

    /**
     * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForContract(address delegate, address vault, address contract_)
        external
        view
        returns (bool);

    /**
     * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param tokenId The token id for the token you're delegating
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForToken(address delegate, address vault, address contract_, uint256 tokenId)
        external
        view
        returns (bool);
}
```

### `DelegationType`

```javascript
enum DelegationType {
    NONE,
    ALL,
    CONTRACT,
    TOKEN
}
```

**概要**
デリゲーションの種類を表す列挙型。

**パラメータ**
- `NONE`
    - デリゲーションなし。
- `ALL`
    - すべてのデリゲーション。
- `CONTRACT`
    - コントラクトレベルのデリゲーション。
- `TOKEN`
    - トークンレベルのデリゲーション。

---

### `DelegationInfo`

```javascript
struct DelegationInfo {
    DelegationType type_;
    address vault;
    address delegate;
    address contract_;
    uint256 tokenId;
}
```

**概要**
オンチェーン列挙のための単一のデリゲーションに関する情報を表す構造体。

**パラメータ**
- `type_`
    - デリゲーションの種類（`DelegationType`列挙型）。
- `vault`
    - ボールトのアドレス。
- `delegate`
    - デリゲートのアドレス。
- `contract_`
    - コントラクトのアドレス。
- `tokenId`
    - トークンのID。

---

### `ContractDelegation`

```javascript
struct ContractDelegation {
    address contract_;
    address delegate;
}
```

**概要**
単一のコントラクトレベルのデリゲーションに関する情報を表す構造体。

**パラメータ**
- `contract_`
    - コントラクトのアドレス。
- `delegate`
    - デリゲートのアドレス。

---

### `TokenDelegation`

```javascript
struct TokenDelegation {
    address contract_;
    uint256 tokenId;
    address delegate;
}
```

**概要**
この構造体は、単一のトークンレベルのデリゲーションに関する情報を表します。

**パラメータ**
- `contract_`
    - コントラクトのアドレス。
- `tokenId`
    - トークンのID。
- `delegate`
    - デリゲートのアドレス。

---

### `DelegateForAll`

```javascript
event DelegateForAll(address vault, address delegate, bool value);
```

**概要**
ユーザーがウォレット全体をデリゲートした時に発行されるイベント。

**パラメータ**
- `vault`
    - ボールトのアドレス。
- `delegate`
    - デリゲートのアドレス。
- `value`
    - デリゲーションの有効/無効の状態（`true`: 有効、`false`: 無効）。

---

### `DelegateForContract`

```javascript
event DelegateForContract(address vault, address delegate, address contract_, bool value);
```

**概要**
ユーザーが特定のコントラクトをデリゲートした時に発行されるイベント。

**詳細**
- `vault`
    - ボールトのアドレス。
- `delegate`
    - デリゲートのアドレス。
- `contract_`
    - コントラクトのアドレス。
- `value`
    - デリゲーションの有効/無効の状態（`true`: 有効、`false`: 無効）。

---

### `DelegateForToken`

```javascript
event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value);
```

**概要**
ユーザーが特定のトークンをデリゲートした時に発行されるイベント。

**詳細**
- `vault`
    - ボールトのアドレス。
- `delegate`
    - デリゲートのアドレス。
- `contract_`
    - コントラクトのアドレス。
- `tokenId`
    - トークンのID。
- `value`
    - デリゲーションの有効/無効の状態（`true`: 有効、`false`: 無効）。

---

### `RevokeAllDelegates`

```javascript
event RevokeAllDelegates(address vault);
```

**概要**
ユーザーがすべてのデリゲーションを取り消した時に発行されるイベント。

**詳細**
- `vault`
    - ボールトのアドレス。

---

### `RevokeDelegate`

```javascript
event RevokeDelegate(address vault, address delegate);
```

**概要**
ユーザーが特定のデリゲートを取り消した時に発行されるイベント。

**詳細**
- `vault`
    - ボールトのアドレス。
- `delegate`
    - デリゲートのアドレス。

---

### `delegateForAll`

```javascript
function delegateForAll(address delegate, bool value) external;
```

**概要**
デリゲートに、すべてのコントラクトに対する操作権限を許可または取り消す関数。

**詳細**
この関数を呼び出すことにより、指定したデリゲートに対して、ユーザーのウォレット内のすべてのコントラクトに対する操作権限を付与または取り消すことができます。
操作権限の有効化は`value`を`true`に設定し、取り消しは`false`に設定します。

**引数**
- `delegate`
    - デリゲートのアドレス。
- `value`
    - 操作権限の有効（`true`）または無効（`false`）。

---

### `delegateForContract`

```javascript
function delegateForContract(address delegate, address contract_, bool value) external;
```

**概要**
デリゲートに、特定のコントラクトに対する操作権限を許可または取り消す関数。

**詳細**
この関数を呼び出すことにより、指定したデリゲートに対して、特定のコントラクトに対する操作権限を付与または取り消すことができます。
操作権限の有効化は`value`を`true`に設定し、取り消しは`false`に設定します。

**引数**
- `delegate`
    - デリゲートのアドレス。
- `contract_`
    - コントラクトのアドレス。
- `value`
    - 操作権限の有効（`true`）または無効（`false`）。

---

### `delegateForToken`

```javascript
function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external;
```

**概要**
デリゲートに、特定のトークンに対する操作権限を許可または取り消す関数。

**詳細**
この関数を呼び出すことにより、指定したデリゲートに対して、特定のトークンに対する操作権限を付与または取り消すことができます。
操作権限の有効化は`value`を`true`に設定し、取り消しは`false`に設定します。

**引数**
- `delegate`
    - デリゲートのアドレス。
- `contract_`
    - コントラクトのアドレス。
- `tokenId`
    - トークンのID。
- `value`
    - 操作権限の有効（`true`）または無効（`false`）。

---

### `revokeAllDelegates`

```javascript
function revokeAllDelegates() external;
```

**概要**
すべてのデリゲートを取り消す関数。

**詳細**
この関数を呼び出すことにより、すべてのデリゲートに対する操作権限を取り消すことができます。

---

### `revokeDelegate`

```javascript
function revokeDelegate(address delegate) external;
```

**概要**
特定のデリゲートの操作権限を取り消す関数。

**詳細**
この関数を呼び出すことにより、指定したデリゲートに対する操作権限を取り消すことができます。

**引数**
- `delegate`
    - デリゲートのアドレス。

---

### `revokeSelf`

```javascript
function revokeSelf(address vault) external;
```

**概要**
自身がデリゲートとして設定されているボールトからのデリゲーションを取り消す関数。

**詳細**
この関数を呼び出すことにより、自身がデリゲートとして設定されている特定のボールトからのデリゲーションを取り消すことができます。

**引数**
- `vault`
    - デリゲーションを取り消す対象のボールトのアドレス。

---

### `getDelegationsByDelegate`

```javascript
function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory);
```

**概要**
指定したデリゲートが取得可能なすべてのアクティブなデリゲーションを返す関数。

**詳細**
この関数を呼び出すことにより、指定したデリゲートによってクレームできるすべてのアクティブなデリゲーション情報を取得できます。
デリゲーション情報は`DelegationInfo`構造体の配列で返されます。

**引数**
- `delegate`
    - デリゲートのアドレス。

**戻り値**
- `info`
    - `DelegationInfo`構造体の配列。
    - 各`DelegationInfo`にはデリゲーションに関する情報が含まれます。

---

### `getDelegatesForAll`

```javascript
function getDelegatesForAll(address vault) external view returns (address[] memory);
```

**概要**
指定したボールトのすべてのウォレットレベルのデリゲートの配列を返す関数。

**詳細**
この関数を呼び出すことにより、指定したボールトによって設定されたすべてのウォレットレベルのデリゲートのアドレス配列を取得できます。

**引数**
- `vault`
    - デリゲートのボールトのアドレス。

**戻り値**
- `addresses`
    - デリゲートのアドレスの配列。

---

### `getDelegatesForContract`

```javascript
function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory);
```

**概要**
指定したボールトとコントラクトに関連するすべてのコントラクトレベルのデリゲートの配列を返す関数。

**引数**
- `vault`
    - デリゲートのボールトのアドレス。
- `contract_`
    - コントラクトのアドレス。

**戻り値**
- `addresses`
    - デリゲートのアドレスの配列。

---

### `getDelegatesForToken`

```javascript
function getDelegatesForToken(address vault, address contract_, uint256 tokenId)
    external
    view
    returns (address[] memory);
```

**概要**
指定したボールト、コントラクト、およびトークンに関連するすべてのトークンレベルのデリゲートの配列を返す関数。

**引数**
- `vault`
    - デリゲートのボールトのアドレス。
- `contract_`
    - コントラクトのアドレス。
- `tokenId`
    - トークンのID。

**戻り値**
- `addresses`
    - デリゲートのアドレスの配列。

---

### `getContractLevelDelegations`

```javascript
function getContractLevelDelegations(address vault)
    external
    view
    returns (ContractDelegation[] memory delegations);
```

**概要**
指定したボールトによって設定されたすべてのコントラクトレベルのデリゲーション情報を返す関数。

**詳細**
この関数を呼び出すことにより、指定したボールトによって設定されたすべてのコントラクトレベルのデリゲーション情報が含まれる`ContractDelegation`構造体の配列を取得できます。

**引数**
- `vault`
    - デリゲーション情報を取得するボールトのアドレス。

**戻り値**
- `delegations`
    - `ContractDelegation`構造体の配列。
    - 各`ContractDelegation`にはコントラクトレベルのデリゲーション情報が含まれます。

---

### `getTokenLevelDelegations`

```javascript
function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations);
```

**概要**
指定したボールトによって設定されたすべてのトークンレベルのデリゲーション情報を返す関数。

**詳細**
この関数を呼び出すことにより、指定したボールトによって設定されたすべてのトークンレベルのデリゲーション情報が含まれる`TokenDelegation`構造体の配列を取得できます。

**引数**
- `vault`
    - デリゲーション情報を取得するボールトのアドレス。

**戻り値**
- `delegations`
    - `TokenDelegation`構造体の配列。
    - 各`TokenDelegation`にはトークンレベルのデリゲーション情報が含まれます。

---

## デリゲーションの確認
dAppまたはスマートコントラクトは、特定のアクションを実行する前にデリゲートが適切に認証されているかどうかを確認する必要があります。
この確認は、**Delegation Registry（デリゲーション レジストリ）**を介して行われます。
以下は、どのように確認が行われるかの要約です。

1. **ボールトに対するデリゲーションの確認**
   - dAppまたはスマートコントラクトは、特定のボールトに対してデリゲートが認証されているかどうかを確認するために、`checkDelegateForAll`という関数を使用します。
   - `checkDelegateForAll`の戻り値をチェックし、デリゲートが認証されていれば、ボールトに対する操作を許可します。
2. **コントラクトに対するデリゲーションの確認**
   - dAppまたはスマートコントラクトが特定のコントラクトに対してデリゲートが認証されているかどうかを確認するために、`checkDelegateForContract`という関数を使用します。
   - `checkDelegateForContract`の戻り値を確認し、デリゲートが認証されていれば、コントラクトに対する操作を許可します。
3. **トークンに対するデリゲーションの確認**
   - dAppまたはスマートコントラクトが特定のトークンがボールトによって所有されているかどうかを確認するために、`checkDelegateForToken`という関数を使用します。
   - `checkDelegateForToken`の戻り値を確認し、デリゲートがトークンに対して認証されていれば、トークンに対する操作を許可します。

デリゲートは、デリゲーションのレベルに応じて異なるアクションを実行できます。
例えば、トークンレベルのデリゲーションがある場合、デリゲートはトークンを操作できます。
同様に、コントラクトレベルのデリゲーションがある場合、デリゲートはコントラクトを操作できます。
ガスを節約するため、デリゲーションの確認がスマートコントラクトレベルで行われる場合、どのレベルのデリゲーションがあるかを示すヒントが提供され、最も効率的な確認方法が選択されます。

これにより、ボールトやコントラクトに関連するアクションを安全に実行するために、デリゲートが適切に認証され、不正なアクセスが制限されます。

# 補足

## ボールト、コントラクト、トークンレベルの委任を可能に

ボールト、コントラクト、トークンレベルのデリゲーションを許可する理由は、さまざまなデリゲーションの使用ケースをサポートするためです。
提案された仕様により、ボールトは制御する資産全体、特定のコントラクトの資産、または特定のトークンにデリゲーションを許可できます。
これにより、ボールトは資産のセキュリティを詳細に制御し、サードパーティのウォレットには関連する資産への制限付きアクセスしか許可しないことができます。

## オンチェーンの列挙
この仕様では、統合と採用の容易さをサポートするために、列挙をサポートすることを選択しました。
オンチェーンの列挙により、dAppのフロントエンドは接続されたウォレットがアクセスできるデリゲーションを識別し、UIセレクタを提供できます。

オンチェーンの列挙がない場合、dAppはユーザーにボールトを手動で入力させるか、すべてのデリゲートイベントをインデックス化する方法が必要です。
これにより、デリゲーションの設定が柔軟に行え、dAppのユーザーエクスペリエンスが向上します。

# セキュリティ考慮事項

このEIPの主要な目的は、セキュリティを向上させ、メインウォレットが必要でない場合やメインウォレットに保持されている資産を移動する必要がない場合でも、ウォレットの制御と資産の所有権を安全に認証する方法を促進することです。
これは、資産の「**読み取り専用**」認証を実現する方法と考えることができます。

:::note info
このEIPは、ウォレットの所有権を確認し、資産を移動する必要がない場合に、ウォレットのセキュリティを向上させる手段を提供します。
メインウォレットが必要ない場合に、安全な認証方法を提供することで、資産のセキュリティを保護します。
:::

# 引用

foobar (@0xfoobar), Wilkins Chung (@wwhchung) <wilkins@manifold.xyz>, ryley-o (@ryley-o), Jake Rockland (@jakerockland), andy8052 (@andy8052), "ERC-5639: Delegation Registry [DRAFT]," Ethereum Improvement Proposals, no. 5639, September 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5639.

# 最後に

今回は「より安全で便利な署名操作を実行するための権限委譲を提案している規格である**ERC5639**」についてまとめてきました！
いかがだったでしょうか？

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