diff --git a/.gitignore b/.gitignore index 50df509..7d48db6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,7 @@ out/ # Ignores development broadcast logs !/broadcast -/broadcast/*/31337/ -/broadcast/**/dry-run/ +/broadcast/* # Docs docs/ diff --git a/.gitmodules b/.gitmodules index aa03082..80d4583 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ -[submodule "lib/pancake-v4-periphery"] - path = lib/pancake-v4-periphery - url = https://github.com/pancakeswap/pancake-v4-periphery [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std [submodule "lib/forge-gas-snapshot"] path = lib/forge-gas-snapshot url = https://github.com/marktoda/forge-gas-snapshot +[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 28dc252..b966d03 100644 --- a/foundry.toml +++ b/foundry.toml @@ -11,7 +11,10 @@ optimizer_runs = 1000 via_ir = true evm_version = 'cancun' ffi = true -fs_permissions = [{ access = "read-write", path = ".forge-snapshots/" }] +fs_permissions = [ + { access = "read-write", path = ".forge-snapshots/" }, + { access = "read", path = "./script/config" }, +] [profile.default.fuzz] runs = 1000 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 539ce11..4b73269 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,8 +1,8 @@ -pancake-v4-periphery/=lib/pancake-v4-periphery/ -pancake-v4-core/=lib/pancake-v4-periphery/lib/pancake-v4-core/ forge-std/=lib/forge-std/src/ ds-test/=lib/forge-std/lib/ds-test/src/ -forge-gas-snapshot/=lib/forge-gas-snapshot/src/ -openzeppelin-contracts/=lib/pancake-v4-periphery/lib/pancake-v4-core/lib/openzeppelin-contracts/ -solmate/=lib/pancake-v4-periphery/lib/pancake-v4-core/lib/solmate/ -permit/=lib/pancake-v4-periphery/lib/permit/ \ 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/script/01_DeployMockVeToken.s.sol b/script/01_DeployMockVeToken.s.sol new file mode 100644 index 0000000..19b806c --- /dev/null +++ b/script/01_DeployMockVeToken.s.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "forge-std/Script.sol"; +import {BaseScript} from "./BaseScript.sol"; + +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; + +/** + * forge script script/01_DeployMockVeToken.s.sol:DeployMockVeTokenScript -vvv \ + * --rpc-url $RPC_URL \ + * --broadcast \ + * --slow \ + * --verify + */ +contract DeployMockVeTokenScript is BaseScript { + function run() public { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + MockERC20 VeCake = new MockERC20("MockVeCake", "VeCake", 18); + emit log_named_address("MockVeCake", address(VeCake)); + + vm.stopBroadcast(); + } +} diff --git a/script/02_DeployCLVeCakeExclusiveHook.s.sol b/script/02_DeployCLVeCakeExclusiveHook.s.sol new file mode 100644 index 0000000..f1bc827 --- /dev/null +++ b/script/02_DeployCLVeCakeExclusiveHook.s.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "forge-std/Script.sol"; +import {BaseScript} from "./BaseScript.sol"; + +import {CLVeCakeExclusiveHook} from "../src/pool-cl/vecake-exclusive/CLVeCakeExclusiveHook.sol"; +import {ICLPoolManager} from "pancake-v4-core/src/pool-cl/interfaces/ICLPoolManager.sol"; + +/** + * forge script script/02_DeployCLVeCakeExclusiveHook.s.sol:DeployCLVeCakeExclusiveHookScript -vvv \ + * --rpc-url $RPC_URL \ + * --broadcast \ + * --slow \ + * --verify + */ +contract DeployCLVeCakeExclusiveHookScript is BaseScript { + function run() public { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + address clPoolManager = getAddressFromConfig("clPoolManager"); + emit log_named_address("CLPoolManager", clPoolManager); + + address veCake = getAddressFromConfig("mockVeCake"); + emit log_named_address("VeCake", veCake); + + CLVeCakeExclusiveHook clVeCakeExclusiveHook = + new CLVeCakeExclusiveHook(ICLPoolManager(clPoolManager), address(veCake)); + emit log_named_address("CLVeCakeExclusiveHook", address(clVeCakeExclusiveHook)); + + vm.stopBroadcast(); + } +} diff --git a/script/03_DeployBinVeCakeExclusiveHook.s.sol b/script/03_DeployBinVeCakeExclusiveHook.s.sol new file mode 100644 index 0000000..8ffa6cf --- /dev/null +++ b/script/03_DeployBinVeCakeExclusiveHook.s.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "forge-std/Script.sol"; +import {BaseScript} from "./BaseScript.sol"; + +import {BinVeCakeExclusiveHook} from "../src/pool-bin/vecake-exclusive/BinVeCakeExclusiveHook.sol"; +import {IBinPoolManager} from "pancake-v4-core/src/pool-bin/interfaces/IBinPoolManager.sol"; + +/** + * forge script script/03_DeployBinVeCakeExclusiveHook.s.sol:DeployBinVeCakeExclusiveHookScript -vvv \ + * --rpc-url $RPC_URL \ + * --broadcast \ + * --slow \ + * --verify + */ +contract DeployBinVeCakeExclusiveHookScript is BaseScript { + function run() public { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + address binPoolManager = getAddressFromConfig("binPoolManager"); + emit log_named_address("BinPoolManager", binPoolManager); + + address veCake = getAddressFromConfig("mockVeCake"); + emit log_named_address("VeCake", veCake); + + BinVeCakeExclusiveHook binVeCakeExclusiveHook = + new BinVeCakeExclusiveHook(IBinPoolManager(binPoolManager), address(veCake)); + emit log_named_address("BinVeCakeExclusiveHook", address(binVeCakeExclusiveHook)); + + vm.stopBroadcast(); + } +} diff --git a/script/BaseScript.sol b/script/BaseScript.sol new file mode 100644 index 0000000..cce3c75 --- /dev/null +++ b/script/BaseScript.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import {Test} from "forge-std/Test.sol"; + +abstract contract BaseScript is Test { + string path; + + function setUp() public virtual { + string memory scriptConfig = vm.envString("SCRIPT_CONFIG"); + emit log(string.concat("[BaseScript] SCRIPT_CONFIG: ", scriptConfig)); + + string memory root = vm.projectRoot(); + path = string.concat(root, "/script/config/", scriptConfig, ".json"); + emit log(string.concat("[BaseScript] Reading config from: ", path)); + } + + // reference: https://github.com/foundry-rs/foundry/blob/master/testdata/default/cheats/Json.t.sol + function getAddressFromConfig(string memory key) public view returns (address) { + string memory json = vm.readFile(path); + bytes memory data = vm.parseJson(json, string.concat(".", key)); + + // seems like foundry decode as 0x20 when address is not set or as "0x" + address decodedData = abi.decode(data, (address)); + require(decodedData != address(0x20), "Address not set"); + + return decodedData; + } +} diff --git a/script/config/bsc-testnet.json b/script/config/bsc-testnet.json new file mode 100644 index 0000000..f24188d --- /dev/null +++ b/script/config/bsc-testnet.json @@ -0,0 +1,11 @@ + { + "vault": "0x08F012b8E2f3021db8bd2A896A7F422F4041F131", + "clPoolManager": "0x969D90aC74A1a5228b66440f8C8326a8dA47A5F9", + "binPoolManager": "0x437ef7C8C00d20a8535ae1786c5800c88413e7Af", + "clPositionManager": "0x89A7D45D007077485CB5aE2abFB740b1fe4FF574", + "binPositionManager": "0xfB84c0D67f217f078E949d791b8d3081FE91Bca2", + "mockVeCake": "0x86668337a40CaAd59F463E89550c6Aa59C056988", + "clVeCakeExclusiveHook": "0x7B07026C721F824ee913D65C5810884dEDf9ED50", + "binVeCakeExclusiveHook": "0x6D211114Ef77F89CD6912441CbaFfFBF71E25587" + } + \ No newline at end of file diff --git a/test/pool-cl/helpers/MockCLPositionManager.sol b/test/pool-cl/helpers/MockCLPositionManager.sol index 5d4fa9e..65bc4e9 100644 --- a/test/pool-cl/helpers/MockCLPositionManager.sol +++ b/test/pool-cl/helpers/MockCLPositionManager.sol @@ -41,14 +41,6 @@ contract MockCLPositionManager is CLPositionManager, CommonBase { this.modifyLiquidities(data, block.timestamp); liquidityMinted = getPositionLiquidity(tokenId, config); - - // Vm.Log[] memory entries = vm.getRecordedLogs(); - // // find IBinFungibleToken.TransferBatch - // for (uint256 i = 0; i < entries.length; i++) { - // if (entries[i].topics[0] == keccak256("TransferBatch(address,address,address,uint256[],uint256[])")) { - // (tokenIds, liquidityMinted) = abi.decode(entries[i].data, (uint256[], uint256[])); - // } - // } } function decreaseLiquidity(