ERC-6617: 基于位的权限
一个基于位的权限和角色系统
Authors | Chiro (@chiro-hiro), Victor Dusart (@vdusart) |
---|---|
Created | 2023-02-27 |
摘要
这个 EIP 提供了一个用于构建基于位的权限和角色系统的标准。每个权限由单个位表示。通过使用 uint256
,可以定义最多 $256$ 个权限和 $2^{256}$ 个角色。我们能够基于位的顺序来指定每个权限的重要性。
规范
本文档中的关键词 “MUST”,“MUST NOT”,“REQUIRED”,“SHALL”,“SHALL NOT”,“SHOULD”,“SHOULD NOT”,“RECOMMENDED”,“NOT RECOMMENDED”,“MAY” 和 “OPTIONAL” 应按照 RFC 2119 和 RFC 8174 中的描述进行解释。
注意 以下规范使用 Solidity 0.8.7
(或以上版本)的语法
参考接口描述如下:
pragma solidity ^0.8.7;
/**
@title EIP-6617 基于位的权限
@dev 参见 https://eips.ethereum.org/EIPS/eip-6617
*/
interface IEIP6617 {
/**
当权限被授予时必须触发。
@param _grantor 权限授予者
@param _permission 被授予的权限
@param _user 接收权限的用户
*/
event PermissionGranted(address indexed _grantor, uint256 indexed _permission, address indexed _user);
/**
当权限被撤销时必须触发。
@param _revoker 权限撤销者
@param _permission 被撤销的权限
@param _user 失去权限的用户
*/
event PermissionRevoked(address indexed _revoker, uint256 indexed _permission, address indexed _user);
/**
@notice 检查用户是否拥有权限
@param _user 需要检查权限的用户的地址
@param _requiredPermission 所需的权限
@return 如果 _permission 是 _requiredPermission 的超集,则返回 True,否则返回 False
*/
function hasPermission(address _user, uint256 _requiredPermission)
external
view
returns (bool);
/**
@notice 向用户添加权限
@param _user 将要添加权限的用户的地址
@param _permissionToAdd 将要添加的权限
@return 包含 _permissionToAdd 的新权限
*/
function grantPermission(address _user, uint256 _permissionToAdd)
external
returns (bool);
/**
@notice 撤销用户的权限
@param _user 将要撤销权限的用户的地址
@param _permissionToRevoke 将要撤销的权限
@return 不包含 _permissionToRevoke 的新权限
*/
function revokePermission(address _user, uint256 _permissionToRevoke)
external
returns (bool);
}
- 兼容的合约必须实现
IEIP6617
- 一个兼容的合约中的权限表示为一个
uint256
。一个权限必须只占用一个uint256
的一位,因此必须是 2 的幂。每个权限必须是唯一的,并且0
必须用于表示没有权限。
元数据接口
建议兼容的合约实现可选的扩展 IEIP6617Meta
。
-
它们应该为基本权限和主要组合定义名称和描述。
-
它们不应该为所有可能的权限子组合定义描述。
/**
* @dev 定义了 EIP6617 元数据的接口,可以不实现
*/
interface IEIP6617Meta {
/**
权限描述的结构体
@param _permission 权限
@param _name 权限的名称
@param _description 权限的描述
*/
struct PermissionDescription {
uint256 permission;
string name;
string description;
}
/**
当描述更新时必须触发。
@param _permission 权限
@param _name 权限的名称
@param _description 权限的描述
*/
event UpdatePermissionDescription(uint256 indexed _permission, string indexed _name, string indexed _description);
/**
返回给定 `_permission` 的描述。
@param _permission 权限
*/
function getPermissionDescription(uint256 _permission) external view returns (PermissionDescription memory description);
/**
如果描述被设置则返回 `true`,否则返回 `false`。它必须触发 `UpdatePermissionDescription` 事件。
@param _permission 权限
@param _name 权限的名称
@param _description 权限的描述
*/
function setPermissionDescription(uint256 _permission, string memory _name, string memory _description)
external
returns (bool success);
}
动机
目前,权限和访问控制是使用单个所有者 (ERC-173) 或使用 bytes32
角色 (ERC-5982) 来执行的。
然而,使用位运算和位掩码操作可以提高 gas 效率和灵活性。
Gas 成本效率
位运算非常便宜且快速。例如,对权限位掩码执行“与”位运算比调用任意数量的 LOAD
操作码便宜得多。
灵活性
有了 uint256
的 256 位,我们可以创建多达 256 种不同的权限,这将产生 $2^{256}$ 种独特的组合(又名角色)。
(角色是多个权限的组合)。 并非所有角色都必须预先定义。
由于权限被定义为无符号整数,我们可以使用二进制 OR 运算符来创建基于多个权限的新角色。
按重要性排序权限
我们可以使用最高有效位来表示最重要的权限,权限之间的比较可以很容易地完成,因为它们都是 uint256
。
关联含义
与通过 ERC-5982 管理的访问控制相比,此 EIP 不提供对权限或角色含义的直接和简单的理解。
为了解决这个问题,您可以设置元数据接口,该接口将名称和描述与每个权限或角色相关联。
参考实现
第一个实现可以在这里找到:
安全考虑
无安全考虑。
版权
版权及相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Chiro (@chiro-hiro), Victor Dusart (@vdusart), "ERC-6617: 基于位的权限 [DRAFT]," Ethereum Improvement Proposals, no. 6617, February 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6617.