@@ -8,6 +8,25 @@ import {State} from "src/Doppler.sol";
88import {LiquidityAmounts} from "v4-core/test/utils/LiquidityAmounts.sol " ;
99import {TickMath} from "v4-core/src/libraries/TickMath.sol " ;
1010
11+ /*
12+
13+ ? totalTokensSold can't underflow
14+ ? totalProceeds can't underflow
15+ ? Computed ticks can't under/overflow
16+ X Amount of asset tokens to be supplied to liquidity positions at once <= numTokensToSell - totalTokensSold
17+ Likely further have to consider the actual available token balance as dust is lost due to rounding
18+ Does not attempt to create liquidity positions with equal upper and lower ticks
19+ Leads to divide by zero error (even just in computing the liquidity amount)
20+ Also relevant for just doing relevant math, e.g. retrieving liquidity given an amount can result in a revert
21+ Cannot trade the price to below the lower slug range
22+ Else it allows for price manipulation
23+ I think this is also a compliance requirement regardless
24+ Always places a lower slug if totalTokensSold > 0
25+ Selling all tokens back in to the curve must exceed the available liquidity
26+ Single tick ranges do not exceed max liquidity per tick
27+ Cannot modify the price in any way prior to the start time
28+ */
29+
1130contract DopplerInvariantsTest is BaseTest {
1231 DopplerHandler public handler;
1332
@@ -28,11 +47,14 @@ contract DopplerInvariantsTest is BaseTest {
2847 }
2948
3049 function afterInvariant () public view {
31- console.log ("Calls: " , handler.totalCalls ());
32- console.log ("buyExactAmountIn: " , handler.calls (handler.buyExactAmountIn.selector ));
33- console.log ("buyExactAmountOut: " , handler.calls (handler.buyExactAmountOut.selector ));
34- console.log ("sellExactIn: " , handler.calls (handler.sellExactIn.selector ));
35- console.log ("sellExactOut: " , handler.calls (handler.sellExactOut.selector ));
50+ console.log ("+-------------------+-----------------------+ " );
51+ console.log ("| Function Name | Calls | " , handler.totalCalls ());
52+ console.log ("+-------------------+-----------------------+ " );
53+ console.log ("| buyExactAmountIn | " , handler.calls (handler.buyExactAmountIn.selector ), " | " );
54+ console.log ("| buyExactAmountOut | " , handler.calls (handler.buyExactAmountOut.selector ), " | " );
55+ console.log ("| sellExactIn | " , handler.calls (handler.sellExactIn.selector ), " | " );
56+ console.log ("| sellExactOut | " , handler.calls (handler.sellExactOut.selector ), " | " );
57+ console.log ("+-------------------+-----------------------+ " );
3658 }
3759
3860 /// forge-config: default.invariant.fail-on-revert = true
@@ -79,4 +101,13 @@ contract DopplerInvariantsTest is BaseTest {
79101 assertTrue (liquidity > 0 );
80102 }
81103 }
104+
105+ /// forge-config: default.invariant.fail-on-revert = true
106+ function invariant_PositionsDifferentTicks () public view {
107+ uint256 slugs = hook.getNumPDSlugs ();
108+ for (uint256 i = 1 ; i < 4 + slugs; i++ ) {
109+ (int24 tickLower , int24 tickUpper , uint128 liquidity ,) = hook.positions (bytes32 (uint256 (i)));
110+ if (liquidity > 0 ) assertTrue (tickLower != tickUpper);
111+ }
112+ }
82113}
0 commit comments