This repository was archived by the owner on Oct 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Draft: AccessControls basics (WIP) #7
Draft
Yashiru
wants to merge
4
commits into
master
Choose a base branch
from
access-control
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
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,167 @@ | ||
| /// @title AccessControl | ||
| /// @author Yashiru <https://github.com/Yashiru> | ||
| /// @dev Contract module that allows children to implement role-based access control | ||
| /// mechanisms. | ||
| /// | ||
| /// Roles are referred to by their `bytes32` identifier. These should be exposed | ||
| /// in the external API and be unique. The best way to achieve this is by | ||
| /// using `constant`: | ||
| /// | ||
| /// ``` | ||
| /// #define constant ADMIN_ROLE = 0xa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775 | ||
| /// ``` | ||
| /// | ||
| /// Roles can be used to represent a set of permissions. To restrict access to a | ||
| /// function call, use HAS_ROLE() in your MAIN jumps: | ||
| /// | ||
| /// ``` | ||
| /// jumpDest1: | ||
| /// MACRO_ONE() | ||
| /// jumpDest2: | ||
| /// MACRO_TWO() | ||
| /// jumpDest3: | ||
| /// HAS_ROLE(caller, ADMIN_ROLE) | ||
| /// MACRO_THREE() | ||
| /// ``` | ||
| /// | ||
| /// Roles can be granted and revoked dynamically via the GRANT_ROLE and | ||
| /// REVOKE_ROLE macros. Each role has an associated admin role, and only | ||
| /// accounts that have a role's admin role can call GRANT_ROLE and REVOKE_ROLE. | ||
| /// | ||
| /// By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means | ||
| /// that only accounts with this role will be able to grant or revoke other | ||
| /// roles. More complex role relationships can be created by using | ||
| /// _SET_ROLE_ADMIN. | ||
| /// | ||
| /// WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to | ||
| /// grant and revoke this role. Extra precautions should be taken to secure | ||
| /// accounts that have been granted it. | ||
|
|
||
| /* Imports */ | ||
| #include "../utils/Map.huff" | ||
| #include "../utils/Require.huff" | ||
|
|
||
| #define function test() nonpayable returns () | ||
|
|
||
| /// @dev Default admin role | ||
| /// keccak256("DEFAULT_ADMIN_ROLE") | ||
| #define constant DEFAULT_ADMIN_ROLE = 0x1effbbff9c66c5e59634f24fe842750c60d18891155c32dd155fc2d661a4c86d | ||
|
|
||
| /* Custom errors */ | ||
| #define error CallerDoesNotHaveRequiredRole() | ||
|
|
||
| /* CONSTRUCTOR */ | ||
| /// @dev GRANT the DEFAULT_ADMIN_ROLE to the caller. | ||
| /// ⚠️ This macro should be caller only in the constructor of a child | ||
| /// contract. | ||
| #define macro ACCESS_CONSTRUCTOR() = takes (0) returns (0) { | ||
| 0x01 [DEFAULT_ADMIN_ROLE] caller STORE_ELEMENT_FROM_KEYS(0x00) | ||
|
Yashiru marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /// @dev Macro that checks that the caller has a specific role. | ||
| /// Reverts with a standardized Error. | ||
| /// @param role The role that the caller must have | ||
| #define macro ONLY_ROLE(role) = takes(1) returns (0) { | ||
| caller | ||
| CHECK_ROLE() | ||
| } | ||
|
|
||
| /// @dev Macro that grant a role to an account. The caller must be an admin | ||
| /// of the role to grant. | ||
| /// | ||
| /// @param role The role to grant to the target account | ||
| #define macro GRANT_ROLE(role) = takes(1) returns (0) { | ||
| // Input stack: [account] | ||
| _GET_ROLE_ADMIN(<role>) // [role_admin, account] | ||
| caller // [caller, role_admin, account] | ||
| CHECK_ROLE() // [account] | ||
|
|
||
| <role> // [role_to_grant, account] | ||
| 0x01 // [0x01, role_to_grant, account] | ||
| swap2 // [account, role_to_grant, 0x01] | ||
|
|
||
| STORE_ELEMENT_FROM_KEYS(0x00) // [] | ||
| } | ||
|
|
||
| /// @dev Macro that revoke a role to an account. The caller must be an admin | ||
| /// of the role to revoke. | ||
| /// | ||
| /// @param role The role to revoke to the target account | ||
| #define macro REVOKE_ROLE(role) = takes(1) returns (0) { | ||
| // Input stack: [account] | ||
| _GET_ROLE_ADMIN(<role>) // [role_admin, account] | ||
| caller // [caller, role_admin, account] | ||
| CHECK_ROLE() // [account] | ||
|
|
||
| <role> // [role_to_revoke, account] | ||
| 0x00 // [0x00, role_to_revoke, account] | ||
| swap2 // [account, role_to_revoke, 0x01] | ||
|
|
||
| STORE_ELEMENT_FROM_KEYS(0x00) // [] | ||
| } | ||
|
|
||
| /// @dev Macro that allow caller to renouce his role a role to an account. | ||
| /// The caller must have the role he want to renounce. | ||
| /// | ||
| /// @param role The role the caller want to renounce | ||
| #define macro RENOUNCE_ROLE(role) = takes(1) returns (0) { | ||
| <role> // [role] | ||
| caller // [caller, role] | ||
| CHECK_ROLE() // [] | ||
|
|
||
| 0x00 // [0x00] | ||
| <role> // [role, 0x00] | ||
| caller // [caller, role, 0x00] | ||
|
|
||
| STORE_ELEMENT_FROM_KEYS(0x00) // [] | ||
| } | ||
|
|
||
| /// @dev Macro that checks that an account has a specific role. | ||
| /// Reverts with a standardized message including the required role. | ||
| /// | ||
| #define macro CHECK_ROLE() = takes(2) returns (0) { | ||
| /// Input stack: [account, role] | ||
| dup1 swap2 swap1 // [account, role, account] | ||
| LOAD_ELEMENT_FROM_KEYS(0x00) // [account_has_role, account] | ||
|
|
||
| swap1 [DEFAULT_ADMIN_ROLE] swap1 // [account, default_admin_role, account_has_role] | ||
| LOAD_ELEMENT_FROM_KEYS(0x00) // [account_is_admin, account_has_role] | ||
|
|
||
| or // [acount_is_admin_or_has_role] | ||
|
|
||
| __ERROR(CallerDoesNotHaveRequiredRole) swap1 | ||
| REQUIRE() | ||
| } | ||
|
|
||
| /// @dev Macro that check if an account as the specified role or not. | ||
| /// Push 0 or 1 onto the stack. | ||
| #define macro HAS_ROLE(role) = takes(1) returns (1) { | ||
| // Input stack: [account] | ||
| <role> swap1 // [account, role] | ||
| LOAD_ELEMENT_FROM_KEYS(0x00) // [account_has_role] | ||
| } | ||
|
|
||
| /// @dev Macro that pushes the administrator role of the provided role | ||
| /// onto the stack. | ||
| #define macro GET_ROLE_ADMIN(role) = takes(0) returns (1) { | ||
| <role> // [role] | ||
| LOAD_ELEMENT(0x00) // [role_admin] | ||
| } | ||
|
|
||
| /// @dev Macro that push onto the the admin role of a role. | ||
| #define macro SET_ROLE_ADMIN(role) = takes(0) returns (1) { | ||
| // Input stack: [role_admin] | ||
| [DEFAULT_ADMIN_ROLE] // [default_admin_role, role_admin] | ||
| caller // [caller, default_admin_role, role_admin] | ||
| CHECK_ROLE() // [, role_admin] | ||
|
|
||
| <role> // [role, role_admin] | ||
| STORE_ELEMENT(0x00) // [] | ||
| } | ||
|
|
||
| #define macro MAIN() = takes(0) returns(0) { | ||
| ACCESS_CONSTRUCTOR() | ||
| 0x654131 | ||
| caller | ||
| CHECK_ROLE() | ||
| } | ||
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,4 @@ | ||
| interface IAccessControl { | ||
| error CallerDoesNotHaveRequiredRole(); | ||
| function test() external; | ||
| } |
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
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
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,26 @@ | ||
| // SPDX-License-Identifier: Unlicense | ||
| pragma solidity ^0.8.16; | ||
|
|
||
| import "foundry-huff/HuffDeployer.sol"; | ||
| import "forge-std/Test.sol"; | ||
| import "forge-std/console.sol"; | ||
| import "test/Constants.sol"; | ||
|
|
||
| import {IAccessControl} from "../../src/access/IAccessControl.sol"; | ||
| import {ITestAccessControl} from "../interfaces/ITestAccessControl.sol"; | ||
|
|
||
| contract AccessControl is Test, ITestAccessControl { | ||
| /// @dev Address of the SimpleStore contract. | ||
| IAccessControl public accessControl; | ||
|
|
||
| /// @dev Setup the testing environment. | ||
| function setUp() public { | ||
| accessControl = IAccessControl(HuffDeployer.deploy( | ||
| "access/AccessControl" | ||
| )); | ||
| } | ||
|
|
||
| function testAccess() public { | ||
| accessControl.test(); | ||
| } | ||
| } |
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,3 @@ | ||
| interface ITestAccessControl { | ||
| error CallerDoseNotHaveRequiredRole(); | ||
| } |
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.