[ERC5982] ロールベースのアクセス制御の仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、コントラクトのロールベースのアクセス制御の仕組みを提案している**ERC5982**についてまとめていきます！

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

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

:::note warn
**5982**は現在（2023年9月22日）では「**Review**」段階です。
:::

# 概要

このEIPは、Ethereumスマートコントラクトにおけるアクセス制御を簡単にする規格です。
アクセス制御は、誰がコントラクトの特定の機能や操作を実行できるかを管理する方法です。

このEIPでは、以下の主要な要素が定義されています。

## 役割 (Roles)**
特定の権限を持つユーザーまたはアクカウントのグループを表すものです。
バイト列（`byte32`）として定義され、例えば「**管理者**」や「**モデレーター**」などのロールを具体的に表現します。

## メソッドセレクタ (Method Selector)
ロール特定のメソッドや機能を呼び出す際に使用される`bytes4`メソッドセレクタを介して識別されます。
どのメソッドがどのロールに対して実行可能かを示します。

## 権限の許可と剥奪
このEIPは、ロールへの操作権限を付与したり剥奪したりする方法を規定しています。
例えば、あるユーザーに「**管理者**」のロールを付与して特定の操作を実行できるようにすることができます。

## ロールのメタデータ**
ロールに関する情報や設定を格納するためのメタデータの形式も規定されています。
これにより、ロールに関連する詳細情報を効果的に管理できます。

このEIPは、スマートコントラクトのセキュリティを向上させ、特定の操作や機能へのアクセスをコントロールするための一般的なフレームワークを提供します。
開発者はこのEIPを使用して、自分のスマートコントラクト内でアクセス制御を実装し、特定のユーザーグループに必要な権限を付与できます。
これにより、コントラクトの安全性と信頼性が向上し、不正なアクセスや操作を防ぐのに役立ちます。

# 動機

特権的なアクションに対するアクセス制御を確立する方法はいくつかありますが、その中でも一般的なアプローチの一つが「**ロールベースのアクセス制御**」です。
この方法では、特定のアクションや操作にアクセス権を持つユーザーを管理するために、「**ロール**」と呼ばれるグループを使います。
各ユーザーは1つ以上のロールに割り当てられ、そのロールによって特権的なアクションへのアクセスが許可されるかどうかが決まります。

以下のポイントが重要になります。

## 役割 (Roles)
ユーザーグループを表すもので、例えば「**管理者**」や「**モデレーター**」などが考えられます。
各ロールは特定の操作や機能に対するアクセス権を持っています。

## アクセス権の付与と剥奪
各ユーザーは1つ以上のロールに割り当てられ、それによって特定のアクセス権が与えられます。
たとえば、管理者ロールを持つユーザーは重要な操作を行うことができます。
逆に、不要なアクセス権を持つユーザーからはその権限を剥奪できます。

## 最小権限の原則
ロールベースのアクセス制御は、セキュリティを向上させるために各ユーザーには必要な権限のみを付与し、不必要な特権を持たせない「**最小権限の原則**」を意識することが重要です。

## 柔軟性
ロールベースのアクセス制御は柔軟で、新しいユーザーを追加したり、既存のユーザーの権限を変更したりするのが簡単です。
これにより、組織やプロジェクトのニーズに応じてアクセス制御を調整できます。

このアプローチは、特に分散型アプリケーションやスマートコントラクトのセキュリティを高めるために非常に有効です。
それぞれのユーザーに必要な権限を的確に与え、不正なアクセスを制限することができます。

# 仕様

インターフェースは以下のように定義されています。

### IERC_ACL_CORE

```javascript
interface IERC_ACL_CORE {
    function hasRole(bytes32 role, address account) external view returns (bool);
    function grantRole(bytes32 role, address account) external;
    function revokeRole(bytes32 role, address account) external;
}
```

- `hasRole(bytes32 role, address account)`
    - 特定のロールが特定のアカウントに割り当てられているか確認する関数。
- `grantRole(bytes32 role, address account)`
    - 特定のロールを特定のアカウントに付与する関数。
- `revokeRole(bytes32 role, address account)`
    - 特定のロールを特定のアカウントから剥奪する関数。

### IERC_ACL_GENERAL

```javascript
interface IERC_ACL_GENERAL {
    event RoleGranted(address indexed grantor, bytes32 indexed role, address indexed grantee, bytes _data);
    event RoleRevoked(address indexed revoker, bytes32 indexed role, address indexed revokee, bytes _data);

    event RoleCreated(address indexed roleGrantor, bytes32 role, bytes32 adminOfRole, string name, string desc, string uri, bytes32 calldata _data);
    event RoleDestroyed(address indexed roleDestroyer, bytes32 role, bytes32 calldata _data);
    event RolePowerSet(address indexed rolePowerSetter, bytes32 role, bytes4 methods, bytes calldata _data);

    function grantRole(bytes32 role, address account, bytes calldata _data) external;
    function revokeRole(bytes32 role, address account, bytes calldata _data) external;

    function createRole(bytes32 role, bytes32 adminOfRole, string name, string desc, string uri, bytes32 calldata _data) external;
    function destroyRole(bytes32 role, bytes32 calldata _data) external;
    function setRolePower(bytes32 role, bytes4 methods, bytes calldata _data) view external returns(bool);

    function hasRole(bytes32 role, address account, bytes calldata _data) external view returns (bool);
    function canGrantRole(bytes32 grantor, bytes32 grantee, bytes calldata _data) view external returns(bool);
    function canRevokeRole(bytes32 revoker, bytes32 revokee, address account, bytes calldata _data) view external returns(bool);
    function canExecute(bytes32 executor, bytes4 methods, bytes32 calldata payload, bytes calldata _data) view external returns(bool);
}
```

