diff --git a/.gitmodules b/.gitmodules index 46f5936..9dd4313 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lib/pancake-v4-periphery"] - path = lib/pancake-v4-periphery - url = https://github.com/pancakeswap/pancake-v4-periphery +[submodule "lib/pancake-v4-universal-router"] + path = lib/pancake-v4-universal-router + url = https://github.com/pancakeswap/pancake-v4-universal-router diff --git a/foundry.toml b/foundry.toml index 96d0bb0..79aaad4 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,7 +1,7 @@ [profile.default] src = 'src' out = 'foundry-out' -solc_version = '0.8.24' libs = ["lib"] +solc_version = '0.8.26' evm_version = 'cancun' via_ir = true diff --git a/lib/pancake-v4-periphery b/lib/pancake-v4-periphery deleted file mode 160000 index d3ccae2..0000000 --- a/lib/pancake-v4-periphery +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d3ccae2f4cbf319351157e6c6be667ea2d18a1e3 diff --git a/lib/pancake-v4-universal-router b/lib/pancake-v4-universal-router new file mode 160000 index 0000000..8cefacb --- /dev/null +++ b/lib/pancake-v4-universal-router @@ -0,0 +1 @@ +Subproject commit 8cefacb472e8fdecdb7b0391527d42b6310b817d diff --git a/remappings.txt b/remappings.txt index 1093f2b..4b73269 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,6 +1,8 @@ forge-std/=lib/forge-std/src/ ds-test/=lib/forge-std/lib/ds-test/src/ -pancake-v4-periphery/=lib/pancake-v4-periphery/ -pancake-v4-core/=lib/pancake-v4-periphery/lib/pancake-v4-core/ -openzeppelin-contracts/=lib/pancake-v4-periphery/lib/pancake-v4-core/lib/openzeppelin-contracts/ -solmate/=lib/pancake-v4-periphery/lib/pancake-v4-core/lib/solmate/ \ No newline at end of file +openzeppelin-contracts/=lib/pancake-v4-universal-router/lib/pancake-v4-periphery/lib/pancake-v4-core/lib/openzeppelin-contracts/ +solmate/=lib/pancake-v4-universal-router/lib/pancake-v4-periphery/lib/pancake-v4-core/lib/solmate/ +pancake-v4-core/=lib/pancake-v4-universal-router/lib/pancake-v4-periphery/lib/pancake-v4-core/ +pancake-v4-periphery/=lib/pancake-v4-universal-router/lib/pancake-v4-periphery/ +pancake-v4-universal-router/=lib/pancake-v4-universal-router/ +permit2/=lib/pancake-v4-universal-router/lib/pancake-v4-periphery/lib/permit2/ diff --git a/src/pool-bin/BinBaseHook.sol b/src/pool-bin/BinBaseHook.sol index 9120353..95cf231 100644 --- a/src/pool-bin/BinBaseHook.sol +++ b/src/pool-bin/BinBaseHook.sol @@ -16,15 +16,15 @@ import { HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET, HOOKS_AFTER_MINT_RETURNS_DELTA_OFFSET, HOOKS_AFTER_BURN_RETURNS_DELTA_OFFSET -} from "@pancakeswap/v4-core/src/pool-bin/interfaces/IBinHooks.sol"; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {BeforeSwapDelta} from "@pancakeswap/v4-core/src/types/BeforeSwapDelta.sol"; -import {BalanceDelta} from "@pancakeswap/v4-core/src/types/BalanceDelta.sol"; -import {IHooks} from "@pancakeswap/v4-core/src/interfaces/IHooks.sol"; -import {IVault} from "@pancakeswap/v4-core/src/interfaces/IVault.sol"; -import {IBinHooks} from "@pancakeswap/v4-core/src/pool-bin/interfaces/IBinHooks.sol"; -import {IBinPoolManager} from "@pancakeswap/v4-core/src/pool-bin/interfaces/IBinPoolManager.sol"; -import {BinPoolManager} from "@pancakeswap/v4-core/src/pool-bin/BinPoolManager.sol"; +} from "pancake-v4-core/src/pool-bin/interfaces/IBinHooks.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {BeforeSwapDelta} from "pancake-v4-core/src/types/BeforeSwapDelta.sol"; +import {BalanceDelta} from "pancake-v4-core/src/types/BalanceDelta.sol"; +import {IHooks} from "pancake-v4-core/src/interfaces/IHooks.sol"; +import {IVault} from "pancake-v4-core/src/interfaces/IVault.sol"; +import {IBinHooks} from "pancake-v4-core/src/pool-bin/interfaces/IBinHooks.sol"; +import {IBinPoolManager} from "pancake-v4-core/src/pool-bin/interfaces/IBinPoolManager.sol"; +import {BinPoolManager} from "pancake-v4-core/src/pool-bin/BinPoolManager.sol"; abstract contract BinBaseHook is IBinHooks { error NotPoolManager(); @@ -110,7 +110,7 @@ abstract contract BinBaseHook is IBinHooks { function beforeMint(address, PoolKey calldata, IBinPoolManager.MintParams calldata, bytes calldata) external virtual - returns (bytes4) + returns (bytes4, uint24) { revert HookNotImplemented(); } diff --git a/src/pool-bin/BinCounterHook.sol b/src/pool-bin/BinCounterHook.sol index 244463b..24e5a6e 100644 --- a/src/pool-bin/BinCounterHook.sol +++ b/src/pool-bin/BinCounterHook.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {BalanceDelta, BalanceDeltaLibrary} from "@pancakeswap/v4-core/src/types/BalanceDelta.sol"; -import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "@pancakeswap/v4-core/src/types/BeforeSwapDelta.sol"; -import {PoolId, PoolIdLibrary} from "@pancakeswap/v4-core/src/types/PoolId.sol"; -import {IBinPoolManager} from "@pancakeswap/v4-core/src/pool-bin/interfaces/IBinPoolManager.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {BalanceDelta, BalanceDeltaLibrary} from "pancake-v4-core/src/types/BalanceDelta.sol"; +import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "pancake-v4-core/src/types/BeforeSwapDelta.sol"; +import {PoolId, PoolIdLibrary} from "pancake-v4-core/src/types/PoolId.sol"; +import {IBinPoolManager} from "pancake-v4-core/src/pool-bin/interfaces/IBinPoolManager.sol"; import {BinBaseHook} from "./BinBaseHook.sol"; /// @notice BinCounterHook is a contract that counts the number of times a hook is called @@ -45,10 +45,10 @@ contract BinCounterHook is BinBaseHook { external override poolManagerOnly - returns (bytes4) + returns (bytes4, uint24) { beforeMintCount[key.toId()]++; - return this.beforeMint.selector; + return (this.beforeMint.selector, 0); } function afterMint(address, PoolKey calldata key, IBinPoolManager.MintParams calldata, BalanceDelta, bytes calldata) diff --git a/src/pool-cl/CLBaseHook.sol b/src/pool-cl/CLBaseHook.sol index 7046132..b7b7357 100644 --- a/src/pool-cl/CLBaseHook.sol +++ b/src/pool-cl/CLBaseHook.sol @@ -16,15 +16,15 @@ import { HOOKS_AFTER_SWAP_RETURNS_DELTA_OFFSET, HOOKS_AFTER_ADD_LIQUIDIY_RETURNS_DELTA_OFFSET, HOOKS_AFTER_REMOVE_LIQUIDIY_RETURNS_DELTA_OFFSET -} from "@pancakeswap/v4-core/src/pool-cl/interfaces/ICLHooks.sol"; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {BalanceDelta} from "@pancakeswap/v4-core/src/types/BalanceDelta.sol"; -import {BeforeSwapDelta} from "@pancakeswap/v4-core/src/types/BeforeSwapDelta.sol"; -import {IHooks} from "@pancakeswap/v4-core/src/interfaces/IHooks.sol"; -import {IVault} from "@pancakeswap/v4-core/src/interfaces/IVault.sol"; -import {ICLHooks} from "@pancakeswap/v4-core/src/pool-cl/interfaces/ICLHooks.sol"; -import {ICLPoolManager} from "@pancakeswap/v4-core/src/pool-cl/interfaces/ICLPoolManager.sol"; -import {CLPoolManager} from "@pancakeswap/v4-core/src/pool-cl/CLPoolManager.sol"; +} from "pancake-v4-core/src/pool-cl/interfaces/ICLHooks.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {BalanceDelta} from "pancake-v4-core/src/types/BalanceDelta.sol"; +import {BeforeSwapDelta} from "pancake-v4-core/src/types/BeforeSwapDelta.sol"; +import {IHooks} from "pancake-v4-core/src/interfaces/IHooks.sol"; +import {IVault} from "pancake-v4-core/src/interfaces/IVault.sol"; +import {ICLHooks} from "pancake-v4-core/src/pool-cl/interfaces/ICLHooks.sol"; +import {ICLPoolManager} from "pancake-v4-core/src/pool-cl/interfaces/ICLPoolManager.sol"; +import {CLPoolManager} from "pancake-v4-core/src/pool-cl/CLPoolManager.sol"; abstract contract CLBaseHook is ICLHooks { error NotPoolManager(); diff --git a/src/pool-cl/CLCounterHook.sol b/src/pool-cl/CLCounterHook.sol index 88e9531..59a087a 100644 --- a/src/pool-cl/CLCounterHook.sol +++ b/src/pool-cl/CLCounterHook.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {BalanceDelta, BalanceDeltaLibrary} from "@pancakeswap/v4-core/src/types/BalanceDelta.sol"; -import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "@pancakeswap/v4-core/src/types/BeforeSwapDelta.sol"; -import {PoolId, PoolIdLibrary} from "@pancakeswap/v4-core/src/types/PoolId.sol"; -import {ICLPoolManager} from "@pancakeswap/v4-core/src/pool-cl/interfaces/ICLPoolManager.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {BalanceDelta, BalanceDeltaLibrary} from "pancake-v4-core/src/types/BalanceDelta.sol"; +import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "pancake-v4-core/src/types/BeforeSwapDelta.sol"; +import {PoolId, PoolIdLibrary} from "pancake-v4-core/src/types/PoolId.sol"; +import {ICLPoolManager} from "pancake-v4-core/src/pool-cl/interfaces/ICLPoolManager.sol"; import {CLBaseHook} from "./CLBaseHook.sol"; /// @notice CLCounterHook is a contract that counts the number of times a hook is called diff --git a/test/pool-bin/BinCounterHook.t.sol b/test/pool-bin/BinCounterHook.t.sol index ccba2f7..f024dcb 100644 --- a/test/pool-bin/BinCounterHook.t.sol +++ b/test/pool-bin/BinCounterHook.t.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol"; +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Test} from "forge-std/Test.sol"; -import {Currency} from "@pancakeswap/v4-core/src/types/Currency.sol"; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {BinPoolParametersHelper} from "@pancakeswap/v4-core/src/pool-bin/libraries/BinPoolParametersHelper.sol"; +import {Currency} from "pancake-v4-core/src/types/Currency.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {BinPoolParametersHelper} from "pancake-v4-core/src/pool-bin/libraries/BinPoolParametersHelper.sol"; import {BinCounterHook} from "../../src/pool-bin/BinCounterHook.sol"; import {BinTestUtils} from "./utils/BinTestUtils.sol"; -import {PoolIdLibrary} from "@pancakeswap/v4-core/src/types/PoolId.sol"; -import {IBinSwapRouterBase} from "@pancakeswap/v4-periphery/src/pool-bin/interfaces/IBinSwapRouterBase.sol"; +import {PoolIdLibrary} from "pancake-v4-core/src/types/PoolId.sol"; +import {IBinRouterBase} from "pancake-v4-periphery/src/pool-bin/interfaces/IBinRouterBase.sol"; contract BinCounterHookTest is Test, BinTestUtils { using PoolIdLibrary for PoolKey; @@ -61,16 +61,14 @@ contract BinCounterHookTest is Test, BinTestUtils { assertEq(counterHook.afterSwapCount(key.toId()), 0); MockERC20(Currency.unwrap(currency0)).mint(address(this), 0.1 ether); - swapRouter.exactInputSingle( - IBinSwapRouterBase.V4BinExactInputSingleParams({ + exactInputSingle( + IBinRouterBase.BinSwapExactInputSingleParams({ poolKey: key, swapForY: true, - recipient: address(this), amountIn: 0.1 ether, amountOutMinimum: 0, hookData: new bytes(0) - }), - block.timestamp + 60 + }) ); assertEq(counterHook.beforeSwapCount(key.toId()), 1); diff --git a/test/pool-bin/utils/BinTestUtils.sol b/test/pool-bin/utils/BinTestUtils.sol index f9f577f..a05cc59 100644 --- a/test/pool-bin/utils/BinTestUtils.sol +++ b/test/pool-bin/utils/BinTestUtils.sol @@ -1,43 +1,74 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol"; +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Test} from "forge-std/Test.sol"; -import {BinPoolManager} from "@pancakeswap/v4-core/src/pool-bin/BinPoolManager.sol"; -import {Vault} from "@pancakeswap/v4-core/src/Vault.sol"; -import {Currency} from "@pancakeswap/v4-core/src/types/Currency.sol"; -import {SortTokens} from "@pancakeswap/v4-core/test/helpers/SortTokens.sol"; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {SafeCast} from "@pancakeswap/v4-core/src/pool-bin/libraries/math/SafeCast.sol"; -import {BinSwapRouter} from "@pancakeswap/v4-periphery/src/pool-bin/BinSwapRouter.sol"; -import {BinFungiblePositionManager} from "@pancakeswap/v4-periphery/src/pool-bin/BinFungiblePositionManager.sol"; -import {IBinFungiblePositionManager} from - "@pancakeswap/v4-periphery/src/pool-bin/interfaces/IBinFungiblePositionManager.sol"; - -contract BinTestUtils { +import {BinPoolManager} from "pancake-v4-core/src/pool-bin/BinPoolManager.sol"; +import {Vault} from "pancake-v4-core/src/Vault.sol"; +import {Currency} from "pancake-v4-core/src/types/Currency.sol"; +import {SortTokens} from "pancake-v4-core/test/helpers/SortTokens.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {SafeCast} from "pancake-v4-core/src/pool-bin/libraries/math/SafeCast.sol"; +import {BinPositionManager} from "pancake-v4-periphery/src/pool-bin/BinPositionManager.sol"; +import {IBinPositionManager} from "pancake-v4-periphery/src/pool-bin/interfaces/IBinPositionManager.sol"; +import {IBinRouterBase} from "pancake-v4-periphery/src/pool-bin/interfaces/IBinRouterBase.sol"; +import {Planner, Plan} from "pancake-v4-periphery/src/libraries/Planner.sol"; +import {Actions} from "pancake-v4-periphery/src/libraries/Actions.sol"; +import {DeployPermit2} from "permit2/test/utils/DeployPermit2.sol"; +import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; +import {UniversalRouter, RouterParameters} from "pancake-v4-universal-router/src/UniversalRouter.sol"; +import {Commands} from "pancake-v4-universal-router/src/libraries/Commands.sol"; +import {ActionConstants} from "pancake-v4-periphery/src/libraries/ActionConstants.sol"; + +contract BinTestUtils is DeployPermit2 { using SafeCast for uint256; + using Planner for Plan; Vault vault; BinPoolManager poolManager; - BinFungiblePositionManager positionManager; - BinSwapRouter swapRouter; + BinPositionManager positionManager; + IAllowanceTransfer permit2; + UniversalRouter universalRouter; function deployContractsWithTokens() internal returns (Currency, Currency) { vault = new Vault(); poolManager = new BinPoolManager(vault, 500000); vault.registerApp(address(poolManager)); - positionManager = new BinFungiblePositionManager(vault, poolManager, address(0)); - swapRouter = new BinSwapRouter(vault, poolManager, address(0)); + permit2 = IAllowanceTransfer(deployPermit2()); + positionManager = new BinPositionManager(vault, poolManager, permit2); + + RouterParameters memory params = RouterParameters({ + permit2: address(permit2), + weth9: address(0), + v2Factory: address(0), + v3Factory: address(0), + v3Deployer: address(0), + v2InitCodeHash: bytes32(0), + v3InitCodeHash: bytes32(0), + stableFactory: address(0), + stableInfo: address(0), + v4Vault: address(vault), + v4ClPoolManager: address(0), + v4BinPoolManager: address(poolManager), + v3NFTPositionManager: address(0), + v4ClPositionManager: address(0), + v4BinPositionManager: address(positionManager) + }); + universalRouter = new UniversalRouter(params); MockERC20 token0 = new MockERC20("token0", "T0", 18); MockERC20 token1 = new MockERC20("token1", "T1", 18); - address[2] memory approvalAddress = [address(positionManager), address(swapRouter)]; - for (uint256 i; i < approvalAddress.length; i++) { - token0.approve(approvalAddress[i], type(uint256).max); - token1.approve(approvalAddress[i], type(uint256).max); - } + // approve permit2 contract to transfer our funds + token0.approve(address(permit2), type(uint256).max); + token1.approve(address(permit2), type(uint256).max); + + permit2.approve(address(token0), address(positionManager), type(uint160).max, uint48(block.timestamp + 1000)); + permit2.approve(address(token1), address(positionManager), type(uint160).max, uint48(block.timestamp + 1000)); + + permit2.approve(address(token0), address(universalRouter), type(uint160).max, uint48(block.timestamp + 1000)); + permit2.approve(address(token1), address(universalRouter), type(uint160).max, uint48(block.timestamp + 1000)); return SortTokens.sort(token0, token1); } @@ -73,7 +104,7 @@ contract BinTestUtils { distribY[i] = binId <= currentActiveId && nbBinY > 0 ? uint256(1e18 / nbBinY).safe64() : 0; } - IBinFungiblePositionManager.AddLiquidityParams memory params = IBinFungiblePositionManager.AddLiquidityParams({ + IBinPositionManager.BinAddLiquidityParams memory params = IBinPositionManager.BinAddLiquidityParams({ poolKey: key, amount0: amountX, amount1: amountY, @@ -84,11 +115,24 @@ contract BinTestUtils { deltaIds: convertToRelative(binIds, currentActiveId), distributionX: distribX, distributionY: distribY, - to: address(this), - deadline: block.timestamp + 600 + to: address(this) }); - positionManager.addLiquidity(params); + Plan memory planner = Planner.init().add(Actions.BIN_ADD_LIQUIDITY, abi.encode(params)); + bytes memory data = planner.finalizeModifyLiquidityWithClose(params.poolKey); + positionManager.modifyLiquidities(data, block.timestamp); + } + + function exactInputSingle(IBinRouterBase.BinSwapExactInputSingleParams memory params) internal { + Plan memory plan = Planner.init().add(Actions.BIN_SWAP_EXACT_IN_SINGLE, abi.encode(params)); + bytes memory data = + plan.finalizeSwap(params.poolKey.currency0, params.poolKey.currency1, ActionConstants.MSG_SENDER); + + bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.V4_SWAP))); + bytes[] memory inputs = new bytes[](1); + inputs[0] = data; + + universalRouter.execute(commands, inputs); } /// @dev Given list of binIds and activeIds, return the delta ids. diff --git a/test/pool-cl/CLCounterHook.t.sol b/test/pool-cl/CLCounterHook.t.sol index fed60de..5c1c77b 100644 --- a/test/pool-cl/CLCounterHook.t.sol +++ b/test/pool-cl/CLCounterHook.t.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol"; +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Test} from "forge-std/Test.sol"; -import {Constants} from "@pancakeswap/v4-core/test/pool-cl/helpers/Constants.sol"; -import {Currency} from "@pancakeswap/v4-core/src/types/Currency.sol"; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {CLPoolParametersHelper} from "@pancakeswap/v4-core/src/pool-cl/libraries/CLPoolParametersHelper.sol"; +import {Constants} from "pancake-v4-core/test/pool-cl/helpers/Constants.sol"; +import {Currency} from "pancake-v4-core/src/types/Currency.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {CLPoolParametersHelper} from "pancake-v4-core/src/pool-cl/libraries/CLPoolParametersHelper.sol"; import {CLCounterHook} from "../../src/pool-cl/CLCounterHook.sol"; import {CLTestUtils} from "./utils/CLTestUtils.sol"; -import {CLPoolParametersHelper} from "@pancakeswap/v4-core/src/pool-cl/libraries/CLPoolParametersHelper.sol"; -import {PoolIdLibrary} from "@pancakeswap/v4-core/src/types/PoolId.sol"; -import {ICLSwapRouterBase} from "@pancakeswap/v4-periphery/src/pool-cl/interfaces/ICLSwapRouterBase.sol"; +import {CLPoolParametersHelper} from "pancake-v4-core/src/pool-cl/libraries/CLPoolParametersHelper.sol"; +import {PoolIdLibrary} from "pancake-v4-core/src/types/PoolId.sol"; +import {ICLRouterBase} from "pancake-v4-periphery/src/pool-cl/interfaces/ICLRouterBase.sol"; contract CLCounterHookTest is Test, CLTestUtils { using PoolIdLibrary for PoolKey; @@ -62,17 +62,15 @@ contract CLCounterHookTest is Test, CLTestUtils { assertEq(hook.afterSwapCount(key.toId()), 0); MockERC20(Currency.unwrap(currency0)).mint(address(this), 0.1 ether); - swapRouter.exactInputSingle( - ICLSwapRouterBase.V4CLExactInputSingleParams({ + exactInputSingle( + ICLRouterBase.CLSwapExactInputSingleParams({ poolKey: key, zeroForOne: true, - recipient: address(this), amountIn: 0.1 ether, amountOutMinimum: 0, sqrtPriceLimitX96: 0, hookData: new bytes(0) - }), - block.timestamp + }) ); assertEq(hook.beforeSwapCount(key.toId()), 1); diff --git a/test/pool-cl/utils/CLTestUtils.sol b/test/pool-cl/utils/CLTestUtils.sol index a3fa2ee..6598b02 100644 --- a/test/pool-cl/utils/CLTestUtils.sol +++ b/test/pool-cl/utils/CLTestUtils.sol @@ -1,60 +1,109 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; -import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol"; +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; import {Test, console} from "forge-std/Test.sol"; -import {CLPoolManager} from "@pancakeswap/v4-core/src/pool-cl/CLPoolManager.sol"; -import {Vault} from "@pancakeswap/v4-core/src/Vault.sol"; -import {Currency} from "@pancakeswap/v4-core/src/types/Currency.sol"; -import {SortTokens} from "@pancakeswap/v4-core/test/helpers/SortTokens.sol"; -import {PoolKey} from "@pancakeswap/v4-core/src/types/PoolKey.sol"; -import {CLSwapRouter} from "@pancakeswap/v4-periphery/src/pool-cl/CLSwapRouter.sol"; -import {NonfungiblePositionManager} from "@pancakeswap/v4-periphery/src/pool-cl/NonfungiblePositionManager.sol"; -import {INonfungiblePositionManager} from - "@pancakeswap/v4-periphery/src/pool-cl/interfaces/INonfungiblePositionManager.sol"; - -contract CLTestUtils { +import {CLPoolManager} from "pancake-v4-core/src/pool-cl/CLPoolManager.sol"; +import {Vault} from "pancake-v4-core/src/Vault.sol"; +import {Currency} from "pancake-v4-core/src/types/Currency.sol"; +import {SortTokens} from "pancake-v4-core/test/helpers/SortTokens.sol"; +import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; +import {CLPositionManager} from "pancake-v4-periphery/src/pool-cl/CLPositionManager.sol"; +import {ICLPositionManager} from "pancake-v4-periphery/src/pool-cl/interfaces/ICLPositionManager.sol"; +import {ICLRouterBase} from "pancake-v4-periphery/src/pool-cl/interfaces/ICLRouterBase.sol"; +import {PositionConfig} from "pancake-v4-periphery/src/pool-cl/libraries/PositionConfig.sol"; +import {Planner, Plan} from "pancake-v4-periphery/src/libraries/Planner.sol"; +import {Actions} from "pancake-v4-periphery/src/libraries/Actions.sol"; +import {DeployPermit2} from "permit2/test/utils/DeployPermit2.sol"; +import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; +import {UniversalRouter, RouterParameters} from "pancake-v4-universal-router/src/UniversalRouter.sol"; +import {Commands} from "pancake-v4-universal-router/src/libraries/Commands.sol"; +import {ActionConstants} from "pancake-v4-periphery/src/libraries/ActionConstants.sol"; +import {LiquidityAmounts} from "pancake-v4-periphery/src/pool-cl/libraries/LiquidityAmounts.sol"; +import {TickMath} from "pancake-v4-core/src/pool-cl/libraries/TickMath.sol"; +import {PoolId, PoolIdLibrary} from "pancake-v4-core/src/types/PoolId.sol"; + +contract CLTestUtils is DeployPermit2 { + using Planner for Plan; + using PoolIdLibrary for PoolKey; + Vault vault; CLPoolManager poolManager; - NonfungiblePositionManager nfp; - CLSwapRouter swapRouter; + CLPositionManager positionManager; + IAllowanceTransfer permit2; + UniversalRouter universalRouter; function deployContractsWithTokens() internal returns (Currency, Currency) { vault = new Vault(); poolManager = new CLPoolManager(vault, 500000); vault.registerApp(address(poolManager)); - nfp = new NonfungiblePositionManager(vault, poolManager, address(0), address(0)); - swapRouter = new CLSwapRouter(vault, poolManager, address(0)); + permit2 = IAllowanceTransfer(deployPermit2()); + positionManager = new CLPositionManager(vault, poolManager, permit2); + + RouterParameters memory params = RouterParameters({ + permit2: address(permit2), + weth9: address(0), + v2Factory: address(0), + v3Factory: address(0), + v3Deployer: address(0), + v2InitCodeHash: bytes32(0), + v3InitCodeHash: bytes32(0), + stableFactory: address(0), + stableInfo: address(0), + v4Vault: address(vault), + v4ClPoolManager: address(poolManager), + v4BinPoolManager: address(0), + v3NFTPositionManager: address(0), + v4ClPositionManager: address(positionManager), + v4BinPositionManager: address(0) + }); + universalRouter = new UniversalRouter(params); MockERC20 token0 = new MockERC20("token0", "T0", 18); MockERC20 token1 = new MockERC20("token1", "T1", 18); - address[2] memory approvalAddress = [address(nfp), address(swapRouter)]; - for (uint256 i; i < approvalAddress.length; i++) { - token0.approve(approvalAddress[i], type(uint256).max); - token1.approve(approvalAddress[i], type(uint256).max); - } + // approve permit2 contract to transfer our funds + token0.approve(address(permit2), type(uint256).max); + token1.approve(address(permit2), type(uint256).max); + + permit2.approve(address(token0), address(positionManager), type(uint160).max, uint48(block.timestamp + 1000)); + permit2.approve(address(token1), address(positionManager), type(uint160).max, uint48(block.timestamp + 1000)); + + permit2.approve(address(token0), address(universalRouter), type(uint160).max, uint48(block.timestamp + 1000)); + permit2.approve(address(token1), address(universalRouter), type(uint160).max, uint48(block.timestamp + 1000)); return SortTokens.sort(token0, token1); } - function addLiquidity(PoolKey memory key, uint256 amount0, uint256 amount1, int24 tickLower, int24 tickUpper) + function addLiquidity(PoolKey memory key, uint128 amount0Max, uint128 amount1Max, int24 tickLower, int24 tickUpper) internal { - INonfungiblePositionManager.MintParams memory mintParams = INonfungiblePositionManager.MintParams({ - poolKey: key, - tickLower: tickLower, - tickUpper: tickUpper, - salt: bytes32(0), - amount0Desired: amount0, - amount1Desired: amount1, - amount0Min: 0, - amount1Min: 0, - recipient: address(this), - deadline: block.timestamp - }); + (uint160 sqrtPriceX96,,,) = poolManager.getSlot0(key.toId()); + uint256 liquidity = LiquidityAmounts.getLiquidityForAmounts( + sqrtPriceX96, + TickMath.getSqrtRatioAtTick(tickLower), + TickMath.getSqrtRatioAtTick(tickUpper), + amount0Max, + amount1Max + ); + PositionConfig memory config = PositionConfig({poolKey: key, tickLower: tickLower, tickUpper: tickUpper}); + Plan memory planner = Planner.init().add( + Actions.CL_MINT_POSITION, abi.encode(config, liquidity, amount0Max, amount1Max, address(this), new bytes(0)) + ); + bytes memory data = planner.finalizeModifyLiquidityWithClose(key); + positionManager.modifyLiquidities(data, block.timestamp); + } + + function exactInputSingle(ICLRouterBase.CLSwapExactInputSingleParams memory params) internal { + Plan memory plan = Planner.init().add(Actions.CL_SWAP_EXACT_IN_SINGLE, abi.encode(params)); + bytes memory data = + plan.finalizeSwap(params.poolKey.currency0, params.poolKey.currency1, ActionConstants.MSG_SENDER); + + bytes memory commands = abi.encodePacked(bytes1(uint8(Commands.V4_SWAP))); + bytes[] memory inputs = new bytes[](1); + inputs[0] = data; - nfp.mint(mintParams); + universalRouter.execute(commands, inputs); } }