@zoralabs/limit-orders 0.2.0 → 0.2.2

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.
Files changed (154) hide show
  1. package/.turbo/turbo-build$colon$js.log +50 -49
  2. package/CHANGELOG.md +73 -0
  3. package/abis/ISetLimitOrderConfig.json +27 -0
  4. package/abis/IWETH.json +118 -0
  5. package/abis/IZoraLimitOrderBook.json +5 -0
  6. package/abis/LimitOrderLiquidity.json +7 -0
  7. package/abis/LimitOrderViews.json +62 -0
  8. package/abis/{SimpleAccessManaged.json → Ownable.json} +29 -10
  9. package/abis/Ownable2Step.json +115 -0
  10. package/abis/PermittedCallers.json +181 -0
  11. package/abis/SwapWithLimitOrders.json +134 -14
  12. package/abis/ZoraLimitOrderBook.json +187 -35
  13. package/cache/solidity-files-cache.json +1 -1
  14. package/dist/index.cjs +219 -34
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +219 -34
  17. package/dist/index.js.map +1 -1
  18. package/dist/wagmiGenerated.d.ts +254 -41
  19. package/dist/wagmiGenerated.d.ts.map +1 -1
  20. package/out/BalanceDelta.sol/BalanceDeltaLibrary.json +1 -1
  21. package/out/BeforeSwapDelta.sol/BeforeSwapDeltaLibrary.json +1 -1
  22. package/out/BitMath.sol/BitMath.json +1 -1
  23. package/out/BytesLib.sol/BytesLib.json +1 -1
  24. package/out/CoinCommon.sol/CoinCommon.json +1 -1
  25. package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -1
  26. package/out/CoinConstants.sol/CoinConstants.json +1 -1
  27. package/out/Context.sol/Context.json +1 -1
  28. package/out/Currency.sol/CurrencyLibrary.json +1 -1
  29. package/out/CurrencyReserves.sol/CurrencyReserves.json +1 -1
  30. package/out/CustomRevert.sol/CustomRevert.json +1 -1
  31. package/out/DopplerMath.sol/DopplerMath.json +1 -1
  32. package/out/FixedPoint128.sol/FixedPoint128.json +1 -1
  33. package/out/FixedPoint96.sol/FixedPoint96.json +1 -1
  34. package/out/FullMath.sol/FullMath.json +1 -1
  35. package/out/IAllowanceTransfer.sol/IAllowanceTransfer.json +1 -1
  36. package/out/ICoin.sol/ICoin.json +1 -1
  37. package/out/ICoin.sol/IHasCoinType.json +1 -1
  38. package/out/ICoin.sol/IHasPoolKey.json +1 -1
  39. package/out/ICoin.sol/IHasSwapPath.json +1 -1
  40. package/out/ICoin.sol/IHasTotalSupplyForPositions.json +1 -1
  41. package/out/IDeployedCoinVersionLookup.sol/IDeployedCoinVersionLookup.json +1 -1
  42. package/out/IDopplerErrors.sol/IDopplerErrors.json +1 -1
  43. package/out/IEIP712.sol/IEIP712.json +1 -1
  44. package/out/IERC1363.sol/IERC1363.json +1 -1
  45. package/out/IERC165.sol/IERC165.json +1 -1
  46. package/out/IERC20.sol/IERC20.json +1 -1
  47. package/out/IERC20Minimal.sol/IERC20Minimal.json +1 -1
  48. package/out/IERC6909Claims.sol/IERC6909Claims.json +1 -1
  49. package/out/IERC7572.sol/IERC7572.json +1 -1
  50. package/out/IExtsload.sol/IExtsload.json +1 -1
  51. package/out/IExttload.sol/IExttload.json +1 -1
  52. package/out/IHasRewardsRecipients.sol/IHasRewardsRecipients.json +1 -1
  53. package/out/IHooks.sol/IHooks.json +1 -1
  54. package/out/IMsgSender.sol/IMsgSender.json +1 -1
  55. package/out/IPoolManager.sol/IPoolManager.json +1 -1
  56. package/out/IProtocolFees.sol/IProtocolFees.json +1 -1
  57. package/out/ISetLimitOrderConfig.sol/ISetLimitOrderConfig.json +1 -0
  58. package/out/ISupportsLimitOrderFill.sol/ISupportsLimitOrderFill.json +1 -1
  59. package/out/ISwapPathRouter.sol/ISwapPathRouter.json +1 -1
  60. package/out/ISwapRouter.sol/ISwapRouter.json +1 -1
  61. package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -1
  62. package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4Hook.json +1 -1
  63. package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4HookWithUpdateableFee.json +1 -1
  64. package/out/IUpgradeableV4Hook.sol/IUpgradeableV4Hook.json +1 -1
  65. package/out/IWETH.sol/IWETH.json +1 -0
  66. package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -1
  67. package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -1
  68. package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -1
  69. package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -1
  70. package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -1
  71. package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -1
  72. package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -1
  73. package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -1
  74. package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -1
  75. package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -1
  76. package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -1
  77. package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -1
  78. package/out/LimitOrderViews.sol/LimitOrderViews.json +1 -0
  79. package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -1
  80. package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -1
  81. package/out/LiquidityMath.sol/LiquidityMath.json +1 -1
  82. package/out/Lock.sol/Lock.json +1 -1
  83. package/out/NonzeroDeltaCount.sol/NonzeroDeltaCount.json +1 -1
  84. package/out/Ownable.sol/Ownable.json +1 -0
  85. package/out/Ownable2Step.sol/Ownable2Step.json +1 -0
  86. package/out/Path.sol/Path.json +1 -1
  87. package/out/PathKey.sol/PathKeyLibrary.json +1 -1
  88. package/out/Permit2Payments.sol/Permit2Payments.json +1 -1
  89. package/out/PermittedCallers.sol/PermittedCallers.json +1 -0
  90. package/out/PoolId.sol/PoolIdLibrary.json +1 -1
  91. package/out/Position.sol/Position.json +1 -1
  92. package/out/SafeCast.sol/SafeCast.json +1 -1
  93. package/out/SafeCast160.sol/SafeCast160.json +1 -1
  94. package/out/SafeERC20.sol/SafeERC20.json +1 -1
  95. package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -1
  96. package/out/StateLibrary.sol/StateLibrary.json +1 -1
  97. package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -1
  98. package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -1
  99. package/out/TickBitmap.sol/TickBitmap.json +1 -1
  100. package/out/TickMath.sol/TickMath.json +1 -1
  101. package/out/TransientSlot.sol/TransientSlot.json +1 -1
  102. package/out/TransientStateLibrary.sol/TransientStateLibrary.json +1 -1
  103. package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -1
  104. package/out/UnsafeMath.sol/UnsafeMath.json +1 -1
  105. package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -1
  106. package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -1
  107. package/out/build-info/37e0124d88d60569.json +1 -0
  108. package/out/uniswap/BitMath.sol/BitMath.json +1 -1
  109. package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -1
  110. package/out/uniswap/FullMath.sol/FullMath.json +1 -1
  111. package/out/uniswap/SafeCast.sol/SafeCast.json +1 -1
  112. package/out/uniswap/TickMath.sol/TickMath.json +1 -1
  113. package/package/wagmiGenerated.ts +218 -33
  114. package/package.json +1 -1
  115. package/src/IZoraLimitOrderBook.sol +5 -5
  116. package/src/ZoraLimitOrderBook.sol +24 -41
  117. package/src/access/PermittedCallers.sol +41 -0
  118. package/src/libs/LimitOrderBitmap.sol +0 -51
  119. package/src/libs/LimitOrderCommon.sol +48 -30
  120. package/src/libs/LimitOrderCreate.sol +5 -18
  121. package/src/libs/LimitOrderFill.sol +32 -161
  122. package/src/libs/LimitOrderLiquidity.sol +92 -71
  123. package/src/libs/LimitOrderViews.sol +168 -0
  124. package/src/libs/LimitOrderWithdraw.sol +13 -4
  125. package/src/libs/SwapLimitOrders.sol +14 -7
  126. package/src/router/ISetLimitOrderConfig.sol +12 -0
  127. package/src/router/SwapWithLimitOrders.sol +46 -33
  128. package/test/LimitOrderAccessControl.t.sol +173 -156
  129. package/test/LimitOrderBitmap.t.sol +13 -7
  130. package/test/LimitOrderFill.t.sol +42 -4
  131. package/test/LimitOrderLibraries.t.sol +18 -10
  132. package/test/LimitOrderLiquidityPayouts.t.sol +280 -3
  133. package/test/LimitOrderWithdraw.t.sol +28 -1
  134. package/test/SwapWithLimitOrders.t.sol +3 -5
  135. package/test/SwapWithLimitOrdersRouter.t.sol +108 -13
  136. package/test/gas/LimitOrderFillGas.t.sol +0 -7
  137. package/test/gas/LimitOrderSwapGas.t.sol +0 -6
  138. package/test/unit/LimitOrderBitmapUnit.t.sol +0 -134
  139. package/test/unit/LimitOrderCreateUnit.t.sol +32 -0
  140. package/test/unit/SwapLimitOrdersUnit.t.sol +231 -33
  141. package/test/unit/SwapLimitOrdersValidation.t.sol +28 -42
  142. package/test/unit/SwapWithLimitOrdersUnit.t.sol +21 -88
  143. package/test/utils/BaseTest.sol +34 -22
  144. package/test/utils/MockWETH.sol +39 -0
  145. package/test/utils/TestableZoraLimitOrderBook.sol +5 -7
  146. package/abis/IAuthority.json +0 -31
  147. package/abis/SimpleAccessManager.json +0 -351
  148. package/out/IAuthority.sol/IAuthority.json +0 -1
  149. package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +0 -1
  150. package/out/SimpleAccessManager.sol/SimpleAccessManager.json +0 -1
  151. package/out/build-info/69718f10d1dc37f0.json +0 -1
  152. package/src/access/SimpleAccessManaged.sol +0 -76
  153. package/src/access/SimpleAccessManager.sol +0 -268
  154. package/test/SimpleAccessManager.t.sol +0 -420
