Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions src/AccessControl/AccessControlFacet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.30;

contract AccessControlFacet {

/// @notice Emitted when the admin role for a role is changed.
/// @param _role The role that was changed.
/// @param _previousAdminRole The previous admin role.
/// @param _newAdminRole The new admin role.
event RoleAdminChanged(bytes32 indexed _role, bytes32 indexed _previousAdminRole, bytes32 indexed _newAdminRole);

/// @notice Emitted when a role is granted to an account.
/// @param _role The role that was granted.
/// @param _account The account that was granted the role.
/// @param _sender The sender that granted the role.
event RoleGranted(bytes32 indexed _role, address indexed _account, address indexed _sender);

/// @notice Emitted when a role is revoked from an account.
/// @param _role The role that was revoked.
/// @param _account The account from which the role was revoked.
/// @param _sender The account that revoked the role.
event RoleRevoked(bytes32 indexed _role, address indexed _account, address indexed _sender);

/// @notice Thrown when the account does not have a specific role.
/// @param _role The role that the account does not have.
/// @param _account The account that does not have the role.
error AccessControlUnauthorizedAccount(address _account, bytes32 _role);

/// @notice Thrown when the sender is not the account to renounce the role from.
/// @param _sender The sender that is not the account to renounce the role from.
/// @param _account The account to renounce the role from.
error AccessControlUnauthorizedSender(address _sender, address _account);

/// @notice Storage slot identifier.
bytes32 constant STORAGE_POSITION = keccak256("compose.accesscontrol");

/// @notice Default admin role.
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00;

/// @notice storage struct for the AccessControl.
struct AccessControlStorage {
mapping(address account => mapping(bytes32 role => bool hasRole)) hasRole;
mapping(bytes32 role => bytes32 adminRole) adminRole;
}

/// @notice Returns the storage for the AccessControl.
/// @return s The storage for the AccessControl.
function getStorage() internal pure returns (AccessControlStorage storage s) {
bytes32 position = STORAGE_POSITION;
assembly {
s.slot := position
}
}

/// @notice Returns if an account has a role.
/// @param _role The role to check.
/// @param _account The account to check the role for.
/// @return True if the account has the role, false otherwise.
function hasRole(bytes32 _role, address _account) external view returns(bool){
AccessControlStorage storage s = getStorage();
return s.hasRole[_account][_role];
}


/// @notice Checks if an account has a required role.
/// @param _role The role to check.
/// @param _account The account to check the role for.
/// @custom:error AccessControlUnauthorizedAccount If the account does not have the role.
function requireRole(bytes32 _role, address _account) external view {
AccessControlStorage storage s = getStorage();
if (!s.hasRole[_account][_role]){
revert AccessControlUnauthorizedAccount(_account, _role);
}
}

/// @notice Returns the admin role for a role.
/// @param _role The role to get the admin for.
/// @return The admin role for the role.
function getRoleAdmin(bytes32 _role) external view returns(bytes32){
AccessControlStorage storage s = getStorage();
return s.adminRole[_role];
}


/// @notice Grants a role to an account.
/// @param _role The role to grant.
/// @param _account The account to grant the role to.
/// @dev Emits a {RoleGranted} event.
/// @custom:error AccessControlUnauthorizedAccount If the caller is not the admin of the role.
function grantRole(bytes32 _role, address _account) external {
AccessControlStorage storage s = getStorage();
bytes32 adminRole = s.adminRole[_role];

// Check if the caller is the admin of the role.
if (!s.hasRole[msg.sender][adminRole]){
revert AccessControlUnauthorizedAccount(msg.sender, adminRole);
}

bool _hasRole = s.hasRole[_account][_role];
if (!_hasRole) {
s.hasRole[_account][_role] = true;
emit RoleGranted(_role, _account, msg.sender);
}
}

/// @notice Revokes a role from an account.
/// @param _role The role to revoke.
/// @param _account The account to revoke the role from.
/// @dev Emits a {RoleRevoked} event.
/// @custom:error AccessControlUnauthorizedAccount If the caller is not the admin of the role.
function revokeRole(bytes32 _role, address _account) external {
AccessControlStorage storage s = getStorage();
bytes32 adminRole = s.adminRole[_role];

// Check if the caller is the admin of the role.
if (!s.hasRole[msg.sender][adminRole]){
revert AccessControlUnauthorizedAccount(msg.sender, adminRole);
}

bool _hasRole = s.hasRole[_account][_role];
if (_hasRole) {
s.hasRole[_account][_role] = false;
emit RoleRevoked(_role, _account, msg.sender);
}
}


/// @notice Renounces a role from the caller.
/// @param _role The role to renounce.
/// @param _account The account to renounce the role from.
/// @dev Emits a {RoleRevoked} event.
/// @custom:error AccessControlUnauthorizedSender If the caller is not the account to renounce the role from.
function renounceRole(bytes32 _role, address _account) external {
AccessControlStorage storage s = getStorage();

// Check If the caller is not the account to renounce the role from.
if(msg.sender != _account){
revert AccessControlUnauthorizedSender(msg.sender, _account);
}
bool _hasRole = s.hasRole[_account][_role];
if (_hasRole) {
s.hasRole[_account][_role] = false;
emit RoleRevoked(_role, _account, msg.sender);
}
}

}
113 changes: 113 additions & 0 deletions src/AccessControl/libraries/LibAccessControl.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.30;

