diff --git a/EIPS/eip-6366.md b/EIPS/eip-6366.md index 855062464a8344..ffc37f7b53433e 100644 --- a/EIPS/eip-6366.md +++ b/EIPS/eip-6366.md @@ -1,10 +1,10 @@ --- eip: 6366 title: Permission Token -description: A new token that held the permission of an address in an ecosystem +description: A token that holds the permission of an address in an ecosystem author: Chiro (@chiro-hiro), Victor Dusart (@vdusart) discussions-to: https://ethereum-magicians.org/t/eip-6366-a-standard-for-permission-token/9105 -status: Stagnant +status: Review type: Standards Track category: ERC created: 2022-01-19 @@ -13,13 +13,13 @@ requires: 6617 ## Abstract -This EIP offers an alternative to Access Control Lists (ACLs) for granting authorization and enhancing security. An `uint256` is used to store permission of given address in a ecosystem. Each permission is represented by a single bit in `uint256` as described in [ERC-6617](./eip-6617.md). Bitwise operators and bitmasks are used to determine the access right which is much more efficient and flexible than `string` or `keccak256` comparison. +This EIP offers an alternative to Access Control Lists (ACLs) for granting authorization and enhancing security. A `uint256` is used to store permission of given address in a ecosystem. Each permission is represented by a single bit in a `uint256` as described in [ERC-6617](./eip-6617.md). Bitwise operators and bitmasks are used to determine the access right which is much more efficient and flexible than `string` or `keccak256` comparison. ## Motivation Special roles like `Owner`, `Operator`, `Manager`, `Validator` are common for many smart contracts because permissioned addresses are used to administer and manage them. It is difficult to audit and maintain these system since these permissions are not managed in a single smart contract. -Since permission and role are reflected by the permission token balance of the relevant account in the given ecosystem, cross-interactivity between many ecosystems will be made simpler. +Since permissions and roles are reflected by the permission token balance of the relevant account in the given ecosystem, cross-interactivity between many ecosystems will be made simpler. ## Specification @@ -65,7 +65,7 @@ interface IEIP6366Core { * Allows `_delegatee` to act for the permission owner's behalf, up to the `_permission`. * If this function is called again it overwrites the current granted with `_permission`. * `approve()` method SHOULD `revert` if granting `_permission` permission is not - * a subset of all available permission of permission owner. + * a subset of all available permissions of permission owner. * @param _delegatee Delegatee * @param _permission Subset permission of permission owner */ @@ -103,67 +103,15 @@ interface IEIP6366Core { ### Metadata Interface -It is RECOMMENDED for compliant contracts to implement the optional extension `IEIP6366Meta`. +It is RECOMMENDED for compliant contracts to implement the optional extension `IEIP6617Meta`. SHOULD define a description for the base permissions and main combinaison. SHOULD NOT define a description for every subcombinaison of permissions possible. -```solidity -interface IEIP6366Meta { - /** - * Structure of permission description - * @param _permission Permission - * @param _name Name of the permission - * @param _description Description of the permission - */ - struct PermissionDescription { - uint256 permission; - string name; - string description; - } - - /** - * MUST trigger when the description is updated. - * @param _permission Permission - * @param _name Name of the permission - * @param _description Description of the permission - */ - event UpdatePermissionDescription(uint256 indexed _permission, string indexed _name, string indexed _description); - - /** - * Returns the name of the token - e.g. `"OpenPermissionToken"`. - */ - function name() external view returns (string memory); - - /** - * Returns the symbol of the token. E.g. `"OPT"`. - */ - function symbol() external view returns (string memory); - - /** - * Returns the description of a given `_permission`. - * @param _permission Permission - */ - function getDescription(uint256 _permission) external view returns (PermissionDescription memory description); - - /** - * Return `true` if the description was set otherwise return `false`. It MUST emit `UpdatePermissionDescription` event. - * @param _permission Permission - * @param _name Name of the permission - * @param _description Description of the permission - */ - function setDescription( - uint256 _permission, - string memory _name, - string memory _description - ) external returns (bool success); -} -``` - ### Error Interface -SHOULD NOT expected `IEIP6366Error` interface was implemented. +Compatible tokens MAY implement `IEIP6366Error` as defined below: ```solidity interface IEIP6366Error { @@ -193,7 +141,6 @@ Needs discussion. First implementation could be found here: - [ERC-6366 Core implementation](../assets/eip-6366/contracts/EIP6366Core.sol) -- [ERC-6366 Meta implementation](../assets/eip-6366/contracts/EIP6366Meta.sol) ## Security Considerations diff --git a/assets/eip-6366/contracts/EIP6366Meta.sol b/assets/eip-6366/contracts/EIP6366Meta.sol deleted file mode 100644 index d8c98ea4237cbb..00000000000000 --- a/assets/eip-6366/contracts/EIP6366Meta.sol +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.7; -import "./interfaces/IEIP6366Meta.sol"; -import "./interfaces/IEIP6366Error.sol"; - -/** - * @dev Implement the metadata of EIP-6366 - */ -contract EIP6366Meta is IEIP6366Meta { - /** - * @dev Name of permission token - */ - string private tname; - - /** - * @dev Symbol of permission token - */ - string private tsymbol; - - /** - * @dev Mapping permission value to permission's name - */ - mapping(uint256 => string) private permissionNames; - - /** - * @dev Mapping permission value to permission's description - */ - mapping(uint256 => string) private permissionDescriptions; - - /** - * @dev Constructor of permission token - */ - constructor(string memory _name, string memory _symbol) { - tname = _name; - tsymbol = _symbol; - } - - /** - * Get the name of permission token - */ - function name() external view virtual override returns (string memory) { - return tname; - } - - /** - * Get symbol of permission token - */ - function symbol() external view virtual override returns (string memory) { - return tsymbol; - } - - /** - * @dev Get permission's description by value - * @param _permission Value of the permission - */ - function getDescription( - uint256 _permission - ) - external - view - virtual - override - returns (PermissionDescription memory description) - { - return _getDescription(_permission); - } - - /** - * @dev Set the description of given permission - * @param _permission Value of the permission - * @param _name Name of the permission - * @param _description Description of the permission - */ - function setDescription( - uint256 _permission, - string memory _name, - string memory _description - ) external virtual override returns (bool) { - // This method is empty, you should override this in your implement - } - - function _getDescription( - uint256 _permission - ) internal view returns (PermissionDescription memory description) { - return - PermissionDescription({ - permission: _permission, - name: permissionNames[_permission], - description: permissionDescriptions[_permission] - }); - } - - function _setDescription( - uint256 _permission, - string memory _name, - string memory _description - ) internal returns (bool success) { - permissionNames[_permission] = _name; - permissionDescriptions[_permission] = _description; - return true; - } -} diff --git a/assets/eip-6366/contracts/interfaces/IEIP6366Meta.sol b/assets/eip-6366/contracts/interfaces/IEIP6366Meta.sol deleted file mode 100644 index 3adbf48e93dce1..00000000000000 --- a/assets/eip-6366/contracts/interfaces/IEIP6366Meta.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.7; - -/** - * @dev Defined the interface of the metadata of EIP6366, SHOULD NOT expect to be implemented - */ -interface IEIP6366Meta { - struct PermissionDescription { - uint256 permission; - string name; - string description; - } - - event UpdatePermissionDescription( - uint256 indexed _permission, - string indexed _name, - string indexed _description - ); - - function name() external view returns (string memory); - - function symbol() external view returns (string memory); - - function getDescription( - uint256 _permission - ) external view returns (PermissionDescription memory description); - - function setDescription( - uint256 _permission, - string memory _name, - string memory _description - ) external returns (bool success); -} diff --git a/assets/eip-6366/example/AEcosystem.sol b/assets/eip-6366/example/AEcosystem.sol deleted file mode 100644 index 5f662b0ce4472c..00000000000000 --- a/assets/eip-6366/example/AEcosystem.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.7; -import "./APermissioned.sol"; - -contract AEcosystem is APermissioned { - constructor(address _permsionToken) APermissioned(_permsionToken) { - // Constructor code - } - - function createProposal( - address _permissionOwner - ) external notBlacklisted allow(_permissionOwner, PERMISSION_CREATE) { - // Only allow owner or delegatee with PERMISSION_CREATE - } - - function vote() external notBlacklisted allowOwner(PERMISSION_VOTE) { - // Only allow permission owner with PERMISSION_VOTE - } - - function execute() external notBlacklisted allowOwner(ROLE_OPERATOR) { - // Only allow permission owner with ROLE_OPERATOR - } - - function stopProposal() external notBlacklisted allowOwner(ROLE_ADMIN) { - // Only allow permission owner with ROLE_ADMIN - } - - function register() external notBlacklisted { - // Permission Token is not only provide the ability to whitelist an address - // but also provide the ability to blacklist an address. - // In this case, blacklisted address wont able to register - } -} diff --git a/assets/eip-6366/example/APermissionToken.sol b/assets/eip-6366/example/APermissionToken.sol deleted file mode 100644 index c6b09c3c950d72..00000000000000 --- a/assets/eip-6366/example/APermissionToken.sol +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.7; -import "../contracts/EIP6366Core.sol"; -import "../contracts/EIP6366Meta.sol"; -import "../contracts/interfaces/IEIP6366Error.sol"; - -/** - * @dev An example for mintable permission token - */ -contract APermissionToken is EIP6366Core, EIP6366Meta { - /** - * @dev Blacklisted - */ - uint256 private constant PERMISSION_DENIED = 2 ** 0; - - /** - * @dev Permission to vote - */ - uint256 internal constant PERMISSION_VOTE = 2 ** 1; - - /** - * @dev Permission to transfer permission token - */ - uint256 internal constant PERMISSION_TRANSFER = 2 ** 2; - - /** - * @dev Permission to execute - */ - uint256 internal constant PERMISSION_EXECUTE = 2 ** 3; - - /** - * @dev Permission to create - */ - uint256 internal constant PERMISSION_CREATE = 2 ** 4; - - /** - * @dev Admin role - */ - uint256 internal constant ROLE_ADMIN = - PERMISSION_VOTE | PERMISSION_EXECUTE | PERMISSION_CREATE; - - /** - * @dev Operator role - */ - uint256 internal constant ROLE_OPERATOR = - PERMISSION_EXECUTE | PERMISSION_VOTE; - - /** - * @dev Permission to manage permission token - */ - uint256 private constant PERMISSION_MASTER = 2 ** 255; - - /** - * @dev Checking for require permissioned from the actor - */ - modifier allow(uint256 required) { - address owner = msg.sender; - if (!_permissionRequire(_permissionOf(owner), required)) { - revert IEIP6366Error.AccessDenied(owner, owner, required); - } - _; - } - - /** - * @dev Deny blacklisted address - */ - modifier notBlacklisted() { - if (_permissionRequire(_permissionOf(msg.sender), PERMISSION_DENIED)) { - revert IEIP6366Error.AccessDenied( - msg.sender, - msg.sender, - PERMISSION_DENIED - ); - } - _; - } - - /** - * @dev Construct ERC-6366 - */ - constructor() EIP6366Meta("Ecosystem A Permission Token", "APT") { - _setDescription( - PERMISSION_DENIED, - "PERMISSION_DENIED", - "Blacklisted address" - ); - _setDescription( - PERMISSION_VOTE, - "PERMISSION_VOTE", - "Permission owner can vote" - ); - _setDescription( - PERMISSION_TRANSFER, - "PERMISSION_TRANSFER", - "Permission owner can transfer" - ); - _setDescription( - PERMISSION_EXECUTE, - "PERMISSION_EXECUTE", - "Permission owner can execute" - ); - _setDescription( - PERMISSION_CREATE, - "PERMISSION_CREATE", - "Permission owner can create" - ); - _setDescription( - PERMISSION_MASTER, - "PERMISSION_MASTER", - "Permission owner can mint and update description" - ); - _setDescription( - ROLE_ADMIN, - "ROLE_ADMIN", - "Admin role can vote, execute and create" - ); - _setDescription( - ROLE_OPERATOR, - "ROLE_OPERATOR", - "Operator role can execute and vote" - ); - - // Assign master permission to deployer - _mint(msg.sender, PERMISSION_MASTER); - } - - /** - * @dev Mint a set of permission to a given target address - */ - function mint( - address _to, - uint256 _permission - ) external allow(PERMISSION_MASTER) returns (bool result) { - return _mint(_to, _permission); - } - - /** - * @dev Burn all permission of a given target address - */ - function burn( - address _to - ) external allow(PERMISSION_MASTER) returns (bool result) { - return _burn(_to); - } - - /** - * @dev Set the description of given index - * @param _index Description's index - * @param _name Name of the permission - * @param _description Description of the permission - */ - function setDescription( - uint256 _index, - string memory _name, - string memory _description - ) external virtual override allow(PERMISSION_MASTER) returns (bool) { - // This method is empty, you should override this in your implement - } - - /** - * @dev Transfer a subset of permission to a given target address - */ - function transfer( - address _to, - uint256 _permission - ) - external - override - allow(PERMISSION_TRANSFER) - notBlacklisted - returns (bool result) - { - return _transfer(_to, _permission); - } -} diff --git a/assets/eip-6366/example/APermissioned.sol b/assets/eip-6366/example/APermissioned.sol deleted file mode 100644 index ee05d69f4d8e63..00000000000000 --- a/assets/eip-6366/example/APermissioned.sol +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 -pragma solidity ^0.8.7; -import "../contracts/interfaces/IEIP6366Core.sol"; -import "../contracts/interfaces/IEIP6366Error.sol"; - -/** - * @dev Centralized definition of all possible permissions and roles - */ -contract APermissioned { - IEIP6366Core private opt; - - /** - * @dev No permission - */ - uint256 internal constant PERMISSION_NONE = 0; - - /** - * @dev Blacklisted - */ - uint256 internal constant PERMISSION_DENIED = 2 ** 0; - - /** - * @dev Permission to vote - */ - uint256 internal constant PERMISSION_VOTE = 2 ** 1; - - /** - * @dev Permission to transfer permission token - */ - uint256 internal constant PERMISSION_TRANSFER = 2 ** 2; - - /** - * @dev Permission to execute - */ - uint256 internal constant PERMISSION_EXECUTE = 2 ** 3; - - /** - * @dev Permission to create - */ - uint256 internal constant PERMISSION_CREATE = 2 ** 4; - - /** - * @dev Admin role - */ - uint256 internal constant ROLE_ADMIN = - PERMISSION_VOTE | PERMISSION_EXECUTE | PERMISSION_CREATE; - - /** - * @dev Operator role - */ - uint256 internal constant ROLE_OPERATOR = - PERMISSION_EXECUTE | PERMISSION_VOTE; - - /** - * @dev Allow the actor who has required permission - */ - modifier allowOwner(uint256 _required) { - if (!opt.permissionRequire(opt.permissionOf(msg.sender), _required)) { - revert IEIP6366Error.AccessDenied( - msg.sender, - msg.sender, - _required - ); - } - _; - } - - /** - * @dev Deny blacklisted address - */ - modifier notBlacklisted() { - if ( - opt.permissionRequire( - opt.permissionOf(msg.sender), - PERMISSION_DENIED - ) - ) { - revert IEIP6366Error.AccessDenied( - msg.sender, - msg.sender, - PERMISSION_DENIED - ); - } - _; - } - - /** - * @dev Allow permission owner or delegatee - */ - modifier allow(address _owner, uint256 _required) { - // The actor should be the permission owner or delegatee - if (!opt.hasPermission(_owner, msg.sender, _required)) { - revert IEIP6366Error.AccessDenied(_owner, msg.sender, _required); - } - _; - } - - /** - * @dev Constructor - */ - constructor(address _opt) { - opt = IEIP6366Core(_opt); - } -}