Skip to content
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

♻️ Make AccessControl Module-Friendly #216

Merged
merged 8 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
948 changes: 474 additions & 474 deletions .gas-snapshot

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## [`0.1.0`](https://github.com/pcaversaccio/snekmate/releases/tag/v0.0.1) (Unreleased)

### ♻️ Refactoring

- **Authentication**
- [`AccessControl`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/auth/AccessControl.vy): Make `AccessControl` module-friendly. ([#216](https://github.com/pcaversaccio/snekmate/pull/216))

### 👀 Full Changelog

- [`v0.0.5...v0.1.0`](https://github.com/pcaversaccio/snekmate/compare/v0.0.5...v0.1.0)
Expand Down
6 changes: 4 additions & 2 deletions GUIDELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Any addition or change to the code must be accompanied by relevant and comprehen

The test suite should run automatically for each change in the repository, and for pull requests, the tests must succeed before merging.

Please consider writing [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. fuzzing), and invariant tests for all contracts, if applicable.
Please consider writing [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. stateless fuzzing), and invariant tests (i.e. stateful fuzzing) for all contracts, if applicable.

## 🪅 Code Style

Expand Down Expand Up @@ -71,7 +71,9 @@ def _as_singleton_array(element: uint256) -> DynArray[uint256, 1]:
- All functions should be provided with full [NatSpec](https://docs.vyperlang.org/en/latest/natspec.html) comments containing the tags `@dev`, `@notice` (if applicable), `@param` for each function parameter, and `@return` if a return statement is present.
- Please note the following order of layout:
- Version pragma statement
- Interface imports
- Vyper built-in interface imports
- Custom interface imports
- Module imports
- `public` constants
- `internal` constants
- `public` immutables
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pnpm add --save-dev snekmate

## 👩🏼‍⚖️ Tests

This repository contains [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. fuzzing), and invariant tests for all contracts, if applicable. All tests are run as part of the CI pipeline [`test-contracts`](./.github/workflows/test-contracts.yml).
This repository contains [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. stateless fuzzing), and invariant tests (i.e. stateful fuzzing) for all contracts, if applicable. All tests are run as part of the CI pipeline [`test-contracts`](./.github/workflows/test-contracts.yml).

> [!NOTE]
> An _invariant_ is a property of a program that should always hold true. Fuzzing is a way of checking whether the invariant is falsifiable.
Expand Down
18 changes: 0 additions & 18 deletions src/snekmate/auth/AccessControl.vy
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,6 @@ implements: IAccessControl
DEFAULT_ADMIN_ROLE: public(constant(bytes32)) = empty(bytes32)


# @dev An additional 32-byte access role.
# @notice Please adjust the naming of the variable
# according to your specific requirement,
# e.g. `MINTER_ROLE`.
ADDITIONAL_ROLE_1: public(constant(bytes32)) = keccak256("ADDITIONAL_ROLE_1")


# @dev An additional 32-byte access role.
# @notice Please adjust the naming of the variable
# according to your specific requirement,
# e.g. `PAUSER_ROLE`. Also, feel free to add more
# roles if necessary. In this case, it is important
# to extend the constructor accordingly.
ADDITIONAL_ROLE_2: public(constant(bytes32)) = keccak256("ADDITIONAL_ROLE_2")


# @dev Stores the ERC-165 interface identifier for each
# imported interface. The ERC-165 interface identifier
# is defined as the XOR of all function selectors in the
Expand Down Expand Up @@ -147,8 +131,6 @@ def __init__():
the `msg.sender`.
"""
self._grant_role(DEFAULT_ADMIN_ROLE, msg.sender)
pcaversaccio marked this conversation as resolved.
Show resolved Hide resolved
self._grant_role(ADDITIONAL_ROLE_1, msg.sender)
self._grant_role(ADDITIONAL_ROLE_2, msg.sender)


@external
Expand Down
70 changes: 70 additions & 0 deletions src/snekmate/auth/mocks/AccessControlMock.vy
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# pragma version ~=0.4.0b5
"""
@title AccessControl Module Reference Implementation
@custom:contract-name AccessControlMock
@license GNU Affero General Public License v3.0 only
@author pcaversaccio
"""


# @dev We import and implement the `IERC165` interface,
# which is a built-in interface of the Vyper compiler.
from ethereum.ercs import IERC165
implements: IERC165


# @dev We import and implement the `IAccessControl`
# interface, which is written using standard Vyper
# syntax.
from ..interfaces import IAccessControl
implements: IAccessControl


# @dev We import and initialise the `AccessControl` module.
from .. import AccessControl as ac
initializes: ac


# @dev An additional 32-byte access role.
ADDITIONAL_ROLE_1: public(constant(bytes32)) = keccak256("ADDITIONAL_ROLE_1")


# @dev An additional 32-byte access role.
ADDITIONAL_ROLE_2: public(constant(bytes32)) = keccak256("ADDITIONAL_ROLE_2")


# @dev We export (i.e. the runtime bytecode exposes these
# functions externally, allowing them to be called using
# the ABI encoding specification) all `external` functions
# from the `AccessControl` module.
# @notice Please note that you must always also export (if
# required by the contract logic) `public` declared `constant`,
# `immutable`, and state variables, for which Vyper automatically
# generates an `external` getter function for the variable.
exports: (
ac.supportsInterface,
ac.DEFAULT_ADMIN_ROLE,
ac.hasRole,
ac.getRoleAdmin,
ac.grantRole,
ac.revokeRole,
ac.renounceRole,
ac.set_role_admin,
)


@deploy
@payable
def __init__():
"""
@dev To omit the opcodes for checking the `msg.value`
in the creation-time EVM bytecode, the constructor
is declared as `payable`.
@notice All predefined roles will be assigned to
the `msg.sender`.
"""
# The following line assigns the `DEFAULT_ADMIN_ROLE`
# to the `msg.sender`.
ac.__init__()
ac._grant_role(ADDITIONAL_ROLE_1, msg.sender)
ac._grant_role(ADDITIONAL_ROLE_2, msg.sender)
19 changes: 14 additions & 5 deletions test/auth/AccessControl.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ contract AccessControlTest is Test {

function setUp() public {
accessControl = IAccessControlExtended(
vyperDeployer.deployContract("src/snekmate/auth/", "AccessControl")
vyperDeployer.deployContract(
"src/snekmate/auth/mocks/",
"AccessControlMock"
)
);
}

Expand Down Expand Up @@ -54,7 +57,10 @@ contract AccessControlTest is Test {
vm.expectEmit(true, true, true, false);
emit IAccessControl.RoleGranted(ADDITIONAL_ROLE_2, deployer, deployer);
accessControlInitialEvent = IAccessControlExtended(
vyperDeployer.deployContract("src/snekmate/auth/", "AccessControl")
vyperDeployer.deployContract(
"src/snekmate/auth/mocks/",
"AccessControlMock"
)
);
assertEq(
accessControlInitialEvent.DEFAULT_ADMIN_ROLE(),
Expand Down Expand Up @@ -645,7 +651,10 @@ contract AccessControlInvariants is Test {

function setUp() public {
accessControl = IAccessControlExtended(
vyperDeployer.deployContract("src/snekmate/auth/", "AccessControl")
vyperDeployer.deployContract(
"src/snekmate/auth/mocks/",
"AccessControlMock"
)
);
accessControlHandler = new AccessControlHandler(
accessControl,
Expand All @@ -657,7 +666,7 @@ contract AccessControlInvariants is Test {
targetContract(address(accessControlHandler));
}

function invariantHasRole() public view {
function statefulFuzzHasRole() public view {
assertEq(
accessControl.hasRole(DEFAULT_ADMIN_ROLE, deployer),
accessControlHandler.hasRole(DEFAULT_ADMIN_ROLE, deployer)
Expand All @@ -672,7 +681,7 @@ contract AccessControlInvariants is Test {
);
}

function invariantGetRoleAdmin() public view {
function statefulFuzzGetRoleAdmin() public view {
assertEq(
accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE),
accessControlHandler.getRoleAdmin(DEFAULT_ADMIN_ROLE)
Expand Down