Skip to content

Commit

Permalink
add liquidity beforehand
Browse files Browse the repository at this point in the history
  • Loading branch information
dianakocsis committed Jan 17, 2025
1 parent bf6a92b commit c109924
Showing 1 changed file with 57 additions and 71 deletions.
128 changes: 57 additions & 71 deletions test/position-managers/PositionManager.modifyLiquidities.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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));
Expand All @@ -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
Expand All @@ -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));

Expand All @@ -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);
}
Expand Down

0 comments on commit c109924

Please sign in to comment.