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

✨ Add checkOwnerOrRole to EnumerableRoles #1219

Merged
merged 2 commits into from
Dec 9, 2024
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
18 changes: 15 additions & 3 deletions src/auth/EnumerableRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,23 @@ abstract contract EnumerableRoles {
}
}

/// @dev Throws if the sender does not have `role`.
/// @dev Reverts if `msg.sender` does not have `role`.
function _checkRole(uint256 role) internal view virtual {
if (!_hasRole(msg.sender, role)) _revertEnumerableRolesUnauthorized();
}

/// @dev Throws if the sender does not have any roles in `encodedRoles`.
/// @dev Reverts if `msg.sender` does not have any role in `encodedRoles`.
function _checkRoles(bytes memory encodedRoles) internal view virtual {
if (!_hasAnyRoles(msg.sender, encodedRoles)) _revertEnumerableRolesUnauthorized();
}

/// @dev Throws if the sender does not have any roles in `encodedRoles`.
/// @dev Reverts if `msg.sender` is not the contract owner and does not have `role`.
function _checkOwnerOrRole(uint256 role) internal view virtual {
if (!_senderIsContractOwner()) _checkRole(role);
}

/// @dev Reverts if `msg.sender` is not the contract owner and
/// does not have any role in `encodedRoles`.
function _checkOwnerOrRoles(bytes memory encodedRoles) internal view virtual {
if (!_senderIsContractOwner()) _checkRoles(encodedRoles);
}
Expand All @@ -276,6 +282,12 @@ abstract contract EnumerableRoles {
_;
}

/// @dev Marks a function as only callable by the owner or by an account with `role`.
modifier onlyOwnerOrRole(uint256 role) virtual {
_checkOwnerOrRole(role);
_;
}

/// @dev Marks a function as only callable by the owner or
/// by an account with any role in `encodedRoles`.
/// Checks for ownership first, then checks for roles.
Expand Down
19 changes: 19 additions & 0 deletions test/EnumerableRoles.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,25 @@ contract EnumerableRolesTest is SoladyTest {
}
}

function testOnlyOwnerOrRole(uint256 allowedRole, uint256 holderRole) public {
address holder = _randomUniqueHashedAddress();
assertEq(mockEnumerableRoles.owner(), address(this));
if (holder == address(this)) return;
mockEnumerableRoles.setAllowedRole(allowedRole);
mockEnumerableRoles.setRoleDirect(holder, holderRole, true);
if (_randomChance(32)) {
mockEnumerableRoles.guardedByOnlyOwnerOrRole();
}
if (holderRole != allowedRole) {
vm.prank(holder);
vm.expectRevert(EnumerableRoles.EnumerableRolesUnauthorized.selector);
mockEnumerableRoles.guardedByOnlyOwnerOrRole();
} else {
vm.prank(holder);
mockEnumerableRoles.guardedByOnlyOwnerOrRole();
}
}

function testSetAndGetRoles(bytes32) public {
_TestTemps memory t;
t.holders = _sampleUniqueAddresses(_randomUniform() & 7);
Expand Down
9 changes: 9 additions & 0 deletions test/utils/mocks/MockEnumerableRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ contract MockEnumerableRoles is EnumerableRoles, Brutalizer {
address owner;
bool ownerReverts;
bytes allowedRolesEncoded;
uint256 allowedRole;
}

event Yo();
Expand Down Expand Up @@ -57,10 +58,18 @@ contract MockEnumerableRoles is EnumerableRoles, Brutalizer {
$.allowedRolesEncoded = value;
}

function setAllowedRole(uint256 role) public {
$.allowedRole = role;
}

function guardedByOnlyOwnerOrRoles() public onlyOwnerOrRoles($.allowedRolesEncoded) {
emit Yo();
}

function guardedByOnlyOwnerOrRole() public onlyOwnerOrRole($.allowedRole) {
emit Yo();
}

function guardedByOnlyRoles() public onlyRoles($.allowedRolesEncoded) {
emit Yo();
}
Expand Down
Loading