@zoralabs/limit-orders 0.2.0
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 +85 -0
- package/AUDIT_NOTES.md +33 -0
- package/AUDIT_RFP.md +408 -0
- package/CHANGELOG.md +25 -0
- package/GAS_COMPARISON_RESULTS.md +194 -0
- package/LICENSE +21 -0
- package/README.md +650 -0
- package/SPEC.md +291 -0
- package/abis/BalanceDeltaLibrary.json +15 -0
- package/abis/BeforeSwapDeltaLibrary.json +15 -0
- package/abis/CurrencyLibrary.json +25 -0
- package/abis/CustomRevert.json +28 -0
- package/abis/IAllowanceTransfer.json +486 -0
- package/abis/IAuthority.json +31 -0
- package/abis/ICoin.json +1074 -0
- package/abis/IDeployedCoinVersionLookup.json +21 -0
- package/abis/IDopplerErrors.json +44 -0
- package/abis/IEIP712.json +15 -0
- package/abis/IERC1363.json +373 -0
- package/abis/IERC165.json +21 -0
- package/abis/IERC20.json +185 -0
- package/abis/IERC20Minimal.json +172 -0
- package/abis/IERC6909Claims.json +288 -0
- package/abis/IERC7572.json +21 -0
- package/abis/IExtsload.json +64 -0
- package/abis/IExttload.json +40 -0
- package/abis/IHasCoinType.json +15 -0
- package/abis/IHasPoolKey.json +42 -0
- package/abis/IHasRewardsRecipients.json +54 -0
- package/abis/IHasSwapPath.json +60 -0
- package/abis/IHasTotalSupplyForPositions.json +15 -0
- package/abis/IHooks.json +789 -0
- package/abis/IMsgSender.json +15 -0
- package/abis/IPoolManager.json +1286 -0
- package/abis/IProtocolFees.json +174 -0
- package/abis/ISupportsLimitOrderFill.json +15 -0
- package/abis/ISwapPathRouter.json +92 -0
- package/abis/ISwapRouter.json +219 -0
- package/abis/IUniswapV3SwapCallback.json +25 -0
- package/abis/IUpgradeableDestinationV4Hook.json +84 -0
- package/abis/IUpgradeableDestinationV4HookWithUpdateableFee.json +95 -0
- package/abis/IUpgradeableV4Hook.json +112 -0
- package/abis/IZoraHookRegistry.json +188 -0
- package/abis/IZoraLimitOrderBook.json +623 -0
- package/abis/IZoraLimitOrderBookCoinsInterface.json +67 -0
- package/abis/IZoraV4CoinHook.json +610 -0
- package/abis/Permit2Payments.json +7 -0
- package/abis/Position.json +7 -0
- package/abis/SafeCast.json +7 -0
- package/abis/SafeCast160.json +7 -0
- package/abis/SafeERC20.json +34 -0
- package/abis/SimpleAccessManaged.json +57 -0
- package/abis/SimpleAccessManager.json +351 -0
- package/abis/SqrtPriceMath.json +22 -0
- package/abis/StateLibrary.json +80 -0
- package/abis/SwapLimitOrders.json +22 -0
- package/abis/SwapWithLimitOrders.json +457 -0
- package/abis/TickBitmap.json +18 -0
- package/abis/TickMath.json +24 -0
- package/abis/V3ToV4SwapLib.json +28 -0
- package/abis/ZoraLimitOrderBook.json +771 -0
- package/cache/solidity-files-cache.json +1 -0
- package/dist/index.cjs +760 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +731 -0
- package/dist/index.js.map +1 -0
- package/dist/wagmiGenerated.d.ts +1012 -0
- package/dist/wagmiGenerated.d.ts.map +1 -0
- package/foundry.toml +29 -0
- package/gas_comparison.py +49 -0
- package/out/BalanceDelta.sol/BalanceDeltaLibrary.json +1 -0
- package/out/BeforeSwapDelta.sol/BeforeSwapDeltaLibrary.json +1 -0
- package/out/BitMath.sol/BitMath.json +1 -0
- package/out/BytesLib.sol/BytesLib.json +1 -0
- package/out/CoinCommon.sol/CoinCommon.json +1 -0
- package/out/CoinConfigurationVersions.sol/CoinConfigurationVersions.json +1 -0
- package/out/CoinConstants.sol/CoinConstants.json +1 -0
- package/out/Context.sol/Context.json +1 -0
- package/out/Currency.sol/CurrencyLibrary.json +1 -0
- package/out/CurrencyReserves.sol/CurrencyReserves.json +1 -0
- package/out/CustomRevert.sol/CustomRevert.json +1 -0
- package/out/DopplerMath.sol/DopplerMath.json +1 -0
- package/out/FixedPoint128.sol/FixedPoint128.json +1 -0
- package/out/FixedPoint96.sol/FixedPoint96.json +1 -0
- package/out/FullMath.sol/FullMath.json +1 -0
- package/out/IAllowanceTransfer.sol/IAllowanceTransfer.json +1 -0
- package/out/IAuthority.sol/IAuthority.json +1 -0
- package/out/ICoin.sol/ICoin.json +1 -0
- package/out/ICoin.sol/IHasCoinType.json +1 -0
- package/out/ICoin.sol/IHasPoolKey.json +1 -0
- package/out/ICoin.sol/IHasSwapPath.json +1 -0
- package/out/ICoin.sol/IHasTotalSupplyForPositions.json +1 -0
- package/out/IDeployedCoinVersionLookup.sol/IDeployedCoinVersionLookup.json +1 -0
- package/out/IDopplerErrors.sol/IDopplerErrors.json +1 -0
- package/out/IEIP712.sol/IEIP712.json +1 -0
- package/out/IERC1363.sol/IERC1363.json +1 -0
- package/out/IERC165.sol/IERC165.json +1 -0
- package/out/IERC20.sol/IERC20.json +1 -0
- package/out/IERC20Minimal.sol/IERC20Minimal.json +1 -0
- package/out/IERC6909Claims.sol/IERC6909Claims.json +1 -0
- package/out/IERC7572.sol/IERC7572.json +1 -0
- package/out/IExtsload.sol/IExtsload.json +1 -0
- package/out/IExttload.sol/IExttload.json +1 -0
- package/out/IHasRewardsRecipients.sol/IHasRewardsRecipients.json +1 -0
- package/out/IHooks.sol/IHooks.json +1 -0
- package/out/IMsgSender.sol/IMsgSender.json +1 -0
- package/out/IPoolManager.sol/IPoolManager.json +1 -0
- package/out/IProtocolFees.sol/IProtocolFees.json +1 -0
- package/out/ISupportsLimitOrderFill.sol/ISupportsLimitOrderFill.json +1 -0
- package/out/ISwapPathRouter.sol/ISwapPathRouter.json +1 -0
- package/out/ISwapRouter.sol/ISwapRouter.json +1 -0
- package/out/IUniswapV3SwapCallback.sol/IUniswapV3SwapCallback.json +1 -0
- package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4Hook.json +1 -0
- package/out/IUpgradeableV4Hook.sol/IUpgradeableDestinationV4HookWithUpdateableFee.json +1 -0
- package/out/IUpgradeableV4Hook.sol/IUpgradeableV4Hook.json +1 -0
- package/out/IZoraHookRegistry.sol/IZoraHookRegistry.json +1 -0
- package/out/IZoraLimitOrderBook.sol/IZoraLimitOrderBook.json +1 -0
- package/out/IZoraLimitOrderBookCoinsInterface.sol/IZoraLimitOrderBookCoinsInterface.json +1 -0
- package/out/IZoraV4CoinHook.sol/IZoraV4CoinHook.json +1 -0
- package/out/LimitOrderBitmap.sol/LimitOrderBitmap.json +1 -0
- package/out/LimitOrderCommon.sol/LimitOrderCommon.json +1 -0
- package/out/LimitOrderCreate.sol/LimitOrderCreate.json +1 -0
- package/out/LimitOrderFill.sol/LimitOrderFill.json +1 -0
- package/out/LimitOrderLiquidity.sol/LimitOrderLiquidity.json +1 -0
- package/out/LimitOrderQueues.sol/LimitOrderQueues.json +1 -0
- package/out/LimitOrderStorage.sol/LimitOrderStorage.json +1 -0
- package/out/LimitOrderTypes.sol/LimitOrderTypes.json +1 -0
- package/out/LimitOrderWithdraw.sol/LimitOrderWithdraw.json +1 -0
- package/out/LiquidityAmounts.sol/LiquidityAmounts.json +1 -0
- package/out/LiquidityMath.sol/LiquidityMath.json +1 -0
- package/out/Lock.sol/Lock.json +1 -0
- package/out/NonzeroDeltaCount.sol/NonzeroDeltaCount.json +1 -0
- package/out/Path.sol/Path.json +1 -0
- package/out/PathKey.sol/PathKeyLibrary.json +1 -0
- package/out/Permit2Payments.sol/Permit2Payments.json +1 -0
- package/out/PoolId.sol/PoolIdLibrary.json +1 -0
- package/out/Position.sol/Position.json +1 -0
- package/out/SafeCast.sol/SafeCast.json +1 -0
- package/out/SafeCast160.sol/SafeCast160.json +1 -0
- package/out/SafeERC20.sol/SafeERC20.json +1 -0
- package/out/SimpleAccessManaged.sol/SimpleAccessManaged.json +1 -0
- package/out/SimpleAccessManager.sol/SimpleAccessManager.json +1 -0
- package/out/SqrtPriceMath.sol/SqrtPriceMath.json +1 -0
- package/out/StateLibrary.sol/StateLibrary.json +1 -0
- package/out/SwapLimitOrders.sol/SwapLimitOrders.json +1 -0
- package/out/SwapWithLimitOrders.sol/SwapWithLimitOrders.json +1 -0
- package/out/TickBitmap.sol/TickBitmap.json +1 -0
- package/out/TickMath.sol/TickMath.json +1 -0
- package/out/TransientSlot.sol/TransientSlot.json +1 -0
- package/out/TransientStateLibrary.sol/TransientStateLibrary.json +1 -0
- package/out/UniV4SwapToCurrency.sol/UniV4SwapToCurrency.json +1 -0
- package/out/UnsafeMath.sol/UnsafeMath.json +1 -0
- package/out/V3ToV4SwapLib.sol/V3ToV4SwapLib.json +1 -0
- package/out/ZoraLimitOrderBook.sol/ZoraLimitOrderBook.json +1 -0
- package/out/build-info/69718f10d1dc37f0.json +1 -0
- package/out/uniswap/BitMath.sol/BitMath.json +1 -0
- package/out/uniswap/CustomRevert.sol/CustomRevert.json +1 -0
- package/out/uniswap/FullMath.sol/FullMath.json +1 -0
- package/out/uniswap/SafeCast.sol/SafeCast.json +1 -0
- package/out/uniswap/TickMath.sol/TickMath.json +1 -0
- package/package/index.ts +1 -0
- package/package/wagmiGenerated.ts +738 -0
- package/package.json +57 -0
- package/remappings.txt +11 -0
- package/src/IZoraLimitOrderBook.sol +195 -0
- package/src/ZoraLimitOrderBook.sol +220 -0
- package/src/access/SimpleAccessManaged.sol +76 -0
- package/src/access/SimpleAccessManager.sol +268 -0
- package/src/libs/LimitOrderBitmap.sol +84 -0
- package/src/libs/LimitOrderCommon.sol +91 -0
- package/src/libs/LimitOrderCreate.sol +277 -0
- package/src/libs/LimitOrderFill.sol +362 -0
- package/src/libs/LimitOrderLiquidity.sol +222 -0
- package/src/libs/LimitOrderQueues.sol +101 -0
- package/src/libs/LimitOrderStorage.sol +34 -0
- package/src/libs/LimitOrderTypes.sol +41 -0
- package/src/libs/LimitOrderWithdraw.sol +100 -0
- package/src/libs/Permit2Payments.sol +41 -0
- package/src/libs/SwapLimitOrders.sol +209 -0
- package/src/router/SwapWithLimitOrders.sol +454 -0
- package/test/LimitOrderAccessControl.t.sol +461 -0
- package/test/LimitOrderBitmap.t.sol +194 -0
- package/test/LimitOrderCreate.t.sol +348 -0
- package/test/LimitOrderFill.t.sol +1005 -0
- package/test/LimitOrderLibraries.t.sol +354 -0
- package/test/LimitOrderLiquidityPayouts.t.sol +333 -0
- package/test/LimitOrderV4Pools.t.sol +157 -0
- package/test/LimitOrderWithdraw.t.sol +653 -0
- package/test/SimpleAccessManager.t.sol +420 -0
- package/test/SwapWithLimitOrders.t.sol +107 -0
- package/test/SwapWithLimitOrdersRouter.t.sol +1073 -0
- package/test/gas/LimitOrderFillGas.t.sol +1008 -0
- package/test/gas/LimitOrderSwapGas.t.sol +403 -0
- package/test/gas/logs/gas_benchmarks_fill_20251201.log +30 -0
- package/test/gas/logs/gas_benchmarks_swap_20251201.log +27 -0
- package/test/unit/LimitOrderBitmapUnit.t.sol +276 -0
- package/test/unit/LimitOrderCreateUnit.t.sol +358 -0
- package/test/unit/SwapLimitOrdersUnit.t.sol +672 -0
- package/test/unit/SwapLimitOrdersValidation.t.sol +423 -0
- package/test/unit/SwapWithLimitOrdersUnit.t.sol +321 -0
- package/test/utils/BaseTest.sol +793 -0
- package/test/utils/TestableZoraLimitOrderBook.sol +54 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +11 -0
- package/wagmi.config.ts +18 -0
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// SPDX-License-Identifier: ZORA-DELAYED-OSL-v1
|
|
2
|
+
// This software is licensed under the Zora Delayed Open Source License.
|
|
3
|
+
// Under this license, you may use, copy, modify, and distribute this software for
|
|
4
|
+
// non-commercial purposes only. Commercial use and competitive products are prohibited
|
|
5
|
+
// until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
|
|
6
|
+
// at which point this software automatically becomes available under the MIT License.
|
|
7
|
+
// Full license terms available at: https://docs.zora.co/coins/license
|
|
8
|
+
pragma solidity ^0.8.23;
|
|
9
|
+
|
|
10
|
+
import {TickBitmap} from "@uniswap/v4-core/src/libraries/TickBitmap.sol";
|
|
11
|
+
import {LimitOrderTypes} from "./LimitOrderTypes.sol";
|
|
12
|
+
|
|
13
|
+
library LimitOrderBitmap {
|
|
14
|
+
function setIfFirst(mapping(int16 => uint256) storage bm, int24 tick, int24 spacing, uint256 sizeBefore) internal {
|
|
15
|
+
if (sizeBefore == 0) {
|
|
16
|
+
int24 compressed = TickBitmap.compress(tick, spacing);
|
|
17
|
+
(int16 wordPos, uint8 bitPos) = TickBitmap.position(compressed);
|
|
18
|
+
bm[wordPos] |= (1 << bitPos);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function clearIfEmpty(mapping(int16 => uint256) storage bm, int24 tick, int24 spacing, uint256 sizeAfter) internal {
|
|
23
|
+
if (sizeAfter == 0) {
|
|
24
|
+
int24 compressed = TickBitmap.compress(tick, spacing);
|
|
25
|
+
(int16 wordPos, uint8 bitPos) = TickBitmap.position(compressed);
|
|
26
|
+
bm[wordPos] &= ~(1 << bitPos);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getExecutableTicks(
|
|
31
|
+
mapping(int16 => uint256) storage bm,
|
|
32
|
+
mapping(int24 => LimitOrderTypes.Queue) storage poolQueue,
|
|
33
|
+
int24 tickSpacing,
|
|
34
|
+
bool zeroForOne,
|
|
35
|
+
int24 tickBeforeSwap,
|
|
36
|
+
int24 tickAfterSwap
|
|
37
|
+
) internal view returns (int24[] memory) {
|
|
38
|
+
uint256 numTicksCrossed = uint256(int256(_abs(tickBeforeSwap - tickAfterSwap)));
|
|
39
|
+
uint256 numTicksToCheck = numTicksCrossed / uint256(int256(tickSpacing)) + 1;
|
|
40
|
+
|
|
41
|
+
int24[] memory ticksToCheck = new int24[](numTicksToCheck);
|
|
42
|
+
uint256 numExecutableTicks;
|
|
43
|
+
|
|
44
|
+
int24 targetTick = tickAfterSwap;
|
|
45
|
+
int24 currentTick = tickBeforeSwap;
|
|
46
|
+
|
|
47
|
+
while (true) {
|
|
48
|
+
if (zeroForOne ? currentTick <= targetTick : currentTick >= targetTick) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
(int24 nextInitializedTick, bool initialized) = TickBitmap.nextInitializedTickWithinOneWord(bm, currentTick, tickSpacing, zeroForOne);
|
|
53
|
+
|
|
54
|
+
bool crossesTarget = zeroForOne ? nextInitializedTick <= targetTick : nextInitializedTick > targetTick;
|
|
55
|
+
|
|
56
|
+
if (crossesTarget) {
|
|
57
|
+
nextInitializedTick = targetTick;
|
|
58
|
+
initialized = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (initialized) {
|
|
62
|
+
if (poolQueue[nextInitializedTick].length > 0) {
|
|
63
|
+
ticksToCheck[numExecutableTicks++] = nextInitializedTick;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (nextInitializedTick == targetTick) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
currentTick = zeroForOne ? nextInitializedTick - 1 : nextInitializedTick;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
assembly {
|
|
75
|
+
mstore(ticksToCheck, numExecutableTicks)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return ticksToCheck;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function _abs(int24 x) private pure returns (int24) {
|
|
82
|
+
return x < 0 ? -x : x;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// SPDX-License-Identifier: ZORA-DELAYED-OSL-v1
|
|
2
|
+
// This software is licensed under the Zora Delayed Open Source License.
|
|
3
|
+
// Under this license, you may use, copy, modify, and distribute this software for
|
|
4
|
+
// non-commercial purposes only. Commercial use and competitive products are prohibited
|
|
5
|
+
// until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
|
|
6
|
+
// at which point this software automatically becomes available under the MIT License.
|
|
7
|
+
// Full license terms available at: https://docs.zora.co/coins/license
|
|
8
|
+
pragma solidity ^0.8.28;
|
|
9
|
+
|
|
10
|
+
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
11
|
+
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
12
|
+
|
|
13
|
+
import {IZoraLimitOrderBook} from "../IZoraLimitOrderBook.sol";
|
|
14
|
+
import {LimitOrderStorage} from "./LimitOrderStorage.sol";
|
|
15
|
+
import {LimitOrderTypes} from "./LimitOrderTypes.sol";
|
|
16
|
+
import {LimitOrderQueues} from "./LimitOrderQueues.sol";
|
|
17
|
+
import {LimitOrderBitmap} from "./LimitOrderBitmap.sol";
|
|
18
|
+
|
|
19
|
+
library LimitOrderCommon {
|
|
20
|
+
/// @dev Currency0 orders are executed when the price rises to the lower tick.
|
|
21
|
+
/// Currency1 orders are executed when the price falls to the upper tick.
|
|
22
|
+
function getOrderTick(LimitOrderTypes.LimitOrder storage order) internal view returns (int24) {
|
|
23
|
+
return order.isCurrency0 ? order.tickLower : order.tickUpper;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getOrderCoin(PoolKey memory key, bool isCurrency0) internal pure returns (address) {
|
|
27
|
+
return Currency.unwrap(isCurrency0 ? key.currency0 : key.currency1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function recordCreation(
|
|
31
|
+
LimitOrderStorage.Layout storage state,
|
|
32
|
+
PoolKey memory key,
|
|
33
|
+
bytes32 poolKeyHash,
|
|
34
|
+
bytes32 orderId,
|
|
35
|
+
address maker,
|
|
36
|
+
address coin,
|
|
37
|
+
bool isCurrency0,
|
|
38
|
+
int24 orderTick,
|
|
39
|
+
int24 currentTick,
|
|
40
|
+
uint256 epoch,
|
|
41
|
+
uint128 liquidity,
|
|
42
|
+
uint128 realizedSize,
|
|
43
|
+
int24 tickLower,
|
|
44
|
+
int24 tickUpper
|
|
45
|
+
) internal {
|
|
46
|
+
LimitOrderTypes.LimitOrder storage order = state.limitOrders[orderId];
|
|
47
|
+
order.orderSize = realizedSize;
|
|
48
|
+
order.liquidity = liquidity;
|
|
49
|
+
order.tickLower = tickLower;
|
|
50
|
+
order.tickUpper = tickUpper;
|
|
51
|
+
order.createdEpoch = uint32(epoch);
|
|
52
|
+
order.status = LimitOrderTypes.OrderStatus.OPEN;
|
|
53
|
+
order.isCurrency0 = isCurrency0;
|
|
54
|
+
order.maker = maker;
|
|
55
|
+
order.poolKeyHash = poolKeyHash;
|
|
56
|
+
|
|
57
|
+
LimitOrderTypes.Queue storage tickQueue = state.tickQueues[poolKeyHash][coin][orderTick];
|
|
58
|
+
tickQueue.balance += realizedSize;
|
|
59
|
+
|
|
60
|
+
LimitOrderBitmap.setIfFirst(state.tickBitmaps[poolKeyHash][coin], orderTick, key.tickSpacing, tickQueue.length);
|
|
61
|
+
LimitOrderQueues.enqueue(tickQueue, state.limitOrders, orderId);
|
|
62
|
+
|
|
63
|
+
uint256 newMakerBalance = state.makerBalances[maker][coin] + realizedSize;
|
|
64
|
+
state.makerBalances[maker][coin] = newMakerBalance;
|
|
65
|
+
|
|
66
|
+
emit IZoraLimitOrderBook.LimitOrderCreated(maker, coin, poolKeyHash, isCurrency0, orderTick, currentTick, realizedSize, orderId);
|
|
67
|
+
emit IZoraLimitOrderBook.MakerBalanceUpdated(maker, coin, newMakerBalance);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function removeOrder(
|
|
71
|
+
LimitOrderStorage.Layout storage state,
|
|
72
|
+
PoolKey memory key,
|
|
73
|
+
address coin,
|
|
74
|
+
LimitOrderTypes.Queue storage tickQueue,
|
|
75
|
+
LimitOrderTypes.LimitOrder storage order
|
|
76
|
+
) internal returns (int24 orderTick) {
|
|
77
|
+
uint128 size = order.orderSize;
|
|
78
|
+
tickQueue.balance -= size;
|
|
79
|
+
|
|
80
|
+
LimitOrderQueues.unlink(tickQueue, state.limitOrders, order);
|
|
81
|
+
LimitOrderQueues.clearLinks(order);
|
|
82
|
+
|
|
83
|
+
orderTick = getOrderTick(order);
|
|
84
|
+
LimitOrderBitmap.clearIfEmpty(state.tickBitmaps[order.poolKeyHash][coin], orderTick, key.tickSpacing, tickQueue.length);
|
|
85
|
+
|
|
86
|
+
address maker = order.maker;
|
|
87
|
+
uint256 newMakerBalance = state.makerBalances[maker][coin] - size;
|
|
88
|
+
state.makerBalances[maker][coin] = newMakerBalance;
|
|
89
|
+
emit IZoraLimitOrderBook.MakerBalanceUpdated(maker, coin, newMakerBalance);
|
|
90
|
+
}
|
|
91
|
+
}
|