The current AccessManaged
contract exposes only the restricted
modifier to enforce access control on functions. However, this approach limits flexibility, as it doesn't allow for more complex conditional logic (e.g., "allow access only if these conditions are met").
Should all access control be implemented strictly through the restricted
modifier? If so, developers are forced to create multiple function variants in order to apply access restrictions dynamically based on external conditions.
Alternatively, should access be checked directly within the function logic using hasRole()
or similar methods? This would enable more granular control and conditional checks, rather than relying solely on the restricted
modifier upfront.
Here a contract example with both approaches:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {AccessManaged} from 'src/dependencies/openzeppelin/AccessManaged.sol';
library Roles {
uint64 public constant DEFAULT_ADMIN_ROLE = 0;
uint64 public constant UPDATE_PARAM_ROLE = 1;
}
contract TargetContract is AccessManaged {
uint256 public targetParam;
error Unauthorized();
constructor(address accessManager) AccessManaged(accessManager) {}
function updateParamOptionA(uint256 newTargetParam) external {
require(isUpdatable(newTargetParam) || hasUpdateParamRole(msg.sender), Unauthorized());
targetParam = newTargetParam;
}
function updateParamOptionB_1(uint256 newTargetParam) external {
require(isUpdatable(newTargetParam), Unauthorized());
targetParam = newTargetParam;
}
function updateParamOptionB_2(uint256 newTargetParam) external restricted {
targetParam = newTargetParam;
}
/// @dev permissionlessly updatable only if block.number is even, otherwise need role
function isUpdatable(uint256 param) internal view returns (bool) {
return param % 2 == 0;
}
function hasUpdateParamRole(address caller) internal view returns (bool) {
(bool result, ) = IAccessManager(authority()).hasRole(Roles.UPDATE_PARAM_ROLE, caller);
return result;
}
}