Browse Source

Rename AccessManager groups to roles (#4580)

Hadrien Croubois 2 years ago
parent
commit
d54f4ac4b7

+ 162 - 164
contracts/access/manager/AccessManager.sol

@@ -15,21 +15,21 @@ import {Time} from "../../utils/types/Time.sol";
  *
  * The smart contracts under the control of an AccessManager instance will have a set of "restricted" functions, and the
  * exact details of how access is restricted for each of those functions is configurable by the admins of the instance.
- * These restrictions are expressed in terms of "groups".
+ * These restrictions are expressed in terms of "roles".
  *
- * An AccessManager instance will define a set of groups. Accounts can be added into any number of these groups. Each of
+ * An AccessManager instance will define a set of roles. Accounts can be added into any number of these roles. Each of
  * them defines a role, and may confer access to some of the restricted functions in the system, as configured by admins
- * through the use of {setFunctionAllowedGroup}.
+ * through the use of {setFunctionAllowedRoles}.
  *
  * Note that a function in a target contract may become permissioned in this way only when: 1) said contract is
  * {AccessManaged} and is connected to this contract as its manager, and 2) said function is decorated with the
  * `restricted` modifier.
  *
- * There is a special group defined by default named "public" which all accounts automatically have.
+ * There is a special role defined by default named "public" which all accounts automatically have.
  *
- * Contracts where functions are mapped to groups are said to be in a "custom" mode, but contracts can also be
- * configured in two special modes: 1) the "open" mode, where all functions are allowed to the "public" group, and 2)
- * the "closed" mode, where no function is allowed to any group.
+ * Contracts where functions are mapped to roles are said to be in a "custom" mode, but contracts can also be
+ * configured in two special modes: 1) the "open" mode, where all functions are allowed to the "public" role, and 2)
+ * the "closed" mode, where no function is allowed to any role.
  *
  * Since all the permissions of the managed system can be modified by the admins of this instance, it is expected that
  * they will be highly secured (e.g., a multisig or a well-configured DAO).