library LibAccessControl {

/// @notice Emitted when the admin role for a role is changed.
/// @param _role The role that was changed.
/// @param _previousAdminRole The previous admin role.
/// @param _newAdminRole The new admin role.
event RoleAdminChanged(bytes32 indexed _role, bytes32 indexed _previousAdminRole, bytes32 indexed _newAdminRole);

/// @notice Emitted when a role is granted to an account.
/// @param _role The role that was granted.
/// @param _account The account that was granted the role.
/// @param _sender The sender that granted the role.
event RoleGranted(bytes32 indexed _role, address indexed _account, address indexed _sender);

/// @notice Emitted when a role is revoked from an account.
/// @param _role The role that was revoked.
/// @param _account The account from which the role was revoked.
/// @param _sender The account that revoked the role.
event RoleRevoked(bytes32 indexed _role, address indexed _account, address indexed _sender);

/// @notice Thrown when the account does not have a specific role.
/// @param _role The role that the account does not have.
/// @param _account The account that does not have the role.
error AccessControlUnauthorizedAccount(address _account, bytes32 _role);

/// @notice Storage slot identifier.
bytes32 constant STORAGE_POSITION = keccak256("compose.accesscontrol");

/// @notice Default admin role.
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00;

/// @notice storage struct for the AccessControl.
struct AccessControlStorage {
mapping(address account => mapping(bytes32 role => bool hasRole)) hasRole;
mapping(bytes32 role => bytes32 adminRole) adminRole;
}

/// @notice Returns the storage for the AccessControl.
/// @return _s The storage for the AccessControl.
function getStorage() internal pure returns (AccessControlStorage storage _s) {
bytes32 position = STORAGE_POSITION;
assembly {
_s.slot := position
}
}

/// @notice function to check if an account has a required role.
/// @param _role The role to assert.
/// @param _account The account to assert the role for.
/// @custom:error AccessControlUnauthorizedAccount If the account does not have the role.
function requireRole(bytes32 _role, address _account) internal view {
AccessControlStorage storage s = getStorage();
if (!s.hasRole[_account][_role]){
revert AccessControlUnauthorizedAccount(_account, _role);
}
}

/// @notice function to check if an account has a role.
/// @param _role The role to check.
/// @param _account The account to check the role for.
/// @return True if the account has the role, false otherwise.
function hasRole(bytes32 _role, address _account) internal view returns (bool) {
AccessControlStorage storage s = getStorage();
return s.hasRole[_account][_role];
}

/// @notice function to set the admin role for a role.
/// @param _role The role to set the admin for.
/// @param _adminRole The admin role to set.
function setRoleAdmin(bytes32 _role, bytes32 _adminRole) internal {
AccessControlStorage storage s = getStorage();
bytes32 previousAdminRole = s.adminRole[_role];
s.adminRole[_role] = _adminRole;
emit RoleAdminChanged(_role, previousAdminRole, _adminRole);
}

/// @notice function to grant a role to an account.
/// @param _role The role to grant.
/// @param _account The account to grant the role to.
/// @return True if the role was granted, false otherwise.
function grantRole(bytes32 _role, address _account) internal returns (bool) {
AccessControlStorage storage s = getStorage();
bool _hasRole = s.hasRole[_account][_role];
if (!_hasRole) {
s.hasRole[_account][_role] = true;
emit RoleGranted(_role, _account, msg.sender);
return true;
} else {
return false;
}
}

/// @notice function to revoke a role from an account.
/// @param _role The role to revoke.
/// @param _account The account to revoke the role from.
/// @return True if the role was revoked, false otherwise.
function revokeRole(bytes32 _role, address _account) internal returns (bool) {
AccessControlStorage storage s = getStorage();
bool _hasRole = s.hasRole[_account][_role];
if (_hasRole) {
s.hasRole[_account][_role] = false;
emit RoleRevoked(_role, _account, msg.sender);
return true;
} else {
return false;
}
}


}
Loading