// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; abstract contract Moderatable is AccessControl { using EnumerableSet for EnumerableSet.AddressSet; EnumerableSet.AddressSet private _moderators; bytes32 public constant ROLE_MODERATOR = keccak256("MODERATOR"); event ModeratorAdded(address indexed moderator, uint timestamp); event ModeratorRemoved(address indexed moderator, uint timestamp); constructor() { _moderators.add(_msgSender()); _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); grantRole(ROLE_MODERATOR, _msgSender()); } function addModerator( address moderator ) public onlyRole(DEFAULT_ADMIN_ROLE) { _moderators.add(moderator); grantRole(ROLE_MODERATOR, moderator); emit ModeratorAdded(moderator, block.timestamp); } function removeModerator( address moderator ) public onlyRole(DEFAULT_ADMIN_ROLE) { renounceRole(ROLE_MODERATOR, moderator); _moderators.remove(moderator); emit ModeratorRemoved(moderator, block.timestamp); } function getModerators() public view returns (address[] memory moderators) { return _moderators.values(); } function getModeratorsCount() public view returns (uint256 moderatorCount) { return _moderators.length(); } function isModerator(address moderator) public view returns (bool) { return _moderators.contains(moderator); } }