@layerzerolabs/utils-upgradeable-evm-contracts 0.2.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-lint.log +491 -0
- package/.turbo/turbo-test.log +1356 -0
- package/LICENSE +23 -0
- package/contracts/access/AccessControl2StepUpgradeable.sol +144 -0
- package/contracts/allowlist/AllowlistBaseUpgradeable.sol +184 -0
- package/contracts/allowlist/AllowlistRBACUpgradeable.sol +55 -0
- package/contracts/fee-accounting/FeeHandlerBaseUpgradeable.sol +69 -0
- package/contracts/fee-accounting/FeeHandlerRBACUpgradeable.sol +34 -0
- package/contracts/fee-config/FeeConfigBaseUpgradeable.sol +128 -0
- package/contracts/fee-config/FeeConfigRBACUpgradeable.sol +44 -0
- package/contracts/libs/EnumerableSetPagination.sol +77 -0
- package/contracts/pause/PauseBaseUpgradeable.sol +107 -0
- package/contracts/pause/PauseRBACUpgradeable.sol +47 -0
- package/contracts/pause-by-id/PauseByIDBaseUpgradeable.sol +127 -0
- package/contracts/pause-by-id/PauseByIDRBACUpgradeable.sol +74 -0
- package/contracts/rate-limiter/RateLimiterBaseUpgradeable.sol +636 -0
- package/contracts/rate-limiter/RateLimiterRBACUpgradeable.sol +89 -0
- package/contracts/rate-limiter/libs/RateLimiterUtils.sol +82 -0
- package/foundry.toml +27 -0
- package/package.json +34 -0
- package/solhint.config.js +3 -0
- package/test/AccessControl2StepUpgradeable.t.sol +374 -0
- package/test/AllowlistBaseUpgradeable.t.sol +380 -0
- package/test/AllowlistRBACUpgradeable.t.sol +84 -0
- package/test/EnumerableSetPagination.t.sol +445 -0
- package/test/FeeConfigBaseUpgradeable.t.sol +232 -0
- package/test/FeeConfigRBACUpgradeable.t.sol +59 -0
- package/test/FeeHandlerBaseUpgradeable.t.sol +78 -0
- package/test/FeeHandlerRBACUpgradeable.t.sol +45 -0
- package/test/PauseBaseUpgradeable.t.sol +244 -0
- package/test/PauseByIDBaseUpgradeable.t.sol +337 -0
- package/test/PauseByIDRBACUpgradeable.t.sol +414 -0
- package/test/PauseRBACUpgradeable.t.sol +258 -0
- package/test/RateLimiterBaseUpgradeable.t.sol +826 -0
- package/test/RateLimiterRBACUpgradeable.t.sol +128 -0
- package/test/RateLimiterRBACUpgradeableInvariant.t.sol +444 -0
- package/test/RateLimiterUtils.t.sol +137 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IPauseByID } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IPauseByID.sol";
|
|
5
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
|
|
7
|
+
import { ERC1967Utils } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
|
|
8
|
+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
9
|
+
import { PauseByIDRBACUpgradeable } from "./../contracts/pause-by-id/PauseByIDRBACUpgradeable.sol";
|
|
10
|
+
import { PauseByIDBaseUpgradeableTest, IPauseByIDBaseMock } from "./PauseByIDBaseUpgradeable.t.sol";
|
|
11
|
+
|
|
12
|
+
contract PauseByIDRBACUpgradeableMock is PauseByIDRBACUpgradeable {
|
|
13
|
+
uint256 public callCount;
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
_disableInitializers();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function initialize(address _initialAdmin) public initializer {
|
|
20
|
+
__AccessControl2Step_init(_initialAdmin);
|
|
21
|
+
_grantRole(PAUSER_ROLE, _initialAdmin);
|
|
22
|
+
_grantRole(UNPAUSER_ROLE, _initialAdmin);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function assertNotPaused(uint256 _id) public view {
|
|
26
|
+
_assertNotPaused(_id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function functionWithModifier(uint256 _id) public whenNotPaused(_id) {
|
|
30
|
+
callCount++;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function functionWithModifierReturns(uint256 _id) public view whenNotPaused(_id) returns (uint256) {
|
|
34
|
+
return 42;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
contract PauseByIDRBACUpgradeableTest is PauseByIDBaseUpgradeableTest {
|
|
39
|
+
address alice = makeAddr("alice");
|
|
40
|
+
address proxyAdmin;
|
|
41
|
+
|
|
42
|
+
function _createPause() internal virtual override returns (IPauseByIDBaseMock) {
|
|
43
|
+
PauseByIDRBACUpgradeableMock impl = new PauseByIDRBACUpgradeableMock();
|
|
44
|
+
|
|
45
|
+
uint256 currentNonce = vm.getNonce(address(this));
|
|
46
|
+
proxyAdmin = vm.computeCreateAddress(vm.computeCreateAddress(address(this), currentNonce), 1);
|
|
47
|
+
|
|
48
|
+
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
|
49
|
+
address(impl),
|
|
50
|
+
address(this),
|
|
51
|
+
abi.encodeWithSelector(PauseByIDRBACUpgradeableMock.initialize.selector, address(this))
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
bytes32 adminSlot = vm.load(address(proxy), ERC1967Utils.ADMIN_SLOT);
|
|
55
|
+
proxyAdmin = address(uint160(uint256(adminSlot)));
|
|
56
|
+
|
|
57
|
+
return IPauseByIDBaseMock(address(proxy));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function setUp() public override {
|
|
61
|
+
pauseHelper = _createPause();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// @dev `PauseByIDRBACUpgradeableMock.initialize(address)` has a different signature.
|
|
65
|
+
function test_initialize_Revert_AlreadyInitialized() public virtual override {
|
|
66
|
+
vm.expectRevert(Initializable.InvalidInitialization.selector);
|
|
67
|
+
PauseByIDRBACUpgradeableMock(address(pauseHelper)).initialize(alice);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function test_setDefaultPaused_Success() public {
|
|
71
|
+
pauseHelper.setDefaultPaused(true);
|
|
72
|
+
assertTrue(pauseHelper.defaultPaused());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function test_setDefaultPaused_Revert_Unauthorized() public {
|
|
76
|
+
bytes32 pauserRole = PauseByIDRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE();
|
|
77
|
+
vm.expectRevert(
|
|
78
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, pauserRole)
|
|
79
|
+
);
|
|
80
|
+
vm.prank(alice);
|
|
81
|
+
pauseHelper.setDefaultPaused(true);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function test_setPaused_Success() public {
|
|
85
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
86
|
+
params[0] = IPauseByID.SetPausedParam(1, true, true);
|
|
87
|
+
pauseHelper.setPaused(params);
|
|
88
|
+
assertTrue(pauseHelper.isPaused(1));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function test_setPaused_Revert_Unauthorized() public {
|
|
92
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
93
|
+
params[0] = IPauseByID.SetPausedParam(1, true, true);
|
|
94
|
+
|
|
95
|
+
bytes32 pauserRole = PauseByIDRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE();
|
|
96
|
+
vm.expectRevert(
|
|
97
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, pauserRole)
|
|
98
|
+
);
|
|
99
|
+
vm.prank(alice);
|
|
100
|
+
pauseHelper.setPaused(params);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function test_setPaused_Success_Batch() public {
|
|
104
|
+
pauseHelper.setDefaultPaused(true);
|
|
105
|
+
assertTrue(pauseHelper.defaultPaused());
|
|
106
|
+
|
|
107
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
108
|
+
params[0] = IPauseByID.SetPausedParam(1, false, true);
|
|
109
|
+
pauseHelper.setPaused(params);
|
|
110
|
+
assertFalse(pauseHelper.isPaused(1));
|
|
111
|
+
|
|
112
|
+
params[0] = IPauseByID.SetPausedParam(2, true, true);
|
|
113
|
+
pauseHelper.setPaused(params);
|
|
114
|
+
assertTrue(pauseHelper.isPaused(2));
|
|
115
|
+
|
|
116
|
+
pauseHelper.setDefaultPaused(false);
|
|
117
|
+
assertFalse(pauseHelper.defaultPaused());
|
|
118
|
+
|
|
119
|
+
IPauseByID.SetPausedParam[] memory batchParams = new IPauseByID.SetPausedParam[](10);
|
|
120
|
+
for (uint32 i = 0; i < 10; i++) {
|
|
121
|
+
batchParams[i] = IPauseByID.SetPausedParam(i + 10, (i + 10) % 2 == 0, true);
|
|
122
|
+
}
|
|
123
|
+
pauseHelper.setPaused(batchParams);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function test_setPaused_Revert_UnpauserCannotCauseEffectivePause() public {
|
|
127
|
+
// `defaultPaused=true` and `enabled=false`.
|
|
128
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
129
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
130
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
131
|
+
|
|
132
|
+
// Set default to paused.
|
|
133
|
+
pauseHelper.setDefaultPaused(true);
|
|
134
|
+
|
|
135
|
+
// Grant only `UNPAUSER_ROLE` to `alice`.
|
|
136
|
+
mock.grantRole(unpauserRole, alice);
|
|
137
|
+
|
|
138
|
+
// `alice` tries to set `enabled=false` with `paused=false` — effective state is paused.
|
|
139
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
140
|
+
params[0] = IPauseByID.SetPausedParam(1, false, false);
|
|
141
|
+
|
|
142
|
+
vm.expectRevert(
|
|
143
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, pauserRole)
|
|
144
|
+
);
|
|
145
|
+
vm.prank(alice);
|
|
146
|
+
pauseHelper.setPaused(params);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function test_setPaused_Revert_PauserCannotCauseEffectiveUnpause() public {
|
|
150
|
+
// `defaultPaused=false` and `enabled=false`.
|
|
151
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
152
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
153
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
154
|
+
|
|
155
|
+
// Default is already false (unpaused).
|
|
156
|
+
assertFalse(pauseHelper.defaultPaused());
|
|
157
|
+
|
|
158
|
+
// Grant only `PAUSER_ROLE` to `alice`.
|
|
159
|
+
mock.grantRole(pauserRole, alice);
|
|
160
|
+
|
|
161
|
+
// `alice` tries to set `enabled=false` with `paused=true` — effective state is unpaused.
|
|
162
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
163
|
+
params[0] = IPauseByID.SetPausedParam(1, true, false);
|
|
164
|
+
|
|
165
|
+
vm.expectRevert(
|
|
166
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, unpauserRole)
|
|
167
|
+
);
|
|
168
|
+
vm.prank(alice);
|
|
169
|
+
pauseHelper.setPaused(params);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function test_setPaused_Success_PauserCanSetDisabledWhenDefaultPaused() public {
|
|
173
|
+
// `defaultPaused=true` and `enabled=false`.
|
|
174
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
175
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
176
|
+
|
|
177
|
+
// Set default to paused.
|
|
178
|
+
pauseHelper.setDefaultPaused(true);
|
|
179
|
+
|
|
180
|
+
// Grant only `PAUSER_ROLE` to `alice`.
|
|
181
|
+
mock.grantRole(pauserRole, alice);
|
|
182
|
+
|
|
183
|
+
// `alice` sets `enabled=false` — effective state is paused, so `PAUSER_ROLE` suffices.
|
|
184
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
185
|
+
params[0] = IPauseByID.SetPausedParam(1, false, false);
|
|
186
|
+
|
|
187
|
+
vm.prank(alice);
|
|
188
|
+
pauseHelper.setPaused(params);
|
|
189
|
+
|
|
190
|
+
assertTrue(pauseHelper.isPaused(1));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function test_setPaused_Success_UnpauserCanSetDisabledWhenDefaultUnpaused() public {
|
|
194
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
195
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
196
|
+
|
|
197
|
+
// Default is already false (unpaused).
|
|
198
|
+
assertFalse(pauseHelper.defaultPaused());
|
|
199
|
+
|
|
200
|
+
// Grant only `UNPAUSER_ROLE` to `alice`.
|
|
201
|
+
mock.grantRole(unpauserRole, alice);
|
|
202
|
+
|
|
203
|
+
// `alice` sets `enabled=false` — effective state is unpaused (from default), so `UNPAUSER_ROLE` suffices.
|
|
204
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
205
|
+
params[0] = IPauseByID.SetPausedParam(1, true, false);
|
|
206
|
+
|
|
207
|
+
vm.prank(alice);
|
|
208
|
+
pauseHelper.setPaused(params);
|
|
209
|
+
|
|
210
|
+
assertFalse(pauseHelper.isPaused(1));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function test_setPaused_Revert_MixedBatchWithDisabledConfigs_NeedsBothRoles() public {
|
|
214
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
215
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
216
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
217
|
+
|
|
218
|
+
// Set default to paused.
|
|
219
|
+
pauseHelper.setDefaultPaused(true);
|
|
220
|
+
|
|
221
|
+
// Grant only `PAUSER_ROLE` to `alice`.
|
|
222
|
+
mock.grantRole(pauserRole, alice);
|
|
223
|
+
|
|
224
|
+
// Batch: one explicitly unpauses (`enabled=true`, `paused=false`), one falls back to default paused (`enabled=false`).
|
|
225
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](2);
|
|
226
|
+
params[0] = IPauseByID.SetPausedParam(1, false, true); // effective: unpaused → needs `UNPAUSER_ROLE`
|
|
227
|
+
params[1] = IPauseByID.SetPausedParam(2, false, false); // effective: paused (default) → needs `PAUSER_ROLE`
|
|
228
|
+
|
|
229
|
+
vm.expectRevert(
|
|
230
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, unpauserRole)
|
|
231
|
+
);
|
|
232
|
+
vm.prank(alice);
|
|
233
|
+
pauseHelper.setPaused(params);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function test_setPaused_Success_MixedBatchWithDisabledConfigs_BothRoles() public {
|
|
237
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
238
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
239
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
240
|
+
|
|
241
|
+
// Set default to paused.
|
|
242
|
+
pauseHelper.setDefaultPaused(true);
|
|
243
|
+
|
|
244
|
+
// Grant both roles to `alice`.
|
|
245
|
+
mock.grantRole(pauserRole, alice);
|
|
246
|
+
mock.grantRole(unpauserRole, alice);
|
|
247
|
+
|
|
248
|
+
// Batch: one explicitly unpauses, one falls back to default paused.
|
|
249
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](2);
|
|
250
|
+
params[0] = IPauseByID.SetPausedParam(1, false, true); // effective: unpaused
|
|
251
|
+
params[1] = IPauseByID.SetPausedParam(2, false, false); // effective: paused (default)
|
|
252
|
+
|
|
253
|
+
vm.prank(alice);
|
|
254
|
+
pauseHelper.setPaused(params);
|
|
255
|
+
|
|
256
|
+
assertFalse(pauseHelper.isPaused(1));
|
|
257
|
+
assertTrue(pauseHelper.isPaused(2));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/// @dev Dormant data planted by one role cannot be activated without the other role.
|
|
261
|
+
function test_setPaused_DormantData() public {
|
|
262
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
263
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
264
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
265
|
+
|
|
266
|
+
address frank = address(0x456);
|
|
267
|
+
mock.grantRole(unpauserRole, alice);
|
|
268
|
+
mock.grantRole(pauserRole, frank);
|
|
269
|
+
|
|
270
|
+
// `defaultPaused=false`. `UNPAUSER_ROLE` stores dormant `paused=true` (`enabled=false`).
|
|
271
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
272
|
+
params[0] = IPauseByID.SetPausedParam(1, true, false);
|
|
273
|
+
vm.prank(alice);
|
|
274
|
+
pauseHelper.setPaused(params);
|
|
275
|
+
assertFalse(pauseHelper.isPaused(1));
|
|
276
|
+
assertTrue(pauseHelper.pauseConfig(1).paused);
|
|
277
|
+
|
|
278
|
+
// `UNPAUSER_ROLE` cannot activate dormant `paused=true`.
|
|
279
|
+
params[0] = IPauseByID.SetPausedParam(1, true, true);
|
|
280
|
+
vm.expectRevert(
|
|
281
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, pauserRole)
|
|
282
|
+
);
|
|
283
|
+
vm.prank(alice);
|
|
284
|
+
pauseHelper.setPaused(params);
|
|
285
|
+
|
|
286
|
+
// `PAUSER_ROLE` can activate it.
|
|
287
|
+
vm.prank(frank);
|
|
288
|
+
pauseHelper.setPaused(params);
|
|
289
|
+
assertTrue(pauseHelper.isPaused(1));
|
|
290
|
+
|
|
291
|
+
// Symmetric: `defaultPaused=true`. `PAUSER_ROLE` stores dormant `paused=false` (`enabled=false`).
|
|
292
|
+
pauseHelper.setDefaultPaused(true);
|
|
293
|
+
params[0] = IPauseByID.SetPausedParam(2, false, false);
|
|
294
|
+
vm.prank(frank);
|
|
295
|
+
pauseHelper.setPaused(params);
|
|
296
|
+
assertTrue(pauseHelper.isPaused(2));
|
|
297
|
+
|
|
298
|
+
// `PAUSER_ROLE` cannot activate dormant `paused=false`.
|
|
299
|
+
params[0] = IPauseByID.SetPausedParam(2, false, true);
|
|
300
|
+
vm.expectRevert(
|
|
301
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, frank, unpauserRole)
|
|
302
|
+
);
|
|
303
|
+
vm.prank(frank);
|
|
304
|
+
pauseHelper.setPaused(params);
|
|
305
|
+
|
|
306
|
+
// `UNPAUSER_ROLE` can activate it.
|
|
307
|
+
vm.prank(alice);
|
|
308
|
+
pauseHelper.setPaused(params);
|
|
309
|
+
assertFalse(pauseHelper.isPaused(2));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function test_setPaused_EmptyArrayWithUnpauserRole() public {
|
|
313
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
314
|
+
|
|
315
|
+
mock.grantRole(mock.UNPAUSER_ROLE(), alice);
|
|
316
|
+
|
|
317
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](0);
|
|
318
|
+
|
|
319
|
+
vm.prank(alice);
|
|
320
|
+
pauseHelper.setPaused(params);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function test_setPaused_Revert_EmptyArrayUnauthorized() public {
|
|
324
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
325
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
326
|
+
|
|
327
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](0);
|
|
328
|
+
|
|
329
|
+
vm.expectRevert(
|
|
330
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, alice, unpauserRole)
|
|
331
|
+
);
|
|
332
|
+
vm.prank(alice);
|
|
333
|
+
pauseHelper.setPaused(params);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/// @dev Correct role succeeds, wrong role reverts, for all effective-state combinations.
|
|
337
|
+
function test_setPaused_Fuzz_EffectiveStateRoleCheck(bool _defaultPaused, bool _paused, bool _enabled) public {
|
|
338
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
339
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
340
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
341
|
+
|
|
342
|
+
if (_defaultPaused) {
|
|
343
|
+
pauseHelper.setDefaultPaused(true);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
bool effectivePaused = _enabled ? _paused : _defaultPaused;
|
|
347
|
+
|
|
348
|
+
IPauseByID.SetPausedParam[] memory params = new IPauseByID.SetPausedParam[](1);
|
|
349
|
+
params[0] = IPauseByID.SetPausedParam(1, _paused, _enabled);
|
|
350
|
+
|
|
351
|
+
// Wrong role reverts.
|
|
352
|
+
address wrongCaller = address(0xBAD);
|
|
353
|
+
if (effectivePaused) {
|
|
354
|
+
mock.grantRole(unpauserRole, wrongCaller);
|
|
355
|
+
} else {
|
|
356
|
+
mock.grantRole(pauserRole, wrongCaller);
|
|
357
|
+
}
|
|
358
|
+
bytes32 missingRole = effectivePaused ? pauserRole : unpauserRole;
|
|
359
|
+
vm.expectRevert(
|
|
360
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, wrongCaller, missingRole)
|
|
361
|
+
);
|
|
362
|
+
vm.prank(wrongCaller);
|
|
363
|
+
pauseHelper.setPaused(params);
|
|
364
|
+
|
|
365
|
+
// Correct role succeeds.
|
|
366
|
+
if (effectivePaused) {
|
|
367
|
+
mock.grantRole(pauserRole, alice);
|
|
368
|
+
} else {
|
|
369
|
+
mock.grantRole(unpauserRole, alice);
|
|
370
|
+
}
|
|
371
|
+
vm.prank(alice);
|
|
372
|
+
pauseHelper.setPaused(params);
|
|
373
|
+
assertEq(pauseHelper.isPaused(1), effectivePaused);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function test_roleManagement_grantAndRevoke() public {
|
|
377
|
+
address newPauser = address(0x123);
|
|
378
|
+
PauseByIDRBACUpgradeableMock mock = PauseByIDRBACUpgradeableMock(address(pauseHelper));
|
|
379
|
+
bytes32 pauserRole = mock.PAUSER_ROLE();
|
|
380
|
+
bytes32 unpauserRole = mock.UNPAUSER_ROLE();
|
|
381
|
+
|
|
382
|
+
mock.grantRole(pauserRole, newPauser);
|
|
383
|
+
|
|
384
|
+
// `newPauser` can now pause.
|
|
385
|
+
vm.prank(newPauser);
|
|
386
|
+
pauseHelper.setDefaultPaused(true);
|
|
387
|
+
assertTrue(pauseHelper.defaultPaused());
|
|
388
|
+
|
|
389
|
+
// But `newPauser` cannot unpause (needs `UNPAUSER_ROLE`).
|
|
390
|
+
vm.expectRevert(
|
|
391
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, newPauser, unpauserRole)
|
|
392
|
+
);
|
|
393
|
+
vm.prank(newPauser);
|
|
394
|
+
pauseHelper.setDefaultPaused(false);
|
|
395
|
+
|
|
396
|
+
// Grant `UNPAUSER_ROLE` to `newPauser`.
|
|
397
|
+
mock.grantRole(unpauserRole, newPauser);
|
|
398
|
+
|
|
399
|
+
// Now `newPauser` can unpause.
|
|
400
|
+
vm.prank(newPauser);
|
|
401
|
+
pauseHelper.setDefaultPaused(false);
|
|
402
|
+
assertFalse(pauseHelper.defaultPaused());
|
|
403
|
+
|
|
404
|
+
// Revoke `PAUSER_ROLE`.
|
|
405
|
+
mock.revokeRole(pauserRole, newPauser);
|
|
406
|
+
|
|
407
|
+
// `newPauser` can no longer pause.
|
|
408
|
+
vm.expectRevert(
|
|
409
|
+
abi.encodeWithSelector(IAccessControl.AccessControlUnauthorizedAccount.selector, newPauser, pauserRole)
|
|
410
|
+
);
|
|
411
|
+
vm.prank(newPauser);
|
|
412
|
+
pauseHelper.setDefaultPaused(true);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IPause } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IPause.sol";
|
|
5
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
|
|
7
|
+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
8
|
+
import { PauseRBACUpgradeable } from "./../contracts/pause/PauseRBACUpgradeable.sol";
|
|
9
|
+
import { PauseBaseUpgradeableTest, IPauseTestHelper } from "./PauseBaseUpgradeable.t.sol";
|
|
10
|
+
|
|
11
|
+
contract PauseRBACUpgradeableMock is PauseRBACUpgradeable {
|
|
12
|
+
uint256 public callCount;
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
_disableInitializers();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function initialize(address _initialAdmin) public initializer {
|
|
19
|
+
__AccessControl2Step_init(_initialAdmin);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function assertNotPaused() public view {
|
|
23
|
+
_assertNotPaused();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function functionWithModifier() public whenNotPaused {
|
|
27
|
+
callCount++;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function functionWithModifierReturns() public view whenNotPaused returns (uint256) {
|
|
31
|
+
return 42;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
contract PauseRBACUpgradeableTest is PauseBaseUpgradeableTest {
|
|
36
|
+
address alice = makeAddr("alice");
|
|
37
|
+
address proxyAdmin;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @dev Override parent test since `PauseRBACUpgradeableMock.initialize(address)` has a different signature.
|
|
41
|
+
*/
|
|
42
|
+
function test_initialize_Revert_AlreadyInitialized() public override {
|
|
43
|
+
vm.expectRevert(Initializable.InvalidInitialization.selector);
|
|
44
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).initialize(address(0x999));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function setUp() public override {
|
|
48
|
+
PauseRBACUpgradeableMock impl = new PauseRBACUpgradeableMock();
|
|
49
|
+
|
|
50
|
+
uint256 currentNonce = vm.getNonce(address(this));
|
|
51
|
+
proxyAdmin = vm.computeCreateAddress(vm.computeCreateAddress(address(this), currentNonce), 1);
|
|
52
|
+
|
|
53
|
+
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
|
54
|
+
address(impl),
|
|
55
|
+
address(this),
|
|
56
|
+
abi.encodeWithSelector(PauseRBACUpgradeableMock.initialize.selector, address(this))
|
|
57
|
+
);
|
|
58
|
+
pauseHelper = IPauseTestHelper(address(proxy));
|
|
59
|
+
|
|
60
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
61
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
62
|
+
address(this)
|
|
63
|
+
);
|
|
64
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
65
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).UNPAUSER_ROLE(),
|
|
66
|
+
address(this)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function test_setPaused_Revert_Unauthorized() public {
|
|
71
|
+
vm.expectRevert(
|
|
72
|
+
abi.encodeWithSelector(
|
|
73
|
+
IAccessControl.AccessControlUnauthorizedAccount.selector,
|
|
74
|
+
alice,
|
|
75
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE()
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
vm.prank(alice);
|
|
79
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function test_setPaused_Success() public {
|
|
83
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
84
|
+
assertTrue(pauseHelper.isPaused());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function test_roleTransfer_GrantAndRevoke() public {
|
|
88
|
+
address newAdmin = address(0x123);
|
|
89
|
+
|
|
90
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
91
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
92
|
+
newAdmin
|
|
93
|
+
);
|
|
94
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
95
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).UNPAUSER_ROLE(),
|
|
96
|
+
newAdmin
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
100
|
+
|
|
101
|
+
vm.prank(newAdmin);
|
|
102
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
103
|
+
assertFalse(pauseHelper.isPaused());
|
|
104
|
+
|
|
105
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).revokeRole(
|
|
106
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
107
|
+
address(this)
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
vm.expectRevert(
|
|
111
|
+
abi.encodeWithSelector(
|
|
112
|
+
IAccessControl.AccessControlUnauthorizedAccount.selector,
|
|
113
|
+
address(this),
|
|
114
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE()
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function test_renounceRole_Success_FunctionsRevert() public {
|
|
121
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).renounceRole(
|
|
122
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
123
|
+
address(this)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
vm.expectRevert(
|
|
127
|
+
abi.encodeWithSelector(
|
|
128
|
+
IAccessControl.AccessControlUnauthorizedAccount.selector,
|
|
129
|
+
address(this),
|
|
130
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE()
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
134
|
+
|
|
135
|
+
vm.expectRevert(
|
|
136
|
+
abi.encodeWithSelector(
|
|
137
|
+
IAccessControl.AccessControlUnauthorizedAccount.selector,
|
|
138
|
+
alice,
|
|
139
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE()
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
vm.prank(alice);
|
|
143
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function test_multipleRoleGrants() public {
|
|
147
|
+
address admin1 = address(0x111);
|
|
148
|
+
address admin2 = address(0x222);
|
|
149
|
+
address admin3 = address(0x333);
|
|
150
|
+
|
|
151
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
152
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
153
|
+
admin1
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
vm.prank(admin1);
|
|
157
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
158
|
+
assertTrue(pauseHelper.isPaused());
|
|
159
|
+
|
|
160
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
161
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
162
|
+
admin2
|
|
163
|
+
);
|
|
164
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
165
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).UNPAUSER_ROLE(),
|
|
166
|
+
admin2
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
vm.prank(admin2);
|
|
170
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
171
|
+
assertFalse(pauseHelper.isPaused());
|
|
172
|
+
|
|
173
|
+
vm.prank(admin1);
|
|
174
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
175
|
+
assertTrue(pauseHelper.isPaused());
|
|
176
|
+
|
|
177
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).revokeRole(
|
|
178
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
179
|
+
admin1
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
vm.expectRevert(
|
|
183
|
+
abi.encodeWithSelector(
|
|
184
|
+
IAccessControl.AccessControlUnauthorizedAccount.selector,
|
|
185
|
+
admin1,
|
|
186
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).UNPAUSER_ROLE()
|
|
187
|
+
)
|
|
188
|
+
);
|
|
189
|
+
vm.prank(admin1);
|
|
190
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
191
|
+
|
|
192
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
193
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).PAUSER_ROLE(),
|
|
194
|
+
admin3
|
|
195
|
+
);
|
|
196
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).grantRole(
|
|
197
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).UNPAUSER_ROLE(),
|
|
198
|
+
admin3
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
vm.prank(admin3);
|
|
202
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
203
|
+
assertFalse(pauseHelper.isPaused());
|
|
204
|
+
|
|
205
|
+
vm.prank(admin2);
|
|
206
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
207
|
+
assertTrue(pauseHelper.isPaused());
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function test_setPaused_Success_MultipleOperations() public {
|
|
211
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
212
|
+
assertTrue(pauseHelper.isPaused());
|
|
213
|
+
|
|
214
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
215
|
+
assertFalse(pauseHelper.isPaused());
|
|
216
|
+
|
|
217
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
218
|
+
assertTrue(pauseHelper.isPaused());
|
|
219
|
+
|
|
220
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
221
|
+
assertFalse(pauseHelper.isPaused());
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function test_initialize_Revert_AlreadyInitialized_AdminUnchanged() public {
|
|
225
|
+
vm.expectRevert(Initializable.InvalidInitialization.selector);
|
|
226
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).initialize(address(0x999));
|
|
227
|
+
|
|
228
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
229
|
+
assertTrue(pauseHelper.isPaused());
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function test_modifierEnforcement_WithRoles() public {
|
|
233
|
+
PauseRBACUpgradeableMock mock = PauseRBACUpgradeableMock(address(pauseHelper));
|
|
234
|
+
|
|
235
|
+
mock.functionWithModifier();
|
|
236
|
+
assertEq(mock.callCount(), 1);
|
|
237
|
+
|
|
238
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).pause();
|
|
239
|
+
|
|
240
|
+
vm.expectRevert(abi.encodeWithSelector(IPause.Paused.selector));
|
|
241
|
+
mock.functionWithModifier();
|
|
242
|
+
assertEq(mock.callCount(), 1);
|
|
243
|
+
|
|
244
|
+
address newAdmin = address(0xabc);
|
|
245
|
+
mock.grantRole(mock.PAUSER_ROLE(), newAdmin);
|
|
246
|
+
mock.grantRole(mock.UNPAUSER_ROLE(), newAdmin);
|
|
247
|
+
|
|
248
|
+
vm.expectRevert(abi.encodeWithSelector(IPause.Paused.selector));
|
|
249
|
+
mock.functionWithModifier();
|
|
250
|
+
assertEq(mock.callCount(), 1);
|
|
251
|
+
|
|
252
|
+
vm.prank(newAdmin);
|
|
253
|
+
PauseRBACUpgradeableMock(address(pauseHelper)).unpause();
|
|
254
|
+
|
|
255
|
+
mock.functionWithModifier();
|
|
256
|
+
assertEq(mock.callCount(), 2);
|
|
257
|
+
}
|
|
258
|
+
}
|