@@ -1,268 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.20;
3
-
4
- import {IAuthority} from "@openzeppelin/contracts/access/manager/IAuthority.sol";
5
- import {Context} from "@openzeppelin/contracts/utils/Context.sol";
6
-
7
- /**
8
- * @title SimpleAccessManager
9
- * @author Zora
10
- * @notice A simplified single-contract access manager providing role-based access control
11
- * without time-based validation.
12
- *
13
- * @dev This contract is designed to manage access for a single target contract by mapping
14
- * function selectors directly to required roles. It implements the IAuthority interface
15
- * for compatibility with SimpleAccessManaged contracts.
16
- *
17
- * Key features:
18
- * - Maps function selectors to roles (selector -> roleId)
19
- * - Immediate role grants/revokes (no delays)
20
- * - PUBLIC_ROLE grants access to all addresses
21
- * - ADMIN_ROLE (role 0) can configure function roles and manage other roles
22
- * - Each role can have a custom admin role for delegation
23
- *
24
- * This is intentionally simpler than OpenZeppelin's AccessManager:
25
- * - No execution delays or scheduled operations
26
- * - No guardian role
27
- * - No target address tracking (single-contract authority)
28
- */
29
- contract SimpleAccessManager is Context, IAuthority {
30
- /// @notice The admin role identifier (0). Members can configure function roles and grant other roles.
31
- uint64 public constant ADMIN_ROLE = type(uint64).min;
32
-
33
- /// @notice The public role identifier (max uint64). All addresses implicitly have this role.
34
- uint64 public constant PUBLIC_ROLE = type(uint64).max;
35
-
36
- /// @notice Configuration for setting a function's required role at deployment
37
- /// @param selector The function selector to configure
38
- /// @param roleId The role required to call the function
39
- struct InitialFunctionRole {
40
- bytes4 selector;
41
- uint64 roleId;
42
- }
43
-
44
- /// @dev Maps function selector to the role required to call it
45
- mapping(bytes4 selector => uint64 roleId) private _functionRoles;
46
-
47
- /// @dev Maps role to its members
48
- mapping(uint64 roleId => mapping(address user => bool isMember)) private _roleMembers;
49
-
50
- /// @dev Maps role to its admin role (the role that can grant/revoke it)
51
- mapping(uint64 roleId => uint64 admin) private _roleAdmins;
52
-
53
- /// @notice Emitted when a role is granted to an account
54
- /// @param roleId The role that was granted
55
- /// @param account The account that received the role
56
- event RoleGranted(uint64 indexed roleId, address indexed account);
57
-
58
- /// @notice Emitted when a role is revoked from an account
59
- /// @param roleId The role that was revoked
60
- /// @param account The account that lost the role
61
- event RoleRevoked(uint64 indexed roleId, address indexed account);
62
-
63
- /// @notice Emitted when a role's admin is changed
64
- /// @param roleId The role whose admin changed
65
- /// @param admin The new admin role
66
- event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);
67
-
68
- /// @notice Emitted when a function's required role is updated
69
- /// @param selector The function selector that was configured
70
- /// @param roleId The new required role
71
- event FunctionRoleUpdated(bytes4 indexed selector, uint64 indexed roleId);
72
-
73
- /// @notice Thrown when the initial admin address is invalid (zero address)
74
- /// @param initialAdmin The invalid admin address provided
75
- error AccessManagerInvalidInitialAdmin(address initialAdmin);
76
-
77
- /// @notice Thrown when an account lacks the required role
78
- /// @param account The account that attempted the action
79
- /// @param roleId The role that was required
80
- error AccessManagerUnauthorizedAccount(address account, uint64 roleId);
81
-
82
- /// @notice Thrown when attempting to modify a locked role (ADMIN_ROLE or PUBLIC_ROLE)
83
- /// @param roleId The locked role that was targeted
84
- error AccessManagerLockedRole(uint64 roleId);
85
-
86
- /// @dev Restricts function access to accounts with ADMIN_ROLE.
87
- modifier onlyAdmin() {
88
- if (!hasRole(ADMIN_ROLE, _msgSender())) {
89
- revert AccessManagerUnauthorizedAccount(_msgSender(), ADMIN_ROLE);
90
- }
91
- _;
92
- }
93
-
94
- /// @dev Restricts function access to accounts that have the admin role for the specified role.
95
- /// @param roleId The role whose admin is required to call the function
96
- modifier onlyRoleAdmin(uint64 roleId) {
97
- uint64 adminRole = getRoleAdmin(roleId);
98
- if (!hasRole(adminRole, _msgSender())) {
99
- revert AccessManagerUnauthorizedAccount(_msgSender(), adminRole);
100
- }
101
- _;
102
- }
103
-
104
- /// @notice Initializes the access manager with an admin and optional function role configurations.
105
- /// @dev The initial admin is granted ADMIN_ROLE immediately. Initial function roles allow
106
- /// configuring access permissions at deployment time without additional transactions.
107
- /// @param initialAdmin The address that will receive ADMIN_ROLE (cannot be zero address)
108
- /// @param initialFunctionRoles Array of selector-to-role mappings to configure at deployment
109
- constructor(address initialAdmin, InitialFunctionRole[] memory initialFunctionRoles) {
110
- if (initialAdmin == address(0)) {
111
- revert AccessManagerInvalidInitialAdmin(address(0));
112
- }
113
-
114
- // Admin is active immediately
115
- _grantRole(ADMIN_ROLE, initialAdmin);
116
-
117
- // Set up initial function roles
118
- for (uint256 i = 0; i < initialFunctionRoles.length; ++i) {
119
- _setFunctionRole(initialFunctionRoles[i].selector, initialFunctionRoles[i].roleId);
120
- }
121
- }
122
-
123
- // =================================================== IAuthority ====================================================
124
-
125
- /// @inheritdoc IAuthority
126
- /// @notice Checks if a caller is authorized to invoke a function.
127
- /// @dev The target parameter is ignored since this is a single-contract authority.
128
- /// Returns true if the caller has the role required for the selector, or if the
129
- /// selector is mapped to PUBLIC_ROLE (which all addresses implicitly have).
130
- /// @param caller The address attempting to call the function
131
- /// @param selector The function selector being called
132
- /// @return True if the caller is authorized to call the function
133
- function canCall(
134
- address caller,
135
- address,
136
- /* target */
137
- bytes4 selector
138
- ) external view override returns (bool) {
139
- uint64 roleId = _functionRoles[selector];
140
- return hasRole(roleId, caller);
141
- }
142
-
143
- // =================================================== GETTERS ====================================================
144
-
145
- /// @notice Returns the role required to call a specific function.
146
- /// @dev If no role has been set for the selector, returns 0 (ADMIN_ROLE), meaning
147
- /// only admins can call unconfigured functions by default.
148
- /// @param selector The function selector to query
149
- /// @return The role ID required to call the function
150
- function getFunctionRole(bytes4 selector) public view returns (uint64) {
151
- return _functionRoles[selector];
152
- }
153
-
154
- /// @notice Returns the admin role for a given role.
155
- /// @dev The admin role is the role that can grant/revoke the specified role.
156
- /// If no admin has been set, returns 0 (ADMIN_ROLE).
157
- /// @param roleId The role to query the admin for
158
- /// @return The admin role ID that can manage the specified role
159
- function getRoleAdmin(uint64 roleId) public view returns (uint64) {
160
- return _roleAdmins[roleId];
161
- }
162
-
163
- /// @notice Checks if an account has a specific role.
164
- /// @dev PUBLIC_ROLE always returns true for any account. For other roles,
165
- /// returns true only if the account has been explicitly granted the role.
166
- /// @param roleId The role to check
167
- /// @param account The account to check
168
- /// @return True if the account has the role
169
- function hasRole(uint64 roleId, address account) public view returns (bool) {
170
- if (roleId == PUBLIC_ROLE) {
171
- return true;
172
- }
173
- return _roleMembers[roleId][account];
174
- }
175
-
176
- // =============================================== ROLE MANAGEMENT ===============================================
177
-
178
- /// @notice Grants a role to an account.
179
- /// @dev Only callable by accounts that have the admin role for the specified role.
180
- /// Emits {RoleGranted} if the account did not already have the role.
181
- /// @param roleId The role to grant
182
- /// @param account The account to receive the role
183
- function grantRole(uint64 roleId, address account) public onlyRoleAdmin(roleId) {
184
- _grantRole(roleId, account);
185
- }
186
-
187
- /// @notice Revokes a role from an account.
188
- /// @dev Only callable by accounts that have the admin role for the specified role.
189
- /// Emits {RoleRevoked} if the account had the role.
190
- /// @param roleId The role to revoke
191
- /// @param account The account to lose the role
192
- function revokeRole(uint64 roleId, address account) public onlyRoleAdmin(roleId) {
193
- _revokeRole(roleId, account);
194
- }
195
-
196
- /// @notice Allows an account to renounce a role it has.
197
- /// @dev The callerConfirmation parameter must match msg.sender to prevent accidental
198
- /// role renunciation. Emits {RoleRevoked} if the account had the role.
199
- /// @param roleId The role to renounce
200
- /// @param callerConfirmation Must be msg.sender's address as confirmation
201
- function renounceRole(uint64 roleId, address callerConfirmation) public {
202
- if (callerConfirmation != _msgSender()) {
203
- revert AccessManagerUnauthorizedAccount(_msgSender(), roleId);
204
- }
205
- _revokeRole(roleId, callerConfirmation);
206
- }
207
-
208
- /// @notice Sets the admin role for a given role.
209
- /// @dev Only callable by accounts with ADMIN_ROLE. Cannot modify the admin of
210
- /// ADMIN_ROLE or PUBLIC_ROLE. Emits {RoleAdminChanged}.
211
- /// @param roleId The role to set the admin for
212
- /// @param admin The new admin role ID
213
- function setRoleAdmin(uint64 roleId, uint64 admin) public onlyAdmin {
214
- if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) {
215
- revert AccessManagerLockedRole(roleId);
216
- }
217
-
218
- _roleAdmins[roleId] = admin;
219
- emit RoleAdminChanged(roleId, admin);
220
- }
221
-
222
- /// @dev Grants a role to an account without access control checks.
223
- /// @param roleId The role to grant (cannot be PUBLIC_ROLE)
224
- /// @param account The account to receive the role
225
- function _grantRole(uint64 roleId, address account) internal {
226
- if (roleId == PUBLIC_ROLE) {
227
- revert AccessManagerLockedRole(roleId);
228
- }
229
-
230
- if (!_roleMembers[roleId][account]) {
231
- _roleMembers[roleId][account] = true;
232
- emit RoleGranted(roleId, account);
233
- }
234
- }
235
-
236
- /// @dev Revokes a role from an account without access control checks.
237
- /// @param roleId The role to revoke (cannot be PUBLIC_ROLE)
238
- /// @param account The account to lose the role
239
- function _revokeRole(uint64 roleId, address account) internal {
240
- if (roleId == PUBLIC_ROLE) {
241
- revert AccessManagerLockedRole(roleId);
242
- }
243
-
244
- if (_roleMembers[roleId][account]) {
245
- _roleMembers[roleId][account] = false;
246
- emit RoleRevoked(roleId, account);
247
- }
248
- }
249
-
250
- // ============================================= FUNCTION MANAGEMENT ==============================================
251
-
252
- /// @notice Sets the role required to call a specific function.
253
- /// @dev Only callable by accounts with ADMIN_ROLE. Set to PUBLIC_ROLE to make a
254
- /// function callable by anyone. Emits {FunctionRoleUpdated}.
255
- /// @param selector The function selector to configure
256
- /// @param roleId The role that will be required to call the function
257
- function setFunctionRole(bytes4 selector, uint64 roleId) public onlyAdmin {
258
- _setFunctionRole(selector, roleId);
259
- }
260
-
261
- /// @dev Sets a function's required role without access control checks.
262
- /// @param selector The function selector to configure
263
- /// @param roleId The role that will be required to call the function
264
- function _setFunctionRole(bytes4 selector, uint64 roleId) internal {
265
- _functionRoles[selector] = roleId;
266
- emit FunctionRoleUpdated(selector, roleId);
267
- }
268
- }
@@ -1,420 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.20;
3
-
4
- import {Test} from "forge-std/Test.sol";
5
- import {Vm} from "forge-std/Vm.sol";
6
- import {SimpleAccessManager} from "../src/access/SimpleAccessManager.sol";
7
-
8
- /// @title SimpleAccessManagerTest
9
- /// @notice Comprehensive tests for SimpleAccessManager contract
10
- contract SimpleAccessManagerTest is Test {
11
- SimpleAccessManager public accessManager;
12
-
13
- address public admin = makeAddr("admin");
14
- address public user1 = makeAddr("user1");
15
- address public user2 = makeAddr("user2");
16
-
17
- uint64 public constant ADMIN_ROLE = type(uint64).min; // 0
18
- uint64 public constant PUBLIC_ROLE = type(uint64).max;
19
- uint64 public constant CUSTOM_ROLE = 1;
20
- uint64 public constant ANOTHER_ROLE = 2;
21
-
22
- bytes4 public constant TEST_SELECTOR = bytes4(keccak256("testFunction()"));
23
- bytes4 public constant ANOTHER_SELECTOR = bytes4(keccak256("anotherFunction()"));
24
-
25
- event RoleGranted(uint64 indexed roleId, address indexed account);
26
- event RoleRevoked(uint64 indexed roleId, address indexed account);
27
- event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);
28
- event FunctionRoleUpdated(bytes4 indexed selector, uint64 indexed roleId);
29
-
30
- function setUp() public {
31
- // Deploy with no initial function roles
32
- SimpleAccessManager.InitialFunctionRole[] memory noRoles = new SimpleAccessManager.InitialFunctionRole[](0);
33
- accessManager = new SimpleAccessManager(admin, noRoles);
34
- }
35
-
36
- // ================================ CONSTRUCTOR TESTS ================================
37
-
38
- function test_constructor_setsInitialAdmin() public view {
39
- assertTrue(accessManager.hasRole(ADMIN_ROLE, admin));
40
- }
41
-
42
- function test_constructor_revertsOnZeroAdmin() public {
43
- SimpleAccessManager.InitialFunctionRole[] memory noRoles = new SimpleAccessManager.InitialFunctionRole[](0);
44
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerInvalidInitialAdmin.selector, address(0)));
45
- new SimpleAccessManager(address(0), noRoles);
46
- }
47
-
48
- function test_constructor_setsInitialFunctionRoles() public {
49
- SimpleAccessManager.InitialFunctionRole[] memory initialRoles = new SimpleAccessManager.InitialFunctionRole[](2);
50
- initialRoles[0] = SimpleAccessManager.InitialFunctionRole({selector: TEST_SELECTOR, roleId: PUBLIC_ROLE});
51
- initialRoles[1] = SimpleAccessManager.InitialFunctionRole({selector: ANOTHER_SELECTOR, roleId: CUSTOM_ROLE});
52
-
53
- SimpleAccessManager manager = new SimpleAccessManager(admin, initialRoles);
54
-
55
- assertEq(manager.getFunctionRole(TEST_SELECTOR), PUBLIC_ROLE);
56
- assertEq(manager.getFunctionRole(ANOTHER_SELECTOR), CUSTOM_ROLE);
57
- }
58
-
59
- function test_constructor_emitsEvents() public {
60
- SimpleAccessManager.InitialFunctionRole[] memory initialRoles = new SimpleAccessManager.InitialFunctionRole[](1);
61
- initialRoles[0] = SimpleAccessManager.InitialFunctionRole({selector: TEST_SELECTOR, roleId: PUBLIC_ROLE});
62
-
63
- vm.expectEmit(true, true, false, false);
64
- emit RoleGranted(ADMIN_ROLE, admin);
65
-
66
- vm.expectEmit(true, true, false, false);
67
- emit FunctionRoleUpdated(TEST_SELECTOR, PUBLIC_ROLE);
68
-
69
- new SimpleAccessManager(admin, initialRoles);
70
- }
71
-
72
- // ================================ canCall TESTS ================================
73
-
74
- function test_canCall_returnsTrueForPublicRole() public {
75
- vm.prank(admin);
76
- accessManager.setFunctionRole(TEST_SELECTOR, PUBLIC_ROLE);
77
-
78
- // Anyone should be able to call
79
- assertTrue(accessManager.canCall(user1, address(0), TEST_SELECTOR));
80
- assertTrue(accessManager.canCall(user2, address(0), TEST_SELECTOR));
81
- assertTrue(accessManager.canCall(address(0), address(0), TEST_SELECTOR));
82
- }
83
-
84
- function test_canCall_returnsTrueForRoleMember() public {
85
- vm.startPrank(admin);
86
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
87
- accessManager.grantRole(CUSTOM_ROLE, user1);
88
- vm.stopPrank();
89
-
90
- assertTrue(accessManager.canCall(user1, address(0), TEST_SELECTOR));
91
- }
92
-
93
- function test_canCall_returnsFalseForNonRoleMember() public {
94
- vm.startPrank(admin);
95
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
96
- accessManager.grantRole(CUSTOM_ROLE, user1);
97
- vm.stopPrank();
98
-
99
- assertFalse(accessManager.canCall(user2, address(0), TEST_SELECTOR));
100
- }
101
-
102
- function test_canCall_defaultsToAdminRoleForUnconfiguredFunctions() public view {
103
- // Unconfigured function defaults to role 0 (ADMIN_ROLE)
104
- assertTrue(accessManager.canCall(admin, address(0), TEST_SELECTOR));
105
- assertFalse(accessManager.canCall(user1, address(0), TEST_SELECTOR));
106
- }
107
-
108
- function test_canCall_ignoresTargetParameter() public {
109
- vm.prank(admin);
110
- accessManager.setFunctionRole(TEST_SELECTOR, PUBLIC_ROLE);
111
-
112
- // Target should be ignored
113
- assertTrue(accessManager.canCall(user1, address(1), TEST_SELECTOR));
114
- assertTrue(accessManager.canCall(user1, address(2), TEST_SELECTOR));
115
- assertTrue(accessManager.canCall(user1, makeAddr("anyTarget"), TEST_SELECTOR));
116
- }
117
-
118
- // ================================ ROLE MANAGEMENT TESTS ================================
119
-
120
- function test_grantRole_byAdmin() public {
121
- vm.prank(admin);
122
- accessManager.grantRole(CUSTOM_ROLE, user1);
123
-
124
- assertTrue(accessManager.hasRole(CUSTOM_ROLE, user1));
125
- }
126
-
127
- function test_grantRole_emitsEvent() public {
128
- vm.expectEmit(true, true, false, false);
129
- emit RoleGranted(CUSTOM_ROLE, user1);
130
-
131
- vm.prank(admin);
132
- accessManager.grantRole(CUSTOM_ROLE, user1);
133
- }
134
-
135
- function test_grantRole_noopIfAlreadyHasRole() public {
136
- vm.startPrank(admin);
137
- accessManager.grantRole(CUSTOM_ROLE, user1);
138
-
139
- // Grant again - should not emit event
140
- vm.recordLogs();
141
- accessManager.grantRole(CUSTOM_ROLE, user1);
142
- Vm.Log[] memory logs = vm.getRecordedLogs();
143
-
144
- // No RoleGranted event should be emitted
145
- for (uint256 i; i < logs.length; ++i) {
146
- assertFalse(logs[i].topics[0] == keccak256("RoleGranted(uint64,address)"));
147
- }
148
- vm.stopPrank();
149
- }
150
-
151
- function test_grantRole_revertsForPublicRole() public {
152
- vm.prank(admin);
153
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerLockedRole.selector, PUBLIC_ROLE));
154
- accessManager.grantRole(PUBLIC_ROLE, user1);
155
- }
156
-
157
- function test_grantRole_revertsIfNotRoleAdmin() public {
158
- vm.prank(user1);
159
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerUnauthorizedAccount.selector, user1, ADMIN_ROLE));
160
- accessManager.grantRole(CUSTOM_ROLE, user2);
161
- }
162
-
163
- function test_revokeRole_byAdmin() public {
164
- vm.startPrank(admin);
165
- accessManager.grantRole(CUSTOM_ROLE, user1);
166
- accessManager.revokeRole(CUSTOM_ROLE, user1);
167
- vm.stopPrank();
168
-
169
- assertFalse(accessManager.hasRole(CUSTOM_ROLE, user1));
170
- }
171
-
172
- function test_revokeRole_emitsEvent() public {
173
- vm.prank(admin);
174
- accessManager.grantRole(CUSTOM_ROLE, user1);
175
-
176
- vm.expectEmit(true, true, false, false);
177
- emit RoleRevoked(CUSTOM_ROLE, user1);
178
-
179
- vm.prank(admin);
180
- accessManager.revokeRole(CUSTOM_ROLE, user1);
181
- }
182
-
183
- function test_revokeRole_noopIfDoesntHaveRole() public {
184
- vm.prank(admin);
185
- vm.recordLogs();
186
- accessManager.revokeRole(CUSTOM_ROLE, user1);
187
- Vm.Log[] memory logs = vm.getRecordedLogs();
188
-
189
- // No RoleRevoked event should be emitted
190
- for (uint256 i; i < logs.length; ++i) {
191
- assertFalse(logs[i].topics[0] == keccak256("RoleRevoked(uint64,address)"));
192
- }
193
- }
194
-
195
- function test_revokeRole_revertsForPublicRole() public {
196
- vm.prank(admin);
197
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerLockedRole.selector, PUBLIC_ROLE));
198
- accessManager.revokeRole(PUBLIC_ROLE, user1);
199
- }
200
-
201
- function test_revokeRole_revertsIfNotRoleAdmin() public {
202
- vm.prank(admin);
203
- accessManager.grantRole(CUSTOM_ROLE, user1);
204
-
205
- vm.prank(user2);
206
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerUnauthorizedAccount.selector, user2, ADMIN_ROLE));
207
- accessManager.revokeRole(CUSTOM_ROLE, user1);
208
- }
209
-
210
- function test_renounceRole_selfRevoke() public {
211
- vm.prank(admin);
212
- accessManager.grantRole(CUSTOM_ROLE, user1);
213
-
214
- vm.prank(user1);
215
- accessManager.renounceRole(CUSTOM_ROLE, user1);
216
-
217
- assertFalse(accessManager.hasRole(CUSTOM_ROLE, user1));
218
- }
219
-
220
- function test_renounceRole_revertsIfConfirmationMismatch() public {
221
- vm.prank(admin);
222
- accessManager.grantRole(CUSTOM_ROLE, user1);
223
-
224
- vm.prank(user1);
225
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerUnauthorizedAccount.selector, user1, CUSTOM_ROLE));
226
- accessManager.renounceRole(CUSTOM_ROLE, user2);
227
- }
228
-
229
- function test_renounceRole_revertsForPublicRole() public {
230
- vm.prank(user1);
231
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerLockedRole.selector, PUBLIC_ROLE));
232
- accessManager.renounceRole(PUBLIC_ROLE, user1);
233
- }
234
-
235
- // ================================ ROLE ADMIN TESTS ================================
236
-
237
- function test_setRoleAdmin_byGlobalAdmin() public {
238
- vm.prank(admin);
239
- accessManager.setRoleAdmin(CUSTOM_ROLE, ANOTHER_ROLE);
240
-
241
- assertEq(accessManager.getRoleAdmin(CUSTOM_ROLE), ANOTHER_ROLE);
242
- }
243
-
244
- function test_setRoleAdmin_emitsEvent() public {
245
- vm.expectEmit(true, true, false, false);
246
- emit RoleAdminChanged(CUSTOM_ROLE, ANOTHER_ROLE);
247
-
248
- vm.prank(admin);
249
- accessManager.setRoleAdmin(CUSTOM_ROLE, ANOTHER_ROLE);
250
- }
251
-
252
- function test_setRoleAdmin_revertsForAdminRole() public {
253
- vm.prank(admin);
254
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerLockedRole.selector, ADMIN_ROLE));
255
- accessManager.setRoleAdmin(ADMIN_ROLE, CUSTOM_ROLE);
256
- }
257
-
258
- function test_setRoleAdmin_revertsForPublicRole() public {
259
- vm.prank(admin);
260
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerLockedRole.selector, PUBLIC_ROLE));
261
- accessManager.setRoleAdmin(PUBLIC_ROLE, CUSTOM_ROLE);
262
- }
263
-
264
- function test_setRoleAdmin_revertsIfNotGlobalAdmin() public {
265
- vm.prank(user1);
266
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerUnauthorizedAccount.selector, user1, ADMIN_ROLE));
267
- accessManager.setRoleAdmin(CUSTOM_ROLE, ANOTHER_ROLE);
268
- }
269
-
270
- function test_grantRole_withCustomRoleAdmin() public {
271
- // Set ANOTHER_ROLE as admin for CUSTOM_ROLE
272
- vm.prank(admin);
273
- accessManager.setRoleAdmin(CUSTOM_ROLE, ANOTHER_ROLE);
274
-
275
- // Grant ANOTHER_ROLE to user1
276
- vm.prank(admin);
277
- accessManager.grantRole(ANOTHER_ROLE, user1);
278
-
279
- // user1 should now be able to grant CUSTOM_ROLE
280
- vm.prank(user1);
281
- accessManager.grantRole(CUSTOM_ROLE, user2);
282
-
283
- assertTrue(accessManager.hasRole(CUSTOM_ROLE, user2));
284
- }
285
-
286
- function test_getRoleAdmin_defaultsToAdminRole() public view {
287
- // Unconfigured role admin defaults to ADMIN_ROLE (0)
288
- assertEq(accessManager.getRoleAdmin(CUSTOM_ROLE), ADMIN_ROLE);
289
- }
290
-
291
- // ================================ FUNCTION ROLE TESTS ================================
292
-
293
- function test_setFunctionRole_byAdmin() public {
294
- vm.prank(admin);
295
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
296
-
297
- assertEq(accessManager.getFunctionRole(TEST_SELECTOR), CUSTOM_ROLE);
298
- }
299
-
300
- function test_setFunctionRole_emitsEvent() public {
301
- vm.expectEmit(true, true, false, false);
302
- emit FunctionRoleUpdated(TEST_SELECTOR, CUSTOM_ROLE);
303
-
304
- vm.prank(admin);
305
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
306
- }
307
-
308
- function test_setFunctionRole_revertsIfNotAdmin() public {
309
- vm.prank(user1);
310
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerUnauthorizedAccount.selector, user1, ADMIN_ROLE));
311
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
312
- }
313
-
314
- function test_setFunctionRole_canUpdateExisting() public {
315
- vm.startPrank(admin);
316
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
317
- accessManager.setFunctionRole(TEST_SELECTOR, ANOTHER_ROLE);
318
- vm.stopPrank();
319
-
320
- assertEq(accessManager.getFunctionRole(TEST_SELECTOR), ANOTHER_ROLE);
321
- }
322
-
323
- function test_getFunctionRole_defaultsToAdminRole() public view {
324
- // Unconfigured function defaults to 0 (ADMIN_ROLE)
325
- assertEq(accessManager.getFunctionRole(TEST_SELECTOR), ADMIN_ROLE);
326
- }
327
-
328
- // ================================ hasRole TESTS ================================
329
-
330
- function test_hasRole_returnsTrueForPublicRole() public view {
331
- // All addresses have PUBLIC_ROLE
332
- assertTrue(accessManager.hasRole(PUBLIC_ROLE, user1));
333
- assertTrue(accessManager.hasRole(PUBLIC_ROLE, user2));
334
- assertTrue(accessManager.hasRole(PUBLIC_ROLE, address(0)));
335
- assertTrue(accessManager.hasRole(PUBLIC_ROLE, address(this)));
336
- }
337
-
338
- function test_hasRole_returnsFalseForNonMember() public view {
339
- assertFalse(accessManager.hasRole(CUSTOM_ROLE, user1));
340
- }
341
-
342
- function test_hasRole_returnsTrueForMember() public {
343
- vm.prank(admin);
344
- accessManager.grantRole(CUSTOM_ROLE, user1);
345
-
346
- assertTrue(accessManager.hasRole(CUSTOM_ROLE, user1));
347
- }
348
-
349
- // ================================ IAuthority INTERFACE TESTS ================================
350
-
351
- function test_implementsIAuthority() public view {
352
- // Verify the contract implements IAuthority
353
- assertTrue(accessManager.canCall(admin, address(0), TEST_SELECTOR) || !accessManager.canCall(admin, address(0), TEST_SELECTOR));
354
- }
355
-
356
- // ================================ INTEGRATION TESTS ================================
357
-
358
- function test_integration_limitOrderBookScenario() public {
359
- // This test simulates the limit order book deployment scenario
360
- bytes4 createSelector = bytes4(keccak256("create(bytes32,address,int24,uint128,bool)"));
361
- bytes4 setMaxFillCountSelector = bytes4(keccak256("setMaxFillCount(uint256)"));
362
-
363
- // Deploy with create() set to PUBLIC_ROLE
364
- SimpleAccessManager.InitialFunctionRole[] memory initialRoles = new SimpleAccessManager.InitialFunctionRole[](1);
365
- initialRoles[0] = SimpleAccessManager.InitialFunctionRole({selector: createSelector, roleId: PUBLIC_ROLE});
366
-
367
- SimpleAccessManager manager = new SimpleAccessManager(admin, initialRoles);
368
-
369
- // create() should be callable by anyone
370
- assertTrue(manager.canCall(user1, address(0), createSelector));
371
- assertTrue(manager.canCall(user2, address(0), createSelector));
372
-
373
- // setMaxFillCount() defaults to ADMIN_ROLE (only admin can call)
374
- assertTrue(manager.canCall(admin, address(0), setMaxFillCountSelector));
375
- assertFalse(manager.canCall(user1, address(0), setMaxFillCountSelector));
376
- }
377
-
378
- function test_integration_delegatedRoleManagement() public {
379
- // Admin sets up a role hierarchy:
380
- // - ADMIN_ROLE can manage ANOTHER_ROLE
381
- // - ANOTHER_ROLE can manage CUSTOM_ROLE
382
-
383
- vm.startPrank(admin);
384
- accessManager.setRoleAdmin(CUSTOM_ROLE, ANOTHER_ROLE);
385
- accessManager.grantRole(ANOTHER_ROLE, user1);
386
- vm.stopPrank();
387
-
388
- // user1 (with ANOTHER_ROLE) can now grant CUSTOM_ROLE
389
- vm.prank(user1);
390
- accessManager.grantRole(CUSTOM_ROLE, user2);
391
-
392
- assertTrue(accessManager.hasRole(CUSTOM_ROLE, user2));
393
-
394
- // user1 can also revoke CUSTOM_ROLE
395
- vm.prank(user1);
396
- accessManager.revokeRole(CUSTOM_ROLE, user2);
397
-
398
- assertFalse(accessManager.hasRole(CUSTOM_ROLE, user2));
399
- }
400
-
401
- function test_integration_adminCannotGrantPublicRole() public {
402
- // Even admin cannot grant PUBLIC_ROLE - it's automatic
403
- vm.prank(admin);
404
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerLockedRole.selector, PUBLIC_ROLE));
405
- accessManager.grantRole(PUBLIC_ROLE, user1);
406
- }
407
-
408
- function test_integration_adminCanRenounceOwnRole() public {
409
- // Admin can renounce their own role (dangerous but allowed)
410
- vm.prank(admin);
411
- accessManager.renounceRole(ADMIN_ROLE, admin);
412
-
413
- assertFalse(accessManager.hasRole(ADMIN_ROLE, admin));
414
-
415
- // Now admin can't do admin things
416
- vm.prank(admin);
417
- vm.expectRevert(abi.encodeWithSelector(SimpleAccessManager.AccessManagerUnauthorizedAccount.selector, admin, ADMIN_ROLE));
418
- accessManager.setFunctionRole(TEST_SELECTOR, CUSTOM_ROLE);
419
- }
420
- }