このインターフェースは、ロールの操作に関するイベントやより詳細な機能を提供します。
- Event系
    - ロールが付与されたり、剥奪されたり、作成されたり、破棄されたりした時に発行されるイベント。
- `grantRole(bytes32 role, address account, bytes calldata _data)`
    - 特定のロールを特定のアカウントに付与し、関連データを提供する関数。
- `revokeRole(bytes32 role, address account, bytes calldata _data)`
    - 特定のロールを特定のアカウントから剥奪し、関連データを提供する関数。
- `createRole(bytes32 role, bytes32 adminOfRole, string name, string desc, string uri, bytes32 calldata _data)`
    - 新しいロールを作成するための関数で、関連データとロールの詳細を提供する関数。
- `destroyRole(bytes32 role, bytes32 calldata _data)`
    - 特定のロールを破棄するための関数で、関連データを提供する関数。
- `setRolePower(bytes32 role, bytes4 methods, bytes calldata _data)`
    - ロールの特権（メソッドへのアクセスなど）を設定する関数。

### IERC_ACL_METADATA

```javascript
interface IERC_ACL_METADATA {
    function roleName(bytes32) external view returns(string);
    function roleDescription(bytes32) external view returns(string);
    function roleURI(bytes32) external view returns(string);
}
```

このインターフェースは、ロールに関するメタデータ情報（名前、説明、URIなど）にアクセスする関数を提供します。
- `roleName(bytes32)`
    - ロールの名前を取得する関数。
- `roleDescription(bytes32)`
    - ロールの説明を取得する関数。
- `roleURI(bytes32)`
    - ロールに関連付けられたURIを取得する関数。

## 仕様の補足

### IERC_ACL_CORE の実装が必要
スマートコントラクトがロールベースのアクセス制御をサポートするために、`IERC_ACL_CORE`インターフェースを実装する必要があります。
このインターフェースには、アカウントにロールを付与したり、ロールを確認したりするための基本的な関数が含まれています。

### IERC_ACL_GENERAL の実装が推奨
オプションですが、ロールベースのアクセス制御をより高度に制御したい場合に便利です。
`IERC_ACL_GENERAL`インターフェースを実装すると、アクセス権の操作やイベントのトラッキングに関する追加の機能が提供され、柔軟性が向上します。

### IERC_ACL_METADATA の実装が許容
これもオプションです。
ロールに関連する詳細情報を提供したい場合に使用します。
たとえば、特定のロールに名前や説明、URIなどのメタデータを関連付けることができます。

### ロールは bytes32 形式
   - 役割は `bytes32` 形式で表現されます。役割名を `keccak256` ハッシュ関数を使ってハッシュ化することで、一意な役割を定義します。これにより、役割名の衝突を防ぎ、セキュリティを向上させます。

### ERC-165 識別子の実装が推奨**:
他のスマートコントラクトやツールとの統合性を高めるため、**ERC165**識別子を実装することが推奨されます。
これにより、スマートコントラクトが特定のインターフェースをサポートしていることを確認でき、他のコントラクトやツールがスマートコントラクトの機能を適切に利用できるようになります。

# 補足

## IERC_ACL_CORE のメソッド名とパラメータ
`IERC_ACL_CORE` インターフェースのメソッド名やパラメータは、OpenZeppelinの実装と互換性を保つために慎重に選ばれました。
既存のOpenZeppelinのスマートコントラクトやライブラリと統合することが容易になり、開発者が既存のコードを再利用できるようにするための重要な決定です。
つまり、OpenZeppelinのコードとこのインターフェースを使用して開発されたスマートコントラクトは、スムーズに連携できるように設計されています。

## IERC_ACL_GENERAL のメソッドは ERC-5750 準拠
`IERC_ACL_GENERAL` インターフェースのメソッドは、**ERC5750**に従って設計されています。
**ERC5750**は、アクセス制御の機能を追加できるようにするための標準であり、このインターフェースを使用するスマートコントラクトが追加の機能を実装しやすくなります。
これにより、アクセス制御の柔軟性が向上し、新しい機能を追加するための柔軟性が提供されます。

## renounceRole メソッドは採用されず、revokeRole と統合**:
`renounceRole` メソッド（ロールを自発的に放棄するためのもの）は取り入れられず、代わりに `revokeRole` メソッド（他のユーザーによってロールを剥奪するためのもの）と統合されました。
この変更は、インターフェースを簡略化し、ロールの操作に関する一貫性を高めるためのものです。
ユーザーはロールを剥奪するか、持続的に保持することができ、よりシンプルなインターフェースが提供されます。

これらの設計決定により、スマートコントラクトは他のスマートコントラクトやライブラリとの統合を容易にし、アクセス制御の柔軟性と効率を向上させることができます。

# 後方互換性

議論が必要です。

# セキュリティ考慮事項

議論が必要です。

# 引用

Zainan Victor Zhou (@xinbenlv), "ERC-5982: Role-based Access Control [DRAFT]," Ethereum Improvement Proposals, no. 5982, November 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5982.

# 最後に

今回は「コントラクトのロールベースのアクセス制御の仕組みを提案している**ERC5982**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58