Change access folder structure (#4359)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: Francisco <fg@frang.io>
This commit is contained in:
Renan Souza
2023-07-13 18:54:22 -03:00
committed by GitHub
parent 84db204a41
commit 9cf873ea14
8 changed files with 20 additions and 11 deletions

View File

@ -0,0 +1,396 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.19;
import {IAccessControlDefaultAdminRules} from "./IAccessControlDefaultAdminRules.sol";
import {AccessControl, IAccessControl} from "../AccessControl.sol";
import {SafeCast} from "../../utils/math/SafeCast.sol";
import {Math} from "../../utils/math/Math.sol";
import {IERC5313} from "../../interfaces/IERC5313.sol";
/**
* @dev Extension of {AccessControl} that allows specifying special rules to manage
* the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions
* over other roles that may potentially have privileged rights in the system.
*
* If a specific role doesn't have an admin role assigned, the holder of the
* `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.
*
* This contract implements the following risk mitigations on top of {AccessControl}:
*
* * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.
* * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
* * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.
* * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.
* * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.
*
* Example usage:
*
* ```solidity
* contract MyToken is AccessControlDefaultAdminRules {
* constructor() AccessControlDefaultAdminRules(
* 3 days,
* msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder
* ) {}
* }
* ```
*/
abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl {
// pending admin pair read/written together frequently
address private _pendingDefaultAdmin;
uint48 private _pendingDefaultAdminSchedule; // 0 == unset
uint48 private _currentDelay;
address private _currentDefaultAdmin;
// pending delay pair read/written together frequently
uint48 private _pendingDelay;
uint48 private _pendingDelaySchedule; // 0 == unset
/**
* @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
*/
constructor(uint48 initialDelay, address initialDefaultAdmin) {
if (initialDefaultAdmin == address(0)) {
revert AccessControlInvalidDefaultAdmin(address(0));
}
_currentDelay = initialDelay;
_grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC5313-owner}.
*/
function owner() public view virtual returns (address) {
return defaultAdmin();
}
///
/// Override AccessControl role management
///
/**
* @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super.grantRole(role, account);
}
/**
* @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super.revokeRole(role, account);
}
/**
* @dev See {AccessControl-renounceRole}.
*
* For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling
* {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule
* has also passed when calling this function.
*
* After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.
*
* NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},
* thereby disabling any functionality that is only available for it, and the possibility of reassigning a
* non-administrated role.
*/
function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
(address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
revert AccessControlEnforcedDefaultAdminDelay(schedule);
}
delete _pendingDefaultAdminSchedule;
}
super.renounceRole(role, account);
}
/**
* @dev See {AccessControl-_grantRole}.
*
* For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the
* role has been previously renounced.
*
* NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE`
* assignable again. Make sure to guarantee this is the expected behavior in your implementation.
*/
function _grantRole(bytes32 role, address account) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE) {
if (defaultAdmin() != address(0)) {
revert AccessControlEnforcedDefaultAdminRules();
}
_currentDefaultAdmin = account;
}
super._grantRole(role, account);
}
/**
* @dev See {AccessControl-_revokeRole}.
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
delete _currentDefaultAdmin;
}
super._revokeRole(role, account);
}
/**
* @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super._setRoleAdmin(role, adminRole);
}
///
/// AccessControlDefaultAdminRules accessors
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdmin() public view virtual returns (address) {
return _currentDefaultAdmin;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelay() public view virtual returns (uint48) {
uint48 schedule = _pendingDelaySchedule;
return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
schedule = _pendingDelaySchedule;
return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
return 5 days;
}
///
/// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_beginDefaultAdminTransfer(newAdmin);
}
/**
* @dev See {beginDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
_setPendingDefaultAdmin(newAdmin, newSchedule);
emit DefaultAdminTransferScheduled(newAdmin, newSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_cancelDefaultAdminTransfer();
}
/**
* @dev See {cancelDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _cancelDefaultAdminTransfer() internal virtual {
_setPendingDefaultAdmin(address(0), 0);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function acceptDefaultAdminTransfer() public virtual {
(address newDefaultAdmin, ) = pendingDefaultAdmin();
if (_msgSender() != newDefaultAdmin) {
// Enforce newDefaultAdmin explicit acceptance.
revert AccessControlInvalidDefaultAdmin(_msgSender());
}
_acceptDefaultAdminTransfer();
}
/**
* @dev See {acceptDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _acceptDefaultAdminTransfer() internal virtual {
(address newAdmin, uint48 schedule) = pendingDefaultAdmin();
if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
revert AccessControlEnforcedDefaultAdminDelay(schedule);
}
_revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
_grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
delete _pendingDefaultAdmin;
delete _pendingDefaultAdminSchedule;
}
///
/// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_changeDefaultAdminDelay(newDelay);
}
/**
* @dev See {changeDefaultAdminDelay}.
*
* Internal function without access restriction.
*/
function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {
uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);
_setPendingDelay(newDelay, newSchedule);
emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_rollbackDefaultAdminDelay();
}
/**
* @dev See {rollbackDefaultAdminDelay}.
*
* Internal function without access restriction.
*/
function _rollbackDefaultAdminDelay() internal virtual {
_setPendingDelay(0, 0);
}
/**
* @dev Returns the amount of seconds to wait after the `newDelay` will
* become the new {defaultAdminDelay}.
*
* The value returned guarantees that if the delay is reduced, it will go into effect
* after a wait that honors the previously set delay.
*
* See {defaultAdminDelayIncreaseWait}.
*/
function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {
uint48 currentDelay = defaultAdminDelay();
// When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up
// to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day
// to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new
// delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like
// using milliseconds instead of seconds.
//
// When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees
// that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled.
// For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days.
return
newDelay > currentDelay
? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48
: currentDelay - newDelay;
}
///
/// Private setters
///
/**
* @dev Setter of the tuple for pending admin and its schedule.
*
* May emit a DefaultAdminTransferCanceled event.
*/
function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {
(, uint48 oldSchedule) = pendingDefaultAdmin();
_pendingDefaultAdmin = newAdmin;
_pendingDefaultAdminSchedule = newSchedule;
// An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.
if (_isScheduleSet(oldSchedule)) {
// Emit for implicit cancellations when another default admin was scheduled.
emit DefaultAdminTransferCanceled();
}
}
/**
* @dev Setter of the tuple for pending delay and its schedule.
*
* May emit a DefaultAdminDelayChangeCanceled event.
*/
function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {
uint48 oldSchedule = _pendingDelaySchedule;
if (_isScheduleSet(oldSchedule)) {
if (_hasSchedulePassed(oldSchedule)) {
// Materialize a virtual delay
_currentDelay = _pendingDelay;
} else {
// Emit for implicit cancellations when another delay was scheduled.
emit DefaultAdminDelayChangeCanceled();
}
}
_pendingDelay = newDelay;
_pendingDelaySchedule = newSchedule;
}
///
/// Private helpers
///
/**
* @dev Defines if an `schedule` is considered set. For consistency purposes.
*/
function _isScheduleSet(uint48 schedule) private pure returns (bool) {
return schedule != 0;
}
/**
* @dev Defines if an `schedule` is considered passed. For consistency purposes.
*/
function _hasSchedulePassed(uint48 schedule) private view returns (bool) {
return schedule < block.timestamp;
}
}