@@ -52,27 +52,26 @@ contract AccessManager is Context, Multicall, IAccessManager {
     using Time for *;
 
     struct TargetConfig {
-        mapping(bytes4 selector => uint64 groupId) allowedGroups;
+        mapping(bytes4 selector => uint64 roleId) allowedRoles;
         Time.Delay adminDelay;
         bool closed;
     }
 
-    // Structure that stores the details for a group/account pair. This structure fits into a single slot.
+    // Structure that stores the details for a role/account pair. This structures fit into a single slot.
     struct Access {
-        // Timepoint at which the user gets the permission. If this is either 0, or in the future, the group permission
+        // Timepoint at which the user gets the permission. If this is either 0, or in the future, the role permission
         // is not available.
         uint48 since;
-        // delay for execution. Only applies to restricted() / execute() calls. This does not restrict access to
-        // functions that use the `onlyGroup` modifier.
+        // delay for execution. Only applies to restricted() / execute() calls.
         Time.Delay delay;
     }
 
-    // Structure that stores the details of a group, including:
-    // - the members of the group
-    // - the admin group (that can grant or revoke permissions)
-    // - the guardian group (that can cancel operations targeting functions that need this group
-    // - the grant delay
-    struct Group {
+    // Structure that stores the details of a role, including:
+    // - the members of the role
+    // - the admin role (that can grant or revoke permissions)
+    // - the guardian role (that can cancel operations targeting functions that need this role)
+    // - the grand delay
+    struct Role {
         mapping(address user => Access access) members;
         uint64 admin;
         uint64 guardian;
@@ -84,11 +83,11 @@ contract AccessManager is Context, Multicall, IAccessManager {
         uint32 nonce;
     }
 
-    uint64 public constant ADMIN_GROUP = type(uint64).min; // 0
-    uint64 public constant PUBLIC_GROUP = type(uint64).max; // 2**64-1
+    uint64 public constant ADMIN_ROLE = type(uint64).min; // 0
+    uint64 public constant PUBLIC_ROLE = type(uint64).max; // 2**64-1
 
     mapping(address target => TargetConfig mode) private _targets;
-    mapping(uint64 groupId => Group) private _groups;
+    mapping(uint64 roleId => Role) private _roles;
     mapping(bytes32 operationId => Schedule) private _schedules;
 
     // This should be transient storage when supported by the EVM.
@@ -109,7 +108,7 @@ contract AccessManager is Context, Multicall, IAccessManager {
         }
 
         // admin is active immediately and without any execution delay.
-        _grantGroup(ADMIN_GROUP, initialAdmin, 0, 0);
+        _grantRole(ADMIN_ROLE, initialAdmin, 0, 0);
     }
 
     // =================================================== GETTERS ====================================================
@@ -137,9 +136,9 @@ contract AccessManager is Context, Multicall, IAccessManager {
             // permissions. We verify that the call "identifier", which is set during {execute}, is correct.
             return (_executionId == _hashExecutionId(target, selector), 0);
         } else {
-            uint64 groupId = getTargetFunctionGroup(target, selector);
-            (bool inGroup, uint32 currentDelay) = hasGroup(groupId, caller);
-            return inGroup ? (currentDelay == 0, currentDelay) : (false, 0);
+            uint64 roleId = getTargetFunctionRole(target, selector);
+            (bool isMember, uint32 currentDelay) = hasRole(roleId, caller);
+            return isMember ? (currentDelay == 0, currentDelay) : (false, 0);
         }
     }
 
@@ -153,7 +152,7 @@ contract AccessManager is Context, Multicall, IAccessManager {
     /**
      * @dev Minimum setback for all delay updates, with the exception of execution delays, which
      * can be increased without setback (and in the event of an accidental increase can be reset
-     * via {revokeGroup}). Defaults to 5 days.
+     * via {revokeRole}). Defaults to 5 days.
      */
     function minSetback() public view virtual returns (uint32) {
         return 5 days;
@@ -167,11 +166,11 @@ contract AccessManager is Context, Multicall, IAccessManager {
     }
 
     /**
-     * @dev Get the permission level (group) required to call a function. This only applies for contract that are
+     * @dev Get the permission level (role) required to call a function. This only applies for contract that are
      * operating under the `Custom` mode.
      */
-    function getTargetFunctionGroup(address target, bytes4 selector) public view virtual returns (uint64) {
-        return _targets[target].allowedGroups[selector];
+    function getTargetFunctionRole(address target, bytes4 selector) public view virtual returns (uint64) {
+        return _targets[target].allowedRoles[selector];
     }
 
     function getTargetAdminDelay(address target) public view virtual returns (uint32) {
@@ -179,35 +178,35 @@ contract AccessManager is Context, Multicall, IAccessManager {
     }
 
     /**
-     * @dev Get the id of the group that acts as an admin for given group.
+     * @dev Get the id of the role that acts as an admin for given role.
      *
-     * The admin permission is required to grant the group, revoke the group and update the execution delay to execute
-     * an operation that is restricted to this group.
+     * The admin permission is required to grant the role, revoke the role and update the execution delay to execute
+     * an operation that is restricted to this role.
      */
-    function getGroupAdmin(uint64 groupId) public view virtual returns (uint64) {
-        return _groups[groupId].admin;
+    function getRoleAdmin(uint64 roleId) public view virtual returns (uint64) {
+        return _roles[roleId].admin;
     }
 
     /**
-     * @dev Get the group that acts as a guardian for a given group.
+     * @dev Get the role that acts as a guardian for a given role.
      *
-     * The guardian permission allows canceling operations that have been scheduled under the group.
+     * The guardian permission allows canceling operations that have been scheduled under the role.
      */
-    function getGroupGuardian(uint64 groupId) public view virtual returns (uint64) {
-        return _groups[groupId].guardian;
+    function getRoleGuardian(uint64 roleId) public view virtual returns (uint64) {
+        return _roles[roleId].guardian;
     }
 
     /**
-     * @dev Get the group current grant delay, that value may change at any point, without an event emitted, following
+     * @dev Get the role current grant delay, that value may change at any point, without an event emitted, following
      * a call to {setGrantDelay}. Changes to this value, including effect timepoint are notified by the
-     * {GroupGrantDelayChanged} event.
+     * {RoleGrantDelayChanged} event.
      */
-    function getGroupGrantDelay(uint64 groupId) public view virtual returns (uint32) {
-        return _groups[groupId].grantDelay.get();
+    function getRoleGrantDelay(uint64 roleId) public view virtual returns (uint32) {
+        return _roles[roleId].grantDelay.get();
     }
 
     /**
-     * @dev Get the access details for a given account in a given group. These details include the timepoint at which
+     * @dev Get the access details for a given account in a given role. These details include the timepoint at which
      * membership becomes active, and the delay applied to all operation by this user that requires this permission
      * level.
      *
@@ -217,8 +216,8 @@ contract AccessManager is Context, Multicall, IAccessManager {
      * [2] Pending execution delay for the account.
      * [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled.
      */
-    function getAccess(uint64 groupId, address account) public view virtual returns (uint48, uint32, uint32, uint48) {
-        Access storage access = _groups[groupId].members[account];
+    function getAccess(uint64 roleId, address account) public view virtual returns (uint48, uint32, uint32, uint48) {
+        Access storage access = _roles[roleId].members[account];
 
         uint48 since = access.since;
         (uint32 currentDelay, uint32 pendingDelay, uint48 effect) = access.delay.getFull();
@@ -227,255 +226,254 @@ contract AccessManager is Context, Multicall, IAccessManager {
     }
 
     /**
-     * @dev Check if a given account currently had the permission level corresponding to a given group. Note that this
+     * @dev Check if a given account currently had the permission level corresponding to a given role. Note that this
      * permission might be associated with a delay. {getAccess} can provide more details.
      */
-    function hasGroup(uint64 groupId, address account) public view virtual returns (bool, uint32) {
-        if (groupId == PUBLIC_GROUP) {
+    function hasRole(uint64 roleId, address account) public view virtual returns (bool, uint32) {
+        if (roleId == PUBLIC_ROLE) {
             return (true, 0);
         } else {
-            (uint48 inGroupSince, uint32 currentDelay, , ) = getAccess(groupId, account);
-            return (inGroupSince != 0 && inGroupSince <= Time.timestamp(), currentDelay);
+            (uint48 hasRoleSince, uint32 currentDelay, , ) = getAccess(roleId, account);
+            return (hasRoleSince != 0 && hasRoleSince <= Time.timestamp(), currentDelay);
         }
     }
 
-    // =============================================== GROUP MANAGEMENT ===============================================
+    // =============================================== ROLE MANAGEMENT ===============================================
     /**
-     * @dev Give a label to a group, for improved group discoverabily by UIs.
+     * @dev Give a label to a role, for improved role discoverabily by UIs.
      *
-     * Emits a {GroupLabel} event.
+     * Emits a {RoleLabel} event.
      */
-    function labelGroup(uint64 groupId, string calldata label) public virtual onlyAuthorized {
-        if (groupId == ADMIN_GROUP || groupId == PUBLIC_GROUP) {
-            revert AccessManagerLockedGroup(groupId);
+    function labelRole(uint64 roleId, string calldata label) public virtual onlyAuthorized {
+        if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
+            revert AccessManagerLockedRole(roleId);
         }
-        emit GroupLabel(groupId, label);
+        emit RoleLabel(roleId, label);
     }
 
     /**
-     * @dev Add `account` to `groupId`, or change its execution delay.
+     * @dev Add `account` to `roleId`, or change its execution delay.
      *
-     * This gives the account the authorization to call any function that is restricted to this group. An optional
+     * This gives the account the authorization to call any function that is restricted to this role. An optional
      * execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation
-     * that is restricted to members this group. The user will only be able to execute the operation after the delay has
+     * that is restricted to members this role. The user will only be able to execute the operation after the delay has
      * passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}).
      *
-     * If the account has already been granted this group, the execution delay will be updated. This update is not
+     * If the account has already been granted this role, the execution delay will be updated. This update is not
      * immediate and follows the delay rules. For example, If a user currently has a delay of 3 hours, and this is
      * called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any
      * operation executed in the 3 hours that follows this update was indeed scheduled before this update.
      *
      * Requirements:
      *
-     * - the caller must be in the group's admins
+     * - the caller must be in the role's admins
      *
-     * Emits a {GroupGranted} event
+     * Emits a {RoleGranted} event
      */
-    function grantGroup(uint64 groupId, address account, uint32 executionDelay) public virtual onlyAuthorized {
-        _grantGroup(groupId, account, getGroupGrantDelay(groupId), executionDelay);
+    function grantRole(uint64 roleId, address account, uint32 executionDelay) public virtual onlyAuthorized {
+        _grantRole(roleId, account, getRoleGrantDelay(roleId), executionDelay);
     }
 
     /**
-     * @dev Remove an account for a group, with immediate effect. If the sender is not in the group, this call has no
+     * @dev Remove an account for a role, with immediate effect. If the sender is not in the role, this call has no
      * effect.
      *
      * Requirements:
      *
-     * - the caller must be in the group's admins
+     * - the caller must be in the role's admins
      *
-     * Emits a {GroupRevoked} event
+     * Emits a {RoleRevoked} event
      */
-    function revokeGroup(uint64 groupId, address account) public virtual onlyAuthorized {
-        _revokeGroup(groupId, account);
+    function revokeRole(uint64 roleId, address account) public virtual onlyAuthorized {
+        _revokeRole(roleId, account);
     }
 
     /**
-     * @dev Renounce group permissions for the calling account, with immediate effect. If the sender is not in
-     * the group, this call has no effect.
+     * @dev Renounce role permissions for the calling account, with immediate effect. If the sender is not in
+     * the role, this call has no effect.
      *
      * Requirements:
      *
      * - the caller must be `callerConfirmation`.
      *
-     * Emits a {GroupRevoked} event
+     * Emits a {RoleRevoked} event
      */
-    function renounceGroup(uint64 groupId, address callerConfirmation) public virtual {
+    function renounceRole(uint64 roleId, address callerConfirmation) public virtual {
         if (callerConfirmation != _msgSender()) {
             revert AccessManagerBadConfirmation();
         }
-        _revokeGroup(groupId, callerConfirmation);
+        _revokeRole(roleId, callerConfirmation);
     }
 
     /**
-     * @dev Change admin group for a given group.
+     * @dev Change admin role for a given role.
      *
      * Requirements:
      *
      * - the caller must be a global admin
      *
-     * Emits a {GroupAdminChanged} event
+     * Emits a {RoleAdminChanged} event
      */
-    function setGroupAdmin(uint64 groupId, uint64 admin) public virtual onlyAuthorized {
-        _setGroupAdmin(groupId, admin);
+    function setRoleAdmin(uint64 roleId, uint64 admin) public virtual onlyAuthorized {
+        _setRoleAdmin(roleId, admin);
     }
 
     /**
-     * @dev Change guardian group for a given group.
+     * @dev Change guardian role for a given role.
      *
      * Requirements:
      *
      * - the caller must be a global admin
      *
-     * Emits a {GroupGuardianChanged} event
+     * Emits a {RoleGuardianChanged} event
      */
-    function setGroupGuardian(uint64 groupId, uint64 guardian) public virtual onlyAuthorized {
-        _setGroupGuardian(groupId, guardian);
+    function setRoleGuardian(uint64 roleId, uint64 guardian) public virtual onlyAuthorized {
+        _setRoleGuardian(roleId, guardian);
     }
 
     /**
-     * @dev Update the delay for granting a `groupId`.
+     * @dev Update the delay for granting a `roleId`.
      *
      * Requirements:
      *
      * - the caller must be a global admin
      *
-     * Emits a {GroupGrantDelayChanged} event
+     * Emits a {RoleGrantDelayChanged} event
      */
-    function setGrantDelay(uint64 groupId, uint32 newDelay) public virtual onlyAuthorized {
-        _setGrantDelay(groupId, newDelay);
+    function setGrantDelay(uint64 roleId, uint32 newDelay) public virtual onlyAuthorized {
+        _setGrantDelay(roleId, newDelay);
     }
 
     /**
-     * @dev Internal version of {grantGroup} without access control. Returns true if the group was newly granted.
+     * @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted.
      *
-     * Emits a {GroupGranted} event
+     * Emits a {RoleGranted} event
      */
-    function _grantGroup(
-        uint64 groupId,
+    function _grantRole(
+        uint64 roleId,
         address account,
         uint32 grantDelay,
         uint32 executionDelay
     ) internal virtual returns (bool) {
-        if (groupId == PUBLIC_GROUP) {
-            revert AccessManagerLockedGroup(groupId);
+        if (roleId == PUBLIC_ROLE) {
+            revert AccessManagerLockedRole(roleId);
         }
 
-        bool inGroup = _groups[groupId].members[account].since != 0;
-
+        bool newMember = _roles[roleId].members[account].since == 0;
         uint48 since;
 
-        if (inGroup) {
+        if (newMember) {
+            since = Time.timestamp() + grantDelay;
+            _roles[roleId].members[account] = Access({since: since, delay: executionDelay.toDelay()});
+        } else {
             // No setback here. Value can be reset by doing revoke + grant, effectively allowing the admin to perform
-            // any change to the execution delay within the duration of the group admin delay.
-            (_groups[groupId].members[account].delay, since) = _groups[groupId].members[account].delay.withUpdate(
+            // any change to the execution delay within the duration of the role admin delay.
+            (_roles[roleId].members[account].delay, since) = _roles[roleId].members[account].delay.withUpdate(
                 executionDelay,
                 0
             );
-        } else {
-            since = Time.timestamp() + grantDelay;
-            _groups[groupId].members[account] = Access({since: since, delay: executionDelay.toDelay()});
         }
 
-        emit GroupGranted(groupId, account, executionDelay, since, !inGroup);
-        return !inGroup;
+        emit RoleGranted(roleId, account, executionDelay, since, newMember);
+        return newMember;
     }
 
     /**
-     * @dev Internal version of {revokeGroup} without access control. This logic is also used by {renounceGroup}.
-     * Returns true if the group was previously granted.
+     * @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}.
+     * Returns true if the role was previously granted.
      *
-     * Emits a {GroupRevoked} event
+     * Emits a {RoleRevoked} event
      */
-    function _revokeGroup(uint64 groupId, address account) internal virtual returns (bool) {
-        if (groupId == PUBLIC_GROUP) {
-            revert AccessManagerLockedGroup(groupId);
+    function _revokeRole(uint64 roleId, address account) internal virtual returns (bool) {
+        if (roleId == PUBLIC_ROLE) {
+            revert AccessManagerLockedRole(roleId);
         }
 
-        if (_groups[groupId].members[account].since == 0) {
+        if (_roles[roleId].members[account].since == 0) {
             return false;
         }
 
-        delete _groups[groupId].members[account];
+        delete _roles[roleId].members[account];
 
-        emit GroupRevoked(groupId, account);
+        emit RoleRevoked(roleId, account);
         return true;
     }
 
     /**
-     * @dev Internal version of {setGroupAdmin} without access control.
+     * @dev Internal version of {setRoleAdmin} without access control.
      *
-     * Emits a {GroupAdminChanged} event
+     * Emits a {RoleAdminChanged} event
      */
-    function _setGroupAdmin(uint64 groupId, uint64 admin) internal virtual {
-        if (groupId == ADMIN_GROUP || groupId == PUBLIC_GROUP) {
-            revert AccessManagerLockedGroup(groupId);
+    function _setRoleAdmin(uint64 roleId, uint64 admin) internal virtual {
+        if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
+            revert AccessManagerLockedRole(roleId);
         }
 
-        _groups[groupId].admin = admin;
+        _roles[roleId].admin = admin;
 
-        emit GroupAdminChanged(groupId, admin);
+        emit RoleAdminChanged(roleId, admin);
     }
 
     /**
-     * @dev Internal version of {setGroupGuardian} without access control.
+     * @dev Internal version of {setRoleGuardian} without access control.
      *
-     * Emits a {GroupGuardianChanged} event
+     * Emits a {RoleGuardianChanged} event
      */
-    function _setGroupGuardian(uint64 groupId, uint64 guardian) internal virtual {
-        if (groupId == ADMIN_GROUP || groupId == PUBLIC_GROUP) {
-            revert AccessManagerLockedGroup(groupId);
+    function _setRoleGuardian(uint64 roleId, uint64 guardian) internal virtual {
+        if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
+            revert AccessManagerLockedRole(roleId);
         }
 
-        _groups[groupId].guardian = guardian;
+        _roles[roleId].guardian = guardian;
 
-        emit GroupGuardianChanged(groupId, guardian);
+        emit RoleGuardianChanged(roleId, guardian);
     }
 
     /**
      * @dev Internal version of {setGrantDelay} without access control.
      *
-     * Emits a {GroupGrantDelayChanged} event
+     * Emits a {RoleGrantDelayChanged} event
      */
-    function _setGrantDelay(uint64 groupId, uint32 newDelay) internal virtual {
-        if (groupId == PUBLIC_GROUP) {
-            revert AccessManagerLockedGroup(groupId);
+    function _setGrantDelay(uint64 roleId, uint32 newDelay) internal virtual {
+        if (roleId == PUBLIC_ROLE) {
+            revert AccessManagerLockedRole(roleId);
         }
 
         uint48 effect;
-        (_groups[groupId].grantDelay, effect) = _groups[groupId].grantDelay.withUpdate(newDelay, minSetback());
+        (_roles[roleId].grantDelay, effect) = _roles[roleId].grantDelay.withUpdate(newDelay, minSetback());
 
-        emit GroupGrantDelayChanged(groupId, newDelay, effect);
+        emit RoleGrantDelayChanged(roleId, newDelay, effect);
     }
 
     // ============================================= FUNCTION MANAGEMENT ==============================================
     /**
-     * @dev Set the level of permission (`group`) required to call functions identified by the `selectors` in the
+     * @dev Set the level of permission (`role`) required to call functions identified by the `selectors` in the
      * `target` contract.
      *
      * Requirements:
      *
      * - the caller must be a global admin
      *
-     * Emits a {FunctionAllowedGroupUpdated} event per selector
+     * Emits a {FunctionAllowedRoleUpdated} event per selector
      */
-    function setTargetFunctionGroup(
+    function setTargetFunctionRole(
         address target,
         bytes4[] calldata selectors,
-        uint64 groupId
+        uint64 roleId
     ) public virtual onlyAuthorized {
         for (uint256 i = 0; i < selectors.length; ++i) {
-            _setTargetFunctionGroup(target, selectors[i], groupId);
+            _setTargetFunctionRole(target, selectors[i], roleId);
         }
     }
 
     /**
-     * @dev Internal version of {setFunctionAllowedGroup} without access control.
+     * @dev Internal version of {setFunctionAllowedRole} without access control.
      *
-     * Emits a {FunctionAllowedGroupUpdated} event
+     * Emits a {FunctionAllowedRoleUpdated} event
      */
-    function _setTargetFunctionGroup(address target, bytes4 selector, uint64 groupId) internal virtual {
-        _targets[target].allowedGroups[selector] = groupId;
-        emit TargetFunctionGroupUpdated(target, selector, groupId);
+    function _setTargetFunctionRole(address target, bytes4 selector, uint64 roleId) internal virtual {
+        _targets[target].allowedRoles[selector] = roleId;
+        emit TargetFunctionRoleUpdated(target, selector, roleId);
     }
 
     /**
@@ -485,7 +483,7 @@ contract AccessManager is Context, Multicall, IAccessManager {
      *
      * - the caller must be a global admin
      *
-     * Emits a {FunctionAllowedGroupUpdated} event per selector
+     * Emits a {FunctionAllowedRoleUpdated} event per selector
      */
     function setTargetAdminDelay(address target, uint32 newDelay) public virtual onlyAuthorized {
         _setTargetAdminDelay(target, newDelay);
@@ -702,9 +700,9 @@ contract AccessManager is Context, Multicall, IAccessManager {
         if (_schedules[operationId].timepoint == 0) {
             revert AccessManagerNotScheduled(operationId);
         } else if (caller != msgsender) {
-            // calls can only be canceled by the account that scheduled them, a global admin, or by a guardian of the required group.
-            (bool isAdmin, ) = hasGroup(ADMIN_GROUP, msgsender);
-            (bool isGuardian, ) = hasGroup(getGroupGuardian(getTargetFunctionGroup(target, selector)), msgsender);
+            // calls can only be canceled by the account that scheduled them, a global admin, or by a guardian of the required role.
+            (bool isAdmin, ) = hasRole(ADMIN_ROLE, msgsender);
+            (bool isGuardian, ) = hasRole(getRoleGuardian(getTargetFunctionRole(target, selector)), msgsender);
             if (!isAdmin && !isGuardian) {
                 revert AccessManagerUnauthorizedCancel(msgsender, caller, target, selector);
             }
@@ -752,8 +750,8 @@ contract AccessManager is Context, Multicall, IAccessManager {
         (bool immediate, uint32 delay) = _canCallExtended(caller, address(this), _msgData());
         if (!immediate) {
             if (delay == 0) {
-                (, uint64 requiredGroup, ) = _getAdminRestrictions(_msgData());
-                revert AccessManagerUnauthorizedAccount(caller, requiredGroup);
+                (, uint64 requiredRole, ) = _getAdminRestrictions(_msgData());
+                revert AccessManagerUnauthorizedAccount(caller, requiredRole);
             } else {
                 _consumeScheduledOp(_hashOperation(caller, address(this), _msgData()));
             }
@@ -765,7 +763,7 @@ contract AccessManager is Context, Multicall, IAccessManager {
      *
      * Returns:
      * - bool restricted: does this data match a restricted operation
-     * - uint64: which group is this operation restricted to
+     * - uint64: which role is this operation restricted to
      * - uint32: minimum delay to enforce for that operation (on top of the admin's execution delay)
      */
     function _getAdminRestrictions(bytes calldata data) private view returns (bool, uint64, uint32) {
@@ -777,33 +775,33 @@ contract AccessManager is Context, Multicall, IAccessManager {
 
         // Restricted to ADMIN with no delay beside any execution delay the caller may have
         if (
-            selector == this.labelGroup.selector ||
-            selector == this.setGroupAdmin.selector ||
-            selector == this.setGroupGuardian.selector ||
+            selector == this.labelRole.selector ||
+            selector == this.setRoleAdmin.selector ||
+            selector == this.setRoleGuardian.selector ||
             selector == this.setGrantDelay.selector ||
             selector == this.setTargetAdminDelay.selector
         ) {
-            return (true, ADMIN_GROUP, 0);
+            return (true, ADMIN_ROLE, 0);
         }
 
         // Restricted to ADMIN with the admin delay corresponding to the target
         if (
             selector == this.updateAuthority.selector ||
             selector == this.setTargetClosed.selector ||
-            selector == this.setTargetFunctionGroup.selector
+            selector == this.setTargetFunctionRole.selector
         ) {
             // First argument is a target.
             address target = abi.decode(data[0x04:0x24], (address));
             uint32 delay = getTargetAdminDelay(target);
-            return (true, ADMIN_GROUP, delay);
+            return (true, ADMIN_ROLE, delay);
         }
 
-        // Restricted to that group's admin with no delay beside any execution delay the caller may have.
-        if (selector == this.grantGroup.selector || selector == this.revokeGroup.selector) {
-            // First argument is a groupId.
-            uint64 groupId = abi.decode(data[0x04:0x24], (uint64));
-            uint64 groupAdminId = getGroupAdmin(groupId);
-            return (true, groupAdminId, 0);
+        // Restricted to that role's admin with no delay beside any execution delay the caller may have.
+        if (selector == this.grantRole.selector || selector == this.revokeRole.selector) {
+            // First argument is a roleId.
+            uint64 roleId = abi.decode(data[0x04:0x24], (uint64));
+            uint64 roleAdminId = getRoleAdmin(roleId);
+            return (true, roleAdminId, 0);
         }
 
         return (false, 0, 0);
@@ -815,13 +813,13 @@ contract AccessManager is Context, Multicall, IAccessManager {
      */
     function _canCallExtended(address caller, address target, bytes calldata data) private view returns (bool, uint32) {
         if (target == address(this)) {
-            (bool enabled, uint64 groupId, uint32 operationDelay) = _getAdminRestrictions(data);
+            (bool enabled, uint64 roleId, uint32 operationDelay) = _getAdminRestrictions(data);
             if (!enabled) {
                 return (false, 0);
             }
 
-            (bool inGroup, uint32 executionDelay) = hasGroup(groupId, caller);
-            if (!inGroup) {
+            (bool inRole, uint32 executionDelay) = hasRole(roleId, caller);
+            if (!inRole) {
                 return (false, 0);
             }
 

+ 23 - 24
contracts/access/manager/IAccessManager.sol

@@ -28,15 +28,14 @@ interface IAccessManager {
      */
     event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce);
 
-    event GroupLabel(uint64 indexed groupId, string label);
-    event GroupGranted(uint64 indexed groupId, address indexed account, uint32 delay, uint48 since, bool newMember);
-    event GroupRevoked(uint64 indexed groupId, address indexed account);
-    event GroupAdminChanged(uint64 indexed groupId, uint64 indexed admin);
-    event GroupGuardianChanged(uint64 indexed groupId, uint64 indexed guardian);
-    event GroupGrantDelayChanged(uint64 indexed groupId, uint32 delay, uint48 since);
-
+    event RoleLabel(uint64 indexed roleId, string label);
+    event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember);
+    event RoleRevoked(uint64 indexed roleId, address indexed account);
+    event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);
+    event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian);
+    event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since);
     event TargetClosed(address indexed target, bool closed);
-    event TargetFunctionGroupUpdated(address indexed target, bytes4 selector, uint64 indexed groupId);
+    event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId);
     event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since);
 
     error AccessManagerAlreadyScheduled(bytes32 operationId);
@@ -44,9 +43,9 @@ interface IAccessManager {
     error AccessManagerNotReady(bytes32 operationId);
     error AccessManagerExpired(bytes32 operationId);
     error AccessManagerLockedAccount(address account);
-    error AccessManagerLockedGroup(uint64 groupId);
+    error AccessManagerLockedRole(uint64 roleId);
     error AccessManagerBadConfirmation();
-    error AccessManagerUnauthorizedAccount(address msgsender, uint64 groupId);
+    error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId);
     error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector);
     error AccessManagerUnauthorizedConsume(address target);
     error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector);
@@ -62,35 +61,35 @@ interface IAccessManager {
 
     function isTargetClosed(address target) external view returns (bool);
 
-    function getTargetFunctionGroup(address target, bytes4 selector) external view returns (uint64);
+    function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64);
 
     function getTargetAdminDelay(address target) external view returns (uint32);
 
-    function getGroupAdmin(uint64 groupId) external view returns (uint64);
+    function getRoleAdmin(uint64 roleId) external view returns (uint64);
 
-    function getGroupGuardian(uint64 groupId) external view returns (uint64);
+    function getRoleGuardian(uint64 roleId) external view returns (uint64);
 
-    function getGroupGrantDelay(uint64 groupId) external view returns (uint32);
+    function getRoleGrantDelay(uint64 roleId) external view returns (uint32);
 
-    function getAccess(uint64 groupId, address account) external view returns (uint48, uint32, uint32, uint48);
+    function getAccess(uint64 roleId, address account) external view returns (uint48, uint32, uint32, uint48);
 
-    function hasGroup(uint64 groupId, address account) external view returns (bool, uint32);
+    function hasRole(uint64 roleId, address account) external view returns (bool, uint32);
 
-    function labelGroup(uint64 groupId, string calldata label) external;
+    function labelRole(uint64 roleId, string calldata label) external;
 
-    function grantGroup(uint64 groupId, address account, uint32 executionDelay) external;
+    function grantRole(uint64 roleId, address account, uint32 executionDelay) external;
 
-    function revokeGroup(uint64 groupId, address account) external;
+    function revokeRole(uint64 roleId, address account) external;
 
-    function renounceGroup(uint64 groupId, address callerConfirmation) external;
+    function renounceRole(uint64 roleId, address callerConfirmation) external;
 
-    function setGroupAdmin(uint64 groupId, uint64 admin) external;
+    function setRoleAdmin(uint64 roleId, uint64 admin) external;
 
-    function setGroupGuardian(uint64 groupId, uint64 guardian) external;
+    function setRoleGuardian(uint64 roleId, uint64 guardian) external;
 
-    function setGrantDelay(uint64 groupId, uint32 newDelay) external;
+    function setGrantDelay(uint64 roleId, uint32 newDelay) external;
 
-    function setTargetFunctionGroup(address target, bytes4[] calldata selectors, uint64 groupId) external;
+    function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external;
 
     function setTargetAdminDelay(address target, uint32 newDelay) external;
 

+ 252 - 264
test/access/manager/AccessManager.test.js

@@ -11,17 +11,16 @@ const Ownable = artifacts.require('$Ownable');
 
 const MAX_UINT64 = web3.utils.toBN((2n ** 64n - 1n).toString());
 
-const GROUPS = {
+const ROLES = {
   ADMIN: web3.utils.toBN(0),
   SOME_ADMIN: web3.utils.toBN(17),
   SOME: web3.utils.toBN(42),
   PUBLIC: MAX_UINT64,
 };
-Object.assign(GROUPS, Object.fromEntries(Object.entries(GROUPS).map(([key, value]) => [value, key])));
+Object.assign(ROLES, Object.fromEntries(Object.entries(ROLES).map(([key, value]) => [value, key])));
 
 const executeDelay = web3.utils.toBN(10);
 const grantDelay = web3.utils.toBN(10);
-
 const MINSETBACK = time.duration.days(5);
 
 const formatAccess = access => [access[0], access[1].toString()];
@@ -32,11 +31,11 @@ contract('AccessManager', function (accounts) {
   beforeEach(async function () {
     this.manager = await AccessManager.new(admin);
 
-    // add member to group
-    await this.manager.$_setGroupAdmin(GROUPS.SOME, GROUPS.SOME_ADMIN);
-    await this.manager.$_setGroupGuardian(GROUPS.SOME, GROUPS.SOME_ADMIN);
-    await this.manager.$_grantGroup(GROUPS.SOME_ADMIN, manager, 0, 0);
-    await this.manager.$_grantGroup(GROUPS.SOME, member, 0, 0);
+    // add member to role
+    await this.manager.$_setRoleAdmin(ROLES.SOME, ROLES.SOME_ADMIN);
+    await this.manager.$_setRoleGuardian(ROLES.SOME, ROLES.SOME_ADMIN);
+    await this.manager.$_grantRole(ROLES.SOME_ADMIN, manager, 0, 0);
+    await this.manager.$_grantRole(ROLES.SOME, member, 0, 0);
   });
 
   it('rejects zero address for initialAdmin', async function () {
@@ -49,165 +48,165 @@ contract('AccessManager', function (accounts) {
     expect(await this.manager.minSetback()).to.be.bignumber.equal(MINSETBACK);
   });
 
-  it('groups are correctly initialized', async function () {
-    // group admin
-    expect(await this.manager.getGroupAdmin(GROUPS.ADMIN)).to.be.bignumber.equal(GROUPS.ADMIN);
-    expect(await this.manager.getGroupAdmin(GROUPS.SOME_ADMIN)).to.be.bignumber.equal(GROUPS.ADMIN);
-    expect(await this.manager.getGroupAdmin(GROUPS.SOME)).to.be.bignumber.equal(GROUPS.SOME_ADMIN);
-    expect(await this.manager.getGroupAdmin(GROUPS.PUBLIC)).to.be.bignumber.equal(GROUPS.ADMIN);
-    // group guardian
-    expect(await this.manager.getGroupGuardian(GROUPS.ADMIN)).to.be.bignumber.equal(GROUPS.ADMIN);
-    expect(await this.manager.getGroupGuardian(GROUPS.SOME_ADMIN)).to.be.bignumber.equal(GROUPS.ADMIN);
-    expect(await this.manager.getGroupGuardian(GROUPS.SOME)).to.be.bignumber.equal(GROUPS.SOME_ADMIN);
-    expect(await this.manager.getGroupGuardian(GROUPS.PUBLIC)).to.be.bignumber.equal(GROUPS.ADMIN);
-    // group members
-    expect(await this.manager.hasGroup(GROUPS.ADMIN, admin).then(formatAccess)).to.be.deep.equal([true, '0']);
-    expect(await this.manager.hasGroup(GROUPS.ADMIN, manager).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.ADMIN, member).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.ADMIN, user).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME_ADMIN, admin).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME_ADMIN, manager).then(formatAccess)).to.be.deep.equal([true, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME_ADMIN, member).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME_ADMIN, user).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME, admin).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME, manager).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
-    expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
-    expect(await this.manager.hasGroup(GROUPS.PUBLIC, admin).then(formatAccess)).to.be.deep.equal([true, '0']);
-    expect(await this.manager.hasGroup(GROUPS.PUBLIC, manager).then(formatAccess)).to.be.deep.equal([true, '0']);
-    expect(await this.manager.hasGroup(GROUPS.PUBLIC, member).then(formatAccess)).to.be.deep.equal([true, '0']);
-    expect(await this.manager.hasGroup(GROUPS.PUBLIC, user).then(formatAccess)).to.be.deep.equal([true, '0']);
+  it('roles are correctly initialized', async function () {
+    // role admin
+    expect(await this.manager.getRoleAdmin(ROLES.ADMIN)).to.be.bignumber.equal(ROLES.ADMIN);
+    expect(await this.manager.getRoleAdmin(ROLES.SOME_ADMIN)).to.be.bignumber.equal(ROLES.ADMIN);
+    expect(await this.manager.getRoleAdmin(ROLES.SOME)).to.be.bignumber.equal(ROLES.SOME_ADMIN);
+    expect(await this.manager.getRoleAdmin(ROLES.PUBLIC)).to.be.bignumber.equal(ROLES.ADMIN);
+    // role guardian
+    expect(await this.manager.getRoleGuardian(ROLES.ADMIN)).to.be.bignumber.equal(ROLES.ADMIN);
+    expect(await this.manager.getRoleGuardian(ROLES.SOME_ADMIN)).to.be.bignumber.equal(ROLES.ADMIN);
+    expect(await this.manager.getRoleGuardian(ROLES.SOME)).to.be.bignumber.equal(ROLES.SOME_ADMIN);
+    expect(await this.manager.getRoleGuardian(ROLES.PUBLIC)).to.be.bignumber.equal(ROLES.ADMIN);
+    // role members
+    expect(await this.manager.hasRole(ROLES.ADMIN, admin).then(formatAccess)).to.be.deep.equal([true, '0']);
+    expect(await this.manager.hasRole(ROLES.ADMIN, manager).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.ADMIN, member).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.ADMIN, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME_ADMIN, admin).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME_ADMIN, manager).then(formatAccess)).to.be.deep.equal([true, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME_ADMIN, member).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME_ADMIN, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME, admin).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME, manager).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
+    expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+    expect(await this.manager.hasRole(ROLES.PUBLIC, admin).then(formatAccess)).to.be.deep.equal([true, '0']);
+    expect(await this.manager.hasRole(ROLES.PUBLIC, manager).then(formatAccess)).to.be.deep.equal([true, '0']);
+    expect(await this.manager.hasRole(ROLES.PUBLIC, member).then(formatAccess)).to.be.deep.equal([true, '0']);
+    expect(await this.manager.hasRole(ROLES.PUBLIC, user).then(formatAccess)).to.be.deep.equal([true, '0']);
   });
 
-  describe('Groups management', function () {
-    describe('label group', function () {
+  describe('Roles management', function () {
+    describe('label role', function () {
       it('admin can emit a label event', async function () {
-        expectEvent(await this.manager.labelGroup(GROUPS.SOME, 'Some label', { from: admin }), 'GroupLabel', {
-          groupId: GROUPS.SOME,
+        expectEvent(await this.manager.labelRole(ROLES.SOME, 'Some label', { from: admin }), 'RoleLabel', {
+          roleId: ROLES.SOME,
           label: 'Some label',
         });
       });
 
       it('admin can re-emit a label event', async function () {
-        await this.manager.labelGroup(GROUPS.SOME, 'Some label', { from: admin });
+        await this.manager.labelRole(ROLES.SOME, 'Some label', { from: admin });
 
-        expectEvent(await this.manager.labelGroup(GROUPS.SOME, 'Updated label', { from: admin }), 'GroupLabel', {
-          groupId: GROUPS.SOME,
+        expectEvent(await this.manager.labelRole(ROLES.SOME, 'Updated label', { from: admin }), 'RoleLabel', {
+          roleId: ROLES.SOME,
           label: 'Updated label',
         });
       });
 
       it('emitting a label is restricted', async function () {
         await expectRevertCustomError(
-          this.manager.labelGroup(GROUPS.SOME, 'Invalid label', { from: other }),
+          this.manager.labelRole(ROLES.SOME, 'Invalid label', { from: other }),
           'AccessManagerUnauthorizedAccount',
-          [other, GROUPS.ADMIN],
+          [other, ROLES.ADMIN],
         );
       });
     });
 
-    describe('grant group', function () {
+    describe('grant role', function () {
       describe('without a grant delay', function () {
         it('without an execute delay', async function () {
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-          const { receipt } = await this.manager.grantGroup(GROUPS.SOME, user, 0, { from: manager });
+          const { receipt } = await this.manager.grantRole(ROLES.SOME, user, 0, { from: manager });
           const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
-          expectEvent(receipt, 'GroupGranted', {
-            groupId: GROUPS.SOME,
+          expectEvent(receipt, 'RoleGranted', {
+            roleId: ROLES.SOME,
             account: user,
             since: timestamp,
             delay: '0',
             newMember: true,
           });
 
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([true, '0']);
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([true, '0']);
 
-          const access = await this.manager.getAccess(GROUPS.SOME, user);
-          expect(access[0]).to.be.bignumber.equal(timestamp); // inGroupSince
+          const access = await this.manager.getAccess(ROLES.SOME, user);
+          expect(access[0]).to.be.bignumber.equal(timestamp); // inRoleSince
           expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
           expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
           expect(access[3]).to.be.bignumber.equal('0'); // effect
         });
 
         it('with an execute delay', async function () {
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-          const { receipt } = await this.manager.grantGroup(GROUPS.SOME, user, executeDelay, { from: manager });
+          const { receipt } = await this.manager.grantRole(ROLES.SOME, user, executeDelay, { from: manager });
           const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
-          expectEvent(receipt, 'GroupGranted', {
-            groupId: GROUPS.SOME,
+          expectEvent(receipt, 'RoleGranted', {
+            roleId: ROLES.SOME,
             account: user,
             since: timestamp,
             delay: executeDelay,
             newMember: true,
           });
 
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([
             true,
             executeDelay.toString(),
           ]);
 
-          const access = await this.manager.getAccess(GROUPS.SOME, user);
-          expect(access[0]).to.be.bignumber.equal(timestamp); // inGroupSince
+          const access = await this.manager.getAccess(ROLES.SOME, user);
+          expect(access[0]).to.be.bignumber.equal(timestamp); // inRoleSince
           expect(access[1]).to.be.bignumber.equal(executeDelay); // currentDelay
           expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
           expect(access[3]).to.be.bignumber.equal('0'); // effect
         });
 
-        it('to a user that is already in the group', async function () {
-          expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
-          await this.manager.grantGroup(GROUPS.SOME, member, 0, { from: manager });
-          expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
+        it('to a user that is already in the role', async function () {
+          expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
+          await this.manager.grantRole(ROLES.SOME, member, 0, { from: manager });
+          expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
         });
 
-        it('to a user that is scheduled for joining the group', async function () {
-          await this.manager.$_grantGroup(GROUPS.SOME, user, 10, 0); // grant delay 10
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
-          await this.manager.grantGroup(GROUPS.SOME, user, 0, { from: manager });
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+        it('to a user that is scheduled for joining the role', async function () {
+          await this.manager.$_grantRole(ROLES.SOME, user, 10, 0); // grant delay 10
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+          await this.manager.grantRole(ROLES.SOME, user, 0, { from: manager });
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
         });
 
-        it('grant group is restricted', async function () {
+        it('grant role is restricted', async function () {
           await expectRevertCustomError(
-            this.manager.grantGroup(GROUPS.SOME, user, 0, { from: other }),
+            this.manager.grantRole(ROLES.SOME, user, 0, { from: other }),
             'AccessManagerUnauthorizedAccount',
-            [other, GROUPS.SOME_ADMIN],
+            [other, ROLES.SOME_ADMIN],
           );
         });
       });
 
       describe('with a grant delay', function () {
         beforeEach(async function () {
-          await this.manager.$_setGrantDelay(GROUPS.SOME, grantDelay);
+          await this.manager.$_setGrantDelay(ROLES.SOME, grantDelay);
           await time.increase(MINSETBACK);
         });
 
-        it('granted group is not active immediately', async function () {
-          const { receipt } = await this.manager.grantGroup(GROUPS.SOME, user, 0, { from: manager });
+        it('granted role is not active immediately', async function () {
+          const { receipt } = await this.manager.grantRole(ROLES.SOME, user, 0, { from: manager });
           const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
-          expectEvent(receipt, 'GroupGranted', {
-            groupId: GROUPS.SOME,
+          expectEvent(receipt, 'RoleGranted', {
+            roleId: ROLES.SOME,
             account: user,
             since: timestamp.add(grantDelay),
             delay: '0',
             newMember: true,
           });
 
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-          const access = await this.manager.getAccess(GROUPS.SOME, user);
-          expect(access[0]).to.be.bignumber.equal(timestamp.add(grantDelay)); // inGroupSince
+          const access = await this.manager.getAccess(ROLES.SOME, user);
+          expect(access[0]).to.be.bignumber.equal(timestamp.add(grantDelay)); // inRoleSince
           expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
           expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
           expect(access[3]).to.be.bignumber.equal('0'); // effect
         });
 
-        it('granted group is active after the delay', async function () {
-          const { receipt } = await this.manager.grantGroup(GROUPS.SOME, user, 0, { from: manager });
+        it('granted role is active after the delay', async function () {
+          const { receipt } = await this.manager.grantRole(ROLES.SOME, user, 0, { from: manager });
           const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
-          expectEvent(receipt, 'GroupGranted', {
-            groupId: GROUPS.SOME,
+          expectEvent(receipt, 'RoleGranted', {
+            roleId: ROLES.SOME,
             account: user,
             since: timestamp.add(grantDelay),
             delay: '0',
@@ -216,153 +215,153 @@ contract('AccessManager', function (accounts) {
 
           await time.increase(grantDelay);
 
-          expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([true, '0']);
+          expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([true, '0']);
 
-          const access = await this.manager.getAccess(GROUPS.SOME, user);
-          expect(access[0]).to.be.bignumber.equal(timestamp.add(grantDelay)); // inGroupSince
+          const access = await this.manager.getAccess(ROLES.SOME, user);
+          expect(access[0]).to.be.bignumber.equal(timestamp.add(grantDelay)); // inRoleSince
           expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
           expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
           expect(access[3]).to.be.bignumber.equal('0'); // effect
         });
       });
 
-      it('cannot grant public group', async function () {
+      it('cannot grant public role', async function () {
         await expectRevertCustomError(
-          this.manager.$_grantGroup(GROUPS.PUBLIC, other, 0, executeDelay, { from: manager }),
-          'AccessManagerLockedGroup',
-          [GROUPS.PUBLIC],
+          this.manager.$_grantRole(ROLES.PUBLIC, other, 0, executeDelay, { from: manager }),
+          'AccessManagerLockedRole',
+          [ROLES.PUBLIC],
         );
       });
     });
 
-    describe('revoke group', function () {
-      it('from a user that is already in the group', async function () {
-        expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
+    describe('revoke role', function () {
+      it('from a user that is already in the role', async function () {
+        expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
 
-        const { receipt } = await this.manager.revokeGroup(GROUPS.SOME, member, { from: manager });
-        expectEvent(receipt, 'GroupRevoked', { groupId: GROUPS.SOME, account: member });
+        const { receipt } = await this.manager.revokeRole(ROLES.SOME, member, { from: manager });
+        expectEvent(receipt, 'RoleRevoked', { roleId: ROLES.SOME, account: member });
 
-        expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([false, '0']);
+        expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-        const access = await this.manager.getAccess(GROUPS.SOME, user);
-        expect(access[0]).to.be.bignumber.equal('0'); // inGroupSince
+        const access = await this.manager.getAccess(ROLES.SOME, user);
+        expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
         expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
         expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(access[3]).to.be.bignumber.equal('0'); // effect
       });
 
-      it('from a user that is scheduled for joining the group', async function () {
-        await this.manager.$_grantGroup(GROUPS.SOME, user, 10, 0); // grant delay 10
+      it('from a user that is scheduled for joining the role', async function () {
+        await this.manager.$_grantRole(ROLES.SOME, user, 10, 0); // grant delay 10
 
-        expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+        expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-        const { receipt } = await this.manager.revokeGroup(GROUPS.SOME, user, { from: manager });
-        expectEvent(receipt, 'GroupRevoked', { groupId: GROUPS.SOME, account: user });
+        const { receipt } = await this.manager.revokeRole(ROLES.SOME, user, { from: manager });
+        expectEvent(receipt, 'RoleRevoked', { roleId: ROLES.SOME, account: user });
 
-        expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+        expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-        const access = await this.manager.getAccess(GROUPS.SOME, user);
-        expect(access[0]).to.be.bignumber.equal('0'); // inGroupSince
+        const access = await this.manager.getAccess(ROLES.SOME, user);
+        expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
         expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
         expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(access[3]).to.be.bignumber.equal('0'); // effect
       });
 
-      it('from a user that is not in the group', async function () {
-        expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
-        await this.manager.revokeGroup(GROUPS.SOME, user, { from: manager });
-        expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+      it('from a user that is not in the role', async function () {
+        expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+        await this.manager.revokeRole(ROLES.SOME, user, { from: manager });
+        expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
       });
 
-      it('revoke group is restricted', async function () {
+      it('revoke role is restricted', async function () {
         await expectRevertCustomError(
-          this.manager.revokeGroup(GROUPS.SOME, member, { from: other }),
+          this.manager.revokeRole(ROLES.SOME, member, { from: other }),
           'AccessManagerUnauthorizedAccount',
-          [other, GROUPS.SOME_ADMIN],
+          [other, ROLES.SOME_ADMIN],
         );
       });
     });
 
-    describe('renounce group', function () {
-      it('for a user that is already in the group', async function () {
-        expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
+    describe('renounce role', function () {
+      it('for a user that is already in the role', async function () {
+        expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([true, '0']);
 
-        const { receipt } = await this.manager.renounceGroup(GROUPS.SOME, member, { from: member });
-        expectEvent(receipt, 'GroupRevoked', { groupId: GROUPS.SOME, account: member });
+        const { receipt } = await this.manager.renounceRole(ROLES.SOME, member, { from: member });
+        expectEvent(receipt, 'RoleRevoked', { roleId: ROLES.SOME, account: member });
 
-        expect(await this.manager.hasGroup(GROUPS.SOME, member).then(formatAccess)).to.be.deep.equal([false, '0']);
+        expect(await this.manager.hasRole(ROLES.SOME, member).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-        const access = await this.manager.getAccess(GROUPS.SOME, member);
-        expect(access[0]).to.be.bignumber.equal('0'); // inGroupSince
+        const access = await this.manager.getAccess(ROLES.SOME, member);
+        expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
         expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
         expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(access[3]).to.be.bignumber.equal('0'); // effect
       });
 
-      it('for a user that is schedule for joining the group', async function () {
-        await this.manager.$_grantGroup(GROUPS.SOME, user, 10, 0); // grant delay 10
+      it('for a user that is schedule for joining the role', async function () {
+        await this.manager.$_grantRole(ROLES.SOME, user, 10, 0); // grant delay 10
 
-        expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+        expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-        const { receipt } = await this.manager.renounceGroup(GROUPS.SOME, user, { from: user });
-        expectEvent(receipt, 'GroupRevoked', { groupId: GROUPS.SOME, account: user });
+        const { receipt } = await this.manager.renounceRole(ROLES.SOME, user, { from: user });
+        expectEvent(receipt, 'RoleRevoked', { roleId: ROLES.SOME, account: user });
 
-        expect(await this.manager.hasGroup(GROUPS.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
+        expect(await this.manager.hasRole(ROLES.SOME, user).then(formatAccess)).to.be.deep.equal([false, '0']);
 
-        const access = await this.manager.getAccess(GROUPS.SOME, user);
-        expect(access[0]).to.be.bignumber.equal('0'); // inGroupSince
+        const access = await this.manager.getAccess(ROLES.SOME, user);
+        expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
         expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
         expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(access[3]).to.be.bignumber.equal('0'); // effect
       });
 
-      it('for a user that is not in the group', async function () {
-        await this.manager.renounceGroup(GROUPS.SOME, user, { from: user });
+      it('for a user that is not in the role', async function () {
+        await this.manager.renounceRole(ROLES.SOME, user, { from: user });
       });
 
       it('bad user confirmation', async function () {
         await expectRevertCustomError(
-          this.manager.renounceGroup(GROUPS.SOME, member, { from: user }),
+          this.manager.renounceRole(ROLES.SOME, member, { from: user }),
           'AccessManagerBadConfirmation',
           [],
         );
       });
     });
 
-    describe('change group admin', function () {
-      it("admin can set any group's admin", async function () {
-        expect(await this.manager.getGroupAdmin(GROUPS.SOME)).to.be.bignumber.equal(GROUPS.SOME_ADMIN);
+    describe('change role admin', function () {
+      it("admin can set any role's admin", async function () {
+        expect(await this.manager.getRoleAdmin(ROLES.SOME)).to.be.bignumber.equal(ROLES.SOME_ADMIN);
 
-        const { receipt } = await this.manager.setGroupAdmin(GROUPS.SOME, GROUPS.ADMIN, { from: admin });
-        expectEvent(receipt, 'GroupAdminChanged', { groupId: GROUPS.SOME, admin: GROUPS.ADMIN });
+        const { receipt } = await this.manager.setRoleAdmin(ROLES.SOME, ROLES.ADMIN, { from: admin });
+        expectEvent(receipt, 'RoleAdminChanged', { roleId: ROLES.SOME, admin: ROLES.ADMIN });
 
-        expect(await this.manager.getGroupAdmin(GROUPS.SOME)).to.be.bignumber.equal(GROUPS.ADMIN);
+        expect(await this.manager.getRoleAdmin(ROLES.SOME)).to.be.bignumber.equal(ROLES.ADMIN);
       });
 
-      it("setting a group's admin is restricted", async function () {
+      it("setting a role's admin is restricted", async function () {
         await expectRevertCustomError(
-          this.manager.setGroupAdmin(GROUPS.SOME, GROUPS.SOME, { from: manager }),
+          this.manager.setRoleAdmin(ROLES.SOME, ROLES.SOME, { from: manager }),
           'AccessManagerUnauthorizedAccount',
-          [manager, GROUPS.ADMIN],
+          [manager, ROLES.ADMIN],
         );
       });
     });
 
-    describe('change group guardian', function () {
-      it("admin can set any group's admin", async function () {
-        expect(await this.manager.getGroupGuardian(GROUPS.SOME)).to.be.bignumber.equal(GROUPS.SOME_ADMIN);
+    describe('change role guardian', function () {
+      it("admin can set any role's admin", async function () {
+        expect(await this.manager.getRoleGuardian(ROLES.SOME)).to.be.bignumber.equal(ROLES.SOME_ADMIN);
 
-        const { receipt } = await this.manager.setGroupGuardian(GROUPS.SOME, GROUPS.ADMIN, { from: admin });
-        expectEvent(receipt, 'GroupGuardianChanged', { groupId: GROUPS.SOME, guardian: GROUPS.ADMIN });
+        const { receipt } = await this.manager.setRoleGuardian(ROLES.SOME, ROLES.ADMIN, { from: admin });
+        expectEvent(receipt, 'RoleGuardianChanged', { roleId: ROLES.SOME, guardian: ROLES.ADMIN });
 
-        expect(await this.manager.getGroupGuardian(GROUPS.SOME)).to.be.bignumber.equal(GROUPS.ADMIN);
+        expect(await this.manager.getRoleGuardian(ROLES.SOME)).to.be.bignumber.equal(ROLES.ADMIN);
       });
 
-      it("setting a group's admin is restricted", async function () {
+      it("setting a role's admin is restricted", async function () {
         await expectRevertCustomError(
-          this.manager.setGroupGuardian(GROUPS.SOME, GROUPS.SOME, { from: other }),
+          this.manager.setRoleGuardian(ROLES.SOME, ROLES.SOME, { from: other }),
           'AccessManagerUnauthorizedAccount',
-          [other, GROUPS.ADMIN],
+          [other, ROLES.ADMIN],
         );
       });
     });
@@ -372,21 +371,21 @@ contract('AccessManager', function (accounts) {
         const oldDelay = web3.utils.toBN(10);
         const newDelay = web3.utils.toBN(100);
 
-        // group is already granted (with no delay) in the initial setup. this update takes time.
-        await this.manager.$_grantGroup(GROUPS.SOME, member, 0, oldDelay);
+        // role is already granted (with no delay) in the initial setup. this update takes time.
+        await this.manager.$_grantRole(ROLES.SOME, member, 0, oldDelay);
 
-        const accessBefore = await this.manager.getAccess(GROUPS.SOME, member);
+        const accessBefore = await this.manager.getAccess(ROLES.SOME, member);
         expect(accessBefore[1]).to.be.bignumber.equal(oldDelay); // currentDelay
         expect(accessBefore[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(accessBefore[3]).to.be.bignumber.equal('0'); // effect
 
-        const { receipt } = await this.manager.grantGroup(GROUPS.SOME, member, newDelay, {
+        const { receipt } = await this.manager.grantRole(ROLES.SOME, member, newDelay, {
           from: manager,
         });
         const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
 
-        expectEvent(receipt, 'GroupGranted', {
-          groupId: GROUPS.SOME,
+        expectEvent(receipt, 'RoleGranted', {
+          roleId: ROLES.SOME,
           account: member,
           since: timestamp,
           delay: newDelay,
@@ -394,7 +393,7 @@ contract('AccessManager', function (accounts) {
         });
 
         // immediate effect
-        const accessAfter = await this.manager.getAccess(GROUPS.SOME, member);
+        const accessAfter = await this.manager.getAccess(ROLES.SOME, member);
         expect(accessAfter[1]).to.be.bignumber.equal(newDelay); // currentDelay
         expect(accessAfter[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(accessAfter[3]).to.be.bignumber.equal('0'); // effect
@@ -404,22 +403,22 @@ contract('AccessManager', function (accounts) {
         const oldDelay = web3.utils.toBN(100);
         const newDelay = web3.utils.toBN(10);
 
-        // group is already granted (with no delay) in the initial setup. this update takes time.
-        await this.manager.$_grantGroup(GROUPS.SOME, member, 0, oldDelay);
+        // role is already granted (with no delay) in the initial setup. this update takes time.
+        await this.manager.$_grantRole(ROLES.SOME, member, 0, oldDelay);
 
-        const accessBefore = await this.manager.getAccess(GROUPS.SOME, member);
+        const accessBefore = await this.manager.getAccess(ROLES.SOME, member);
         expect(accessBefore[1]).to.be.bignumber.equal(oldDelay); // currentDelay
         expect(accessBefore[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(accessBefore[3]).to.be.bignumber.equal('0'); // effect
 
-        const { receipt } = await this.manager.grantGroup(GROUPS.SOME, member, newDelay, {
+        const { receipt } = await this.manager.grantRole(ROLES.SOME, member, newDelay, {
           from: manager,
         });
         const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
         const setback = oldDelay.sub(newDelay);
 
-        expectEvent(receipt, 'GroupGranted', {
-          groupId: GROUPS.SOME,
+        expectEvent(receipt, 'RoleGranted', {
+          roleId: ROLES.SOME,
           account: member,
           since: timestamp.add(setback),
           delay: newDelay,
@@ -427,29 +426,29 @@ contract('AccessManager', function (accounts) {
         });
 
         // no immediate effect
-        const accessAfter = await this.manager.getAccess(GROUPS.SOME, member);
+        const accessAfter = await this.manager.getAccess(ROLES.SOME, member);
         expect(accessAfter[1]).to.be.bignumber.equal(oldDelay); // currentDelay
         expect(accessAfter[2]).to.be.bignumber.equal(newDelay); // pendingDelay
         expect(accessAfter[3]).to.be.bignumber.equal(timestamp.add(setback)); // effect
 
         // delayed effect
         await time.increase(setback);
-        const accessAfterSetback = await this.manager.getAccess(GROUPS.SOME, member);
+        const accessAfterSetback = await this.manager.getAccess(ROLES.SOME, member);
         expect(accessAfterSetback[1]).to.be.bignumber.equal(newDelay); // currentDelay
         expect(accessAfterSetback[2]).to.be.bignumber.equal('0'); // pendingDelay
         expect(accessAfterSetback[3]).to.be.bignumber.equal('0'); // effect
       });
 
       it('can set a user execution delay during the grant delay', async function () {
-        await this.manager.$_grantGroup(GROUPS.SOME, other, 10, 0);
-        // here: "other" is pending to get the group, but doesn't yet have it.
+        await this.manager.$_grantRole(ROLES.SOME, other, 10, 0);
+        // here: "other" is pending to get the role, but doesn't yet have it.
 
-        const { receipt } = await this.manager.grantGroup(GROUPS.SOME, other, executeDelay, { from: manager });
+        const { receipt } = await this.manager.grantRole(ROLES.SOME, other, executeDelay, { from: manager });
         const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
 
         // increasing the execution delay from 0 to executeDelay is immediate
-        expectEvent(receipt, 'GroupGranted', {
-          groupId: GROUPS.SOME,
+        expectEvent(receipt, 'RoleGranted', {
+          roleId: ROLES.SOME,
           account: other,
           since: timestamp,
           delay: executeDelay,
@@ -463,82 +462,82 @@ contract('AccessManager', function (accounts) {
         const oldDelay = web3.utils.toBN(10);
         const newDelay = web3.utils.toBN(100);
 
-        await this.manager.$_setGrantDelay(GROUPS.SOME, oldDelay);
+        await this.manager.$_setGrantDelay(ROLES.SOME, oldDelay);
         await time.increase(MINSETBACK);
 
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(oldDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(oldDelay);
 
-        const { receipt } = await this.manager.setGrantDelay(GROUPS.SOME, newDelay, { from: admin });
+        const { receipt } = await this.manager.setGrantDelay(ROLES.SOME, newDelay, { from: admin });
         const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
         const setback = web3.utils.BN.max(MINSETBACK, oldDelay.sub(newDelay));
 
         expect(setback).to.be.bignumber.equal(MINSETBACK);
-        expectEvent(receipt, 'GroupGrantDelayChanged', {
-          groupId: GROUPS.SOME,
+        expectEvent(receipt, 'RoleGrantDelayChanged', {
+          roleId: ROLES.SOME,
           delay: newDelay,
           since: timestamp.add(setback),
         });
 
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(oldDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(oldDelay);
         await time.increase(setback);
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(newDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(newDelay);
       });
 
       it('increasing the delay has delay effect #1', async function () {
         const oldDelay = web3.utils.toBN(100);
         const newDelay = web3.utils.toBN(10);
 
-        await this.manager.$_setGrantDelay(GROUPS.SOME, oldDelay);
+        await this.manager.$_setGrantDelay(ROLES.SOME, oldDelay);
         await time.increase(MINSETBACK);
 
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(oldDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(oldDelay);
 
-        const { receipt } = await this.manager.setGrantDelay(GROUPS.SOME, newDelay, { from: admin });
+        const { receipt } = await this.manager.setGrantDelay(ROLES.SOME, newDelay, { from: admin });
         const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
         const setback = web3.utils.BN.max(MINSETBACK, oldDelay.sub(newDelay));
 
         expect(setback).to.be.bignumber.equal(MINSETBACK);
-        expectEvent(receipt, 'GroupGrantDelayChanged', {
-          groupId: GROUPS.SOME,
+        expectEvent(receipt, 'RoleGrantDelayChanged', {
+          roleId: ROLES.SOME,
           delay: newDelay,
           since: timestamp.add(setback),
         });
 
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(oldDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(oldDelay);
         await time.increase(setback);
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(newDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(newDelay);
       });
 
       it('increasing the delay has delay effect #2', async function () {
         const oldDelay = time.duration.days(30); // more than the minsetback
         const newDelay = web3.utils.toBN(10);
 
-        await this.manager.$_setGrantDelay(GROUPS.SOME, oldDelay);
+        await this.manager.$_setGrantDelay(ROLES.SOME, oldDelay);
         await time.increase(MINSETBACK);
 
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(oldDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(oldDelay);
 
-        const { receipt } = await this.manager.setGrantDelay(GROUPS.SOME, newDelay, { from: admin });
+        const { receipt } = await this.manager.setGrantDelay(ROLES.SOME, newDelay, { from: admin });
         const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
         const setback = web3.utils.BN.max(MINSETBACK, oldDelay.sub(newDelay));
 
         expect(setback).to.be.bignumber.gt(MINSETBACK);
-        expectEvent(receipt, 'GroupGrantDelayChanged', {
-          groupId: GROUPS.SOME,
+        expectEvent(receipt, 'RoleGrantDelayChanged', {
+          roleId: ROLES.SOME,
           delay: newDelay,
           since: timestamp.add(setback),
         });
 
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(oldDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(oldDelay);
         await time.increase(setback);
-        expect(await this.manager.getGroupGrantDelay(GROUPS.SOME)).to.be.bignumber.equal(newDelay);
+        expect(await this.manager.getRoleGrantDelay(ROLES.SOME)).to.be.bignumber.equal(newDelay);
       });
 
       it('changing the grant delay is restricted', async function () {
         await expectRevertCustomError(
-          this.manager.setGrantDelay(GROUPS.SOME, grantDelay, { from: other }),
+          this.manager.setGrantDelay(ROLES.SOME, grantDelay, { from: other }),
           'AccessManagerUnauthorizedAccount',
-          [GROUPS.ADMIN, other],
+          [ROLES.ADMIN, other],
         );
       });
     });
@@ -562,84 +561,75 @@ contract('AccessManager', function (accounts) {
     describe('Change function permissions', function () {
       const sigs = ['someFunction()', 'someOtherFunction(uint256)', 'oneMoreFunction(address,uint8)'].map(selector);
 
-      it('admin can set function group', async function () {
+      it('admin can set function role', async function () {
         for (const sig of sigs) {
-          expect(await this.manager.getTargetFunctionGroup(this.target.address, sig)).to.be.bignumber.equal(
-            GROUPS.ADMIN,
-          );
+          expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal(ROLES.ADMIN);
         }
 
-        const { receipt: receipt1 } = await this.manager.setTargetFunctionGroup(
-          this.target.address,
-          sigs,
-          GROUPS.SOME,
-          {
-            from: admin,
-          },
-        );
+        const { receipt: receipt1 } = await this.manager.setTargetFunctionRole(this.target.address, sigs, ROLES.SOME, {
+          from: admin,
+        });
 
         for (const sig of sigs) {
-          expectEvent(receipt1, 'TargetFunctionGroupUpdated', {
+          expectEvent(receipt1, 'TargetFunctionRoleUpdated', {
             target: this.target.address,
             selector: sig,
-            groupId: GROUPS.SOME,
+            roleId: ROLES.SOME,
           });
-          expect(await this.manager.getTargetFunctionGroup(this.target.address, sig)).to.be.bignumber.equal(
-            GROUPS.SOME,
-          );
+          expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal(ROLES.SOME);
         }
 
-        const { receipt: receipt2 } = await this.manager.setTargetFunctionGroup(
+        const { receipt: receipt2 } = await this.manager.setTargetFunctionRole(
           this.target.address,
           [sigs[1]],
-          GROUPS.SOME_ADMIN,
+          ROLES.SOME_ADMIN,
           {
             from: admin,
           },
         );
-        expectEvent(receipt2, 'TargetFunctionGroupUpdated', {
+        expectEvent(receipt2, 'TargetFunctionRoleUpdated', {
           target: this.target.address,
           selector: sigs[1],
-          groupId: GROUPS.SOME_ADMIN,
+          roleId: ROLES.SOME_ADMIN,
         });
 
         for (const sig of sigs) {
-          expect(await this.manager.getTargetFunctionGroup(this.target.address, sig)).to.be.bignumber.equal(
-            sig == sigs[1] ? GROUPS.SOME_ADMIN : GROUPS.SOME,
+          expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal(
+            sig == sigs[1] ? ROLES.SOME_ADMIN : ROLES.SOME,
           );
         }
       });
 
-      it('non-admin cannot set function group', async function () {
+      it('non-admin cannot set function role', async function () {
         await expectRevertCustomError(
-          this.manager.setTargetFunctionGroup(this.target.address, sigs, GROUPS.SOME, { from: other }),
+          this.manager.setTargetFunctionRole(this.target.address, sigs, ROLES.SOME, { from: other }),
           'AccessManagerUnauthorizedAccount',
-          [other, GROUPS.ADMIN],
+          [other, ROLES.ADMIN],
         );
       });
     });
 
     // WIP
     describe('Calling restricted & unrestricted functions', function () {
-      for (const [callerGroups, fnGroup, closed, delay] of product(
-        [[], [GROUPS.SOME]],
-        [undefined, GROUPS.ADMIN, GROUPS.SOME, GROUPS.PUBLIC],
+      for (const [callerRoles, fnRole, closed, delay] of product(
+        [[], [ROLES.SOME]],
+        [undefined, ROLES.ADMIN, ROLES.SOME, ROLES.PUBLIC],
         [false, true],
         [null, executeDelay],
       )) {
         // can we call with a delay ?
-        const indirectSuccess = (fnGroup == GROUPS.PUBLIC || callerGroups.includes(fnGroup)) && !closed;
+        const indirectSuccess = (fnRole == ROLES.PUBLIC || callerRoles.includes(fnRole)) && !closed;
 
         // can we call without a delay ?
-        const directSuccess = (fnGroup == GROUPS.PUBLIC || (callerGroups.includes(fnGroup) && !delay)) && !closed;
+        const directSuccess = (fnRole == ROLES.PUBLIC || (callerRoles.includes(fnRole) && !delay)) && !closed;
 
         const description = [
-          'Caller in groups',
-          '[' + (callerGroups ?? []).map(groupId => GROUPS[groupId]).join(', ') + ']',
+          'Caller in roles',
+          '[' + (callerRoles ?? []).map(roleId => ROLES[roleId]).join(', ') + ']',
           delay ? 'with a delay' : 'without a delay',
           '+',
-          'functions open to groups',
-          '[' + (GROUPS[fnGroup] ?? '') + ']',
+          'functions open to roles',
+          '[' + (ROLES[fnRole] ?? '') + ']',
           closed ? `(closed)` : '',
         ].join(' ');
 
@@ -648,36 +638,34 @@ contract('AccessManager', function (accounts) {
             // setup
             await Promise.all([
               this.manager.$_setTargetClosed(this.target.address, closed),
-              fnGroup &&
-                this.manager.$_setTargetFunctionGroup(this.target.address, selector('fnRestricted()'), fnGroup),
-              fnGroup &&
-                this.manager.$_setTargetFunctionGroup(this.target.address, selector('fnUnrestricted()'), fnGroup),
-              ...callerGroups
-                .filter(groupId => groupId != GROUPS.PUBLIC)
-                .map(groupId => this.manager.$_grantGroup(groupId, user, 0, delay ?? 0)),
+              fnRole && this.manager.$_setTargetFunctionRole(this.target.address, selector('fnRestricted()'), fnRole),
+              fnRole && this.manager.$_setTargetFunctionRole(this.target.address, selector('fnUnrestricted()'), fnRole),
+              ...callerRoles
+                .filter(roleId => roleId != ROLES.PUBLIC)
+                .map(roleId => this.manager.$_grantRole(roleId, user, 0, delay ?? 0)),
             ]);
 
             // post setup checks
             expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(closed);
 
-            if (fnGroup) {
+            if (fnRole) {
               expect(
-                await this.manager.getTargetFunctionGroup(this.target.address, selector('fnRestricted()')),
-              ).to.be.bignumber.equal(fnGroup);
+                await this.manager.getTargetFunctionRole(this.target.address, selector('fnRestricted()')),
+              ).to.be.bignumber.equal(fnRole);
               expect(
-                await this.manager.getTargetFunctionGroup(this.target.address, selector('fnUnrestricted()')),
-              ).to.be.bignumber.equal(fnGroup);
+                await this.manager.getTargetFunctionRole(this.target.address, selector('fnUnrestricted()')),
+              ).to.be.bignumber.equal(fnRole);
             }
 
-            for (const groupId of callerGroups) {
-              const access = await this.manager.getAccess(groupId, user);
-              if (groupId == GROUPS.PUBLIC) {
-                expect(access[0]).to.be.bignumber.equal('0'); // inGroupSince
+            for (const roleId of callerRoles) {
+              const access = await this.manager.getAccess(roleId, user);
+              if (roleId == ROLES.PUBLIC) {
+                expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
                 expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
                 expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
                 expect(access[3]).to.be.bignumber.equal('0'); // effect
               } else {
-                expect(access[0]).to.be.bignumber.gt('0'); // inGroupSince
+                expect(access[0]).to.be.bignumber.gt('0'); // inRoleSince
                 expect(access[1]).to.be.bignumber.eq(String(delay ?? 0)); // currentDelay
                 expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
                 expect(access[3]).to.be.bignumber.equal('0'); // effect
@@ -745,7 +733,7 @@ contract('AccessManager', function (accounts) {
               if (directSuccess) {
                 const { receipt, tx } = await this.execute();
                 await expectEvent.inTransaction(tx, this.target, 'CalledRestricted', { caller: this.manager.address });
-                if (delay && fnGroup !== GROUPS.PUBLIC) {
+                if (delay && fnRole !== ROLES.PUBLIC) {
                   expectEvent(receipt, 'OperationExecuted', { operationId: this.opId });
                   expect(await this.manager.getSchedule(this.opId)).to.be.bignumber.equal('0');
                 }
@@ -783,7 +771,7 @@ contract('AccessManager', function (accounts) {
               if (directSuccess || indirectSuccess) {
                 const { receipt, tx } = await this.execute();
                 await expectEvent.inTransaction(tx, this.target, 'CalledRestricted', { caller: this.manager.address });
-                if (delay && fnGroup !== GROUPS.PUBLIC) {
+                if (delay && fnRole !== ROLES.PUBLIC) {
                   expectEvent(receipt, 'OperationExecuted', { operationId: this.opId });
                   expect(await this.manager.getSchedule(this.opId)).to.be.bignumber.equal('0');
                 }
@@ -879,8 +867,8 @@ contract('AccessManager', function (accounts) {
 
     describe('Indirect execution corner-cases', async function () {
       beforeEach(async function () {
-        await this.manager.$_setTargetFunctionGroup(this.target.address, this.callData, GROUPS.SOME);
-        await this.manager.$_grantGroup(GROUPS.SOME, user, 0, executeDelay);
+        await this.manager.$_setTargetFunctionRole(this.target.address, this.callData, ROLES.SOME);
+        await this.manager.$_grantRole(ROLES.SOME, user, 0, executeDelay);
       });
 
       it('Checking canCall when caller is the manager depend on the _executionId', async function () {
@@ -1002,13 +990,13 @@ contract('AccessManager', function (accounts) {
   });
 
   describe('with Ownable target contract', function () {
-    const groupId = web3.utils.toBN(1);
+    const roleId = web3.utils.toBN(1);
 
     beforeEach(async function () {
       this.ownable = await Ownable.new(this.manager.address);
 
-      // add user to group
-      await this.manager.$_grantGroup(groupId, user, 0, 0);
+      // add user to role
+      await this.manager.$_grantRole(roleId, user, 0, 0);
     });
 
     it('initial state', async function () {
@@ -1024,7 +1012,7 @@ contract('AccessManager', function (accounts) {
         await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [user]);
       });
 
-      it('relayed call (with group): reverts', async function () {
+      it('relayed call (with role): reverts', async function () {
         await expectRevertCustomError(
           this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }),
           'AccessManagerUnauthorizedCall',
@@ -1032,7 +1020,7 @@ contract('AccessManager', function (accounts) {
         );
       });
 
-      it('relayed call (without group): reverts', async function () {
+      it('relayed call (without role): reverts', async function () {
         await expectRevertCustomError(
           this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }),
           'AccessManagerUnauthorizedCall',
@@ -1042,9 +1030,9 @@ contract('AccessManager', function (accounts) {
     });
 
     describe('Contract is managed', function () {
-      describe('function is open to specific group', function () {
+      describe('function is open to specific role', function () {
         beforeEach(async function () {
-          await this.manager.$_setTargetFunctionGroup(this.ownable.address, selector('$_checkOwner()'), groupId);
+          await this.manager.$_setTargetFunctionRole(this.ownable.address, selector('$_checkOwner()'), roleId);
         });
 
         it('directly call: reverts', async function () {
@@ -1053,11 +1041,11 @@ contract('AccessManager', function (accounts) {
           ]);
         });
 
-        it('relayed call (with group): success', async function () {
+        it('relayed call (with role): success', async function () {
           await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user });
         });
 
-        it('relayed call (without group): reverts', async function () {
+        it('relayed call (without role): reverts', async function () {
           await expectRevertCustomError(
             this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }),
             'AccessManagerUnauthorizedCall',
@@ -1066,9 +1054,9 @@ contract('AccessManager', function (accounts) {
         });
       });
 
-      describe('function is open to public group', function () {
+      describe('function is open to public role', function () {
         beforeEach(async function () {
-          await this.manager.$_setTargetFunctionGroup(this.ownable.address, selector('$_checkOwner()'), GROUPS.PUBLIC);
+          await this.manager.$_setTargetFunctionRole(this.ownable.address, selector('$_checkOwner()'), ROLES.PUBLIC);
         });
 
         it('directly call: reverts', async function () {
@@ -1077,11 +1065,11 @@ contract('AccessManager', function (accounts) {
           ]);
         });
 
-        it('relayed call (with group): success', async function () {
+        it('relayed call (with role): success', async function () {
           await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user });
         });
 
-        it('relayed call (without group): success', async function () {
+        it('relayed call (without role): success', async function () {
           await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other });
         });
       });
@@ -1115,7 +1103,7 @@ contract('AccessManager', function (accounts) {
       await expectRevertCustomError(
         this.manager.updateAuthority(this.target.address, this.newManager.address, { from: other }),
         'AccessManagerUnauthorizedAccount',
-        [other, GROUPS.ADMIN],
+        [other, ROLES.ADMIN],
       );
     });
 

+ 9 - 9
test/governance/extensions/GovernorTimelockAccess.test.js

@@ -130,12 +130,12 @@ contract('GovernorTimelockAccess', function (accounts) {
 
       it('single operation with access manager delay', async function () {
         const delay = 1000;
-        const groupId = '1';
+        const roleId = '1';
 
-        await this.manager.setTargetFunctionGroup(this.receiver.address, [this.restricted.selector], groupId, {
+        await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, {
           from: admin,
         });
-        await this.manager.grantGroup(groupId, this.mock.address, delay, { from: admin });
+        await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin });
 
         this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr');
 
@@ -167,16 +167,16 @@ contract('GovernorTimelockAccess', function (accounts) {
 
       it('bundle of varied operations', async function () {
         const managerDelay = 1000;
-        const groupId = '1';
+        const roleId = '1';
 
         const baseDelay = managerDelay * 2;
 
         await this.mock.$_setBaseDelaySeconds(baseDelay);
 
-        await this.manager.setTargetFunctionGroup(this.receiver.address, [this.restricted.selector], groupId, {
+        await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, {
           from: admin,
         });
-        await this.manager.grantGroup(groupId, this.mock.address, managerDelay, { from: admin });
+        await this.manager.grantRole(roleId, this.mock.address, managerDelay, { from: admin });
 
         this.proposal = await this.helper.setProposal(
           [this.restricted.operation, this.unrestricted.operation],
@@ -212,12 +212,12 @@ contract('GovernorTimelockAccess', function (accounts) {
 
       it('cancellation after queue (internal)', async function () {
         const delay = 1000;
-        const groupId = '1';
+        const roleId = '1';
 
-        await this.manager.setTargetFunctionGroup(this.receiver.address, [this.restricted.selector], groupId, {
+        await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, {
           from: admin,
         });
-        await this.manager.grantGroup(groupId, this.mock.address, delay, { from: admin });
+        await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin });
 
         this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr');