AccessControlEnumerable.sol 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/AccessControlEnumerable.sol)
  3. pragma solidity ^0.8.20;
  4. import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol";
  5. import {AccessControl} from "../AccessControl.sol";
  6. import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol";
  7. import {IERC165} from "../../utils/introspection/ERC165.sol";
  8. /**
  9. * @dev Extension of {AccessControl} that allows enumerating the members of each role.
  10. */
  11. abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
  12. using EnumerableSet for EnumerableSet.AddressSet;
  13. mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers;
  14. /// @inheritdoc IERC165
  15. function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
  16. return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
  17. }
  18. /**
  19. * @dev Returns one of the accounts that have `role`. `index` must be a
  20. * value between 0 and {getRoleMemberCount}, non-inclusive.
  21. *
  22. * Role bearers are not sorted in any particular way, and their ordering may
  23. * change at any point.
  24. *
  25. * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
  26. * you perform all queries on the same block. See the following
  27. * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
  28. * for more information.
  29. */
  30. function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
  31. return _roleMembers[role].at(index);
  32. }
  33. /**
  34. * @dev Returns the number of accounts that have `role`. Can be used
  35. * together with {getRoleMember} to enumerate all bearers of a role.
  36. */
  37. function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
  38. return _roleMembers[role].length();
  39. }
  40. /**
  41. * @dev Return all accounts that have `role`
  42. *
  43. * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
  44. * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
  45. * this function has an unbounded cost, and using it as part of a state-changing function may render the function
  46. * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
  47. */
  48. function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
  49. return _roleMembers[role].values();
  50. }
  51. /**
  52. * @dev Overload {AccessControl-_grantRole} to track enumerable memberships
  53. */
  54. function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
  55. bool granted = super._grantRole(role, account);
  56. if (granted) {
  57. _roleMembers[role].add(account);
  58. }
  59. return granted;
  60. }
  61. /**
  62. * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
  63. */
  64. function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
  65. bool revoked = super._revokeRole(role, account);
  66. if (revoked) {
  67. _roleMembers[role].remove(account);
  68. }
  69. return revoked;
  70. }
  71. }