View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.19;
import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol";
import {AccessControl} from "../AccessControl.sol";
import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_roleMembers[role].remove(account);
}
}

View File

@ -0,0 +1,192 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/IAccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.19;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection.
*/
interface IAccessControlDefaultAdminRules is IAccessControl {
/**
* @dev The new default admin is not a valid default admin.
*/
error AccessControlInvalidDefaultAdmin(address defaultAdmin);
/**
* @dev At least one of the following rules was violated:
*
* - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.
* - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.
* - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.
*/
error AccessControlEnforcedDefaultAdminRules();
/**
* @dev The delay for transferring the default admin delay is enforced and
* the operation must wait until `schedule`.
*
* NOTE: `schedule` can be 0 indicating there's no transfer scheduled.
*/
error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);
/**
* @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next
* address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`
* passes.
*/
event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);
/**
* @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule.
*/
event DefaultAdminTransferCanceled();
/**
* @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next
* delay to be applied between default admin transfer after `effectSchedule` has passed.
*/
event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);
/**
* @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass.
*/
event DefaultAdminDelayChangeCanceled();
/**
* @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder.
*/
function defaultAdmin() external view returns (address);
/**
* @dev Returns a tuple of a `newAdmin` and an accept schedule.
*
* After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role
* by calling {acceptDefaultAdminTransfer}, completing the role transfer.
*
* A zero value only in `acceptSchedule` indicates no pending admin transfer.
*
* NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced.
*/
function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule);
/**
* @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started.
*
* This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set
* the acceptance schedule.
*
* NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this
* function returns the new delay. See {changeDefaultAdminDelay}.
*/
function defaultAdminDelay() external view returns (uint48);
/**
* @dev Returns a tuple of `newDelay` and an effect schedule.
*
* After the `schedule` passes, the `newDelay` will get into effect immediately for every
* new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}.
*
* A zero value only in `effectSchedule` indicates no pending delay change.
*
* NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay}
* will be zero after the effect schedule.
*/
function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule);
/**
* @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance
* after the current timestamp plus a {defaultAdminDelay}.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* Emits a DefaultAdminRoleChangeStarted event.
*/
function beginDefaultAdminTransfer(address newAdmin) external;
/**
* @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
*
* A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* May emit a DefaultAdminTransferCanceled event.
*/
function cancelDefaultAdminTransfer() external;
/**
* @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
*
* After calling the function:
*
* - `DEFAULT_ADMIN_ROLE` should be granted to the caller.
* - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder.
* - {pendingDefaultAdmin} should be reset to zero values.
*
* Requirements:
*
* - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`.
* - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed.
*/
function acceptDefaultAdminTransfer() external;
/**
* @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting
* into effect after the current timestamp plus a {defaultAdminDelay}.
*
* This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this
* method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay}
* set before calling.
*
* The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then
* calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin}
* complete transfer (including acceptance).
*
* The schedule is designed for two scenarios:
*
* - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by
* {defaultAdminDelayIncreaseWait}.
* - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`.
*
* A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event.
*/
function changeDefaultAdminDelay(uint48 newDelay) external;
/**
* @dev Cancels a scheduled {defaultAdminDelay} change.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* May emit a DefaultAdminDelayChangeCanceled event.
*/
function rollbackDefaultAdminDelay() external;
/**
* @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay})
* to take effect. Default to 5 days.
*
* When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with
* the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds)
* that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can
* be overrode for a custom {defaultAdminDelay} increase scheduling.
*
* IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise,
* there's a risk of setting a high new delay that goes into effect almost immediately without the
* possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds).
*/
function defaultAdminDelayIncreaseWait() external view returns (uint48);
}

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.19;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}