From c109924b82e9bca7a3c75461ee2546e84a5a7f72 Mon Sep 17 00:00:00 2001
From: dianakocsis <diana.kocsis@uniswap.org>
Date: Fri, 17 Jan 2025 14:48:17 -0500
Subject: [PATCH] add liquidity beforehand

---
 .../PositionManager.modifyLiquidities.t.sol   | 128 ++++++++----------
 1 file changed, 57 insertions(+), 71 deletions(-)

diff --git a/test/position-managers/PositionManager.modifyLiquidities.t.sol b/test/position-managers/PositionManager.modifyLiquidities.t.sol
index 148598b41..c2f5b0fcc 100644
--- a/test/position-managers/PositionManager.modifyLiquidities.t.sol
+++ b/test/position-managers/PositionManager.modifyLiquidities.t.sol
@@ -982,59 +982,18 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
         }
     }
 
-    function test_fuzz_mintFromDeltas_burn_maxFot_cannotRedeemBothTokens(
-        uint256 amount0,
-        uint256 amount1,
-        int24 tickLower,
-        int24 tickUpper
-    ) public {
-        MockFOT(address(fotToken)).setFee(10_000);
-        tickLower = int24(
-            bound(
-                tickLower,
-                fotKey.tickSpacing * (TickMath.MIN_TICK / fotKey.tickSpacing),
-                fotKey.tickSpacing * (TickMath.MAX_TICK / fotKey.tickSpacing)
-            )
-        );
-        tickUpper = int24(
-            bound(
-                tickUpper,
-                fotKey.tickSpacing * (TickMath.MIN_TICK / fotKey.tickSpacing),
-                fotKey.tickSpacing * (TickMath.MAX_TICK / fotKey.tickSpacing)
-            )
-        );
-
-        tickLower = fotKey.tickSpacing * (tickLower / fotKey.tickSpacing);
-        tickUpper = fotKey.tickSpacing * (tickUpper / fotKey.tickSpacing);
-        vm.assume(tickUpper > tickLower);
-
+    function test_mintFromDeltas_burn_maxFot_cannotRedeemBothTokens() public {
+        int24 tickUpper = 60;
         (uint160 sqrtPriceX96,,,) = manager.getSlot0(fotKey.toId());
-        {
-            uint128 maxLiquidityPerTick = Pool.tickSpacingToMaxLiquidityPerTick(fotKey.tickSpacing);
-            (uint256 maxAmount0, uint256 maxAmount1) = LiquidityAmounts.getAmountsForLiquidity(
-                sqrtPriceX96,
-                TickMath.getSqrtPriceAtTick(tickLower),
-                TickMath.getSqrtPriceAtTick(tickUpper),
-                maxLiquidityPerTick
-            );
-
-            maxAmount0 = maxAmount0 == 0 ? 1 : maxAmount0 > STARTING_USER_BALANCE ? STARTING_USER_BALANCE : maxAmount0;
-            maxAmount1 = maxAmount1 == 0 ? 1 : maxAmount1 > STARTING_USER_BALANCE ? STARTING_USER_BALANCE : maxAmount1;
-            amount0 = bound(amount0, 1, maxAmount0);
-            amount1 = bound(amount1, 1, maxAmount1);
-        }
+        // current tick is 0, tickLower is -60
+        int24 tickLower = TickMath.getTickAtSqrtPrice(sqrtPriceX96) - fotKey.tickSpacing;
 
         uint256 tokenId = lpm.nextTokenId();
 
-        BalanceDiff memory balance0 = BalanceDiff(fotKey.currency0.balanceOf(address(this)), 0);
-        BalanceDiff memory balance1 = BalanceDiff(fotKey.currency1.balanceOf(address(this)), 0);
-        BalanceDiff memory balance0PM = BalanceDiff(fotKey.currency0.balanceOf(address(manager)), 0);
-        BalanceDiff memory balance1PM = BalanceDiff(fotKey.currency1.balanceOf(address(manager)), 0);
-
         Plan memory planner = Planner.init();
 
-        planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, amount0, true));
-        planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, amount1, true));
+        planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, 1 ether, true));
+        planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, 1 ether, true));
         planner.add(
             Actions.MINT_POSITION_FROM_DELTAS,
             abi.encode(
@@ -1050,19 +1009,51 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
         // take the excess of each currency
         planner.add(Actions.TAKE_PAIR, abi.encode(fotKey.currency0, fotKey.currency1, ActionConstants.MSG_SENDER));
 
-        // needed to remove variables because of stack too deep
-        // Read below as:
-        // bool currency0IsFOT = fotKey.currency0 == Currency.wrap(address(fotToken));
-        // bool positionIsEntirelyInOtherToken = currency0IsFOT
-        //     ? TickMath.getSqrtPriceAtTick(tickUpper) <= sqrtPriceX96
-        //     : TickMath.getSqrtPriceAtTick(tickLower) >= sqrtPriceX96;
-        // if (positionIsEntirelyInOtherToken) {
-        if (
-            fotKey.currency0 == Currency.wrap(address(fotToken))
-                ? TickMath.getSqrtPriceAtTick(tickUpper) <= sqrtPriceX96
-                : TickMath.getSqrtPriceAtTick(tickLower) >= sqrtPriceX96
-        ) {
+        // alice adds the liquidity in range [-60, 60]
+        vm.prank(alice);
+        seedToken(fotToken, alice);
+        IERC20(Currency.unwrap(fotKey.currency1)).approve(address(permit2), type(uint256).max);
+        permit2.approve(Currency.unwrap(fotKey.currency1), alice, type(uint160).max, type(uint48).max);
+        lpm.modifyLiquidities(planner.encode(), _deadline);
+        vm.stopPrank();
+
+        // set tick lower to current tick, making the new position that will be added entirely in other token
+        // tickLower = 0 = current tick
+        tickLower = TickMath.getTickAtSqrtPrice(sqrtPriceX96);
+
+        BalanceDiff memory balance0 = BalanceDiff(fotKey.currency0.balanceOf(address(this)), 0);
+        BalanceDiff memory balance1 = BalanceDiff(fotKey.currency1.balanceOf(address(this)), 0);
+        BalanceDiff memory balance0PM = BalanceDiff(fotKey.currency0.balanceOf(address(manager)), 0);
+        BalanceDiff memory balance1PM = BalanceDiff(fotKey.currency1.balanceOf(address(manager)), 0);
+
+        // set fee of fotToken to 100%
+        MockFOT(address(fotToken)).setFee(10_000);
+
+        // assume currency1 is fotToken
+        if (!(fotKey.currency0 == Currency.wrap(address(fotToken)))) {
             // MINT FROM DELTAS.
+            tokenId = lpm.nextTokenId();
+
+            planner = Planner.init();
+
+            planner.add(Actions.SETTLE, abi.encode(fotKey.currency0, 1 ether, true));
+            planner.add(Actions.SETTLE, abi.encode(fotKey.currency1, 1 ether, true));
+            planner.add(
+                Actions.MINT_POSITION_FROM_DELTAS,
+                abi.encode(
+                    fotKey,
+                    tickLower,
+                    tickUpper,
+                    MAX_SLIPPAGE_INCREASE,
+                    MAX_SLIPPAGE_INCREASE,
+                    ActionConstants.MSG_SENDER,
+                    ZERO_BYTES
+                )
+            );
+            // take the excess of each currency
+            planner.add(Actions.TAKE_PAIR, abi.encode(fotKey.currency0, fotKey.currency1, ActionConstants.MSG_SENDER));
+
+            // add liquidity
             lpm.modifyLiquidities(planner.encode(), _deadline);
 
             balance0._after = fotKey.currency0.balanceOf(address(this));
@@ -1073,13 +1064,13 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
             // Calculate the expected resulting balances used to create liquidity after the fee is applied.
             Balance memory expected;
             {
-                bool currency0IsFOT = fotKey.currency0 == Currency.wrap(address(fotToken));
-                uint256 expectedFee = (currency0IsFOT ? amount0 : amount1).calculatePortion(10_000);
-                (expected._0, expected._1) = currency0IsFOT
-                    ? (balance0._before - balance0._after - expectedFee, balance1._before - balance1._after)
-                    : (balance0._before - balance0._after, balance1._before - balance1._after - expectedFee);
+                // expected fee is the same amount that was sent, since fee is now 100%
+                uint256 expectedFee = 1 ether;
+                (expected._0, expected._1) =
+                    (balance0._before - balance0._after, balance1._before - balance1._after - expectedFee);
             }
             assertEq(expected._0, balance0PM._after - balance0PM._before);
+            // expected._1 is 0 because no fotToken was sent to PM because of 100% fee
             assertEq(expected._1, balance1PM._after - balance1PM._before);
             {
                 // the liquidity that was created is a diff of the balance change
@@ -1097,12 +1088,7 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
             // BURN.
             planner = Planner.init();
             // Note that the slippage does not include the fee from the transfer.
-            planner.add(
-                Actions.BURN_POSITION,
-                abi.encode(
-                    tokenId, expected._0 == 0 ? 0 : expected._0 - 1, expected._1 == 0 ? 0 : expected._1 - 1, ZERO_BYTES
-                )
-            );
+            planner.add(Actions.BURN_POSITION, abi.encode(tokenId, expected._0 - 1, 0, ZERO_BYTES));
 
             planner.add(Actions.TAKE_PAIR, abi.encode(fotKey.currency0, fotKey.currency1, ActionConstants.MSG_SENDER));
 
@@ -1113,7 +1099,7 @@ contract PositionManagerModifyLiquiditiesTest is Test, PosmTestSetup, LiquidityF
 
             // After redeeming the position, the liquidity provider should not have received any of the fot token since the position was entirely in the other token.
             assertEq(fotKey.currency1.balanceOf(address(this)), balance1._after);
-            assertGe(fotKey.currency0.balanceOf(address(this)), balance0._after);
+            assertGt(fotKey.currency0.balanceOf(address(this)), balance0._after);
 
             assertEq(lpm.getPositionLiquidity(tokenId), 0);
         }