@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.
- package/.turbo/turbo-build$colon$js.log +50 -49
- package/CHANGELOG.md +73 -0
- package/abis/ISetLimitOrderConfig.json +27 -0
- package/abis/IWETH.json +118 -0
- package/abis/IZoraLimitOrderBook.json +5 -0
- package/abis/LimitOrderLiquidity.json +7 -0
- package/abis/LimitOrderViews.json +62 -0
- package/abis/{SimpleAccessManaged.json → Ownable.json} +29 -10
- package/abis/Ownable2Step.json +115 -0
- package/abis/PermittedCallers.json +181 -0
- package/abis/SwapWithLimitOrders.json +134 -14
- package/abis/ZoraLimitOrderBook.json +187 -35
- package/cache/solidity-files-cache.json +1 -1
- package/dist/index.cjs +219 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +219 -34
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +254 -41
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/out/BalanceDelta.sol/BalanceDeltaLibrary.json +1 -1
- package/out/BeforeSwapDelta.sol/BeforeSwapDeltaLibrary.json +1 -1
- package/out/BitMath.sol/BitMath.json +1 -1
- package/out/BytesLib.sol/BytesLib.json +1 -1
- package/out/CoinCommon.sol/CoinCommon.json +1 -1
- package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -1
- package/out/CoinConstants.sol/CoinConstants.json +1 -1
- package/out/Context.sol/Context.json +1 -1
- package/out/Currency.sol/CurrencyLibrary.json +1 -1
- package/out/CurrencyReserves.sol/CurrencyReserves.json +1 -1
- package/out/CustomRevert.sol/CustomRevert.json +1 -1
- package/out/DopplerMath.sol/DopplerMath.json +1 -1
- package/out/FixedPoint128.sol/FixedPoint128.json +1 -1
- package/out/FixedPoint96.sol/FixedPoint96.json +1 -1
- package/out/FullMath.sol/FullMath.json +1 -1
- package/out/IAllowanceTransfer.sol/IAllowanceTransfer.json +1 -1
- package/out/ICoin.sol/ICoin.json +1 -1
- package/out/ICoin.sol/IHasCoinType.json +1 -1
- package/out/ICoin.sol/IHasPoolKey.json +1 -1
- package/out/ICoin.sol/IHasSwapPath.json +1 -1
- package/out/ICoin.sol/IHasTotalSupplyForPositions.json +1 -1
- package/out/IDeployedCoinVersionLookup.sol/IDeployedCoinVersionLookup.json +1 -1
- package/out/IDopplerErrors.sol/IDopplerErrors.json +1 -1
- package/out/IEIP712.sol/IEIP712.json +1 -1
- package/out/IERC1363.sol/IERC1363.json +1 -1
- package/out/IERC165.sol/IERC165.json +1 -1
- package/out/IERC20.sol/IERC20.json +1 -1
- package/out/IERC20Minimal.sol/IERC20Minimal.json +1 -1
- package/out/IERC6909Claims.sol/IERC6909Claims.json +1 -1
- package/out/IERC7572.sol/IERC7572.json +1 -1
- package/out/IExtsload.sol/IExtsload.json +1 -1
- package/out/IExttload.sol/IExttload.json +1 -1
- package/out/IHasRewardsRecipients.sol/IHasRewardsRecipients.json +1 -1
- package/out/IHooks.sol/IHooks.json +1 -1
- package/out/IMsgSender.sol/IMsgSender.json +1 -1
- package/out/IPoolManager.sol/IPoolManager.json +1 -1
- package/out/IProtocolFees.sol/IProtocolFees.json +1 -1
- package/out/ISetLimitOrderConfig.sol/ISetLimitOrderConfig.json +1 -0
- package/out/ISupportsLimitOrderFill.sol/ISupportsLimitOrderFill.json +1 -1
- package/out/ISwapPathRouter.sol/ISwapPathRouter.json +1 -1
- package/out/ISwapRouter.sol/ISwapRouter.json +1 -1
- package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -1
- package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4Hook.json +1 -1
- package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4HookWithUpdateableFee.json +1 -1
- package/out/IUpgradeableV4Hook.sol/IUpgradeableV4Hook.json +1 -1
- package/out/IWETH.sol/IWETH.json +1 -0
- package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -1
- package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -1
- package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -1
- package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -1
- package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -1
- package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -1
- package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -1
- package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -1
- package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -1
- package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -1
- package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -1
- package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -1
- package/out/LimitOrderViews.sol/LimitOrderViews.json +1 -0
- package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -1
- package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -1
- package/out/LiquidityMath.sol/LiquidityMath.json +1 -1
- package/out/Lock.sol/Lock.json +1 -1
- package/out/NonzeroDeltaCount.sol/NonzeroDeltaCount.json +1 -1
- package/out/Ownable.sol/Ownable.json +1 -0
- package/out/Ownable2Step.sol/Ownable2Step.json +1 -0
- package/out/Path.sol/Path.json +1 -1
- package/out/PathKey.sol/PathKeyLibrary.json +1 -1
- package/out/Permit2Payments.sol/Permit2Payments.json +1 -1
- package/out/PermittedCallers.sol/PermittedCallers.json +1 -0
- package/out/PoolId.sol/PoolIdLibrary.json +1 -1
- package/out/Position.sol/Position.json +1 -1
- package/out/SafeCast.sol/SafeCast.json +1 -1
- package/out/SafeCast160.sol/SafeCast160.json +1 -1
- package/out/SafeERC20.sol/SafeERC20.json +1 -1
- package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -1
- package/out/StateLibrary.sol/StateLibrary.json +1 -1
- package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -1
- package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -1
- package/out/TickBitmap.sol/TickBitmap.json +1 -1
- package/out/TickMath.sol/TickMath.json +1 -1
- package/out/TransientSlot.sol/TransientSlot.json +1 -1
- package/out/TransientStateLibrary.sol/TransientStateLibrary.json +1 -1
- package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -1
- package/out/UnsafeMath.sol/UnsafeMath.json +1 -1
- package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -1
- package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -1
- package/out/build-info/37e0124d88d60569.json +1 -0
- package/out/uniswap/BitMath.sol/BitMath.json +1 -1
- package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -1
- package/out/uniswap/FullMath.sol/FullMath.json +1 -1
- package/out/uniswap/SafeCast.sol/SafeCast.json +1 -1
- package/out/uniswap/TickMath.sol/TickMath.json +1 -1
- package/package/wagmiGenerated.ts +218 -33
- package/package.json +1 -1
- package/src/IZoraLimitOrderBook.sol +5 -5
- package/src/ZoraLimitOrderBook.sol +24 -41
- package/src/access/PermittedCallers.sol +41 -0
- package/src/libs/LimitOrderBitmap.sol +0 -51
- package/src/libs/LimitOrderCommon.sol +48 -30
- package/src/libs/LimitOrderCreate.sol +5 -18
- package/src/libs/LimitOrderFill.sol +32 -161
- package/src/libs/LimitOrderLiquidity.sol +92 -71
- package/src/libs/LimitOrderViews.sol +168 -0
- package/src/libs/LimitOrderWithdraw.sol +13 -4
- package/src/libs/SwapLimitOrders.sol +14 -7
- package/src/router/ISetLimitOrderConfig.sol +12 -0
- package/src/router/SwapWithLimitOrders.sol +46 -33
- package/test/LimitOrderAccessControl.t.sol +173 -156
- package/test/LimitOrderBitmap.t.sol +13 -7
- package/test/LimitOrderFill.t.sol +42 -4
- package/test/LimitOrderLibraries.t.sol +18 -10
- package/test/LimitOrderLiquidityPayouts.t.sol +280 -3
- package/test/LimitOrderWithdraw.t.sol +28 -1
- package/test/SwapWithLimitOrders.t.sol +3 -5
- package/test/SwapWithLimitOrdersRouter.t.sol +108 -13
- package/test/gas/LimitOrderFillGas.t.sol +0 -7
- package/test/gas/LimitOrderSwapGas.t.sol +0 -6
- package/test/unit/LimitOrderBitmapUnit.t.sol +0 -134
- package/test/unit/LimitOrderCreateUnit.t.sol +32 -0
- package/test/unit/SwapLimitOrdersUnit.t.sol +231 -33
- package/test/unit/SwapLimitOrdersValidation.t.sol +28 -42
- package/test/unit/SwapWithLimitOrdersUnit.t.sol +21 -88
- package/test/utils/BaseTest.sol +34 -22
- package/test/utils/MockWETH.sol +39 -0
- package/test/utils/TestableZoraLimitOrderBook.sol +5 -7
- package/abis/IAuthority.json +0 -31
- package/abis/SimpleAccessManager.json +0 -351
- package/out/IAuthority.sol/IAuthority.json +0 -1
- package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +0 -1
- package/out/SimpleAccessManager.sol/SimpleAccessManager.json +0 -1
- package/out/build-info/69718f10d1dc37f0.json +0 -1
- package/src/access/SimpleAccessManaged.sol +0 -76
- package/src/access/SimpleAccessManager.sol +0 -268
- 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
|
-
}
|