@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,321 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.13;
|
|
3
|
+
|
|
4
|
+
import {Test} from "forge-std/Test.sol";
|
|
5
|
+
|
|
6
|
+
/// @notice Wrapper contract to expose testable logic from SwapWithLimitOrders
|
|
7
|
+
/// @dev We extract and test the core branching logic without requiring full contract integration
|
|
8
|
+
contract SwapWithLimitOrdersLogicWrapper {
|
|
9
|
+
/// @notice Tests _fillOrders maxFillCount == 0 branch (line 394)
|
|
10
|
+
function shouldFill_maxFillCount(uint256 maxFillCount) external pure returns (bool) {
|
|
11
|
+
if (maxFillCount == 0) {
|
|
12
|
+
return false; // Early return, don't fill
|
|
13
|
+
}
|
|
14
|
+
return true; // Would proceed to fill
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/// @notice Tests tick ordering logic for currency0 (lines 403-406)
|
|
18
|
+
function orderTicks_currency0(int24 tickBeforeSwap, int24 tickAfterSwap) external pure returns (int24 startTick, int24 endTick) {
|
|
19
|
+
bool isCurrency0 = true;
|
|
20
|
+
if (isCurrency0) {
|
|
21
|
+
// Currency0 orders need ascending tick range
|
|
22
|
+
startTick = tickBeforeSwap < tickAfterSwap ? tickBeforeSwap : tickAfterSwap;
|
|
23
|
+
endTick = tickBeforeSwap < tickAfterSwap ? tickAfterSwap : tickBeforeSwap;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// @notice Tests tick ordering logic for currency1 (lines 407-411)
|
|
28
|
+
function orderTicks_currency1(int24 tickBeforeSwap, int24 tickAfterSwap) external pure returns (int24 startTick, int24 endTick) {
|
|
29
|
+
bool isCurrency0 = false;
|
|
30
|
+
if (!isCurrency0) {
|
|
31
|
+
// Currency1 orders need descending tick range
|
|
32
|
+
startTick = tickBeforeSwap > tickAfterSwap ? tickBeforeSwap : tickAfterSwap;
|
|
33
|
+
endTick = tickBeforeSwap > tickAfterSwap ? tickAfterSwap : tickBeforeSwap;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// @notice Tests settlement unallocated branch (line 356)
|
|
38
|
+
function shouldTakeUnallocated(uint128 unallocated) external pure returns (bool) {
|
|
39
|
+
if (unallocated > 0) {
|
|
40
|
+
return true; // Would call poolManager.take()
|
|
41
|
+
}
|
|
42
|
+
return false; // Skip take
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @notice Tests currency type detection for settlement (line 365)
|
|
46
|
+
function isERC20Settlement(address token) external pure returns (bool) {
|
|
47
|
+
if (token != address(0)) {
|
|
48
|
+
return true; // ERC20 path (lines 366-373)
|
|
49
|
+
} else {
|
|
50
|
+
return false; // ETH path (line 375)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// @notice Tests hook fill support check logic (line 198)
|
|
55
|
+
function shouldRouterFill(bool hookSupportsFill, uint256 orderIdsLength, int24 tickBeforeSwap, int24 currentTick) external pure returns (bool) {
|
|
56
|
+
if (!hookSupportsFill && orderIdsLength > 0 && tickBeforeSwap != currentTick) {
|
|
57
|
+
return true; // Router fills
|
|
58
|
+
} else {
|
|
59
|
+
return false; // Hook handles or no fill needed
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @notice Tests V4 route validation (line 150)
|
|
64
|
+
function isValidV4Route(uint256 routeLength) external pure returns (bool) {
|
|
65
|
+
if (routeLength > 0) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false; // Would revert with EmptyV4Route
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// @notice Tests constructor validation branches (lines 120-122)
|
|
72
|
+
function validateConstructorParams(address poolManager, address orderBook, address router) external pure returns (string memory) {
|
|
73
|
+
if (poolManager == address(0)) {
|
|
74
|
+
return "PoolManager cannot be zero";
|
|
75
|
+
}
|
|
76
|
+
if (orderBook == address(0)) {
|
|
77
|
+
return "ZoraLimitOrderBook cannot be zero";
|
|
78
|
+
}
|
|
79
|
+
if (router == address(0)) {
|
|
80
|
+
return "SwapRouter cannot be zero";
|
|
81
|
+
}
|
|
82
|
+
return "Valid";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// @notice Direct unit tests for SwapWithLimitOrders router logic
|
|
87
|
+
contract SwapWithLimitOrdersUnitTest is Test {
|
|
88
|
+
SwapWithLimitOrdersLogicWrapper internal wrapper;
|
|
89
|
+
|
|
90
|
+
function setUp() public {
|
|
91
|
+
wrapper = new SwapWithLimitOrdersLogicWrapper();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// @notice Tests that maxFillCount == 0 returns early
|
|
95
|
+
function test_shouldFill_maxFillCountZero_returnsFalse() public view {
|
|
96
|
+
bool shouldFill = wrapper.shouldFill_maxFillCount(0);
|
|
97
|
+
assertFalse(shouldFill, "should not fill when maxFillCount is 0");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// @notice Tests that maxFillCount > 0 proceeds to fill
|
|
101
|
+
function test_shouldFill_maxFillCountNonZero_returnsTrue() public view {
|
|
102
|
+
bool shouldFill = wrapper.shouldFill_maxFillCount(10);
|
|
103
|
+
assertTrue(shouldFill, "should fill when maxFillCount > 0");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// @notice Tests with maxFillCount == 1 (boundary)
|
|
107
|
+
function test_shouldFill_maxFillCountOne_returnsTrue() public view {
|
|
108
|
+
bool shouldFill = wrapper.shouldFill_maxFillCount(1);
|
|
109
|
+
assertTrue(shouldFill, "should fill when maxFillCount is 1");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// @notice Tests currency0 tick ordering when tickBefore < tickAfter (ascending)
|
|
113
|
+
function test_orderTicks_currency0_ascending() public view {
|
|
114
|
+
int24 tickBefore = 1000;
|
|
115
|
+
int24 tickAfter = 2000;
|
|
116
|
+
|
|
117
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(tickBefore, tickAfter);
|
|
118
|
+
|
|
119
|
+
assertEq(startTick, 1000, "startTick should be tickBefore");
|
|
120
|
+
assertEq(endTick, 2000, "endTick should be tickAfter");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// @notice Tests currency0 tick ordering when tickBefore > tickAfter (needs swap)
|
|
124
|
+
function test_orderTicks_currency0_descending_swaps() public view {
|
|
125
|
+
int24 tickBefore = 2000;
|
|
126
|
+
int24 tickAfter = 1000;
|
|
127
|
+
|
|
128
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(tickBefore, tickAfter);
|
|
129
|
+
|
|
130
|
+
assertEq(startTick, 1000, "startTick should be minimum");
|
|
131
|
+
assertEq(endTick, 2000, "endTick should be maximum");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// @notice Tests currency0 tick ordering when ticks are equal
|
|
135
|
+
function test_orderTicks_currency0_equal() public view {
|
|
136
|
+
int24 tickBefore = 1500;
|
|
137
|
+
int24 tickAfter = 1500;
|
|
138
|
+
|
|
139
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(tickBefore, tickAfter);
|
|
140
|
+
|
|
141
|
+
assertEq(startTick, 1500, "startTick should equal tickBefore");
|
|
142
|
+
assertEq(endTick, 1500, "endTick should equal tickBefore");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// @notice Tests currency1 tick ordering when tickBefore > tickAfter (descending)
|
|
146
|
+
function test_orderTicks_currency1_descending() public view {
|
|
147
|
+
int24 tickBefore = 2000;
|
|
148
|
+
int24 tickAfter = 1000;
|
|
149
|
+
|
|
150
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency1(tickBefore, tickAfter);
|
|
151
|
+
|
|
152
|
+
assertEq(startTick, 2000, "startTick should be tickBefore");
|
|
153
|
+
assertEq(endTick, 1000, "endTick should be tickAfter");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/// @notice Tests currency1 tick ordering when tickBefore < tickAfter (needs swap)
|
|
157
|
+
function test_orderTicks_currency1_ascending_swaps() public view {
|
|
158
|
+
int24 tickBefore = 1000;
|
|
159
|
+
int24 tickAfter = 2000;
|
|
160
|
+
|
|
161
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency1(tickBefore, tickAfter);
|
|
162
|
+
|
|
163
|
+
assertEq(startTick, 2000, "startTick should be maximum");
|
|
164
|
+
assertEq(endTick, 1000, "endTick should be minimum");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// @notice Tests currency1 tick ordering with negative ticks
|
|
168
|
+
function test_orderTicks_currency1_negativeTicks() public view {
|
|
169
|
+
int24 tickBefore = -1000;
|
|
170
|
+
int24 tickAfter = -2000;
|
|
171
|
+
|
|
172
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency1(tickBefore, tickAfter);
|
|
173
|
+
|
|
174
|
+
assertEq(startTick, -1000, "startTick should be -1000");
|
|
175
|
+
assertEq(endTick, -2000, "endTick should be -2000");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// @notice Tests that unallocated > 0 triggers take
|
|
179
|
+
function test_shouldTakeUnallocated_nonZero_returnsTrue() public view {
|
|
180
|
+
bool shouldTake = wrapper.shouldTakeUnallocated(100);
|
|
181
|
+
assertTrue(shouldTake, "should take when unallocated > 0");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// @notice Tests that unallocated == 0 skips take
|
|
185
|
+
function test_shouldTakeUnallocated_zero_returnsFalse() public view {
|
|
186
|
+
bool shouldTake = wrapper.shouldTakeUnallocated(0);
|
|
187
|
+
assertFalse(shouldTake, "should not take when unallocated is 0");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// @notice Tests with boundary value (1)
|
|
191
|
+
function test_shouldTakeUnallocated_one_returnsTrue() public view {
|
|
192
|
+
bool shouldTake = wrapper.shouldTakeUnallocated(1);
|
|
193
|
+
assertTrue(shouldTake, "should take when unallocated is 1");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// @notice Tests ERC20 settlement path (token != address(0))
|
|
197
|
+
function test_isERC20Settlement_nonZeroAddress_returnsTrue() public view {
|
|
198
|
+
bool isERC20 = wrapper.isERC20Settlement(address(0x1234));
|
|
199
|
+
assertTrue(isERC20, "should be ERC20 path for non-zero address");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/// @notice Tests ETH settlement path (token == address(0))
|
|
203
|
+
function test_isERC20Settlement_zeroAddress_returnsFalse() public view {
|
|
204
|
+
bool isERC20 = wrapper.isERC20Settlement(address(0));
|
|
205
|
+
assertFalse(isERC20, "should be ETH path for zero address");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/// @notice Tests router fill when hook doesn't support fill
|
|
209
|
+
function test_shouldRouterFill_hookDoesNotSupport_returnsTrue() public view {
|
|
210
|
+
bool shouldFill = wrapper.shouldRouterFill(
|
|
211
|
+
false, // hookSupportsFill
|
|
212
|
+
2, // orderIdsLength > 0
|
|
213
|
+
1000, // tickBeforeSwap
|
|
214
|
+
1500 // currentTick (different)
|
|
215
|
+
);
|
|
216
|
+
assertTrue(shouldFill, "router should fill when hook doesn't support");
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/// @notice Tests no router fill when hook supports fill
|
|
220
|
+
function test_shouldRouterFill_hookSupports_returnsFalse() public view {
|
|
221
|
+
bool shouldFill = wrapper.shouldRouterFill(
|
|
222
|
+
true, // hookSupportsFill
|
|
223
|
+
2, // orderIdsLength > 0
|
|
224
|
+
1000, // tickBeforeSwap
|
|
225
|
+
1500 // currentTick (different)
|
|
226
|
+
);
|
|
227
|
+
assertFalse(shouldFill, "router should not fill when hook supports");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/// @notice Tests no router fill when no orders created
|
|
231
|
+
function test_shouldRouterFill_noOrders_returnsFalse() public view {
|
|
232
|
+
bool shouldFill = wrapper.shouldRouterFill(
|
|
233
|
+
false, // hookSupportsFill
|
|
234
|
+
0, // orderIdsLength == 0 (no orders)
|
|
235
|
+
1000, // tickBeforeSwap
|
|
236
|
+
1500 // currentTick (different)
|
|
237
|
+
);
|
|
238
|
+
assertFalse(shouldFill, "router should not fill when no orders");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// @notice Tests no router fill when tick hasn't moved
|
|
242
|
+
function test_shouldRouterFill_tickNotMoved_returnsFalse() public view {
|
|
243
|
+
bool shouldFill = wrapper.shouldRouterFill(
|
|
244
|
+
false, // hookSupportsFill
|
|
245
|
+
2, // orderIdsLength > 0
|
|
246
|
+
1000, // tickBeforeSwap
|
|
247
|
+
1000 // currentTick (same - no movement)
|
|
248
|
+
);
|
|
249
|
+
assertFalse(shouldFill, "router should not fill when tick hasn't moved");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/// @notice Tests all conditions must be met for router fill
|
|
253
|
+
function test_shouldRouterFill_allConditionsMet_returnsTrue() public view {
|
|
254
|
+
bool shouldFill = wrapper.shouldRouterFill(
|
|
255
|
+
false, // !hookSupportsFill
|
|
256
|
+
5, // orderIdsLength > 0
|
|
257
|
+
1000, // tickBeforeSwap
|
|
258
|
+
2000 // currentTick != tickBeforeSwap
|
|
259
|
+
);
|
|
260
|
+
assertTrue(shouldFill, "router should fill when all conditions met");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/// @notice Tests valid V4 route with length > 0
|
|
264
|
+
function test_isValidV4Route_nonEmpty_returnsTrue() public view {
|
|
265
|
+
bool isValid = wrapper.isValidV4Route(1);
|
|
266
|
+
assertTrue(isValid, "should be valid for non-empty route");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/// @notice Tests invalid V4 route with length == 0
|
|
270
|
+
function test_isValidV4Route_empty_returnsFalse() public view {
|
|
271
|
+
bool isValid = wrapper.isValidV4Route(0);
|
|
272
|
+
assertFalse(isValid, "should be invalid for empty route");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/// @notice Tests V4 route with multiple pools
|
|
276
|
+
function test_isValidV4Route_multiplePools_returnsTrue() public view {
|
|
277
|
+
bool isValid = wrapper.isValidV4Route(3);
|
|
278
|
+
assertTrue(isValid, "should be valid for multi-hop route");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/// @notice Tests constructor with zero poolManager
|
|
282
|
+
function test_validateConstructorParams_zeroPoolManager() public view {
|
|
283
|
+
string memory result = wrapper.validateConstructorParams(address(0), address(0x1), address(0x2));
|
|
284
|
+
assertEq(result, "PoolManager cannot be zero");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// @notice Tests constructor with zero orderBook
|
|
288
|
+
function test_validateConstructorParams_zeroOrderBook() public view {
|
|
289
|
+
string memory result = wrapper.validateConstructorParams(address(0x1), address(0), address(0x2));
|
|
290
|
+
assertEq(result, "ZoraLimitOrderBook cannot be zero");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/// @notice Tests constructor with zero router
|
|
294
|
+
function test_validateConstructorParams_zeroRouter() public view {
|
|
295
|
+
string memory result = wrapper.validateConstructorParams(address(0x1), address(0x2), address(0));
|
|
296
|
+
assertEq(result, "SwapRouter cannot be zero");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/// @notice Tests constructor with all valid params
|
|
300
|
+
function test_validateConstructorParams_allValid() public view {
|
|
301
|
+
string memory result = wrapper.validateConstructorParams(address(0x1), address(0x2), address(0x3));
|
|
302
|
+
assertEq(result, "Valid");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/// @notice Tests tick ordering with max int24 values
|
|
306
|
+
function test_orderTicks_maxValues() public view {
|
|
307
|
+
int24 maxTick = type(int24).max;
|
|
308
|
+
int24 minTick = type(int24).min;
|
|
309
|
+
|
|
310
|
+
(int24 startTick, int24 endTick) = wrapper.orderTicks_currency0(maxTick, minTick);
|
|
311
|
+
|
|
312
|
+
assertEq(startTick, minTick, "should handle max/min correctly");
|
|
313
|
+
assertEq(endTick, maxTick, "should handle max/min correctly");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/// @notice Tests unallocated with max uint128 value
|
|
317
|
+
function test_shouldTakeUnallocated_maxValue() public view {
|
|
318
|
+
bool shouldTake = wrapper.shouldTakeUnallocated(type(uint128).max);
|
|
319
|
+
assertTrue(shouldTake, "should take with max value");
|
|
320
|
+
}
|
|
321
|
+
}
|