diff --git a/foundry.toml b/foundry.toml index 5aaeca4..a37fb43 100644 --- a/foundry.toml +++ b/foundry.toml @@ -11,7 +11,10 @@ optimizer_runs=100000000 # maximum value allowed by etherscan's verifier XD. The viaIR=true #gas_reports = ['PartyPool', 'PartyPoolBalancedPair', 'PartyPlanner', 'PartyPoolSwapImpl', 'PartyPoolMintImpl',] gas_reports = ['PartyPool', 'PartyPoolBalancedPair', 'PartyPlanner', 'GasHarness'] -fs_permissions = [{ access = "write", path = "liqp-deployments.json"}] +fs_permissions = [ + { access = "write", path = "liqp-deployments.json"}, # used for mockchain + { access = "read", path = "deployment/liqp-deployments.json"}, # production deployments +] [lint] lint_on_build=false # more annoying than helpful diff --git a/script/DeployEthereum.sol b/script/DeployEthereum.sol index b144980..ad05c4f 100644 --- a/script/DeployEthereum.sol +++ b/script/DeployEthereum.sol @@ -16,33 +16,16 @@ import {PartyPoolMintImpl} from "../src/PartyPoolMintImpl.sol"; import {PartyPoolSwapImpl} from "../src/PartyPoolSwapImpl.sol"; contract DeployEthereum is Script { + address constant public ADMIN = 0x12db90820dafed100e40e21128e40dcd4ff6b331; address constant public PROTOCOL_FEE_ADDRESS = 0x0E280F5eDA58872d7cDaA8AC0A57A55fD6133AEd; uint256 constant public PROTOCOL_FEE_PPM = 10_0000; // 10% of LP fees NativeWrapper constant public WETH = NativeWrapper(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); - IERC20 constant public USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); - IERC20 constant public USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); - IERC20 constant public WBTC = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599); - IERC20 constant public BNB = IERC20(0xB8c77482e45F1F44dE1745F52C74426C631bDD52); - IERC20 constant public TRX = IERC20(0x50327c6c5a14DCaDE707ABad2E27eB517df87AB5); - IERC20 constant public WSOL = IERC20(0xd1D82d3Ab815E0B47e38EC2d666c5b8AA05Ae501); // IBC not Wormhole - IERC20 constant public PEPE = IERC20(0x6982508145454Ce325dDbE47a25d4ec3d2311933); - IERC20 constant public SHIB = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE); function run() public { require(block.chainid == 1, 'Not Ethereum'); vm.startBroadcast(); - vm.label(address(WETH), 'WETH'); - vm.label(address(USDT), 'USDT'); - vm.label(address(USDC), 'USDC'); - vm.label(address(WBTC), 'WBTC'); - vm.label(address(BNB), 'BNB'); - vm.label(address(TRX), 'TRX'); - vm.label(address(WSOL), 'WSOL'); - vm.label(address(PEPE), 'PEPE'); - vm.label(address(SHIB), 'SHIB'); - console2.log('creating swap impl'); PartyPoolSwapImpl swapImpl = new PartyPoolSwapImpl(WETH); console2.log('creating mint impl'); @@ -55,7 +38,7 @@ contract DeployEthereum is Script { PartyPoolBalancedPairInitCode bpInit = new PartyPoolBalancedPairInitCode(); console2.log('creating planner'); PartyPlanner planner = new PartyPlanner( - msg.sender, // admin address is the same as the deployer + ADMIN, // admin address is the same as the deployer WETH, swapImpl, mintImpl, diff --git a/script/ExercisePOC.sol b/script/ExercisePOC.sol new file mode 100644 index 0000000..82de239 --- /dev/null +++ b/script/ExercisePOC.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.30; + +import "forge-std/console2.sol"; +import {Script} from "../lib/forge-std/src/Script.sol"; +import {IERC3156FlashBorrower} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol"; +import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {IPartyInfo} from "../src/IPartyInfo.sol"; +import {IPartyPool} from "../src/IPartyPool.sol"; +import {MockFlashBorrower} from "../test/MockFlashBorrower.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {IPartyPlanner} from "../src/IPartyPlanner.sol"; + + +contract ExercisePOC is Script { + + IPartyPlanner private immutable planner; + IPartyInfo private immutable info; + + constructor() { + require(block.chainid==1, 'Not Ethereum'); + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/deployment/liqp-deployments.json"); + string memory json = vm.readFile(path); + bytes memory partyPlannerRaw = stdJson.parseRaw(json, ".1.v1.PartyPlanner"); + planner = IPartyPlanner(abi.decode(partyPlannerRaw, (address))); + bytes memory partyInfoRaw = stdJson.parseRaw(json, ".1.v1.PartyInfo"); + info = IPartyInfo(abi.decode(partyInfoRaw, (address))); + } + + function run() public { + exercise(planner.getAllPools(0,1)[0]); + } + + function exercise(IPartyPool pool) internal { + console2.log('Exercising pool at', address(pool)); + uint8 WETH_index = 3; + // gather tokens and denominators + IERC20[] memory tokens = pool.allTokens(); + uint256 n = tokens.length; + IERC20 WETH = tokens[WETH_index]; + require(address(WETH) == address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2), 'Expected WETH as the fourth token'); + + // approve all + for (uint256 i=0; i LP) + uint256 amountIn = WETH.balanceOf(address(pool)) / 100; // trade 1% of what's in the pool + require( WETH.balanceOf(msg.sender) >= amountIn, 'Insufficient WETH for swapMint'); + (, uint256 lpMinted,) = pool.swapMint(msg.sender, msg.sender, WETH_index, amountIn, 0); + + // 5) regular swap (token 0 -> last token) + require( WETH.balanceOf(msg.sender) >= amountIn, 'Insufficient WETH for swap'); + WETH.approve(address(pool), amountIn); + uint256 inputIndex = WETH_index; + uint256 outputIndex = 0; + pool.swap(msg.sender, bytes4(0), msg.sender, WETH_index, outputIndex, amountIn, int128(0), 0, false, ''); + + // 6) Collect protocol fees now (after some swaps) so some will have been moved out + pool.collectProtocolFees(); + + // 7) Final swap-style operation: burnSwap (burn LP then swap to single asset) + // ensure we have some LP allowance + pool.burnSwap(msg.sender, msg.sender, lpMinted, WETH_index, 0, false); + } + +}