Skip to content

Commit f6316ed

Browse files
authored
fix: pausing & unpausing have the same role (#66)
Fixes recallnet/ipc#487
1 parent b242eee commit f6316ed

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

src/token/Recall.sol

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ contract Recall is
3131
bytes32 internal _itsSalt;
3232

3333
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); // solhint-disable-line var-name-mixedcase
34+
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); // solhint-disable-line var-name-mixedcase
3435
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); // solhint-disable-line var-name-mixedcase
3536

3637
/// @custom:oz-upgrades-unsafe-allow constructor
@@ -55,7 +56,9 @@ contract Recall is
5556

5657
_grantRole(ADMIN_ROLE, msg.sender);
5758
_grantRole(MINTER_ROLE, msg.sender);
59+
_grantRole(PAUSER_ROLE, msg.sender);
5860
_setRoleAdmin(MINTER_ROLE, ADMIN_ROLE);
61+
_setRoleAdmin(PAUSER_ROLE, ADMIN_ROLE);
5962
_setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE);
6063
}
6164

@@ -67,7 +70,7 @@ contract Recall is
6770
}
6871

6972
/// @dev Pauses all token transfers
70-
function pause() external onlyRole(ADMIN_ROLE) {
73+
function pause() external onlyRole(PAUSER_ROLE) {
7174
_pause();
7275
}
7376

test/Recall.t.sol

+50
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,54 @@ contract RecallTest is Test {
156156
vm.prank(user);
157157
token.transfer(address(0x456), 100);
158158
}
159+
160+
function testPauserRolePermissions() public {
161+
address pauser = address(0x789);
162+
bytes32 pauserRole = token.PAUSER_ROLE();
163+
bytes32 adminRole = token.ADMIN_ROLE();
164+
165+
// Grant PAUSER_ROLE to new address
166+
vm.prank(TESTER);
167+
token.grantRole(pauserRole, pauser);
168+
169+
// Pauser can pause
170+
vm.prank(pauser);
171+
token.pause();
172+
assertTrue(token.paused());
173+
174+
// Pauser cannot unpause (only ADMIN can)
175+
vm.prank(pauser);
176+
vm.expectRevert(abi.encodeWithSignature("AccessControlUnauthorizedAccount(address,bytes32)", pauser, adminRole));
177+
token.unpause();
178+
179+
// Random address cannot pause
180+
vm.prank(user);
181+
vm.expectRevert(abi.encodeWithSignature("AccessControlUnauthorizedAccount(address,bytes32)", user, pauserRole));
182+
token.pause();
183+
184+
// Admin can unpause
185+
vm.prank(TESTER);
186+
token.unpause();
187+
assertFalse(token.paused());
188+
}
189+
190+
function testRemoveAdminPauserRole() public {
191+
bytes32 pauserRole = token.PAUSER_ROLE();
192+
193+
// Initially admin can pause
194+
vm.prank(TESTER);
195+
token.pause();
196+
assertTrue(token.paused());
197+
198+
// Remove PAUSER_ROLE from admin
199+
vm.prank(TESTER);
200+
token.revokeRole(pauserRole, TESTER);
201+
202+
// Admin can no longer pause after role removal
203+
vm.prank(TESTER);
204+
vm.expectRevert(
205+
abi.encodeWithSignature("AccessControlUnauthorizedAccount(address,bytes32)", TESTER, pauserRole)
206+
);
207+
token.pause();
208+
}
159209
}

0 commit comments

Comments
 (0)