diff --git a/packages/hardhat/helper.config.ts b/packages/hardhat/helper.config.ts index 2bd96737..135aa51b 100644 --- a/packages/hardhat/helper.config.ts +++ b/packages/hardhat/helper.config.ts @@ -6,6 +6,15 @@ interface NetworkConfigEntryTypes { routerAddr: string; batchRouterAddr: string; }; + customPool: { + name: string; + tokenConfig: { + token: string; + tokenType: number; + rateProvider: string; + yieldFeeExempt: boolean; + }[]; + }; } // Contracts have constructors that require contract address args that are network specific @@ -18,6 +27,23 @@ const networkConfig: { [key: number]: NetworkConfigEntryTypes } = { routerAddr: "0xA0De078cd5cFa7088821B83e0bD7545ccfb7c883", batchRouterAddr: "0x8A8B9f35765899B3a0291700141470D79EA2eA88", }, + customPool: { + name: "ConstantPricePool", + tokenConfig: [ + { + token: "0xB77EB1A70A96fDAAeB31DB1b42F2b8b5846b2613", // sepoliaDAI + tokenType: 0, // STANDARD + rateProvider: "0x0000000000000000000000000000000000000000", // https://docs-v3.balancer.fi/reference/contracts/rate-providers.html#none-of-the-assets + yieldFeeExempt: false, + }, + { + token: "0x80D6d3946ed8A1Da4E226aa21CCdDc32bd127d1A", // sepoliaUSDC + tokenType: 0, // STANDARD + rateProvider: "0x0000000000000000000000000000000000000000", // https://docs-v3.balancer.fi/reference/contracts/rate-providers.html#none-of-the-assets + yieldFeeExempt: false, + }, + ], + }, }, }; diff --git a/packages/hardhat/scripts/initializePool.ts b/packages/hardhat/scripts/initializePool.ts new file mode 100644 index 00000000..bd1129aa --- /dev/null +++ b/packages/hardhat/scripts/initializePool.ts @@ -0,0 +1,107 @@ +import hre from "hardhat"; +import { networkConfig } from "../helper.config"; +import { Contract } from "ethers"; + +/** + * Initialize a pool that has already been registered on sepolia + * + * balancer docs + * https://docs-v3.balancer.fi/concepts/router/overview.html#initialize + * + * initialize() function + * https://github.com/balancer/balancer-v3-monorepo/blob/2ad8501c85e8afb2f25d970344af700a571b1d0b/pkg/vault/contracts/VaultExtension.sol#L130-L149 + * + */ + +const routerAbi = [ + { + inputs: [ + { + internalType: "address", + name: "pool", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "contract IERC20[]", + name: "tokens", + type: "address[]", + }, + { + internalType: "uint256[]", + name: "exactAmountsIn", + type: "uint256[]", + }, + { + internalType: "uint256", + name: "minBptAmountOut", + type: "uint256", + }, + { + internalType: "bytes", + name: "userData", + type: "bytes", + }, + ], + name: "initialize", + outputs: [ + { + internalType: "uint256", + name: "bptAmountOut", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, +]; + +async function main() { + const privateKey = process.env.DEPLOYER_PRIVATE_KEY; + if (!privateKey) { + console.log("🚫️ Please set a PRIVATE_KEY var at packages/hardhat/.env"); + return; + } + if (hre.network.name !== "sepolia") { + throw new Error("This script is only configured for sepolia network"); + } + const chainId = Number(await hre.ethers.provider.getNetwork().then(network => network.chainId)); + + // grab the Router contract + const { balancer, customPool } = networkConfig[chainId]; + const [signer] = await hre.ethers.getSigners(); + const router = await hre.ethers.getContractAt(routerAbi, balancer.routerAddr, signer); + + /*************************** + * args for initialize * + ***************************/ + // 1. Address of pool to initialize + const { target: poolAddress } = await hre.ethers.getContract(customPool.name, signer); + // 2. Tokens used to seed the pool (must match the registered tokens) + const tokens = customPool.tokenConfig.map((token: any) => token.token); + // 3. Exact amounts of tokens to be added, sorted in token registration order + const exactAmountsIn = [100, 100]; + // 4. Minimum amount of pool tokens to be received + const minBptAmountOut = 0; + // 5. If true, incoming ETH will be wrapped to WETH; otherwise the Vault will pull WETH tokens + const wethIsEth = false; + // 6. Additional (optional) data required for adding initial liquidity + const userData = "0x"; + + console.log("Sending tx to initialize pool..."); + const txResponse = await router.initialize(poolAddress, tokens, exactAmountsIn, minBptAmountOut, wethIsEth, userData); + console.log(txResponse); + console.log("Waiting for tx to be mined..."); + const txReceipt = await txResponse.wait(); + console.log("Pool registered!!!"); + console.log(txReceipt); +} + +main().catch(error => { + console.error(error); + process.exitCode = 1; +}); diff --git a/packages/hardhat/scripts/registerPool.ts b/packages/hardhat/scripts/registerPool.ts index be2c2a02..8b4a18d1 100644 --- a/packages/hardhat/scripts/registerPool.ts +++ b/packages/hardhat/scripts/registerPool.ts @@ -26,32 +26,23 @@ async function main() { const chainId = Number(await hre.ethers.provider.getNetwork().then(network => network.chainId)); // grab the VaultExtension contract - const { vaultExtensionAddr } = networkConfig[chainId].balancer; + const { balancer, customPool } = networkConfig[chainId]; const { abi: vaultExtensionAbi } = await hre.artifacts.readArtifact("IVaultExtension"); const [signer] = await hre.ethers.getSigners(); - const vaultExtension = await hre.ethers.getContractAt(vaultExtensionAbi, vaultExtensionAddr, signer); + const vaultExtension = await hre.ethers.getContractAt(vaultExtensionAbi, balancer.vaultExtensionAddr, signer); - // args for registerPool - const { target: poolAddress } = await hre.ethers.getContract("ConstantPricePool", signer); - const tokenConfig = [ - { - token: "0xB77EB1A70A96fDAAeB31DB1b42F2b8b5846b2613", // sepoliaDAI - tokenType: 0, // STANDARD - rateProvider: "0x0000000000000000000000000000000000000000", // https://docs-v3.balancer.fi/reference/contracts/rate-providers.html#none-of-the-assets - yieldFeeExempt: false, - }, - { - token: "0x80D6d3946ed8A1Da4E226aa21CCdDc32bd127d1A", // sepoliaUSDC - tokenType: 0, // STANDARD - rateProvider: "0x0000000000000000000000000000000000000000", // https://docs-v3.balancer.fi/reference/contracts/rate-providers.html#none-of-the-assets - yieldFeeExempt: false, - }, - ]; - // The timestamp after which it is no longer possible to pause the pool + /***************************** + * args for registerPool * + *****************************/ + // 1. Address of pool to register + const { target: poolAddress } = await hre.ethers.getContract(customPool.name, signer); + // 2. An array of descriptors for the tokens the pool will manage. + const tokenConfig = customPool.tokenConfig; + // 3. The timestamp after which it is no longer possible to pause the pool const pauseWindowEndTime = 0; - // Optional contract the Vault will allow to pause the pool + // 4. Optional contract the Vault will allow to pause the pool const pauseManager = hre.ethers.ZeroAddress; - // Flags indicating which hooks the pool supports + // 5. Flags indicating which hooks the pool supports const hookConfig = { shouldCallBeforeInitialize: false, shouldCallAfterInitialize: false, @@ -62,6 +53,7 @@ async function main() { shouldCallBeforeRemoveLiquidity: false, shouldCallAfterRemoveLiquidity: false, }; + // 6. Liquidity management flags with implemented methods const liquidityManagement = { supportsAddLiquidityCustom: false, supportsRemoveLiquidityCustom: false,