Skip to content

Commit de26d48

Browse files
committed
test: add invariant_PositionsDifferentTicks invariant test
1 parent 55c388b commit de26d48

File tree

1 file changed

+36
-5
lines changed

1 file changed

+36
-5
lines changed

test/invariant/DopplerInvariants.sol

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ import {State} from "src/Doppler.sol";
88
import {LiquidityAmounts} from "v4-core/test/utils/LiquidityAmounts.sol";
99
import {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+
1130
contract 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

Comments
 (0)