// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {Auth, Authority} from "../Auth.sol"; /// @notice Flexible and target agnostic role based Authority that supports up to 256 roles. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/authorities/MultiRolesAuthority.sol) contract MultiRolesAuthority is Auth, Authority { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event UserRoleUpdated(address indexed user, uint8 indexed role, bool enabled); event PublicCapabilityUpdated(bytes4 indexed functionSig, bool enabled); event RoleCapabilityUpdated(uint8 indexed role, bytes4 indexed functionSig, bool enabled); event TargetCustomAuthorityUpdated(address indexed target, Authority indexed authority); /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(address _owner, Authority _authority) Auth(_owner, _authority) {} /*////////////////////////////////////////////////////////////// CUSTOM TARGET AUTHORITY STORAGE //////////////////////////////////////////////////////////////*/ mapping(address => Authority) public getTargetCustomAuthority; /*////////////////////////////////////////////////////////////// ROLE/USER STORAGE //////////////////////////////////////////////////////////////*/ mapping(address => bytes32) public getUserRoles; mapping(bytes4 => bool) public isCapabilityPublic; mapping(bytes4 => bytes32) public getRolesWithCapability; function doesUserHaveRole(address user, uint8 role) public view virtual returns (bool) { return (uint256(getUserRoles[user]) >> role) & 1 != 0; } function doesRoleHaveCapability(uint8 role, bytes4 functionSig) public view virtual returns (bool) { return (uint256(getRolesWithCapability[functionSig]) >> role) & 1 != 0; } /*////////////////////////////////////////////////////////////// AUTHORIZATION LOGIC //////////////////////////////////////////////////////////////*/ function canCall( address user, address target, bytes4 functionSig ) public view virtual override returns (bool) { Authority customAuthority = getTargetCustomAuthority[target]; if (address(customAuthority) != address(0)) return customAuthority.canCall(user, target, functionSig); return isCapabilityPublic[functionSig] || bytes32(0) != getUserRoles[user] & getRolesWithCapability[functionSig]; } /*/////////////////////////////////////////////////////////////// CUSTOM TARGET AUTHORITY CONFIGURATION LOGIC //////////////////////////////////////////////////////////////*/ function setTargetCustomAuthority(address target, Authority customAuthority) public virtual requiresAuth { getTargetCustomAuthority[target] = customAuthority; emit TargetCustomAuthorityUpdated(target, customAuthority); } /*////////////////////////////////////////////////////////////// PUBLIC CAPABILITY CONFIGURATION LOGIC //////////////////////////////////////////////////////////////*/ function setPublicCapability(bytes4 functionSig, bool enabled) public virtual requiresAuth { isCapabilityPublic[functionSig] = enabled; emit PublicCapabilityUpdated(functionSig, enabled); } /*////////////////////////////////////////////////////////////// USER ROLE ASSIGNMENT LOGIC //////////////////////////////////////////////////////////////*/ function setUserRole( address user, uint8 role, bool enabled ) public virtual requiresAuth { if (enabled) { getUserRoles[user] |= bytes32(1 << role); } else { getUserRoles[user] &= ~bytes32(1 << role); } emit UserRoleUpdated(user, role, enabled); } /*////////////////////////////////////////////////////////////// ROLE CAPABILITY CONFIGURATION LOGIC //////////////////////////////////////////////////////////////*/ function setRoleCapability( uint8 role, bytes4 functionSig, bool enabled ) public virtual requiresAuth { if (enabled) { getRolesWithCapability[functionSig] |= bytes32(1 << role); } else { getRolesWithCapability[functionSig] &= ~bytes32(1 << role); } emit RoleCapabilityUpdated(role, functionSig, enabled); } }