@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
|
@@ -2,25 +2,28 @@
|
|
|
2
2
|
pragma solidity ^0.8.28;
|
|
3
3
|
|
|
4
4
|
import {BaseTest} from "./utils/BaseTest.sol";
|
|
5
|
-
import {
|
|
6
|
-
import {SimpleAccessManaged} from "../src/access/SimpleAccessManaged.sol";
|
|
5
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
7
6
|
import {IZoraLimitOrderBook} from "../src/IZoraLimitOrderBook.sol";
|
|
7
|
+
import {PermittedCallers} from "../src/access/PermittedCallers.sol";
|
|
8
8
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
9
9
|
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
10
10
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
11
11
|
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
12
|
+
import {SwapWithLimitOrders} from "../src/router/SwapWithLimitOrders.sol";
|
|
13
|
+
import {LimitOrderConfig} from "../src/libs/SwapLimitOrders.sol";
|
|
12
14
|
|
|
13
15
|
contract LimitOrderAccessControlTest is BaseTest {
|
|
14
|
-
uint64 public constant CREATOR_ROLE = 1;
|
|
15
16
|
address public unauthorizedUser;
|
|
16
|
-
address public
|
|
17
|
+
address public authorizedCaller;
|
|
18
|
+
address public newOwner;
|
|
17
19
|
|
|
18
20
|
function setUp() public override {
|
|
19
21
|
super.setUpNonForked();
|
|
20
22
|
|
|
21
23
|
// Set up test users
|
|
22
24
|
unauthorizedUser = makeAddr("unauthorizedUser");
|
|
23
|
-
|
|
25
|
+
authorizedCaller = makeAddr("authorizedCaller");
|
|
26
|
+
newOwner = makeAddr("newOwner");
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
function _prepareOrder(
|
|
@@ -69,120 +72,146 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
69
72
|
zoraHookRegistry.registerHooks(hooks, tags);
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
function
|
|
75
|
+
function _setPublicAccess(bool isPublic) internal {
|
|
76
|
+
address[] memory callers = new address[](1);
|
|
77
|
+
callers[0] = address(0); // PUBLIC_ACCESS sentinel
|
|
78
|
+
bool[] memory permitted = new bool[](1);
|
|
79
|
+
permitted[0] = isPublic;
|
|
80
|
+
limitOrderBook.setPermittedCallers(callers, permitted);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Test: create() works in public mode (default)
|
|
84
|
+
function test_create_publicMode() public {
|
|
73
85
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
74
86
|
|
|
87
|
+
// Verify any address is permitted by default (public mode)
|
|
88
|
+
assertTrue(limitOrderBook.isPermittedCaller(unauthorizedUser), "any address should be permitted in public mode");
|
|
89
|
+
|
|
90
|
+
// Anyone can create orders in public mode
|
|
75
91
|
(bool isCurrency0, address orderCoin, uint256[] memory orderSizes, int24[] memory orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
76
92
|
_createOrder(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser, orderCoin);
|
|
77
93
|
}
|
|
78
94
|
|
|
79
|
-
|
|
95
|
+
// Test: setPermittedCallers can toggle public access control via address(0)
|
|
96
|
+
function test_setPermittedCallers_togglesPublicAccessControl() public {
|
|
80
97
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
81
98
|
|
|
82
|
-
// Initially anyone can create
|
|
99
|
+
// Initially public - anyone can create
|
|
100
|
+
assertTrue(limitOrderBook.isPermittedCaller(unauthorizedUser));
|
|
83
101
|
(bool isCurrency0, address orderCoin, uint256[] memory orderSizes, int24[] memory orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
84
102
|
_createOrder(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser, orderCoin);
|
|
85
103
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Grant role to authorized router
|
|
90
|
-
accessManager.grantRole(CREATOR_ROLE, authorizedRouter, 0);
|
|
91
|
-
|
|
92
|
-
// Switch function to require CREATOR_ROLE
|
|
93
|
-
bytes4[] memory selectors = new bytes4[](1);
|
|
94
|
-
selectors[0] = IZoraLimitOrderBook.create.selector;
|
|
95
|
-
accessManager.setTargetFunctionRole(address(limitOrderBook), selectors, CREATOR_ROLE);
|
|
104
|
+
// Owner sets to permissioned mode by disabling address(0)
|
|
105
|
+
_setPublicAccess(false);
|
|
106
|
+
assertFalse(limitOrderBook.isPermittedCaller(unauthorizedUser));
|
|
96
107
|
|
|
97
108
|
// Now unauthorized user should fail
|
|
98
109
|
(isCurrency0, orderCoin, orderSizes, orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
99
|
-
vm.expectRevert(
|
|
110
|
+
vm.expectRevert(PermittedCallers.CallerNotPermitted.selector);
|
|
100
111
|
limitOrderBook.create{value: orderCoin == address(0) ? 1 ether : 0}(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser);
|
|
101
112
|
vm.stopPrank();
|
|
102
113
|
|
|
103
|
-
//
|
|
104
|
-
(
|
|
105
|
-
|
|
114
|
+
// Owner sets back to public mode
|
|
115
|
+
_setPublicAccess(true);
|
|
116
|
+
assertTrue(limitOrderBook.isPermittedCaller(unauthorizedUser));
|
|
106
117
|
|
|
107
|
-
//
|
|
118
|
+
// Now anyone can create again
|
|
119
|
+
(isCurrency0, orderCoin, orderSizes, orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
120
|
+
_createOrder(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser, orderCoin);
|
|
108
121
|
}
|
|
109
122
|
|
|
110
|
-
|
|
123
|
+
// Test: unauthorized user cannot create in permissioned mode
|
|
124
|
+
function test_create_permissionedMode_unauthorizedFails() public {
|
|
111
125
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
112
126
|
|
|
113
|
-
// Set
|
|
114
|
-
|
|
115
|
-
accessManager.grantRole(CREATOR_ROLE, authorizedRouter, 0);
|
|
116
|
-
|
|
117
|
-
bytes4[] memory selectors = new bytes4[](1);
|
|
118
|
-
selectors[0] = IZoraLimitOrderBook.create.selector;
|
|
119
|
-
accessManager.setTargetFunctionRole(address(limitOrderBook), selectors, CREATOR_ROLE);
|
|
127
|
+
// Set to permissioned mode
|
|
128
|
+
_setPublicAccess(false);
|
|
120
129
|
|
|
121
130
|
// Unauthorized user tries to create
|
|
122
131
|
(bool isCurrency0, address orderCoin, uint256[] memory orderSizes, int24[] memory orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
123
|
-
vm.expectRevert(
|
|
132
|
+
vm.expectRevert(PermittedCallers.CallerNotPermitted.selector);
|
|
124
133
|
limitOrderBook.create{value: orderCoin == address(0) ? 1 ether : 0}(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser);
|
|
125
134
|
vm.stopPrank();
|
|
126
135
|
}
|
|
127
136
|
|
|
128
|
-
|
|
137
|
+
// Test: setPermittedCallers grants and revokes access
|
|
138
|
+
function test_setPermittedCallers_grantsAndRevokesAccess() public {
|
|
129
139
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
130
140
|
|
|
131
|
-
// Set
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
bytes4[] memory selectors = new bytes4[](1);
|
|
135
|
-
selectors[0] = IZoraLimitOrderBook.create.selector;
|
|
136
|
-
accessManager.setTargetFunctionRole(address(limitOrderBook), selectors, CREATOR_ROLE);
|
|
141
|
+
// Set to permissioned mode
|
|
142
|
+
_setPublicAccess(false);
|
|
137
143
|
|
|
138
144
|
// Initially unauthorized user cannot create
|
|
139
145
|
(bool isCurrency0, address orderCoin, uint256[] memory orderSizes, int24[] memory orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
140
|
-
vm.expectRevert(
|
|
146
|
+
vm.expectRevert(PermittedCallers.CallerNotPermitted.selector);
|
|
141
147
|
limitOrderBook.create{value: orderCoin == address(0) ? 1 ether : 0}(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser);
|
|
142
148
|
vm.stopPrank();
|
|
143
149
|
|
|
144
|
-
// Grant
|
|
145
|
-
|
|
150
|
+
// Grant access to user
|
|
151
|
+
address[] memory callers = new address[](1);
|
|
152
|
+
callers[0] = unauthorizedUser;
|
|
153
|
+
bool[] memory permitted = new bool[](1);
|
|
154
|
+
permitted[0] = true;
|
|
155
|
+
limitOrderBook.setPermittedCallers(callers, permitted);
|
|
156
|
+
|
|
157
|
+
assertTrue(limitOrderBook.isPermittedCaller(unauthorizedUser), "user should be permitted");
|
|
146
158
|
|
|
147
159
|
// Now user can create
|
|
148
160
|
(isCurrency0, orderCoin, orderSizes, orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
149
161
|
_createOrder(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser, orderCoin);
|
|
150
162
|
|
|
151
|
-
// Revoke
|
|
152
|
-
|
|
163
|
+
// Revoke access
|
|
164
|
+
permitted[0] = false;
|
|
165
|
+
limitOrderBook.setPermittedCallers(callers, permitted);
|
|
166
|
+
|
|
167
|
+
assertFalse(limitOrderBook.isPermittedCaller(unauthorizedUser), "user should not be permitted");
|
|
153
168
|
|
|
154
169
|
// Now user cannot create again
|
|
155
170
|
(isCurrency0, orderCoin, orderSizes, orderTicks) = _prepareOrder(unauthorizedUser, key);
|
|
156
|
-
vm.expectRevert(
|
|
171
|
+
vm.expectRevert(PermittedCallers.CallerNotPermitted.selector);
|
|
157
172
|
limitOrderBook.create{value: orderCoin == address(0) ? 1 ether : 0}(key, isCurrency0, orderSizes, orderTicks, unauthorizedUser);
|
|
158
173
|
vm.stopPrank();
|
|
159
174
|
}
|
|
160
175
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
(
|
|
183
|
-
|
|
176
|
+
// Test: setPermittedCallers works with multiple addresses
|
|
177
|
+
function test_setPermittedCallers_batchUpdate() public {
|
|
178
|
+
address caller1 = makeAddr("caller1");
|
|
179
|
+
address caller2 = makeAddr("caller2");
|
|
180
|
+
address caller3 = makeAddr("caller3");
|
|
181
|
+
|
|
182
|
+
_setPublicAccess(false);
|
|
183
|
+
|
|
184
|
+
// Grant access to multiple callers
|
|
185
|
+
address[] memory callers = new address[](3);
|
|
186
|
+
callers[0] = caller1;
|
|
187
|
+
callers[1] = caller2;
|
|
188
|
+
callers[2] = caller3;
|
|
189
|
+
// set public to false
|
|
190
|
+
bool[] memory permitted = new bool[](3);
|
|
191
|
+
permitted[0] = true;
|
|
192
|
+
permitted[1] = true;
|
|
193
|
+
permitted[2] = true;
|
|
194
|
+
|
|
195
|
+
limitOrderBook.setPermittedCallers(callers, permitted);
|
|
196
|
+
|
|
197
|
+
assertTrue(limitOrderBook.isPermittedCaller(caller1));
|
|
198
|
+
assertTrue(limitOrderBook.isPermittedCaller(caller2));
|
|
199
|
+
assertTrue(limitOrderBook.isPermittedCaller(caller3));
|
|
200
|
+
|
|
201
|
+
// Revoke access from caller2
|
|
202
|
+
address[] memory revokeList = new address[](1);
|
|
203
|
+
revokeList[0] = caller2;
|
|
204
|
+
bool[] memory revokePermitted = new bool[](1);
|
|
205
|
+
revokePermitted[0] = false;
|
|
206
|
+
|
|
207
|
+
limitOrderBook.setPermittedCallers(revokeList, revokePermitted);
|
|
208
|
+
|
|
209
|
+
assertTrue(limitOrderBook.isPermittedCaller(caller1));
|
|
210
|
+
assertFalse(limitOrderBook.isPermittedCaller(caller2));
|
|
211
|
+
assertTrue(limitOrderBook.isPermittedCaller(caller3));
|
|
184
212
|
}
|
|
185
213
|
|
|
214
|
+
// Test: non-hook cannot fill while unlocked
|
|
186
215
|
function test_nonHookCannotFillWhileUnlocked() public {
|
|
187
216
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
188
217
|
|
|
@@ -194,6 +223,7 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
194
223
|
caller.attemptUnlockedFill(key, false, -type(int24).max, type(int24).max, 1, address(0));
|
|
195
224
|
}
|
|
196
225
|
|
|
226
|
+
// Test: registered hook can fill while unlocked
|
|
197
227
|
function test_fillRegisteredHookCanFillWhileUnlocked() public {
|
|
198
228
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
199
229
|
|
|
@@ -217,6 +247,7 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
217
247
|
assertEq(_makerBalance(users.seller, created[0].coin), 0, "maker balance should be zero");
|
|
218
248
|
}
|
|
219
249
|
|
|
250
|
+
// Test: unregistered hook cannot fill while unlocked
|
|
220
251
|
function test_fillUnregisteredHookCannotFillWhileUnlocked() public {
|
|
221
252
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
222
253
|
UnlockedFillCaller caller = new UnlockedFillCaller(address(limitOrderBook), address(poolManager));
|
|
@@ -225,6 +256,7 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
225
256
|
caller.attemptUnlockedFill(key, true, -type(int24).max, type(int24).max, 5, address(0));
|
|
226
257
|
}
|
|
227
258
|
|
|
259
|
+
// Test: fill maxFillCount defaults to storage
|
|
228
260
|
function test_fill_MaxFillCountDefaultsToStorage() public {
|
|
229
261
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
230
262
|
|
|
@@ -237,7 +269,6 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
237
269
|
_movePriceBeyondTicksWithAutoFillDisabled(created);
|
|
238
270
|
|
|
239
271
|
uint256 previousMax = limitOrderBook.getMaxFillCount();
|
|
240
|
-
vm.prank(users.factoryOwner);
|
|
241
272
|
limitOrderBook.setMaxFillCount(2);
|
|
242
273
|
(int24 startTick, int24 endTick) = _tickWindow(created, key);
|
|
243
274
|
|
|
@@ -246,10 +277,10 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
246
277
|
FilledOrderLog[] memory fills = _decodeFilledLogs(vm.getRecordedLogs());
|
|
247
278
|
assertEq(fills.length, 2, "should use stored maxFillCount when input is zero");
|
|
248
279
|
|
|
249
|
-
vm.prank(users.factoryOwner);
|
|
250
280
|
limitOrderBook.setMaxFillCount(previousMax);
|
|
251
281
|
}
|
|
252
282
|
|
|
283
|
+
// Test: fillBatch ignores empty order arrays
|
|
253
284
|
function test_fillBatchIgnoresEmptyOrderArrays() public {
|
|
254
285
|
PoolKey memory key = creatorCoin.getPoolKey();
|
|
255
286
|
|
|
@@ -288,138 +319,128 @@ contract LimitOrderAccessControlTest is BaseTest {
|
|
|
288
319
|
assertApproxEqAbs(makerBalanceBefore - makerBalanceAfter, expectedDelta, 3, "unexpected maker balance delta");
|
|
289
320
|
}
|
|
290
321
|
|
|
322
|
+
// Test: unlockCallback reverts for non-poolManager
|
|
291
323
|
function test_unlockCallbackRevertsForNonPoolManager() public {
|
|
292
324
|
vm.expectRevert(IZoraLimitOrderBook.NotPoolManager.selector);
|
|
293
325
|
limitOrderBook.unlockCallback(bytes(""));
|
|
294
326
|
}
|
|
295
327
|
|
|
328
|
+
// Test: receive reverts for non-poolManager
|
|
296
329
|
function test_receiveRevertsForNonPoolManager() public {
|
|
297
330
|
vm.deal(address(this), 1 ether);
|
|
298
331
|
vm.expectRevert(IZoraLimitOrderBook.NotPoolManager.selector);
|
|
299
332
|
payable(address(limitOrderBook)).transfer(1 wei);
|
|
300
333
|
}
|
|
301
334
|
|
|
302
|
-
|
|
335
|
+
// Test: setMaxFillCount - owner can set
|
|
336
|
+
function test_setMaxFillCount_ownerCanSet() public {
|
|
303
337
|
// Initially max fill count should be 50 (set in BaseTest)
|
|
304
338
|
assertEq(limitOrderBook.getMaxFillCount(), 50);
|
|
305
339
|
|
|
306
|
-
//
|
|
307
|
-
// Any user should be able to set it
|
|
308
|
-
vm.prank(unauthorizedUser);
|
|
340
|
+
// Owner (this contract) should be able to set it
|
|
309
341
|
limitOrderBook.setMaxFillCount(20);
|
|
310
342
|
|
|
311
343
|
assertEq(limitOrderBook.getMaxFillCount(), 20);
|
|
312
344
|
}
|
|
313
345
|
|
|
346
|
+
// Test: setMaxFillCount - unauthorized user cannot set
|
|
314
347
|
function test_setMaxFillCount_unauthorizedUserCannotSet() public {
|
|
315
|
-
uint64 MAX_FILL_COUNT_ROLE = 2;
|
|
316
|
-
|
|
317
|
-
// Set up permissioned mode for setMaxFillCount
|
|
318
|
-
accessManager.labelRole(MAX_FILL_COUNT_ROLE, "MAX_FILL_COUNT_SETTER");
|
|
319
|
-
accessManager.grantRole(MAX_FILL_COUNT_ROLE, authorizedRouter, 0);
|
|
320
|
-
|
|
321
|
-
bytes4[] memory selectors = new bytes4[](1);
|
|
322
|
-
selectors[0] = IZoraLimitOrderBook.setMaxFillCount.selector;
|
|
323
|
-
accessManager.setTargetFunctionRole(address(limitOrderBook), selectors, MAX_FILL_COUNT_ROLE);
|
|
324
|
-
|
|
325
348
|
// Unauthorized user tries to set max fill count
|
|
326
349
|
vm.prank(unauthorizedUser);
|
|
327
|
-
vm.expectRevert(
|
|
350
|
+
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, unauthorizedUser));
|
|
328
351
|
limitOrderBook.setMaxFillCount(20);
|
|
329
352
|
|
|
330
353
|
// Verify value hasn't changed (still 50 from BaseTest)
|
|
331
354
|
assertEq(limitOrderBook.getMaxFillCount(), 50);
|
|
332
355
|
}
|
|
333
356
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
bytes4[] memory selectors = new bytes4[](1);
|
|
342
|
-
selectors[0] = IZoraLimitOrderBook.setMaxFillCount.selector;
|
|
343
|
-
accessManager.setTargetFunctionRole(address(limitOrderBook), selectors, MAX_FILL_COUNT_ROLE);
|
|
357
|
+
// Test: setPermittedCallers - owner can set
|
|
358
|
+
function test_setPermittedCallers_ownerCanSet() public {
|
|
359
|
+
address[] memory callers = new address[](1);
|
|
360
|
+
callers[0] = authorizedCaller;
|
|
361
|
+
bool[] memory permitted = new bool[](1);
|
|
362
|
+
permitted[0] = true;
|
|
344
363
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
limitOrderBook.setMaxFillCount(25);
|
|
348
|
-
|
|
349
|
-
assertEq(limitOrderBook.getMaxFillCount(), 25);
|
|
364
|
+
limitOrderBook.setPermittedCallers(callers, permitted);
|
|
365
|
+
assertTrue(limitOrderBook.isPermittedCaller(authorizedCaller));
|
|
350
366
|
}
|
|
351
367
|
|
|
352
|
-
|
|
353
|
-
|
|
368
|
+
// Test: setPermittedCallers - unauthorized user cannot set
|
|
369
|
+
function test_setPermittedCallers_unauthorizedUserCannotSet() public {
|
|
370
|
+
address[] memory callers = new address[](0);
|
|
371
|
+
bool[] memory permitted = new bool[](0);
|
|
354
372
|
|
|
355
|
-
|
|
356
|
-
|
|
373
|
+
vm.prank(unauthorizedUser);
|
|
374
|
+
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, unauthorizedUser));
|
|
375
|
+
limitOrderBook.setPermittedCallers(callers, permitted);
|
|
376
|
+
}
|
|
357
377
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
378
|
+
// Test: setLimitOrderConfig - owner can set
|
|
379
|
+
function test_setLimitOrderConfig_ownerCanSet() public {
|
|
380
|
+
// Owner (this contract) should be able to set limit order config
|
|
381
|
+
uint256[] memory multiples = new uint256[](2);
|
|
382
|
+
multiples[0] = 2e18; // 2x
|
|
383
|
+
multiples[1] = 3e18; // 3x
|
|
361
384
|
|
|
362
|
-
|
|
363
|
-
|
|
385
|
+
uint256[] memory percentages = new uint256[](2);
|
|
386
|
+
percentages[0] = 5000; // 50%
|
|
387
|
+
percentages[1] = 5000; // 50%
|
|
364
388
|
|
|
365
|
-
|
|
366
|
-
limitOrderBook.setMaxFillCount(30);
|
|
389
|
+
LimitOrderConfig memory config = LimitOrderConfig({multiples: multiples, percentages: percentages});
|
|
367
390
|
|
|
368
|
-
|
|
391
|
+
swapWithLimitOrders.setLimitOrderConfig(config);
|
|
369
392
|
}
|
|
370
393
|
|
|
371
|
-
|
|
372
|
-
|
|
394
|
+
// Test: setLimitOrderConfig - unauthorized user cannot set
|
|
395
|
+
function test_setLimitOrderConfig_unauthorizedUserCannotSet() public {
|
|
396
|
+
uint256[] memory multiples = new uint256[](2);
|
|
397
|
+
multiples[0] = 2e18;
|
|
398
|
+
multiples[1] = 3e18;
|
|
373
399
|
|
|
374
|
-
|
|
375
|
-
|
|
400
|
+
uint256[] memory percentages = new uint256[](2);
|
|
401
|
+
percentages[0] = 5000;
|
|
402
|
+
percentages[1] = 5000;
|
|
376
403
|
|
|
377
|
-
|
|
378
|
-
selectors[0] = IZoraLimitOrderBook.setMaxFillCount.selector;
|
|
379
|
-
accessManager.setTargetFunctionRole(address(limitOrderBook), selectors, MAX_FILL_COUNT_ROLE);
|
|
404
|
+
LimitOrderConfig memory config = LimitOrderConfig({multiples: multiples, percentages: percentages});
|
|
380
405
|
|
|
381
|
-
//
|
|
406
|
+
// Unauthorized user tries to set config
|
|
382
407
|
vm.prank(unauthorizedUser);
|
|
383
|
-
vm.expectRevert(
|
|
384
|
-
|
|
408
|
+
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, unauthorizedUser));
|
|
409
|
+
swapWithLimitOrders.setLimitOrderConfig(config);
|
|
410
|
+
}
|
|
385
411
|
|
|
386
|
-
|
|
387
|
-
|
|
412
|
+
// Test: ownership transfer (two-step process)
|
|
413
|
+
function test_ownershipTransfer() public {
|
|
414
|
+
// Initial owner is this contract
|
|
415
|
+
assertEq(limitOrderBook.owner(), address(this));
|
|
388
416
|
|
|
389
|
-
//
|
|
390
|
-
|
|
391
|
-
limitOrderBook.setMaxFillCount(15);
|
|
392
|
-
assertEq(limitOrderBook.getMaxFillCount(), 15);
|
|
417
|
+
// Step 1: Current owner proposes transfer
|
|
418
|
+
limitOrderBook.transferOwnership(newOwner);
|
|
393
419
|
|
|
394
|
-
//
|
|
395
|
-
|
|
420
|
+
// Ownership hasn't changed yet
|
|
421
|
+
assertEq(limitOrderBook.owner(), address(this));
|
|
422
|
+
assertEq(limitOrderBook.pendingOwner(), newOwner);
|
|
396
423
|
|
|
397
|
-
//
|
|
398
|
-
vm.prank(
|
|
399
|
-
vm.expectRevert(
|
|
400
|
-
limitOrderBook.setMaxFillCount(
|
|
424
|
+
// New owner cannot perform owner actions yet
|
|
425
|
+
vm.prank(newOwner);
|
|
426
|
+
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, newOwner));
|
|
427
|
+
limitOrderBook.setMaxFillCount(100);
|
|
401
428
|
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
429
|
+
// Step 2: New owner accepts transfer
|
|
430
|
+
vm.prank(newOwner);
|
|
431
|
+
limitOrderBook.acceptOwnership();
|
|
405
432
|
|
|
406
|
-
|
|
407
|
-
|
|
433
|
+
// Now ownership has transferred
|
|
434
|
+
assertEq(limitOrderBook.owner(), newOwner);
|
|
408
435
|
|
|
409
|
-
|
|
410
|
-
vm.
|
|
411
|
-
limitOrderBook.
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
function test_setAuthority_revertsForNonContractAddress() public {
|
|
415
|
-
// Deploy a simple test contract with test contract as authority
|
|
416
|
-
AuthorityTester tester = new AuthorityTester(address(this));
|
|
417
|
-
|
|
418
|
-
address eoaAddress = makeAddr("eoa");
|
|
436
|
+
// New owner can perform owner actions
|
|
437
|
+
vm.prank(newOwner);
|
|
438
|
+
limitOrderBook.setMaxFillCount(100);
|
|
439
|
+
assertEq(limitOrderBook.getMaxFillCount(), 100);
|
|
419
440
|
|
|
420
|
-
//
|
|
421
|
-
vm.expectRevert(abi.encodeWithSelector(
|
|
422
|
-
|
|
441
|
+
// Old owner cannot perform owner actions
|
|
442
|
+
vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(this)));
|
|
443
|
+
limitOrderBook.setMaxFillCount(50);
|
|
423
444
|
}
|
|
424
445
|
}
|
|
425
446
|
|
|
@@ -455,7 +476,3 @@ contract UnlockedFillCaller {
|
|
|
455
476
|
return bytes("");
|
|
456
477
|
}
|
|
457
478
|
}
|
|
458
|
-
|
|
459
|
-
contract AuthorityTester is SimpleAccessManaged {
|
|
460
|
-
constructor(address initialAuthority) SimpleAccessManaged(initialAuthority) {}
|
|
461
|
-
}
|
|
@@ -30,7 +30,8 @@ contract LimitOrderBitmapTest is BaseTest {
|
|
|
30
30
|
|
|
31
31
|
// Verify all ticks are initialized in bitmap
|
|
32
32
|
for (uint256 i; i < orderTicks.length; ++i) {
|
|
33
|
-
|
|
33
|
+
int24 fillableTick = _fillableTick(isCurrency0, orderTicks[i], key.tickSpacing);
|
|
34
|
+
assertTrue(_isTickInitialized(poolKeyHash, orderCoin, fillableTick, key.tickSpacing), "tick should be initialized");
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -52,7 +53,8 @@ contract LimitOrderBitmapTest is BaseTest {
|
|
|
52
53
|
bytes32 poolKeyHash = created[0].poolKeyHash;
|
|
53
54
|
|
|
54
55
|
// Verify tick is initialized
|
|
55
|
-
|
|
56
|
+
int24 fillableTick = _fillableTick(isCurrency0, orderTicks[0], key.tickSpacing);
|
|
57
|
+
assertTrue(_isTickInitialized(poolKeyHash, orderCoin, fillableTick, key.tickSpacing), "tick should be initialized after create");
|
|
56
58
|
|
|
57
59
|
// Withdraw order
|
|
58
60
|
bytes32[] memory orderIds = new bytes32[](1);
|
|
@@ -61,7 +63,7 @@ contract LimitOrderBitmapTest is BaseTest {
|
|
|
61
63
|
limitOrderBook.withdraw(orderIds, orderCoin, 0, users.seller);
|
|
62
64
|
|
|
63
65
|
// Verify tick is cleared in bitmap
|
|
64
|
-
assertFalse(_isTickInitialized(poolKeyHash, orderCoin,
|
|
66
|
+
assertFalse(_isTickInitialized(poolKeyHash, orderCoin, fillableTick, key.tickSpacing), "tick should be cleared after withdraw");
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
function test_bitmap_RemainsSetWithPartialOrders() public {
|
|
@@ -95,7 +97,8 @@ contract LimitOrderBitmapTest is BaseTest {
|
|
|
95
97
|
limitOrderBook.withdraw(orderIds, orderCoin, 0, users.seller);
|
|
96
98
|
|
|
97
99
|
// Bitmap should still be set because second order remains
|
|
98
|
-
|
|
100
|
+
int24 fillableTick = _fillableTick(isCurrency0, tick, key.tickSpacing);
|
|
101
|
+
assertTrue(_isTickInitialized(poolKeyHash, orderCoin, fillableTick, key.tickSpacing), "tick should remain initialized with remaining order");
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
function test_bitmap_wordBoundaries() public {
|
|
@@ -129,7 +132,8 @@ contract LimitOrderBitmapTest is BaseTest {
|
|
|
129
132
|
|
|
130
133
|
// Verify all boundary ticks are initialized
|
|
131
134
|
for (uint256 i = 0; i < boundaryTicks.length; i++) {
|
|
132
|
-
|
|
135
|
+
int24 fillableTick = _fillableTick(isCurrency0, boundaryTicks[i], spacing);
|
|
136
|
+
assertTrue(_isTickInitialized(poolKeyHash, orderCoin, fillableTick, spacing), "boundary tick should be initialized");
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -171,8 +175,10 @@ contract LimitOrderBitmapTest is BaseTest {
|
|
|
171
175
|
bytes32 poolKeyHash = created[0].poolKeyHash;
|
|
172
176
|
|
|
173
177
|
// Verify extreme ticks are initialized
|
|
174
|
-
|
|
175
|
-
|
|
178
|
+
int24 fillableTick0 = _fillableTick(isCurrency0, extremeTicks[0], spacing);
|
|
179
|
+
int24 fillableTick1 = _fillableTick(isCurrency0, extremeTicks[1], spacing);
|
|
180
|
+
assertTrue(_isTickInitialized(poolKeyHash, orderCoin, fillableTick0, spacing), "far tick 1 should be initialized");
|
|
181
|
+
assertTrue(_isTickInitialized(poolKeyHash, orderCoin, fillableTick1, spacing), "far tick 2 should be initialized");
|
|
176
182
|
}
|
|
177
183
|
|
|
178
184
|
function _fundAndApprove(address user, address token, uint256 amount) internal {
|
|
@@ -202,7 +202,6 @@ contract LimitOrderFillTest is BaseTest {
|
|
|
202
202
|
bool isCurrency0 = Currency.unwrap(key.currency0) == address(creatorCoin);
|
|
203
203
|
address orderCoin = _orderCoin(key, isCurrency0);
|
|
204
204
|
|
|
205
|
-
vm.prank(users.factoryOwner);
|
|
206
205
|
limitOrderBook.setMaxFillCount(2);
|
|
207
206
|
|
|
208
207
|
(uint256[] memory orderSizes, int24[] memory orderTicks) = _buildDeterministicOrders(key, isCurrency0, 3, 20e18);
|
|
@@ -336,7 +335,6 @@ contract LimitOrderFillTest is BaseTest {
|
|
|
336
335
|
|
|
337
336
|
// 3. Now DISABLE hook auto-fills
|
|
338
337
|
uint256 originalMaxFillCount = limitOrderBook.getMaxFillCount();
|
|
339
|
-
vm.prank(users.factoryOwner);
|
|
340
338
|
limitOrderBook.setMaxFillCount(0);
|
|
341
339
|
|
|
342
340
|
// 4. Move price past the order WITHOUT triggering hook fills
|
|
@@ -345,7 +343,6 @@ contract LimitOrderFillTest is BaseTest {
|
|
|
345
343
|
_swapSomeCurrencyForCoin(ICoin(address(creatorCoin)), address(zoraToken), swapAmount, swapper);
|
|
346
344
|
|
|
347
345
|
// 5. Restore original maxFillCount
|
|
348
|
-
vm.prank(users.factoryOwner);
|
|
349
346
|
limitOrderBook.setMaxFillCount(originalMaxFillCount);
|
|
350
347
|
|
|
351
348
|
// 6. Verify order exists and check epoch
|
|
@@ -775,7 +772,6 @@ contract LimitOrderFillTest is BaseTest {
|
|
|
775
772
|
address orderCoin = _orderCoin(key, isCurrency0);
|
|
776
773
|
|
|
777
774
|
// Set max fill count to 2 so we can verify default is used
|
|
778
|
-
vm.prank(users.factoryOwner);
|
|
779
775
|
limitOrderBook.setMaxFillCount(2);
|
|
780
776
|
|
|
781
777
|
// Create 5 orders that can be filled
|
|
@@ -814,6 +810,48 @@ contract LimitOrderFillTest is BaseTest {
|
|
|
814
810
|
assertEq(fills.length, 2, "should fill default max count of 2 orders");
|
|
815
811
|
}
|
|
816
812
|
|
|
813
|
+
/// @notice Tests fill() caps maxFillCount to configured default
|
|
814
|
+
function test_fill_maxFillCountExceedsDefault_isCapped() public {
|
|
815
|
+
PoolKey memory key = creatorCoin.getPoolKey();
|
|
816
|
+
bool isCurrency0 = Currency.unwrap(key.currency0) == address(creatorCoin);
|
|
817
|
+
address orderCoin = _orderCoin(key, isCurrency0);
|
|
818
|
+
|
|
819
|
+
// Set max fill count to 2
|
|
820
|
+
limitOrderBook.setMaxFillCount(2);
|
|
821
|
+
|
|
822
|
+
// Create 5 fillable orders
|
|
823
|
+
(uint256[] memory orderSizes, int24[] memory orderTicks) = _buildDeterministicOrders(key, isCurrency0, 5, 20e18);
|
|
824
|
+
uint256 totalSize;
|
|
825
|
+
for (uint256 i; i < orderSizes.length; ++i) {
|
|
826
|
+
totalSize += orderSizes[i];
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (orderCoin == address(0)) {
|
|
830
|
+
vm.deal(users.seller, totalSize);
|
|
831
|
+
} else {
|
|
832
|
+
deal(orderCoin, users.seller, totalSize);
|
|
833
|
+
vm.startPrank(users.seller);
|
|
834
|
+
IERC20(orderCoin).approve(address(limitOrderBook), totalSize);
|
|
835
|
+
vm.stopPrank();
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
vm.recordLogs();
|
|
839
|
+
vm.prank(users.seller);
|
|
840
|
+
limitOrderBook.create{value: orderCoin == address(0) ? totalSize : 0}(key, isCurrency0, orderSizes, orderTicks, users.seller);
|
|
841
|
+
CreatedOrderLog[] memory created = _decodeCreatedLogs(vm.getRecordedLogs());
|
|
842
|
+
|
|
843
|
+
_movePriceBeyondTicksWithAutoFillDisabled(created);
|
|
844
|
+
(int24 startTick, int24 endTick) = _tickWindow(created, key);
|
|
845
|
+
|
|
846
|
+
// Call fill with maxFillCount = 100 (way above default of 2)
|
|
847
|
+
vm.recordLogs();
|
|
848
|
+
limitOrderBook.fill(key, isCurrency0, startTick, endTick, 100, address(0));
|
|
849
|
+
FilledOrderLog[] memory fills = _decodeFilledLogs(vm.getRecordedLogs());
|
|
850
|
+
|
|
851
|
+
// Should cap to 2 orders (the configured max)
|
|
852
|
+
assertEq(fills.length, 2, "should cap to configured max of 2 orders");
|
|
853
|
+
}
|
|
854
|
+
|
|
817
855
|
/// @notice Tests batch fill with empty orderIds array (line 134)
|
|
818
856
|
/// @dev This tests the branch: if (batch.orderIds.length != 0)
|
|
819
857
|
function test_batchFill_emptyOrderIds_skips() public {
|