-
Notifications
You must be signed in to change notification settings - Fork 61
Access control facet and lib #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2b1a3af
feat: implemented access control facet and library
Rushikesh0125 43e80ff
fix: exposed assertOnlyRole function
Rushikesh0125 c2805d9
Refactor: refactored error and event names similar to oz
Rushikesh0125 5bb5526
Refactor: refactored facet and lib names
Rushikesh0125 b2ac77d
refactor: refactored assert to require, reorg role data
Rushikesh0125 25d5396
refactor: renamed facet to 'AccessControlFacet' and refactored to fol…
Rushikesh0125 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| // 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); | ||
| } | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| // 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); | ||
Rushikesh0125 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /// @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; | ||
Rushikesh0125 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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); | ||
Rushikesh0125 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /// @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 { | ||
Rushikesh0125 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.