From a9e463d6ccabb219a31e50f785bbc317a1502338 Mon Sep 17 00:00:00 2001 From: diana Date: Fri, 2 Aug 2024 18:13:42 -0400 Subject: [PATCH] Settle pair (#242) * clean * format * with currencydeltas library * remove currencydeltas library --- ...er_increaseLiquidity_erc20_withClose.snap} | 0 ...ncreaseLiquidity_erc20_withSettlePair.snap | 1 + ...anager_mint_nativeWithSweep_withClose.snap | 1 + ...r_mint_nativeWithSweep_withSettlePair.snap | 1 + ...nManager_mint_settleWithBalance_sweep.snap | 2 +- ...ap => PositionManager_mint_withClose.snap} | 0 .../PositionManager_mint_withSettlePair.snap | 1 + src/PositionManager.sol | 10 ++ src/libraries/Actions.sol | 22 ++-- src/libraries/CalldataDecoder.sol | 8 ++ src/libraries/CurrencyDeltas.sol | 42 ------- test/libraries/CalldataDecoder.t.sol | 8 ++ test/libraries/CurrencyDeltas.t.sol | 82 -------------- test/mocks/MockCalldataDecoder.sol | 4 + test/mocks/MockCurrencyDeltaReader.sol | 71 ------------ test/position-managers/Execute.t.sol | 40 ++++++- .../position-managers/IncreaseLiquidity.t.sol | 2 +- test/position-managers/NativeToken.t.sol | 105 +++++++++++++++++- .../PositionManager.gas.t.sol | 93 ++++++++++++---- .../PositionManager.multicall.t.sol | 2 +- test/shared/LiquidityOperations.sol | 10 +- test/shared/Planner.sol | 15 ++- test/shared/fuzz/LiquidityFuzzers.sol | 2 +- 23 files changed, 278 insertions(+), 244 deletions(-) rename .forge-snapshots/{PositionManager_increaseLiquidity_erc20.snap => PositionManager_increaseLiquidity_erc20_withClose.snap} (100%) create mode 100644 .forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap create mode 100644 .forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap create mode 100644 .forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap rename .forge-snapshots/{PositionManager_mint.snap => PositionManager_mint_withClose.snap} (100%) create mode 100644 .forge-snapshots/PositionManager_mint_withSettlePair.snap delete mode 100644 src/libraries/CurrencyDeltas.sol delete mode 100644 test/libraries/CurrencyDeltas.t.sol delete mode 100644 test/mocks/MockCurrencyDeltaReader.sol diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap similarity index 100% rename from .forge-snapshots/PositionManager_increaseLiquidity_erc20.snap rename to .forge-snapshots/PositionManager_increaseLiquidity_erc20_withClose.snap diff --git a/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap new file mode 100644 index 000000000..6ce3534b4 --- /dev/null +++ b/.forge-snapshots/PositionManager_increaseLiquidity_erc20_withSettlePair.snap @@ -0,0 +1 @@ +151341 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap new file mode 100644 index 000000000..6398f05ae --- /dev/null +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withClose.snap @@ -0,0 +1 @@ +345169 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap new file mode 100644 index 000000000..141f9455c --- /dev/null +++ b/.forge-snapshots/PositionManager_mint_nativeWithSweep_withSettlePair.snap @@ -0,0 +1 @@ +344710 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap index 2e9e23a44..977b82bc0 100644 --- a/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap +++ b/.forge-snapshots/PositionManager_mint_settleWithBalance_sweep.snap @@ -1 +1 @@ -370923 \ No newline at end of file +370969 \ No newline at end of file diff --git a/.forge-snapshots/PositionManager_mint.snap b/.forge-snapshots/PositionManager_mint_withClose.snap similarity index 100% rename from .forge-snapshots/PositionManager_mint.snap rename to .forge-snapshots/PositionManager_mint_withClose.snap diff --git a/.forge-snapshots/PositionManager_mint_withSettlePair.snap b/.forge-snapshots/PositionManager_mint_withSettlePair.snap new file mode 100644 index 000000000..2a78d147d --- /dev/null +++ b/.forge-snapshots/PositionManager_mint_withSettlePair.snap @@ -0,0 +1 @@ +371342 \ No newline at end of file diff --git a/src/PositionManager.sol b/src/PositionManager.sol index 8bc6782aa..d14188976 100644 --- a/src/PositionManager.sol +++ b/src/PositionManager.sol @@ -126,6 +126,9 @@ contract PositionManager is } else if (action == Actions.SETTLE) { (Currency currency, uint256 amount, bool payerIsUser) = params.decodeCurrencyUint256AndBool(); _settle(currency, _mapPayer(payerIsUser), _mapSettleAmount(amount, currency)); + } else if (action == Actions.SETTLE_PAIR) { + (Currency currency0, Currency currency1) = params.decodeCurrencyPair(); + _settlePair(currency0, currency1); } else if (action == Actions.SWEEP) { (Currency currency, address to) = params.decodeCurrencyAndAddress(); _sweep(currency, _mapRecipient(to)); @@ -214,6 +217,13 @@ contract PositionManager is poolManager.clear(currency, uint256(currencyDelta)); } + function _settlePair(Currency currency0, Currency currency1) internal { + // the locker is the payer when settling + address caller = _msgSender(); + _settle(currency0, caller, _getFullSettleAmount(currency0)); + _settle(currency1, caller, _getFullSettleAmount(currency1)); + } + /// @dev this is overloaded with ERC721Permit._burn function _burn( uint256 tokenId, diff --git a/src/libraries/Actions.sol b/src/libraries/Actions.sol index ae9544246..e0005b2e5 100644 --- a/src/libraries/Actions.sol +++ b/src/libraries/Actions.sol @@ -20,19 +20,19 @@ library Actions { // closing deltas on the pool manager // settling - uint256 constant SETTLE_ALL = 0x10; - uint256 constant SETTLE = 0x11; + uint256 constant SETTLE_ALL = 0x09; + uint256 constant SETTLE = 0x10; + uint256 constant SETTLE_PAIR = 0x11; // taking - uint256 constant TAKE = 0x13; - uint256 constant TAKE_ALL = 0x14; - uint256 constant TAKE_PORTION = 0x15; + uint256 constant TAKE = 0x12; + uint256 constant TAKE_ALL = 0x13; + uint256 constant TAKE_PORTION = 0x14; - uint256 constant CLOSE_CURRENCY = 0x16; - uint256 constant CLOSE_PAIR = 0x17; - uint256 constant CLEAR = 0x18; - uint256 constant SWEEP = 0x19; + uint256 constant CLOSE_CURRENCY = 0x15; + uint256 constant CLEAR = 0x16; + uint256 constant SWEEP = 0x17; // minting/burning 6909s to close deltas - uint256 constant MINT_6909 = 0x20; - uint256 constant BURN_6909 = 0x21; + uint256 constant MINT_6909 = 0x18; + uint256 constant BURN_6909 = 0x19; } diff --git a/src/libraries/CalldataDecoder.sol b/src/libraries/CalldataDecoder.sol index fee5d705a..0a1dd24af 100644 --- a/src/libraries/CalldataDecoder.sol +++ b/src/libraries/CalldataDecoder.sol @@ -166,6 +166,14 @@ library CalldataDecoder { } } + /// @dev equivalent to: abi.decode(params, (Currency, Currency)) in calldata + function decodeCurrencyPair(bytes calldata params) internal pure returns (Currency currency0, Currency currency1) { + assembly ("memory-safe") { + currency0 := calldataload(params.offset) + currency1 := calldataload(add(params.offset, 0x20)) + } + } + /// @dev equivalent to: abi.decode(params, (Currency, address)) in calldata function decodeCurrencyAndAddress(bytes calldata params) internal diff --git a/src/libraries/CurrencyDeltas.sol b/src/libraries/CurrencyDeltas.sol deleted file mode 100644 index 2a7b85f80..000000000 --- a/src/libraries/CurrencyDeltas.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.21; - -import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; -import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; -import {BalanceDelta, toBalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; -import {SafeCast} from "@uniswap/v4-core/src/libraries/SafeCast.sol"; - -/// @title Currency Deltas -/// @notice Fetch two currency deltas in a single call -library CurrencyDeltas { - using SafeCast for int256; - - /// @notice Get the current delta for a caller in the two given currencies - /// @param _caller The address of the caller - /// @param currency0 The currency to lookup the delta - /// @param currency1 The other currency to lookup the delta - /// @return BalanceDelta The delta of the two currencies packed - /// amount0 corresponding to currency0 and amount1 corresponding to currency1 - function currencyDeltas(IPoolManager manager, address _caller, Currency currency0, Currency currency1) - internal - view - returns (BalanceDelta) - { - bytes32 tloadSlot0; - bytes32 tloadSlot1; - assembly { - mstore(0, _caller) - mstore(32, currency0) - tloadSlot0 := keccak256(0, 64) - - mstore(0, _caller) - mstore(32, currency1) - tloadSlot1 := keccak256(0, 64) - } - bytes32[] memory slots = new bytes32[](2); - slots[0] = tloadSlot0; - slots[1] = tloadSlot1; - bytes32[] memory result = manager.exttload(slots); - return toBalanceDelta(int256(uint256(result[0])).toInt128(), int256(uint256(result[1])).toInt128()); - } -} diff --git a/test/libraries/CalldataDecoder.t.sol b/test/libraries/CalldataDecoder.t.sol index 25f8593d8..b71d2667f 100644 --- a/test/libraries/CalldataDecoder.t.sol +++ b/test/libraries/CalldataDecoder.t.sol @@ -152,6 +152,14 @@ contract CalldataDecoderTest is Test { assertEq(Currency.unwrap(currency), Currency.unwrap(_currency)); } + function test_fuzz_decodeCurrencyPair(Currency _currency0, Currency _currency1) public view { + bytes memory params = abi.encode(_currency0, _currency1); + (Currency currency0, Currency currency1) = decoder.decodeCurrencyPair(params); + + assertEq(Currency.unwrap(currency0), Currency.unwrap(_currency0)); + assertEq(Currency.unwrap(currency1), Currency.unwrap(_currency1)); + } + function test_fuzz_decodeCurrencyAndUint256(Currency _currency, uint256 _amount) public view { bytes memory params = abi.encode(_currency, _amount); (Currency currency, uint256 amount) = decoder.decodeCurrencyAndUint256(params); diff --git a/test/libraries/CurrencyDeltas.t.sol b/test/libraries/CurrencyDeltas.t.sol deleted file mode 100644 index 53dad9e45..000000000 --- a/test/libraries/CurrencyDeltas.t.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import "forge-std/Test.sol"; -import {IERC20} from "forge-std/interfaces/IERC20.sol"; -import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; -import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; -import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol"; -import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol"; -import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol"; - -import {MockCurrencyDeltaReader} from "../mocks/MockCurrencyDeltaReader.sol"; - -contract CurrencyDeltasTest is Test, Deployers { - using CurrencyLibrary for Currency; - - MockCurrencyDeltaReader reader; - - function setUp() public { - deployFreshManagerAndRouters(); - deployMintAndApprove2Currencies(); - - reader = new MockCurrencyDeltaReader(manager); - - IERC20 token0 = IERC20(Currency.unwrap(currency0)); - IERC20 token1 = IERC20(Currency.unwrap(currency1)); - - token0.approve(address(reader), type(uint256).max); - token1.approve(address(reader), type(uint256).max); - - // send tokens to PoolManager so tests can .take() - token0.transfer(address(manager), 1_000_000e18); - token1.transfer(address(manager), 1_000_000e18); - - // convert some ERC20s into ERC6909 - claimsRouter.deposit(currency0, address(this), 1_000_000e18); - claimsRouter.deposit(currency1, address(this), 1_000_000e18); - manager.approve(address(reader), currency0.toId(), type(uint256).max); - manager.approve(address(reader), currency1.toId(), type(uint256).max); - } - - function test_fuzz_currencyDeltas(uint8 depth, uint256 seed, uint128 amount0, uint128 amount1) public { - int128 delta0Expected = 0; - int128 delta1Expected = 0; - - bytes[] memory calls = new bytes[](depth); - for (uint256 i = 0; i < depth; i++) { - amount0 = uint128(bound(amount0, 1, 100e18)); - amount1 = uint128(bound(amount1, 1, 100e18)); - uint256 _seed = seed % (i + 1); - if (_seed % 8 == 0) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.settle.selector, currency0, amount0); - delta0Expected += int128(amount0); - } else if (_seed % 8 == 1) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.settle.selector, currency1, amount1); - delta1Expected += int128(amount1); - } else if (_seed % 8 == 2) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.burn.selector, currency0, amount0); - delta0Expected += int128(amount0); - } else if (_seed % 8 == 3) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.burn.selector, currency1, amount1); - delta1Expected += int128(amount1); - } else if (_seed % 8 == 4) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.take.selector, currency0, amount0); - delta0Expected -= int128(amount0); - } else if (_seed % 8 == 5) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.take.selector, currency1, amount1); - delta1Expected -= int128(amount1); - } else if (_seed % 8 == 6) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.mint.selector, currency0, amount0); - delta0Expected -= int128(amount0); - } else if (_seed % 8 == 7) { - calls[i] = abi.encodeWithSelector(MockCurrencyDeltaReader.mint.selector, currency1, amount1); - delta1Expected -= int128(amount1); - } - } - - BalanceDelta delta = reader.execute(calls, currency0, currency1); - assertEq(delta.amount0(), delta0Expected); - assertEq(delta.amount1(), delta1Expected); - } -} diff --git a/test/mocks/MockCalldataDecoder.sol b/test/mocks/MockCalldataDecoder.sol index 2839e6a57..358252285 100644 --- a/test/mocks/MockCalldataDecoder.sol +++ b/test/mocks/MockCalldataDecoder.sol @@ -98,6 +98,10 @@ contract MockCalldataDecoder { return params.decodeCurrency(); } + function decodeCurrencyPair(bytes calldata params) external pure returns (Currency currency0, Currency currency1) { + return params.decodeCurrencyPair(); + } + function decodeCurrencyAndUint256(bytes calldata params) external pure returns (Currency currency, uint256 _uint) { return params.decodeCurrencyAndUint256(); } diff --git a/test/mocks/MockCurrencyDeltaReader.sol b/test/mocks/MockCurrencyDeltaReader.sol deleted file mode 100644 index 94aa3db77..000000000 --- a/test/mocks/MockCurrencyDeltaReader.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol"; -import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol"; -import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; -import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol"; -import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol"; -import {CurrencySettler} from "@uniswap/v4-core/test/utils/CurrencySettler.sol"; - -import {CurrencyDeltas} from "../../src/libraries/CurrencyDeltas.sol"; - -/// @dev A minimal helper strictly for testing -contract MockCurrencyDeltaReader { - using TransientStateLibrary for IPoolManager; - using CurrencyDeltas for IPoolManager; - using CurrencySettler for Currency; - - IPoolManager public poolManager; - - address sender; - - constructor(IPoolManager _poolManager) { - poolManager = _poolManager; - } - - /// @param calls an array of abi.encodeWithSelector - function execute(bytes[] calldata calls, Currency currency0, Currency currency1) external returns (BalanceDelta) { - sender = msg.sender; - return abi.decode(poolManager.unlock(abi.encode(calls, currency0, currency1)), (BalanceDelta)); - } - - function unlockCallback(bytes calldata data) external returns (bytes memory) { - (bytes[] memory calls, Currency currency0, Currency currency1) = abi.decode(data, (bytes[], Currency, Currency)); - for (uint256 i; i < calls.length; i++) { - (bool success,) = address(this).call(calls[i]); - if (!success) revert("CurrencyDeltaReader"); - } - - BalanceDelta delta = poolManager.currencyDeltas(address(this), currency0, currency1); - int256 delta0 = poolManager.currencyDelta(address(this), currency0); - int256 delta1 = poolManager.currencyDelta(address(this), currency1); - - // confirm agreement between currencyDeltas and single-read currencyDelta - require(delta.amount0() == int128(delta0), "CurrencyDeltaReader: delta0"); - require(delta.amount1() == int128(delta1), "CurrencyDeltaReader: delta1"); - - // close deltas - if (delta.amount0() < 0) currency0.settle(poolManager, sender, uint256(-int256(delta.amount0())), false); - if (delta.amount1() < 0) currency1.settle(poolManager, sender, uint256(-int256(delta.amount1())), false); - if (delta.amount0() > 0) currency0.take(poolManager, sender, uint256(int256(delta.amount0())), false); - if (delta.amount1() > 0) currency1.take(poolManager, sender, uint256(int256(delta.amount1())), false); - return abi.encode(delta); - } - - function settle(Currency currency, uint256 amount) external { - currency.settle(poolManager, sender, amount, false); - } - - function burn(Currency currency, uint256 amount) external { - currency.settle(poolManager, sender, amount, true); - } - - function take(Currency currency, uint256 amount) external { - currency.take(poolManager, sender, amount, false); - } - - function mint(Currency currency, uint256 amount) external { - currency.take(poolManager, sender, amount, true); - } -} diff --git a/test/position-managers/Execute.t.sol b/test/position-managers/Execute.t.sol index 6ff19dce3..4556c55d4 100644 --- a/test/position-managers/Execute.t.sol +++ b/test/position-managers/Execute.t.sol @@ -79,7 +79,7 @@ contract ExecuteTest is Test, PosmTestSetup, LiquidityFuzzers { assertEq(liquidity, initialLiquidity + liquidityToAdd); } - function test_fuzz_execute_increaseLiquidity_twice( + function test_fuzz_execute_increaseLiquidity_twice_withClose( uint256 initialLiquidity, uint256 liquidityToAdd, uint256 liquidityToAdd2 @@ -101,7 +101,39 @@ contract ExecuteTest is Test, PosmTestSetup, LiquidityFuzzers { abi.encode(tokenId, config, liquidityToAdd2, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); + lpm.modifyLiquidities(calls, _deadline); + + bytes32 positionId = + Position.calculatePositionKey(address(lpm), config.tickLower, config.tickUpper, bytes32(tokenId)); + (uint256 liquidity,,) = manager.getPositionInfo(config.poolKey.toId(), positionId); + + assertEq(liquidity, initialLiquidity + liquidityToAdd + liquidityToAdd2); + } + + function test_fuzz_execute_increaseLiquidity_twice_withSettlePair( + uint256 initialLiquidity, + uint256 liquidityToAdd, + uint256 liquidityToAdd2 + ) public { + initialLiquidity = bound(initialLiquidity, 1e18, 1000e18); + liquidityToAdd = bound(liquidityToAdd, 1e18, 1000e18); + liquidityToAdd2 = bound(liquidityToAdd2, 1e18, 1000e18); + uint256 tokenId = lpm.nextTokenId(); + mint(config, initialLiquidity, address(this), ZERO_BYTES); + + Plan memory planner = Planner.init(); + + planner.add( + Actions.INCREASE_LIQUIDITY, + abi.encode(tokenId, config, liquidityToAdd, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) + ); + planner.add( + Actions.INCREASE_LIQUIDITY, + abi.encode(tokenId, config, liquidityToAdd2, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) + ); + + bytes memory calls = planner.finalizeModifyLiquidityWithSettlePair(config.poolKey); lpm.modifyLiquidities(calls, _deadline); bytes32 positionId = @@ -131,7 +163,7 @@ contract ExecuteTest is Test, PosmTestSetup, LiquidityFuzzers { abi.encode(tokenId, config, liquidityToAdd, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); bytes32 positionId = @@ -178,7 +210,7 @@ contract ExecuteTest is Test, PosmTestSetup, LiquidityFuzzers { newConfig, newLiquidity, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES ) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); { diff --git a/test/position-managers/IncreaseLiquidity.t.sol b/test/position-managers/IncreaseLiquidity.t.sol index d96fdb0b9..c6d076f40 100644 --- a/test/position-managers/IncreaseLiquidity.t.sol +++ b/test/position-managers/IncreaseLiquidity.t.sol @@ -120,7 +120,7 @@ contract IncreaseLiquidityTest is Test, PosmTestSetup, Fuzzers { planner.add( Actions.INCREASE_LIQUIDITY, abi.encode(tokenIdAlice, config, liquidityDelta, 0 wei, 0 wei, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); vm.startPrank(alice); lpm.modifyLiquidities(calls, _deadline); vm.stopPrank(); diff --git a/test/position-managers/NativeToken.t.sol b/test/position-managers/NativeToken.t.sol index d98258c46..7d03721c5 100644 --- a/test/position-managers/NativeToken.t.sol +++ b/test/position-managers/NativeToken.t.sol @@ -96,7 +96,7 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers { } // minting with excess native tokens are returned to caller - function test_fuzz_mint_native_excess(IPoolManager.ModifyLiquidityParams memory params) public { + function test_fuzz_mint_native_excess_withClose(IPoolManager.ModifyLiquidityParams memory params) public { params = createFuzzyLiquidityParams(nativeKey, params, SQRT_PRICE_1_1); vm.assume(params.tickLower < 0 && 0 < params.tickUpper); // two-sided liquidity @@ -146,6 +146,53 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers { assertEq(balance1Before - currency1.balanceOfSelf(), uint256(int256(-delta.amount1()))); } + function test_fuzz_mint_native_excess_withSettlePair(IPoolManager.ModifyLiquidityParams memory params) public { + params = createFuzzyLiquidityParams(nativeKey, params, SQRT_PRICE_1_1); + vm.assume(params.tickLower < 0 && 0 < params.tickUpper); // two-sided liquidity + + uint256 liquidityToAdd = + params.liquidityDelta < 0 ? uint256(-params.liquidityDelta) : uint256(params.liquidityDelta); + PositionConfig memory config = + PositionConfig({poolKey: nativeKey, tickLower: params.tickLower, tickUpper: params.tickUpper}); + + uint256 balance0Before = currency0.balanceOfSelf(); + uint256 balance1Before = currency1.balanceOfSelf(); + + uint256 tokenId = lpm.nextTokenId(); + + Plan memory planner = Planner.init(); + planner.add( + Actions.MINT_POSITION, + abi.encode(config, liquidityToAdd, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, address(this), ZERO_BYTES) + ); + planner.add(Actions.SETTLE_PAIR, abi.encode(nativeKey.currency0, nativeKey.currency1)); + // sweep the excess eth + planner.add(Actions.SWEEP, abi.encode(currency0, address(this))); + + bytes memory calls = planner.encode(); + + (uint256 amount0,) = LiquidityAmounts.getAmountsForLiquidity( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(params.tickLower), + TickMath.getSqrtPriceAtTick(params.tickUpper), + liquidityToAdd.toUint128() + ); + + // Mint with excess native tokens + lpm.modifyLiquidities{value: amount0 * 2 + 1}(calls, _deadline); + BalanceDelta delta = getLastDelta(); + + bytes32 positionId = + Position.calculatePositionKey(address(lpm), config.tickLower, config.tickUpper, bytes32(tokenId)); + (uint256 liquidity,,) = manager.getPositionInfo(config.poolKey.toId(), positionId); + assertEq(liquidity, uint256(params.liquidityDelta)); + + // only paid the delta amount, with excess tokens returned to caller + assertEq(balance0Before - currency0.balanceOfSelf(), uint256(int256(-delta.amount0()))); + assertEq(balance0Before - currency0.balanceOfSelf(), amount0 + 1); // TODO: off by one?? + assertEq(balance1Before - currency1.balanceOfSelf(), uint256(int256(-delta.amount1()))); + } + function test_fuzz_burn_native_emptyPosition(IPoolManager.ModifyLiquidityParams memory params) public { uint256 balance0Start = address(this).balance; uint256 balance1Start = currency1.balanceOfSelf(); @@ -289,7 +336,9 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers { } // overpaying native tokens on increase liquidity is returned to caller - function test_fuzz_increaseLiquidity_native_excess(IPoolManager.ModifyLiquidityParams memory params) public { + function test_fuzz_increaseLiquidity_native_excess_withClose(IPoolManager.ModifyLiquidityParams memory params) + public + { // fuzz for the range params = createFuzzyLiquidityParams(nativeKey, params, SQRT_PRICE_1_1); vm.assume(params.tickLower < 0 && 0 < params.tickUpper); // two-sided liquidity @@ -340,6 +389,58 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers { assertEq(balance1Before - currency1.balanceOfSelf(), uint256(int256(-delta.amount1()))); } + function test_fuzz_increaseLiquidity_native_excess_withSettlePair(IPoolManager.ModifyLiquidityParams memory params) + public + { + // fuzz for the range + params = createFuzzyLiquidityParams(nativeKey, params, SQRT_PRICE_1_1); + vm.assume(params.tickLower < 0 && 0 < params.tickUpper); // two-sided liquidity + + // TODO: figure out if we can fuzz the increase liquidity delta. we're annoyingly getting TickLiquidityOverflow + uint256 liquidityToAdd = 1e18; + PositionConfig memory config = + PositionConfig({poolKey: nativeKey, tickLower: params.tickLower, tickUpper: params.tickUpper}); + + // mint the position with native token liquidity + uint256 tokenId = lpm.nextTokenId(); + mintWithNative(SQRT_PRICE_1_1, config, liquidityToAdd, address(this), ZERO_BYTES); + + uint256 balance0Before = address(this).balance; + uint256 balance1Before = currency1.balanceOfSelf(); + + // calculate how much native token is required for the liquidity increase (doubling the liquidity) + (uint256 amount0,) = LiquidityAmounts.getAmountsForLiquidity( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(params.tickLower), + TickMath.getSqrtPriceAtTick(params.tickUpper), + uint128(liquidityToAdd) + ); + + Plan memory planner = Planner.init(); + planner.add( + Actions.INCREASE_LIQUIDITY, + abi.encode(tokenId, config, liquidityToAdd, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) + ); + planner.add(Actions.SETTLE_PAIR, abi.encode(nativeKey.currency0, nativeKey.currency1)); + // sweep the excess eth + planner.add(Actions.SWEEP, abi.encode(currency0, address(this))); + bytes memory calls = planner.encode(); + + lpm.modifyLiquidities{value: amount0 * 2}(calls, _deadline); // overpay on increase liquidity + BalanceDelta delta = getLastDelta(); + + // verify position liquidity increased + bytes32 positionId = + Position.calculatePositionKey(address(lpm), config.tickLower, config.tickUpper, bytes32(tokenId)); + (uint256 liquidity,,) = manager.getPositionInfo(config.poolKey.toId(), positionId); + assertEq(liquidity, liquidityToAdd + liquidityToAdd); // liquidity was doubled + + // verify native token balances changed as expected, with overpaid tokens returned + assertEq(balance0Before - currency0.balanceOfSelf(), amount0 + 1 wei); + assertEq(balance0Before - currency0.balanceOfSelf(), uint256(int256(-delta.amount0()))); + assertEq(balance1Before - currency1.balanceOfSelf(), uint256(int256(-delta.amount1()))); + } + function test_fuzz_decreaseLiquidity_native( IPoolManager.ModifyLiquidityParams memory params, uint256 decreaseLiquidityDelta diff --git a/test/position-managers/PositionManager.gas.t.sol b/test/position-managers/PositionManager.gas.t.sol index 9b63023d8..84da682ba 100644 --- a/test/position-managers/PositionManager.gas.t.sol +++ b/test/position-managers/PositionManager.gas.t.sol @@ -70,16 +70,26 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { configNative = PositionConfig({poolKey: nativeKey, tickLower: -300, tickUpper: 300}); } - function test_gas_mint() public { + function test_gas_mint_withClose() public { Plan memory planner = Planner.init().add( Actions.MINT_POSITION, abi.encode( config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES ) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); - snapLastCall("PositionManager_mint"); + snapLastCall("PositionManager_mint_withClose"); + } + + function test_gas_mint_withSettlePair() public { + Plan memory planner = Planner.init().add( + Actions.MINT_POSITION, + abi.encode(config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, address(this), ZERO_BYTES) + ); + bytes memory calls = planner.finalizeModifyLiquidityWithSettlePair(config.poolKey); + lpm.modifyLiquidities(calls, _deadline); + snapLastCall("PositionManager_mint_withSettlePair"); } function test_gas_mint_differentRanges() public { @@ -95,7 +105,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES ) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); vm.prank(alice); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_mint_warmedPool_differentRange"); @@ -114,7 +124,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES ) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); vm.prank(alice); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_mint_onSameTickLower"); @@ -133,13 +143,13 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES ) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); vm.prank(alice); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_mint_onSameTickUpper"); } - function test_gas_increaseLiquidity_erc20() public { + function test_gas_increaseLiquidity_erc20_withClose() public { uint256 tokenId = lpm.nextTokenId(); mint(config, 10_000 ether, Constants.MSG_SENDER, ZERO_BYTES); @@ -148,9 +158,23 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { abi.encode(tokenId, config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); + lpm.modifyLiquidities(calls, _deadline); + snapLastCall("PositionManager_increaseLiquidity_erc20_withClose"); + } + + function test_gas_increaseLiquidity_erc20_withSettlePair() public { + uint256 tokenId = lpm.nextTokenId(); + mint(config, 10_000 ether, address(this), ZERO_BYTES); + + Plan memory planner = Planner.init().add( + Actions.INCREASE_LIQUIDITY, + abi.encode(tokenId, config, 10_000 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) + ); + + bytes memory calls = planner.finalizeModifyLiquidityWithSettlePair(config.poolKey); lpm.modifyLiquidities(calls, _deadline); - snapLastCall("PositionManager_increaseLiquidity_erc20"); + snapLastCall("PositionManager_increaseLiquidity_erc20_withSettlePair"); } function test_gas_autocompound_exactUnclaimedFees() public { @@ -287,7 +311,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { abi.encode(tokenIdAlice, config, liquidityDelta, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); vm.prank(alice); lpm.modifyLiquidities(calls, _deadline); @@ -303,7 +327,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { abi.encode(tokenId, config, 10_000 ether, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_decreaseLiquidity"); } @@ -326,7 +350,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { Actions.MINT_POSITION, abi.encode(config, 100e18, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES) ); - bytes memory actions = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory actions = planner.finalizeModifyLiquidityWithClose(config.poolKey); calls[1] = abi.encodeWithSelector(IPositionManager.modifyLiquidities.selector, actions, _deadline); @@ -347,7 +371,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { abi.encode(tokenId, config, 0, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_collect"); } @@ -362,7 +386,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { config, 10_001 ether, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES ) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); vm.prank(alice); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_mint_sameRange"); @@ -382,7 +406,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { abi.encode(tokenId, config, 10_000 ether, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_decrease_sameRange_allLiquidity"); } @@ -404,7 +428,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { abi.encode(tokenId, config, 0, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_collect_sameRange"); } @@ -416,7 +440,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { Plan memory planner = Planner.init().add( Actions.BURN_POSITION, abi.encode(tokenId, config, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_burn_nonEmpty"); @@ -452,7 +476,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { ); // We must include CLOSE commands. - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_decrease_burnEmpty"); } @@ -476,7 +500,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { snapLastCall("PositionManager_mint_native"); } - function test_gas_mint_native_excess() public { + function test_gas_mint_native_excess_withClose() public { uint256 liquidityToAdd = 10_000 ether; Plan memory planner = Planner.init(); @@ -504,7 +528,32 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { ); // overpay on the native token lpm.modifyLiquidities{value: amount0 * 2}(calls, _deadline); - snapLastCall("PositionManager_mint_nativeWithSweep"); + snapLastCall("PositionManager_mint_nativeWithSweep_withClose"); + } + + function test_gas_mint_native_excess_withSettlePair() public { + uint256 liquidityToAdd = 10_000 ether; + + Plan memory planner = Planner.init(); + planner.add( + Actions.MINT_POSITION, + abi.encode( + configNative, liquidityToAdd, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, address(this), ZERO_BYTES + ) + ); + planner.add(Actions.SETTLE_PAIR, abi.encode(nativeKey.currency0, nativeKey.currency1)); + planner.add(Actions.SWEEP, abi.encode(CurrencyLibrary.NATIVE, address(this))); + bytes memory calls = planner.encode(); + + (uint256 amount0,) = LiquidityAmounts.getAmountsForLiquidity( + SQRT_PRICE_1_1, + TickMath.getSqrtPriceAtTick(configNative.tickLower), + TickMath.getSqrtPriceAtTick(configNative.tickUpper), + uint128(liquidityToAdd) + ); + // overpay on the native token + lpm.modifyLiquidities{value: amount0 * 2}(calls, _deadline); + snapLastCall("PositionManager_mint_nativeWithSweep_withSettlePair"); } function test_gas_increase_native() public { @@ -553,7 +602,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { Actions.BURN_POSITION, abi.encode(tokenId, configNative, MIN_SLIPPAGE_DECREASE, MIN_SLIPPAGE_DECREASE, ZERO_BYTES) ); - bytes memory calls = planner.finalizeModifyLiquidity(configNative.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(configNative.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_burn_nonEmpty_native"); @@ -588,7 +637,7 @@ contract PosMGasTest is Test, PosmTestSetup, GasSnapshot { planner.add(Actions.BURN_POSITION, abi.encode(tokenId, configNative, 0 wei, 0 wei, ZERO_BYTES)); // We must include CLOSE commands. - bytes memory calls = planner.finalizeModifyLiquidity(configNative.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(configNative.poolKey); lpm.modifyLiquidities(calls, _deadline); snapLastCall("PositionManager_decrease_burnEmpty_native"); } diff --git a/test/position-managers/PositionManager.multicall.t.sol b/test/position-managers/PositionManager.multicall.t.sol index 5eaf45b8e..e5efff11d 100644 --- a/test/position-managers/PositionManager.multicall.t.sol +++ b/test/position-managers/PositionManager.multicall.t.sol @@ -91,7 +91,7 @@ contract PositionManagerMulticallTest is Test, Permit2SignatureHelpers, PosmTest Actions.MINT_POSITION, abi.encode(config, 100e18, MAX_SLIPPAGE_INCREASE, MAX_SLIPPAGE_INCREASE, Constants.MSG_SENDER, ZERO_BYTES) ); - bytes memory actions = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory actions = planner.finalizeModifyLiquidityWithClose(config.poolKey); calls[1] = abi.encodeWithSelector(IPositionManager.modifyLiquidities.selector, actions, _deadline); diff --git a/test/shared/LiquidityOperations.sol b/test/shared/LiquidityOperations.sol index a46230920..026abe8c2 100644 --- a/test/shared/LiquidityOperations.sol +++ b/test/shared/LiquidityOperations.sol @@ -101,7 +101,7 @@ abstract contract LiquidityOperations is CommonBase { Plan memory planner = Planner.init(); planner.add(Actions.MINT_POSITION, abi.encode(config, liquidity, amount0Max, amount1Max, recipient, hookData)); - return planner.finalizeModifyLiquidity(config.poolKey); + return planner.finalizeModifyLiquidityWithClose(config.poolKey); } function getIncreaseEncoded( @@ -127,7 +127,7 @@ abstract contract LiquidityOperations is CommonBase { planner.add( Actions.INCREASE_LIQUIDITY, abi.encode(tokenId, config, liquidityToAdd, amount0Max, amount1Max, hookData) ); - return planner.finalizeModifyLiquidity(config.poolKey); + return planner.finalizeModifyLiquidityWithClose(config.poolKey); } function getDecreaseEncoded( @@ -153,7 +153,7 @@ abstract contract LiquidityOperations is CommonBase { planner.add( Actions.DECREASE_LIQUIDITY, abi.encode(tokenId, config, liquidityToRemove, amount0Min, amount1Min, hookData) ); - return planner.finalizeModifyLiquidity(config.poolKey); + return planner.finalizeModifyLiquidityWithClose(config.poolKey); } function getCollectEncoded(uint256 tokenId, PositionConfig memory config, bytes memory hookData) @@ -173,7 +173,7 @@ abstract contract LiquidityOperations is CommonBase { ) internal pure returns (bytes memory) { Plan memory planner = Planner.init(); planner.add(Actions.DECREASE_LIQUIDITY, abi.encode(tokenId, config, 0, amount0Min, amount1Min, hookData)); - return planner.finalizeModifyLiquidity(config.poolKey); + return planner.finalizeModifyLiquidityWithClose(config.poolKey); } function getBurnEncoded(uint256 tokenId, PositionConfig memory config, bytes memory hookData) @@ -194,6 +194,6 @@ abstract contract LiquidityOperations is CommonBase { Plan memory planner = Planner.init(); planner.add(Actions.BURN_POSITION, abi.encode(tokenId, config, amount0Min, amount1Min, hookData)); // Close needed on burn in case there is liquidity left in the position. - return planner.finalizeModifyLiquidity(config.poolKey); + return planner.finalizeModifyLiquidityWithClose(config.poolKey); } } diff --git a/test/shared/Planner.sol b/test/shared/Planner.sol index 2321eccc5..ffcd10fda 100644 --- a/test/shared/Planner.sol +++ b/test/shared/Planner.sol @@ -37,12 +37,25 @@ library Planner { return plan; } - function finalizeModifyLiquidity(Plan memory plan, PoolKey memory poolKey) internal pure returns (bytes memory) { + function finalizeModifyLiquidityWithClose(Plan memory plan, PoolKey memory poolKey) + internal + pure + returns (bytes memory) + { plan.add(Actions.CLOSE_CURRENCY, abi.encode(poolKey.currency0)); plan.add(Actions.CLOSE_CURRENCY, abi.encode(poolKey.currency1)); return plan.encode(); } + function finalizeModifyLiquidityWithSettlePair(Plan memory plan, PoolKey memory poolKey) + internal + pure + returns (bytes memory) + { + plan.add(Actions.SETTLE_PAIR, abi.encode(poolKey.currency0, poolKey.currency1)); + return plan.encode(); + } + function encode(Plan memory plan) internal pure returns (bytes memory) { return abi.encode(plan.actions, plan.params); } diff --git a/test/shared/fuzz/LiquidityFuzzers.sol b/test/shared/fuzz/LiquidityFuzzers.sol index 5bbfbc73e..02d6583f4 100644 --- a/test/shared/fuzz/LiquidityFuzzers.sol +++ b/test/shared/fuzz/LiquidityFuzzers.sol @@ -41,7 +41,7 @@ contract LiquidityFuzzers is Fuzzers { ); uint256 tokenId = lpm.nextTokenId(); - bytes memory calls = planner.finalizeModifyLiquidity(config.poolKey); + bytes memory calls = planner.finalizeModifyLiquidityWithClose(config.poolKey); lpm.modifyLiquidities(calls, block.timestamp + 1); return (tokenId, params);