From 46d61a42f55848e42bda1b10a30b567acef11e73 Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Mon, 22 Jul 2024 14:20:47 -0700 Subject: [PATCH 1/7] Update deploy script patterns --- packages/foundry/package.json | 5 +- packages/foundry/script/00_DeploySetup.s.sol | 62 - packages/foundry/script/Deploy.s.sol | 36 + ....s.sol => DeployConstantProductPool.s.sol} | 53 +- ...Pool.s.sol => DeployConstantSumPool.s.sol} | 48 +- .../foundry/script/DeployMockTokens.s.sol | 35 + packages/foundry/scripts-js/generateTsAbis.js | 2 +- .../nextjs/contracts/deployedContracts.ts | 1742 +++++++++-------- 8 files changed, 1002 insertions(+), 981 deletions(-) delete mode 100644 packages/foundry/script/00_DeploySetup.s.sol create mode 100644 packages/foundry/script/Deploy.s.sol rename packages/foundry/script/{02_DeployConstantProductPool.s.sol => DeployConstantProductPool.s.sol} (79%) rename packages/foundry/script/{01_DeployConstantSumPool.s.sol => DeployConstantSumPool.s.sol} (83%) create mode 100644 packages/foundry/script/DeployMockTokens.s.sol diff --git a/packages/foundry/package.json b/packages/foundry/package.json index 5d6478b3..c98d1913 100644 --- a/packages/foundry/package.json +++ b/packages/foundry/package.json @@ -5,10 +5,7 @@ "account": "node script/ListAccount.js", "chain": "anvil --config-out localhost.json", "compile": "forge compile", - "deploy": "yarn deploy:setup && yarn deploy:sum && yarn deploy:product", - "deploy:setup": "forge build --build-info --build-info-path out/build-info/ && forge script script/00_DeploySetup.s.sol --rpc-url ${1:-default_network} --broadcast --legacy && node scripts-js/generateTsAbis.js", - "deploy:sum": "forge script script/01_DeployConstantSumPool.s.sol --rpc-url ${1:-default_network} --broadcast", - "deploy:product": "forge script script/02_DeployConstantProductPool.s.sol --rpc-url ${1:-default_network} --broadcast", + "deploy": "forge build --build-info --build-info-path out/build-info/ && forge script script/Deploy.s.sol --rpc-url ${1:-default_network} --broadcast --legacy && node scripts-js/generateTsAbis.js", "flatten": "forge flatten", "fork": "anvil --fork-url ${0:-sepolia} --chain-id 31337 --config-out localhost.json", "format": "npx prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol' 'test/**/*.sol' 'script/*.sol' 'utils/*.sol'", diff --git a/packages/foundry/script/00_DeploySetup.s.sol b/packages/foundry/script/00_DeploySetup.s.sol deleted file mode 100644 index 44a8b413..00000000 --- a/packages/foundry/script/00_DeploySetup.s.sol +++ /dev/null @@ -1,62 +0,0 @@ -//SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; - -import { PoolHelpers } from "./PoolHelpers.sol"; -import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; -import { ConstantSumFactory } from "../contracts/pools/ConstantSumFactory.sol"; -import { ConstantProductFactory } from "../contracts/pools/ConstantProductFactory.sol"; -import { VeBALFeeDiscountHook } from "../contracts/hooks/VeBALFeeDiscountHook.sol"; -import { MockToken1 } from "../contracts/mocks/MockToken1.sol"; -import { MockToken2 } from "../contracts/mocks/MockToken2.sol"; -import { MockVeBAL } from "../contracts/mocks/MockVeBAL.sol"; - -/** - * @title Deploy Setup - * @notice Deploys mock tokens, factory contracts, and hooks contracts to be used by the pools - * @dev This script runs as part of `yarn deploy`, but can also be run discretely with `yarn deploy:setup` - * @dev Set the pauseWindowDuration for the factory contracts below - */ -contract DeploySetup is PoolHelpers, ScaffoldHelpers { - function run() external virtual { - uint256 deployerPrivateKey = getDeployerPrivateKey(); - - uint32 pauseWindowDuration = 365 days; // The period during which pools can be paused and unpaused ( starting from deployment of the factory ) - - vm.startBroadcast(deployerPrivateKey); - - // Deploy the factory contracts - ConstantSumFactory sumFactory = new ConstantSumFactory(IVault(vault), pauseWindowDuration); - ConstantProductFactory productFactory = new ConstantProductFactory(IVault(vault), pauseWindowDuration); - console.log("Constant Sum Factory deployed at: %s", address(sumFactory)); - console.log("Constant Product Factory deployed at: %s", address(productFactory)); - - // Deploy mock tokens - IERC20 token1 = new MockToken1("Mock Token 1", "MT1", 1000e18); - IERC20 token2 = new MockToken2("Mock Token 2", "MT2", 1000e18); - IERC20 veBAL = new MockVeBAL("Vote-escrow BAL", "veBAL", 1000e18); - console.log("MockToken1 deployed at: %s", address(token1)); - console.log("MockToken2 deployed at: %s", address(token2)); - console.log("Mock Vote-escrow BAL deployed at: %s", address(veBAL)); - - // Deploy a hooks contract for the Constant Product Factory - VeBALFeeDiscountHook poolHooksContract = new VeBALFeeDiscountHook( - IVault(vault), - address(productFactory), - address(veBAL), - address(router) - ); - console.log("VeBALFeeDiscountHook deployed at address: %s", address(poolHooksContract)); - - vm.stopBroadcast(); - - /** - * This function generates the file containing the contracts Abi definitions that are carried from /foundry to /nextjs. - * These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example. - * This function should be called last. - */ - exportDeployments(); - } -} diff --git a/packages/foundry/script/Deploy.s.sol b/packages/foundry/script/Deploy.s.sol new file mode 100644 index 00000000..38d543ba --- /dev/null +++ b/packages/foundry/script/Deploy.s.sol @@ -0,0 +1,36 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +// import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; + +import { PoolHelpers } from "./PoolHelpers.sol"; +import { ScaffoldHelpers } from "./ScaffoldHelpers.sol"; +import { DeployMockTokens } from "./DeployMockTokens.s.sol"; +import { DeployConstantSumPool } from "./DeployConstantSumPool.s.sol"; +import { DeployConstantProductPool } from "./DeployConstantProductPool.s.sol"; + +/** + * @title Deploy Script + * @notice Deploys mock tokens, a constant sum pool, and a constant product pool + * @dev Run this script with `yarn deploy` + */ +contract DeployScript is DeployMockTokens, DeployConstantSumPool, DeployConstantProductPool { + function run() external virtual { + // Deploy the mock tokens + (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) = deployMockTokens(); + + // Deploy a constant sum factory pool + deployConstantSumPool(mockToken1, mockToken2); + + // Deploy a constant product pool + deployConstantProductPool(mockToken1, mockToken2, mockVeBAL); + + /** + * This function generates the file containing the contracts Abi definitions that are carried from /foundry to /nextjs. + * These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example. + * This function should be called last. + */ + exportDeployments(); + } +} diff --git a/packages/foundry/script/02_DeployConstantProductPool.s.sol b/packages/foundry/script/DeployConstantProductPool.s.sol similarity index 79% rename from packages/foundry/script/02_DeployConstantProductPool.s.sol rename to packages/foundry/script/DeployConstantProductPool.s.sol index 6ba3de8f..e3b625a0 100644 --- a/packages/foundry/script/02_DeployConstantProductPool.s.sol +++ b/packages/foundry/script/DeployConstantProductPool.s.sol @@ -15,42 +15,39 @@ import { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol"; import { PoolHelpers } from "./PoolHelpers.sol"; import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; +import { VeBALFeeDiscountHook } from "../contracts/hooks/VeBALFeeDiscountHook.sol"; import { ConstantProductFactory } from "../contracts/pools/ConstantProductFactory.sol"; /** * @title Deploy Constant Product Pool - * @notice Deploys, registers, and initializes a Constant Product Pool - * @dev Set the registration & initialization configurations in the internal getter functions - * @dev This script runs as part of `yarn deploy`, but can also be run discretely with `yarn deploy:product` + * @notice Deploys a factory and hooks contract before deploying, registering, and initializing a Constant Product Pool */ contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { - function run() external virtual { + function deployConstantProductPool(IERC20 token1, IERC20 token2, IERC20 veBAL) internal { + // Set the deployment configurations + uint32 pauseWindowDuration = 365 days; + RegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); + InitializationConfig memory initConfig = getPoolInitializationConfig(token1, token2); + + // Start creating the transactions uint256 deployerPrivateKey = getDeployerPrivateKey(); + vm.startBroadcast(deployerPrivateKey); - // Grab the latest deployment addresses for the mock tokens, constant product factory, and hooks contract - address token1 = DevOpsTools.get_most_recent_deployment( - "MockToken1", // Must match the mock token contract name - block.chainid - ); - address token2 = DevOpsTools.get_most_recent_deployment( - "MockToken2", // Must match the mock token contract name - block.chainid - ); - address factory = DevOpsTools.get_most_recent_deployment( - "ConstantProductFactory", // Must match the mock token contract name - block.chainid - ); - address poolHooksContract = DevOpsTools.get_most_recent_deployment( - "VeBALFeeDiscountHook", // Must match the hooks contract name - block.chainid + // Deploy a constant sum factory contract + ConstantProductFactory factory = new ConstantProductFactory(IVault(vault), pauseWindowDuration); + console.log("Constant Product Factory deployed at: %s", address(factory)); + + // Deploy a hooks contract that permits pools created by the Constant Product factory + VeBALFeeDiscountHook poolHooksContract = new VeBALFeeDiscountHook( + IVault(vault), + address(factory), + address(veBAL), + address(router) ); - // Grab arguments for pool deployment and initialization outside of broadcast to save gas - RegistrationConfig memory regConfig = getRegistrationConfig(IERC20(token1), IERC20(token2)); - InitializationConfig memory initConfig = getInitializationConfig(IERC20(token1), IERC20(token2)); + console.log("VeBALFeeDiscountHook deployed at address: %s", address(poolHooksContract)); - vm.startBroadcast(deployerPrivateKey); // Deploy a pool and register it with the vault - address pool = ConstantProductFactory(factory).create( + address pool = factory.create( regConfig.name, regConfig.symbol, regConfig.salt, @@ -58,7 +55,7 @@ contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { regConfig.swapFeePercentage, regConfig.protocolFeeExempt, regConfig.roleAccounts, - poolHooksContract, + address(poolHooksContract), regConfig.liquidityManagement ); console.log("Constant Product Pool deployed at: %s", pool); @@ -83,7 +80,7 @@ contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { * For STANDARD tokens, the rate provider address must be 0, and paysYieldFees must be false. * All WITH_RATE tokens need a rate provider, and may or may not be yield-bearing. */ - function getRegistrationConfig( + function getPoolRegistrationConfig( IERC20 token1, IERC20 token2 ) internal view returns (RegistrationConfig memory regConfig) { @@ -137,7 +134,7 @@ contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { * @dev Set the pool initialization configurations here * @notice This is where the amounts of tokens to seed the pool with initial liquidity are set */ - function getInitializationConfig( + function getPoolInitializationConfig( IERC20 token1, IERC20 token2 ) internal pure returns (InitializationConfig memory poolInitConfig) { diff --git a/packages/foundry/script/01_DeployConstantSumPool.s.sol b/packages/foundry/script/DeployConstantSumPool.s.sol similarity index 83% rename from packages/foundry/script/01_DeployConstantSumPool.s.sol rename to packages/foundry/script/DeployConstantSumPool.s.sol index 7dfa8604..920b5506 100644 --- a/packages/foundry/script/01_DeployConstantSumPool.s.sol +++ b/packages/foundry/script/DeployConstantSumPool.s.sol @@ -10,6 +10,7 @@ import { import { IRateProvider } from "@balancer-labs/v3-interfaces/contracts/vault/IRateProvider.sol"; import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; import { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol"; import { PoolHelpers } from "./PoolHelpers.sol"; @@ -19,33 +20,24 @@ import { ConstantSumFactory } from "../contracts/pools/ConstantSumFactory.sol"; /** * @title Deploy Constant Sum Pool * @notice Deploys, registers, and initializes a Constant Sum Pool - * @dev Set the registration & initialization configurations in the internal getter functions below - * @dev This script runs as part of `yarn deploy`, but can also be run discretely with `yarn deploy:sum` */ contract DeployConstantSumPool is PoolHelpers, ScaffoldHelpers { - function run() external virtual { - uint256 deployerPrivateKey = getDeployerPrivateKey(); - - // Grab the latest deployment addresses for the mock tokens and constant sum factory - address token1 = DevOpsTools.get_most_recent_deployment( - "MockToken1", // Must match the mock token contract name - block.chainid - ); - address token2 = DevOpsTools.get_most_recent_deployment( - "MockToken2", // Must match the mock token contract name - block.chainid - ); - address factory = DevOpsTools.get_most_recent_deployment( - "ConstantSumFactory", // Must match the factory contract name - block.chainid - ); - // Grab arguments for pool deployment and initialization outside of broadcast to save gas + function deployConstantSumPool(IERC20 token1, IERC20 token2) internal { + // Set the deployment configurations + uint32 pauseWindowDuration = 365 days; RegistrationConfig memory regConfig = getRegistrationConfig(token1, token2); InitializationConfig memory initConfig = getInitializationConfig(token1, token2); + // Start creating the transactions + uint256 deployerPrivateKey = getDeployerPrivateKey(); vm.startBroadcast(deployerPrivateKey); + + // Deploy a constant sum factory contract + ConstantSumFactory factory = new ConstantSumFactory(IVault(vault), pauseWindowDuration); + console.log("Constant Sum Factory deployed at: %s", address(factory)); + // Deploy a pool and register it with the vault - address pool = ConstantSumFactory(factory).create( + address pool = factory.create( regConfig.name, regConfig.symbol, regConfig.salt, @@ -78,8 +70,8 @@ contract DeployConstantSumPool is PoolHelpers, ScaffoldHelpers { * All WITH_RATE tokens need a rate provider, and may or may not be yield-bearing. */ function getRegistrationConfig( - address token1, - address token2 + IERC20 token1, + IERC20 token2 ) internal view returns (RegistrationConfig memory regConfig) { string memory name = "Constant Sum Pool"; // name for the pool string memory symbol = "CSP"; // symbol for the BPT @@ -90,13 +82,13 @@ contract DeployConstantSumPool is PoolHelpers, ScaffoldHelpers { TokenConfig[] memory tokenConfig = new TokenConfig[](2); // An array of descriptors for the tokens the pool will manage. tokenConfig[0] = TokenConfig({ // Make sure to have proper token order (alphanumeric) - token: IERC20(token1), + token: token1, tokenType: TokenType.STANDARD, // STANDARD or WITH_RATE rateProvider: IRateProvider(address(0)), // The rate provider for a token (see further documentation above) paysYieldFees: false // Flag indicating whether yield fees should be charged on this token }); tokenConfig[1] = TokenConfig({ // Make sure to have proper token order (alphanumeric) - token: IERC20(token2), + token: token2, tokenType: TokenType.STANDARD, // STANDARD or WITH_RATE rateProvider: IRateProvider(address(0)), // The rate provider for a token (see further documentation above) paysYieldFees: false // Flag indicating whether yield fees should be charged on this token @@ -132,12 +124,12 @@ contract DeployConstantSumPool is PoolHelpers, ScaffoldHelpers { * @notice this is where the amounts of tokens to be initially added to the pool are set */ function getInitializationConfig( - address token1, - address token2 + IERC20 token1, + IERC20 token2 ) internal pure returns (InitializationConfig memory poolInitConfig) { IERC20[] memory tokens = new IERC20[](2); // Array of tokens to be used in the pool - tokens[0] = IERC20(token1); - tokens[1] = IERC20(token2); + tokens[0] = token1; + tokens[1] = token2; uint256[] memory exactAmountsIn = new uint256[](2); // Exact amounts of tokens to be added, sorted in token alphanumeric order exactAmountsIn[0] = 50e18; // amount of token1 to send during pool initialization exactAmountsIn[1] = 50e18; // amount of token2 to send during pool initialization diff --git a/packages/foundry/script/DeployMockTokens.s.sol b/packages/foundry/script/DeployMockTokens.s.sol new file mode 100644 index 00000000..ba09e64a --- /dev/null +++ b/packages/foundry/script/DeployMockTokens.s.sol @@ -0,0 +1,35 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; + +import { PoolHelpers } from "./PoolHelpers.sol"; +import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; +import { MockToken1 } from "../contracts/mocks/MockToken1.sol"; +import { MockToken2 } from "../contracts/mocks/MockToken2.sol"; +import { MockVeBAL } from "../contracts/mocks/MockVeBAL.sol"; + +/** + * @title Deploy Mock Tokens + * @notice Deploys mock tokens for use with pools and hooks + */ +contract DeployMockTokens is PoolHelpers, ScaffoldHelpers { + function deployMockTokens() internal returns (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) { + uint256 deployerPrivateKey = getDeployerPrivateKey(); + + vm.startBroadcast(deployerPrivateKey); + + // For use with pool contracts + mockToken1 = new MockToken1("Mock Token 1", "MT1", 1000e18); + mockToken2 = new MockToken2("Mock Token 2", "MT2", 1000e18); + console.log("MockToken1 deployed at: %s", address(mockToken1)); + console.log("MockToken2 deployed at: %s", address(mockToken2)); + + // For use with VeBALFeeDiscountHook + mockVeBAL = new MockVeBAL("Vote-escrow BAL", "veBAL", 1000e18); + console.log("Mock Vote-escrow BAL deployed at: %s", address(mockVeBAL)); + + vm.stopBroadcast(); + } +} diff --git a/packages/foundry/scripts-js/generateTsAbis.js b/packages/foundry/scripts-js/generateTsAbis.js index c05c8873..4553e35a 100644 --- a/packages/foundry/scripts-js/generateTsAbis.js +++ b/packages/foundry/scripts-js/generateTsAbis.js @@ -60,7 +60,7 @@ function getInheritedFunctions(mainArtifact) { } function main() { - const current_path_to_broadcast = path.join(__dirname, '..', 'broadcast/00_DeploySetup.s.sol'); + const current_path_to_broadcast = path.join(__dirname, '..', 'broadcast/Deploy.s.sol'); console.log('current_path_to_broadcast', current_path_to_broadcast); const current_path_to_deployments = path.join(__dirname, '..', 'deployments'); diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 70232685..7c65c0a5 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -6,28 +6,11 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; const deployedContracts = { 31337: { - ConstantSumFactory: { - address: "0x8e8cB505973E04200554Bd98741086C7Eca9f42a", + MockToken1: { + address: "0x539383fDc37eE70495088826ec32F6B28153245C", abi: [ { type: "constructor", - inputs: [ - { - name: "vault", - type: "address", - internalType: "contract IVault", - }, - { - name: "pauseWindowDuration", - type: "uint32", - internalType: "uint32", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "create", inputs: [ { name: "name", @@ -40,365 +23,352 @@ const deployedContracts = { internalType: "string", }, { - name: "salt", - type: "bytes32", - internalType: "bytes32", - }, - { - name: "tokens", - type: "tuple[]", - internalType: "struct TokenConfig[]", - components: [ - { - name: "token", - type: "address", - internalType: "contract IERC20", - }, - { - name: "tokenType", - type: "uint8", - internalType: "enum TokenType", - }, - { - name: "rateProvider", - type: "address", - internalType: "contract IRateProvider", - }, - { - name: "paysYieldFees", - type: "bool", - internalType: "bool", - }, - ], - }, - { - name: "swapFeePercentage", + name: "initialSupply", type: "uint256", internalType: "uint256", }, - { - name: "protocolFeeExempt", - type: "bool", - internalType: "bool", - }, - { - name: "roleAccounts", - type: "tuple", - internalType: "struct PoolRoleAccounts", - components: [ - { - name: "pauseManager", - type: "address", - internalType: "address", - }, - { - name: "swapFeeManager", - type: "address", - internalType: "address", - }, - { - name: "poolCreator", - type: "address", - internalType: "address", - }, - ], - }, - { - name: "poolHooksContract", - type: "address", - internalType: "address", - }, - { - name: "liquidityManagement", - type: "tuple", - internalType: "struct LiquidityManagement", - components: [ - { - name: "disableUnbalancedLiquidity", - type: "bool", - internalType: "bool", - }, - { - name: "enableAddLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableRemoveLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableDonation", - type: "bool", - internalType: "bool", - }, - ], - }, ], - outputs: [ - { - name: "pool", - type: "address", - internalType: "address", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "disable", - inputs: [], - outputs: [], stateMutability: "nonpayable", }, { type: "function", - name: "getActionId", + name: "allowance", inputs: [ { - name: "selector", - type: "bytes4", - internalType: "bytes4", + name: "owner", + type: "address", + internalType: "address", + }, + { + name: "spender", + type: "address", + internalType: "address", }, ], outputs: [ { name: "", - type: "bytes32", - internalType: "bytes32", + type: "uint256", + internalType: "uint256", }, ], stateMutability: "view", }, { type: "function", - name: "getAuthorizer", - inputs: [], - outputs: [ + name: "approve", + inputs: [ { - name: "", + name: "spender", type: "address", - internalType: "contract IAuthorizer", + internalType: "address", }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "getDefaultLiquidityManagement", - inputs: [], - outputs: [ { - name: "liquidityManagement", - type: "tuple", - internalType: "struct LiquidityManagement", - components: [ - { - name: "disableUnbalancedLiquidity", - type: "bool", - internalType: "bool", - }, - { - name: "enableAddLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableRemoveLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableDonation", - type: "bool", - internalType: "bool", - }, - ], + name: "value", + type: "uint256", + internalType: "uint256", }, ], - stateMutability: "pure", - }, - { - type: "function", - name: "getDefaultPoolHooksContract", - inputs: [], outputs: [ { name: "", - type: "address", - internalType: "address", + type: "bool", + internalType: "bool", }, ], - stateMutability: "pure", + stateMutability: "nonpayable", }, { type: "function", - name: "getDeploymentAddress", + name: "balanceOf", inputs: [ { - name: "salt", - type: "bytes32", - internalType: "bytes32", + name: "account", + type: "address", + internalType: "address", }, ], outputs: [ { name: "", - type: "address", - internalType: "address", + type: "uint256", + internalType: "uint256", }, ], stateMutability: "view", }, { type: "function", - name: "getNewPoolPauseWindowEndTime", + name: "decimals", inputs: [], outputs: [ { name: "", - type: "uint32", - internalType: "uint32", + type: "uint8", + internalType: "uint8", }, ], stateMutability: "view", }, { type: "function", - name: "getOriginalPauseWindowEndTime", - inputs: [], - outputs: [ + name: "mint", + inputs: [ { - name: "", - type: "uint32", - internalType: "uint32", + name: "amount", + type: "uint256", + internalType: "uint256", }, ], - stateMutability: "view", + outputs: [], + stateMutability: "nonpayable", }, { type: "function", - name: "getPauseWindowDuration", + name: "name", inputs: [], outputs: [ { name: "", - type: "uint32", - internalType: "uint32", + type: "string", + internalType: "string", }, ], stateMutability: "view", }, { type: "function", - name: "getVault", + name: "symbol", inputs: [], outputs: [ { name: "", - type: "address", - internalType: "contract IVault", + type: "string", + internalType: "string", }, ], stateMutability: "view", }, { type: "function", - name: "isDisabled", + name: "totalSupply", inputs: [], outputs: [ { name: "", - type: "bool", - internalType: "bool", + type: "uint256", + internalType: "uint256", }, ], stateMutability: "view", }, { type: "function", - name: "isPoolFromFactory", + name: "transfer", inputs: [ { - name: "pool", + name: "to", type: "address", internalType: "address", }, - ], - outputs: [ + { + name: "value", + type: "uint256", + internalType: "uint256", + }, + ], + outputs: [ { name: "", type: "bool", internalType: "bool", }, ], - stateMutability: "view", + stateMutability: "nonpayable", + }, + { + type: "function", + name: "transferFrom", + inputs: [ + { + name: "from", + type: "address", + internalType: "address", + }, + { + name: "to", + type: "address", + internalType: "address", + }, + { + name: "value", + type: "uint256", + internalType: "uint256", + }, + ], + outputs: [ + { + name: "", + type: "bool", + internalType: "bool", + }, + ], + stateMutability: "nonpayable", }, { type: "event", - name: "FactoryDisabled", - inputs: [], + name: "Approval", + inputs: [ + { + name: "owner", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "spender", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "value", + type: "uint256", + indexed: false, + internalType: "uint256", + }, + ], anonymous: false, }, { type: "event", - name: "PoolCreated", + name: "Transfer", inputs: [ { - name: "pool", + name: "from", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "to", type: "address", indexed: true, internalType: "address", }, + { + name: "value", + type: "uint256", + indexed: false, + internalType: "uint256", + }, ], anonymous: false, }, { type: "error", - name: "Disabled", - inputs: [], + name: "ERC20InsufficientAllowance", + inputs: [ + { + name: "spender", + type: "address", + internalType: "address", + }, + { + name: "allowance", + type: "uint256", + internalType: "uint256", + }, + { + name: "needed", + type: "uint256", + internalType: "uint256", + }, + ], }, { type: "error", - name: "PoolPauseWindowDurationOverflow", - inputs: [], + name: "ERC20InsufficientBalance", + inputs: [ + { + name: "sender", + type: "address", + internalType: "address", + }, + { + name: "balance", + type: "uint256", + internalType: "uint256", + }, + { + name: "needed", + type: "uint256", + internalType: "uint256", + }, + ], }, { type: "error", - name: "SenderNotAllowed", - inputs: [], + name: "ERC20InvalidApprover", + inputs: [ + { + name: "approver", + type: "address", + internalType: "address", + }, + ], }, { type: "error", - name: "StandardPoolWithCreator", - inputs: [], + name: "ERC20InvalidReceiver", + inputs: [ + { + name: "receiver", + type: "address", + internalType: "address", + }, + ], }, - ], - inheritedFunctions: {}, - }, - ConstantProductFactory: { - address: "0xC2D1A7c03C0459a8d0Ee885283CE828DE5fFf617", - abi: [ { - type: "constructor", + type: "error", + name: "ERC20InvalidSender", inputs: [ { - name: "vault", + name: "sender", type: "address", - internalType: "contract IVault", + internalType: "address", }, + ], + }, + { + type: "error", + name: "ERC20InvalidSpender", + inputs: [ { - name: "pauseWindowDuration", - type: "uint32", - internalType: "uint32", + name: "spender", + type: "address", + internalType: "address", }, ], - stateMutability: "nonpayable", }, + ], + inheritedFunctions: { + allowance: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + approve: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + balanceOf: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + decimals: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + name: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + symbol: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + totalSupply: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + transfer: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + transferFrom: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + }, + }, + MockToken2: { + address: "0x69d2485148F2F6e408db39C2516D948Ac1CD69Ab", + abi: [ { - type: "function", - name: "create", + type: "constructor", inputs: [ { name: "name", @@ -411,273 +381,160 @@ const deployedContracts = { internalType: "string", }, { - name: "salt", - type: "bytes32", - internalType: "bytes32", + name: "initialSupply", + type: "uint256", + internalType: "uint256", + }, + ], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "allowance", + inputs: [ + { + name: "owner", + type: "address", + internalType: "address", }, { - name: "tokens", - type: "tuple[]", - internalType: "struct TokenConfig[]", - components: [ - { - name: "token", - type: "address", - internalType: "contract IERC20", - }, - { - name: "tokenType", - type: "uint8", - internalType: "enum TokenType", - }, - { - name: "rateProvider", - type: "address", - internalType: "contract IRateProvider", - }, - { - name: "paysYieldFees", - type: "bool", - internalType: "bool", - }, - ], + name: "spender", + type: "address", + internalType: "address", }, + ], + outputs: [ { - name: "swapFeePercentage", + name: "", type: "uint256", internalType: "uint256", }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "approve", + inputs: [ { - name: "protocolFeeExempt", + name: "spender", + type: "address", + internalType: "address", + }, + { + name: "value", + type: "uint256", + internalType: "uint256", + }, + ], + outputs: [ + { + name: "", type: "bool", internalType: "bool", }, - { - name: "roleAccounts", - type: "tuple", - internalType: "struct PoolRoleAccounts", - components: [ - { - name: "pauseManager", - type: "address", - internalType: "address", - }, - { - name: "swapFeeManager", - type: "address", - internalType: "address", - }, - { - name: "poolCreator", - type: "address", - internalType: "address", - }, - ], - }, - { - name: "poolHooksContract", - type: "address", - internalType: "address", - }, - { - name: "liquidityManagement", - type: "tuple", - internalType: "struct LiquidityManagement", - components: [ - { - name: "disableUnbalancedLiquidity", - type: "bool", - internalType: "bool", - }, - { - name: "enableAddLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableRemoveLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableDonation", - type: "bool", - internalType: "bool", - }, - ], - }, ], - outputs: [ - { - name: "pool", - type: "address", - internalType: "address", - }, - ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "disable", - inputs: [], - outputs: [], stateMutability: "nonpayable", }, { type: "function", - name: "getActionId", + name: "balanceOf", inputs: [ { - name: "selector", - type: "bytes4", - internalType: "bytes4", + name: "account", + type: "address", + internalType: "address", }, ], outputs: [ { name: "", - type: "bytes32", - internalType: "bytes32", + type: "uint256", + internalType: "uint256", }, ], stateMutability: "view", }, { type: "function", - name: "getAuthorizer", + name: "decimals", inputs: [], outputs: [ { name: "", - type: "address", - internalType: "contract IAuthorizer", + type: "uint8", + internalType: "uint8", }, ], stateMutability: "view", }, { type: "function", - name: "getDefaultLiquidityManagement", - inputs: [], - outputs: [ - { - name: "liquidityManagement", - type: "tuple", - internalType: "struct LiquidityManagement", - components: [ - { - name: "disableUnbalancedLiquidity", - type: "bool", - internalType: "bool", - }, - { - name: "enableAddLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableRemoveLiquidityCustom", - type: "bool", - internalType: "bool", - }, - { - name: "enableDonation", - type: "bool", - internalType: "bool", - }, - ], - }, - ], - stateMutability: "pure", - }, - { - type: "function", - name: "getDefaultPoolHooksContract", - inputs: [], - outputs: [ - { - name: "", - type: "address", - internalType: "address", - }, - ], - stateMutability: "pure", - }, - { - type: "function", - name: "getDeploymentAddress", + name: "mint", inputs: [ { - name: "salt", - type: "bytes32", - internalType: "bytes32", - }, - ], - outputs: [ - { - name: "", - type: "address", - internalType: "address", + name: "amount", + type: "uint256", + internalType: "uint256", }, ], - stateMutability: "view", + outputs: [], + stateMutability: "nonpayable", }, { type: "function", - name: "getNewPoolPauseWindowEndTime", + name: "name", inputs: [], outputs: [ { name: "", - type: "uint32", - internalType: "uint32", + type: "string", + internalType: "string", }, ], stateMutability: "view", }, { type: "function", - name: "getOriginalPauseWindowEndTime", + name: "symbol", inputs: [], outputs: [ { name: "", - type: "uint32", - internalType: "uint32", + type: "string", + internalType: "string", }, ], stateMutability: "view", }, { type: "function", - name: "getPauseWindowDuration", + name: "totalSupply", inputs: [], outputs: [ { name: "", - type: "uint32", - internalType: "uint32", + type: "uint256", + internalType: "uint256", }, ], stateMutability: "view", }, { type: "function", - name: "getVault", - inputs: [], - outputs: [ + name: "transfer", + inputs: [ { - name: "", + name: "to", type: "address", - internalType: "contract IVault", + internalType: "address", + }, + { + name: "value", + type: "uint256", + internalType: "uint256", }, ], - stateMutability: "view", - }, - { - type: "function", - name: "isDisabled", - inputs: [], outputs: [ { name: "", @@ -685,17 +542,27 @@ const deployedContracts = { internalType: "bool", }, ], - stateMutability: "view", + stateMutability: "nonpayable", }, { type: "function", - name: "isPoolFromFactory", + name: "transferFrom", inputs: [ { - name: "pool", + name: "from", + type: "address", + internalType: "address", + }, + { + name: "to", type: "address", internalType: "address", }, + { + name: "value", + type: "uint256", + internalType: "uint256", + }, ], outputs: [ { @@ -704,52 +571,159 @@ const deployedContracts = { internalType: "bool", }, ], - stateMutability: "view", + stateMutability: "nonpayable", }, { type: "event", - name: "FactoryDisabled", - inputs: [], + name: "Approval", + inputs: [ + { + name: "owner", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "spender", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "value", + type: "uint256", + indexed: false, + internalType: "uint256", + }, + ], anonymous: false, }, { type: "event", - name: "PoolCreated", + name: "Transfer", inputs: [ { - name: "pool", + name: "from", + type: "address", + indexed: true, + internalType: "address", + }, + { + name: "to", type: "address", indexed: true, internalType: "address", }, + { + name: "value", + type: "uint256", + indexed: false, + internalType: "uint256", + }, ], anonymous: false, }, { type: "error", - name: "Disabled", - inputs: [], - }, - { - type: "error", - name: "PoolPauseWindowDurationOverflow", - inputs: [], - }, - { - type: "error", - name: "SenderNotAllowed", - inputs: [], - }, - { - type: "error", - name: "StandardPoolWithCreator", - inputs: [], + name: "ERC20InsufficientAllowance", + inputs: [ + { + name: "spender", + type: "address", + internalType: "address", + }, + { + name: "allowance", + type: "uint256", + internalType: "uint256", + }, + { + name: "needed", + type: "uint256", + internalType: "uint256", + }, + ], + }, + { + type: "error", + name: "ERC20InsufficientBalance", + inputs: [ + { + name: "sender", + type: "address", + internalType: "address", + }, + { + name: "balance", + type: "uint256", + internalType: "uint256", + }, + { + name: "needed", + type: "uint256", + internalType: "uint256", + }, + ], + }, + { + type: "error", + name: "ERC20InvalidApprover", + inputs: [ + { + name: "approver", + type: "address", + internalType: "address", + }, + ], + }, + { + type: "error", + name: "ERC20InvalidReceiver", + inputs: [ + { + name: "receiver", + type: "address", + internalType: "address", + }, + ], + }, + { + type: "error", + name: "ERC20InvalidSender", + inputs: [ + { + name: "sender", + type: "address", + internalType: "address", + }, + ], + }, + { + type: "error", + name: "ERC20InvalidSpender", + inputs: [ + { + name: "spender", + type: "address", + internalType: "address", + }, + ], }, ], - inheritedFunctions: {}, + inheritedFunctions: { + allowance: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + approve: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + balanceOf: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + decimals: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + name: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + symbol: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + totalSupply: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + transfer: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + transferFrom: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + }, }, - MockToken1: { - address: "0x906e3a6d1baf80e3e3fa3D57A5DA73099Da86C4c", + MockVeBAL: { + address: "0xE5A9Ef3838184697602d9c95782304E9b86E230D", abi: [ { type: "constructor", @@ -1106,177 +1080,307 @@ const deployedContracts = { transferFrom: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", }, }, - MockToken2: { - address: "0x68c87F9fB214Bb4856a13c9123f9b0624944D1A6", + ConstantSumFactory: { + address: "0x0EAa0A56CF3260e1999067c174E1f044389C9f5b", abi: [ { type: "constructor", inputs: [ { - name: "name", - type: "string", - internalType: "string", - }, - { - name: "symbol", - type: "string", - internalType: "string", + name: "vault", + type: "address", + internalType: "contract IVault", }, { - name: "initialSupply", - type: "uint256", - internalType: "uint256", + name: "pauseWindowDuration", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "nonpayable", }, { type: "function", - name: "allowance", + name: "create", inputs: [ { - name: "owner", - type: "address", - internalType: "address", + name: "name", + type: "string", + internalType: "string", }, { - name: "spender", - type: "address", - internalType: "address", + name: "symbol", + type: "string", + internalType: "string", }, - ], - outputs: [ { - name: "", + name: "salt", + type: "bytes32", + internalType: "bytes32", + }, + { + name: "tokens", + type: "tuple[]", + internalType: "struct TokenConfig[]", + components: [ + { + name: "token", + type: "address", + internalType: "contract IERC20", + }, + { + name: "tokenType", + type: "uint8", + internalType: "enum TokenType", + }, + { + name: "rateProvider", + type: "address", + internalType: "contract IRateProvider", + }, + { + name: "paysYieldFees", + type: "bool", + internalType: "bool", + }, + ], + }, + { + name: "swapFeePercentage", type: "uint256", internalType: "uint256", }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "approve", - inputs: [ { - name: "spender", + name: "protocolFeeExempt", + type: "bool", + internalType: "bool", + }, + { + name: "roleAccounts", + type: "tuple", + internalType: "struct PoolRoleAccounts", + components: [ + { + name: "pauseManager", + type: "address", + internalType: "address", + }, + { + name: "swapFeeManager", + type: "address", + internalType: "address", + }, + { + name: "poolCreator", + type: "address", + internalType: "address", + }, + ], + }, + { + name: "poolHooksContract", type: "address", internalType: "address", }, { - name: "value", - type: "uint256", - internalType: "uint256", + name: "liquidityManagement", + type: "tuple", + internalType: "struct LiquidityManagement", + components: [ + { + name: "disableUnbalancedLiquidity", + type: "bool", + internalType: "bool", + }, + { + name: "enableAddLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableRemoveLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableDonation", + type: "bool", + internalType: "bool", + }, + ], }, ], outputs: [ { - name: "", - type: "bool", - internalType: "bool", + name: "pool", + type: "address", + internalType: "address", }, ], stateMutability: "nonpayable", }, { type: "function", - name: "balanceOf", + name: "disable", + inputs: [], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "getActionId", inputs: [ { - name: "account", - type: "address", - internalType: "address", + name: "selector", + type: "bytes4", + internalType: "bytes4", }, ], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", + type: "bytes32", + internalType: "bytes32", }, ], stateMutability: "view", }, { type: "function", - name: "decimals", + name: "getAuthorizer", inputs: [], outputs: [ { name: "", - type: "uint8", - internalType: "uint8", + type: "address", + internalType: "contract IAuthorizer", }, ], stateMutability: "view", }, { type: "function", - name: "mint", - inputs: [ + name: "getDefaultLiquidityManagement", + inputs: [], + outputs: [ { - name: "amount", - type: "uint256", - internalType: "uint256", + name: "liquidityManagement", + type: "tuple", + internalType: "struct LiquidityManagement", + components: [ + { + name: "disableUnbalancedLiquidity", + type: "bool", + internalType: "bool", + }, + { + name: "enableAddLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableRemoveLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableDonation", + type: "bool", + internalType: "bool", + }, + ], }, ], - outputs: [], - stateMutability: "nonpayable", + stateMutability: "pure", }, { type: "function", - name: "name", + name: "getDefaultPoolHooksContract", inputs: [], outputs: [ { name: "", - type: "string", - internalType: "string", + type: "address", + internalType: "address", + }, + ], + stateMutability: "pure", + }, + { + type: "function", + name: "getDeploymentAddress", + inputs: [ + { + name: "salt", + type: "bytes32", + internalType: "bytes32", + }, + ], + outputs: [ + { + name: "", + type: "address", + internalType: "address", }, ], stateMutability: "view", }, { type: "function", - name: "symbol", + name: "getNewPoolPauseWindowEndTime", inputs: [], outputs: [ { name: "", - type: "string", - internalType: "string", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "view", }, { type: "function", - name: "totalSupply", + name: "getOriginalPauseWindowEndTime", inputs: [], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "view", }, { type: "function", - name: "transfer", - inputs: [ + name: "getPauseWindowDuration", + inputs: [], + outputs: [ { - name: "to", - type: "address", - internalType: "address", + name: "", + type: "uint32", + internalType: "uint32", }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "getVault", + inputs: [], + outputs: [ { - name: "value", - type: "uint256", - internalType: "uint256", + name: "", + type: "address", + internalType: "contract IVault", }, ], + stateMutability: "view", + }, + { + type: "function", + name: "isDisabled", + inputs: [], outputs: [ { name: "", @@ -1284,27 +1388,17 @@ const deployedContracts = { internalType: "bool", }, ], - stateMutability: "nonpayable", + stateMutability: "view", }, { type: "function", - name: "transferFrom", + name: "isPoolFromFactory", inputs: [ { - name: "from", - type: "address", - internalType: "address", - }, - { - name: "to", + name: "pool", type: "address", internalType: "address", }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, ], outputs: [ { @@ -1313,328 +1407,364 @@ const deployedContracts = { internalType: "bool", }, ], - stateMutability: "nonpayable", + stateMutability: "view", }, { type: "event", - name: "Approval", + name: "FactoryDisabled", + inputs: [], + anonymous: false, + }, + { + type: "event", + name: "PoolCreated", inputs: [ { - name: "owner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "spender", + name: "pool", type: "address", indexed: true, internalType: "address", }, - { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", - }, ], anonymous: false, }, { - type: "event", - name: "Transfer", + type: "error", + name: "Disabled", + inputs: [], + }, + { + type: "error", + name: "PoolPauseWindowDurationOverflow", + inputs: [], + }, + { + type: "error", + name: "SenderNotAllowed", + inputs: [], + }, + { + type: "error", + name: "StandardPoolWithCreator", + inputs: [], + }, + ], + inheritedFunctions: { + disable: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getActionId: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getAuthorizer: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getDefaultLiquidityManagement: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getDefaultPoolHooksContract: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getDeploymentAddress: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getNewPoolPauseWindowEndTime: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getOriginalPauseWindowEndTime: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getPauseWindowDuration: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getVault: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + isDisabled: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + isPoolFromFactory: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + }, + }, + ConstantProductFactory: { + address: "0xD15Fcc7b91470BDd22a5756B5Add434E9421cea4", + abi: [ + { + type: "constructor", inputs: [ { - name: "from", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "to", + name: "vault", type: "address", - indexed: true, - internalType: "address", + internalType: "contract IVault", }, { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", + name: "pauseWindowDuration", + type: "uint32", + internalType: "uint32", }, ], - anonymous: false, + stateMutability: "nonpayable", }, { - type: "error", - name: "ERC20InsufficientAllowance", + type: "function", + name: "create", inputs: [ { - name: "spender", - type: "address", - internalType: "address", + name: "name", + type: "string", + internalType: "string", }, { - name: "allowance", - type: "uint256", - internalType: "uint256", + name: "symbol", + type: "string", + internalType: "string", }, { - name: "needed", - type: "uint256", - internalType: "uint256", + name: "salt", + type: "bytes32", + internalType: "bytes32", }, - ], - }, - { - type: "error", - name: "ERC20InsufficientBalance", - inputs: [ { - name: "sender", - type: "address", - internalType: "address", + name: "tokens", + type: "tuple[]", + internalType: "struct TokenConfig[]", + components: [ + { + name: "token", + type: "address", + internalType: "contract IERC20", + }, + { + name: "tokenType", + type: "uint8", + internalType: "enum TokenType", + }, + { + name: "rateProvider", + type: "address", + internalType: "contract IRateProvider", + }, + { + name: "paysYieldFees", + type: "bool", + internalType: "bool", + }, + ], }, { - name: "balance", + name: "swapFeePercentage", type: "uint256", internalType: "uint256", }, { - name: "needed", - type: "uint256", - internalType: "uint256", + name: "protocolFeeExempt", + type: "bool", + internalType: "bool", }, - ], - }, - { - type: "error", - name: "ERC20InvalidApprover", - inputs: [ { - name: "approver", + name: "roleAccounts", + type: "tuple", + internalType: "struct PoolRoleAccounts", + components: [ + { + name: "pauseManager", + type: "address", + internalType: "address", + }, + { + name: "swapFeeManager", + type: "address", + internalType: "address", + }, + { + name: "poolCreator", + type: "address", + internalType: "address", + }, + ], + }, + { + name: "poolHooksContract", type: "address", internalType: "address", }, + { + name: "liquidityManagement", + type: "tuple", + internalType: "struct LiquidityManagement", + components: [ + { + name: "disableUnbalancedLiquidity", + type: "bool", + internalType: "bool", + }, + { + name: "enableAddLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableRemoveLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableDonation", + type: "bool", + internalType: "bool", + }, + ], + }, ], - }, - { - type: "error", - name: "ERC20InvalidReceiver", - inputs: [ + outputs: [ { - name: "receiver", + name: "pool", type: "address", internalType: "address", }, ], + stateMutability: "nonpayable", }, { - type: "error", - name: "ERC20InvalidSender", + type: "function", + name: "disable", + inputs: [], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "getActionId", inputs: [ { - name: "sender", - type: "address", - internalType: "address", + name: "selector", + type: "bytes4", + internalType: "bytes4", }, ], + outputs: [ + { + name: "", + type: "bytes32", + internalType: "bytes32", + }, + ], + stateMutability: "view", }, { - type: "error", - name: "ERC20InvalidSpender", - inputs: [ + type: "function", + name: "getAuthorizer", + inputs: [], + outputs: [ { - name: "spender", + name: "", type: "address", - internalType: "address", + internalType: "contract IAuthorizer", }, ], + stateMutability: "view", }, - ], - inheritedFunctions: { - allowance: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - approve: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - balanceOf: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - decimals: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - name: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - symbol: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - totalSupply: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - transfer: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - transferFrom: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - }, - }, - MockVeBAL: { - address: "0xBcd2152CD06E3e65f88f3f21aeBDc5473d8EAef4", - abi: [ { - type: "constructor", - inputs: [ - { - name: "name", - type: "string", - internalType: "string", - }, - { - name: "symbol", - type: "string", - internalType: "string", - }, + type: "function", + name: "getDefaultLiquidityManagement", + inputs: [], + outputs: [ { - name: "initialSupply", - type: "uint256", - internalType: "uint256", + name: "liquidityManagement", + type: "tuple", + internalType: "struct LiquidityManagement", + components: [ + { + name: "disableUnbalancedLiquidity", + type: "bool", + internalType: "bool", + }, + { + name: "enableAddLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableRemoveLiquidityCustom", + type: "bool", + internalType: "bool", + }, + { + name: "enableDonation", + type: "bool", + internalType: "bool", + }, + ], }, ], - stateMutability: "nonpayable", + stateMutability: "pure", }, { type: "function", - name: "allowance", - inputs: [ - { - name: "owner", - type: "address", - internalType: "address", - }, - { - name: "spender", - type: "address", - internalType: "address", - }, - ], + name: "getDefaultPoolHooksContract", + inputs: [], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", - }, - ], - stateMutability: "view", - }, - { - type: "function", - name: "approve", - inputs: [ - { - name: "spender", type: "address", internalType: "address", }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [ - { - name: "", - type: "bool", - internalType: "bool", - }, ], - stateMutability: "nonpayable", + stateMutability: "pure", }, { type: "function", - name: "balanceOf", + name: "getDeploymentAddress", inputs: [ { - name: "account", - type: "address", - internalType: "address", + name: "salt", + type: "bytes32", + internalType: "bytes32", }, ], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", + type: "address", + internalType: "address", }, ], stateMutability: "view", }, { type: "function", - name: "decimals", + name: "getNewPoolPauseWindowEndTime", inputs: [], outputs: [ { name: "", - type: "uint8", - internalType: "uint8", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "view", }, { type: "function", - name: "mint", - inputs: [ - { - name: "amount", - type: "uint256", - internalType: "uint256", - }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "name", + name: "getOriginalPauseWindowEndTime", inputs: [], outputs: [ { name: "", - type: "string", - internalType: "string", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "view", }, { type: "function", - name: "symbol", + name: "getPauseWindowDuration", inputs: [], outputs: [ { name: "", - type: "string", - internalType: "string", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "view", }, { type: "function", - name: "totalSupply", + name: "getVault", inputs: [], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", + type: "address", + internalType: "contract IVault", }, ], stateMutability: "view", }, { type: "function", - name: "transfer", - inputs: [ - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], + name: "isDisabled", + inputs: [], outputs: [ { name: "", @@ -1642,27 +1772,17 @@ const deployedContracts = { internalType: "bool", }, ], - stateMutability: "nonpayable", + stateMutability: "view", }, { type: "function", - name: "transferFrom", + name: "isPoolFromFactory", inputs: [ { - name: "from", - type: "address", - internalType: "address", - }, - { - name: "to", + name: "pool", type: "address", internalType: "address", }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, ], outputs: [ { @@ -1671,159 +1791,65 @@ const deployedContracts = { internalType: "bool", }, ], - stateMutability: "nonpayable", + stateMutability: "view", }, { type: "event", - name: "Approval", - inputs: [ - { - name: "owner", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "spender", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", - }, - ], + name: "FactoryDisabled", + inputs: [], anonymous: false, }, { type: "event", - name: "Transfer", + name: "PoolCreated", inputs: [ { - name: "from", - type: "address", - indexed: true, - internalType: "address", - }, - { - name: "to", + name: "pool", type: "address", indexed: true, internalType: "address", }, - { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", - }, ], anonymous: false, }, { type: "error", - name: "ERC20InsufficientAllowance", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - { - name: "allowance", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ERC20InsufficientBalance", - inputs: [ - { - name: "sender", - type: "address", - internalType: "address", - }, - { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", - }, - ], - }, - { - type: "error", - name: "ERC20InvalidApprover", - inputs: [ - { - name: "approver", - type: "address", - internalType: "address", - }, - ], + name: "Disabled", + inputs: [], }, { type: "error", - name: "ERC20InvalidReceiver", - inputs: [ - { - name: "receiver", - type: "address", - internalType: "address", - }, - ], + name: "PoolPauseWindowDurationOverflow", + inputs: [], }, { type: "error", - name: "ERC20InvalidSender", - inputs: [ - { - name: "sender", - type: "address", - internalType: "address", - }, - ], + name: "SenderNotAllowed", + inputs: [], }, { type: "error", - name: "ERC20InvalidSpender", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - ], + name: "StandardPoolWithCreator", + inputs: [], }, ], inheritedFunctions: { - allowance: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - approve: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - balanceOf: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - decimals: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - name: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - symbol: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - totalSupply: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - transfer: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", - transferFrom: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", + disable: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getActionId: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getAuthorizer: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getDefaultLiquidityManagement: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getDefaultPoolHooksContract: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getDeploymentAddress: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getNewPoolPauseWindowEndTime: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getOriginalPauseWindowEndTime: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getPauseWindowDuration: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + getVault: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + isDisabled: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", + isPoolFromFactory: "lib/balancer-v3-monorepo/pkg/pool-utils/contracts/BasePoolFactory.sol", }, }, VeBALFeeDiscountHook: { - address: "0x0A6338Be5da861e4F864C2B4a8dC219C2A20AA27", + address: "0xd3d3399b02b8Bde3b4A77295393679d95C380f10", abi: [ { type: "constructor", From 0d6a157682a289cef4bfe103262945f377723490 Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Mon, 22 Jul 2024 15:22:08 -0700 Subject: [PATCH 2/7] Improve comments and script names --- packages/foundry/script/Deploy.s.sol | 21 ++++++++----------- ...Pool.s.sol => DeployConstantProduct.s.sol} | 11 +++++----- ...tSumPool.s.sol => DeployConstantSum.s.sol} | 7 +++---- .../foundry/script/DeployMockTokens.s.sol | 3 +-- 4 files changed, 18 insertions(+), 24 deletions(-) rename packages/foundry/script/{DeployConstantProductPool.s.sol => DeployConstantProduct.s.sol} (93%) rename packages/foundry/script/{DeployConstantSumPool.s.sol => DeployConstantSum.s.sol} (96%) diff --git a/packages/foundry/script/Deploy.s.sol b/packages/foundry/script/Deploy.s.sol index 38d543ba..7dd86dea 100644 --- a/packages/foundry/script/Deploy.s.sol +++ b/packages/foundry/script/Deploy.s.sol @@ -1,30 +1,27 @@ //SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -// import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { PoolHelpers } from "./PoolHelpers.sol"; -import { ScaffoldHelpers } from "./ScaffoldHelpers.sol"; import { DeployMockTokens } from "./DeployMockTokens.s.sol"; -import { DeployConstantSumPool } from "./DeployConstantSumPool.s.sol"; -import { DeployConstantProductPool } from "./DeployConstantProductPool.s.sol"; +import { DeployConstantSum } from "./DeployConstantSum.s.sol"; +import { DeployConstantProduct } from "./DeployConstantProduct.s.sol"; /** * @title Deploy Script - * @notice Deploys mock tokens, a constant sum pool, and a constant product pool + * @notice Import all deploy scripts here so that scaffold can exportDeployments() * @dev Run this script with `yarn deploy` */ -contract DeployScript is DeployMockTokens, DeployConstantSumPool, DeployConstantProductPool { +contract DeployScript is DeployMockTokens, DeployConstantSum, DeployConstantProduct { function run() external virtual { - // Deploy the mock tokens + // Deploy mock tokens to be used for pools and hooks contracts (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) = deployMockTokens(); - // Deploy a constant sum factory pool - deployConstantSumPool(mockToken1, mockToken2); + // Deploy a constant sum factory and a pool + deployConstantSum(mockToken1, mockToken2); - // Deploy a constant product pool - deployConstantProductPool(mockToken1, mockToken2, mockVeBAL); + // Deploy a constant product factory, a hooks contract, and a pool + deployConstantProduct(mockToken1, mockToken2, mockVeBAL); /** * This function generates the file containing the contracts Abi definitions that are carried from /foundry to /nextjs. diff --git a/packages/foundry/script/DeployConstantProductPool.s.sol b/packages/foundry/script/DeployConstantProduct.s.sol similarity index 93% rename from packages/foundry/script/DeployConstantProductPool.s.sol rename to packages/foundry/script/DeployConstantProduct.s.sol index e3b625a0..de5da367 100644 --- a/packages/foundry/script/DeployConstantProductPool.s.sol +++ b/packages/foundry/script/DeployConstantProduct.s.sol @@ -11,7 +11,6 @@ import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { IRateProvider } from "@balancer-labs/v3-interfaces/contracts/vault/IRateProvider.sol"; import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol"; import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; -import { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol"; import { PoolHelpers } from "./PoolHelpers.sol"; import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; @@ -19,11 +18,11 @@ import { VeBALFeeDiscountHook } from "../contracts/hooks/VeBALFeeDiscountHook.so import { ConstantProductFactory } from "../contracts/pools/ConstantProductFactory.sol"; /** - * @title Deploy Constant Product Pool - * @notice Deploys a factory and hooks contract before deploying, registering, and initializing a Constant Product Pool + * @title Deploy Constant Product + * @notice Deploys a factory and hooks contract and then deploys, registers, and initializes a constant product pool */ -contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { - function deployConstantProductPool(IERC20 token1, IERC20 token2, IERC20 veBAL) internal { +contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { + function deployConstantProduct(IERC20 token1, IERC20 token2, IERC20 veBAL) internal { // Set the deployment configurations uint32 pauseWindowDuration = 365 days; RegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); @@ -37,7 +36,7 @@ contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { ConstantProductFactory factory = new ConstantProductFactory(IVault(vault), pauseWindowDuration); console.log("Constant Product Factory deployed at: %s", address(factory)); - // Deploy a hooks contract that permits pools created by the Constant Product factory + // Deploy a hooks contract VeBALFeeDiscountHook poolHooksContract = new VeBALFeeDiscountHook( IVault(vault), address(factory), diff --git a/packages/foundry/script/DeployConstantSumPool.s.sol b/packages/foundry/script/DeployConstantSum.s.sol similarity index 96% rename from packages/foundry/script/DeployConstantSumPool.s.sol rename to packages/foundry/script/DeployConstantSum.s.sol index 920b5506..686f2ed2 100644 --- a/packages/foundry/script/DeployConstantSumPool.s.sol +++ b/packages/foundry/script/DeployConstantSum.s.sol @@ -11,18 +11,17 @@ import { IRateProvider } from "@balancer-labs/v3-interfaces/contracts/vault/IRat import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; -import { DevOpsTools } from "lib/foundry-devops/src/DevOpsTools.sol"; import { PoolHelpers } from "./PoolHelpers.sol"; import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; import { ConstantSumFactory } from "../contracts/pools/ConstantSumFactory.sol"; /** - * @title Deploy Constant Sum Pool + * @title Deploy Constant Sum * @notice Deploys, registers, and initializes a Constant Sum Pool */ -contract DeployConstantSumPool is PoolHelpers, ScaffoldHelpers { - function deployConstantSumPool(IERC20 token1, IERC20 token2) internal { +contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { + function deployConstantSum(IERC20 token1, IERC20 token2) internal { // Set the deployment configurations uint32 pauseWindowDuration = 365 days; RegistrationConfig memory regConfig = getRegistrationConfig(token1, token2); diff --git a/packages/foundry/script/DeployMockTokens.s.sol b/packages/foundry/script/DeployMockTokens.s.sol index ba09e64a..4e58bb76 100644 --- a/packages/foundry/script/DeployMockTokens.s.sol +++ b/packages/foundry/script/DeployMockTokens.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.24; import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { PoolHelpers } from "./PoolHelpers.sol"; import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; import { MockToken1 } from "../contracts/mocks/MockToken1.sol"; import { MockToken2 } from "../contracts/mocks/MockToken2.sol"; @@ -14,7 +13,7 @@ import { MockVeBAL } from "../contracts/mocks/MockVeBAL.sol"; * @title Deploy Mock Tokens * @notice Deploys mock tokens for use with pools and hooks */ -contract DeployMockTokens is PoolHelpers, ScaffoldHelpers { +contract DeployMockTokens is ScaffoldHelpers { function deployMockTokens() internal returns (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) { uint256 deployerPrivateKey = getDeployerPrivateKey(); From d1db3c5cd0dfe90125a6966c52a1d101c6b2fd68 Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Mon, 22 Jul 2024 17:25:51 -0700 Subject: [PATCH 3/7] simplyify mock token contract comments --- .../foundry/contracts/hooks/VeBALFeeDiscountHook.sol | 3 ++- packages/foundry/contracts/mocks/MockToken1.sol | 11 ++--------- packages/foundry/contracts/mocks/MockToken2.sol | 11 ++--------- packages/foundry/contracts/mocks/MockVeBAL.sol | 11 ++--------- packages/nextjs/contracts/deployedContracts.ts | 12 ++++++------ 5 files changed, 14 insertions(+), 34 deletions(-) diff --git a/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol b/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol index 1f0e9c61..806d9c1e 100644 --- a/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol +++ b/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol @@ -15,7 +15,8 @@ import { IRouterCommon } from "@balancer-labs/v3-interfaces/contracts/vault/IRou import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** - * @title VeBAL Fee Discount Hook Example + * @title VeBAL Fee Discount Hook + * @notice Applies a 50% discount to the swap fee for users holding veBAL tokens */ contract VeBALFeeDiscountHook is BaseHooks { // only pools from the allowedFactory are able to register and use this hook diff --git a/packages/foundry/contracts/mocks/MockToken1.sol b/packages/foundry/contracts/mocks/MockToken1.sol index ed3776c2..9bf86226 100644 --- a/packages/foundry/contracts/mocks/MockToken1.sol +++ b/packages/foundry/contracts/mocks/MockToken1.sol @@ -3,20 +3,13 @@ pragma solidity ^0.8.24; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -/** - * @title Mock Token 1 - * @notice Entire initial supply is minted to the deployer - * @dev Default decimals is 18, but you can override the decimals function from ERC20 - */ contract MockToken1 is ERC20 { + // Mint the initial supply to the deployer constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) { _mint(msg.sender, initialSupply); } - /** - * Allow any user to mint any amount of tokens to their wallet - * This function is accessible on the frontend's "Debug" page - */ + // Allow any user to mint any amount of tokens to their wallet function mint(uint256 amount) external { _mint(msg.sender, amount); } diff --git a/packages/foundry/contracts/mocks/MockToken2.sol b/packages/foundry/contracts/mocks/MockToken2.sol index 1264bcf3..3474d914 100644 --- a/packages/foundry/contracts/mocks/MockToken2.sol +++ b/packages/foundry/contracts/mocks/MockToken2.sol @@ -3,20 +3,13 @@ pragma solidity ^0.8.24; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -/** - * @title Mock Token 2 - * @notice Entire initial supply is minted to the deployer - * @dev Default decimals is 18, but you can override the decimals function from ERC20 - */ contract MockToken2 is ERC20 { + // Mint the initial supply to the deployer constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) { _mint(msg.sender, initialSupply); } - /** - * Allow any user to mint any amount of tokens to their wallet - * This function is accessible on the frontend's "Debug" page - */ + // Allow any user to mint any amount of tokens to their wallet function mint(uint256 amount) external { _mint(msg.sender, amount); } diff --git a/packages/foundry/contracts/mocks/MockVeBAL.sol b/packages/foundry/contracts/mocks/MockVeBAL.sol index 832666ee..107a5bd8 100644 --- a/packages/foundry/contracts/mocks/MockVeBAL.sol +++ b/packages/foundry/contracts/mocks/MockVeBAL.sol @@ -3,20 +3,13 @@ pragma solidity ^0.8.24; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -/** - * @title Mock VeBAL - * @notice Entire initial supply is minted to the deployer - * @dev Default decimals is 18, but you can override the decimals function from ERC20 - */ contract MockVeBAL is ERC20 { + // Mint the initial supply to the deployer constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) { _mint(msg.sender, initialSupply); } - /** - * Allow any user to mint any amount of tokens to their wallet - * This function is accessible on the frontend's "Debug" page - */ + // Allow any user to mint any amount of tokens to their wallet function mint(uint256 amount) external { _mint(msg.sender, amount); } diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 7c65c0a5..c513effa 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -7,7 +7,7 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; const deployedContracts = { 31337: { MockToken1: { - address: "0x539383fDc37eE70495088826ec32F6B28153245C", + address: "0x8e8cB505973E04200554Bd98741086C7Eca9f42a", abi: [ { type: "constructor", @@ -365,7 +365,7 @@ const deployedContracts = { }, }, MockToken2: { - address: "0x69d2485148F2F6e408db39C2516D948Ac1CD69Ab", + address: "0xC2D1A7c03C0459a8d0Ee885283CE828DE5fFf617", abi: [ { type: "constructor", @@ -723,7 +723,7 @@ const deployedContracts = { }, }, MockVeBAL: { - address: "0xE5A9Ef3838184697602d9c95782304E9b86E230D", + address: "0x906e3a6d1baf80e3e3fa3D57A5DA73099Da86C4c", abi: [ { type: "constructor", @@ -1081,7 +1081,7 @@ const deployedContracts = { }, }, ConstantSumFactory: { - address: "0x0EAa0A56CF3260e1999067c174E1f044389C9f5b", + address: "0x68c87F9fB214Bb4856a13c9123f9b0624944D1A6", abi: [ { type: "constructor", @@ -1465,7 +1465,7 @@ const deployedContracts = { }, }, ConstantProductFactory: { - address: "0xD15Fcc7b91470BDd22a5756B5Add434E9421cea4", + address: "0x2a374E85Ca5F1af906De5CdDa3658219e8759097", abi: [ { type: "constructor", @@ -1849,7 +1849,7 @@ const deployedContracts = { }, }, VeBALFeeDiscountHook: { - address: "0xd3d3399b02b8Bde3b4A77295393679d95C380f10", + address: "0xb33ca895101aB93835fd846d8C23FBdBC29d5843", abi: [ { type: "constructor", From 0bca6e3817785cff6f859dad0fe5b54321b5f3c5 Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Thu, 25 Jul 2024 15:10:35 -0700 Subject: [PATCH 4/7] Update deploy scripts to be more consistent and readable --- .../contracts/hooks/VeBALFeeDiscountHook.sol | 54 ++++++++++++------- packages/foundry/script/Deploy.s.sol | 15 +++--- .../script/DeployConstantProduct.s.sol | 31 ++++++----- .../foundry/script/DeployConstantSum.s.sol | 29 +++++----- .../foundry/script/DeployMockTokens.s.sol | 2 +- packages/foundry/script/PoolHelpers.sol | 38 ++++--------- .../foundry/test/VeBALFeeDiscountHook.t.sol | 3 +- .../nextjs/contracts/deployedContracts.ts | 24 +++------ 8 files changed, 99 insertions(+), 97 deletions(-) diff --git a/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol b/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol index 806d9c1e..3ce87035 100644 --- a/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol +++ b/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol @@ -9,8 +9,8 @@ import { TokenConfig, LiquidityManagement } from "@balancer-labs/v3-vault/contracts/BaseHooks.sol"; -import { IBasePoolFactory } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePoolFactory.sol"; import { IBasePool } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePool.sol"; +import { IBasePoolFactory } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePoolFactory.sol"; import { IRouterCommon } from "@balancer-labs/v3-interfaces/contracts/vault/IRouterCommon.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -19,54 +19,70 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; * @notice Applies a 50% discount to the swap fee for users holding veBAL tokens */ contract VeBALFeeDiscountHook is BaseHooks { - // only pools from the allowedFactory are able to register and use this hook address private immutable _allowedFactory; - // only calls from a trusted routers are allowed to call this hook, because the hook relies on the getSender - // implementation to work properly address private immutable _trustedRouter; IERC20 private immutable _veBAL; - constructor(IVault vault, address allowedFactory, address veBAL, address trustedRouter) BaseHooks(vault) { + constructor(IVault vault, address allowedFactory, address trustedRouter, IERC20 veBAL) BaseHooks(vault) { _allowedFactory = allowedFactory; _trustedRouter = trustedRouter; - _veBAL = IERC20(veBAL); - } - - /// @inheritdoc IHooks - function getHookFlags() external pure override returns (IHooks.HookFlags memory hookFlags) { - hookFlags.shouldCallComputeDynamicSwapFee = true; + _veBAL = veBAL; } - /// @inheritdoc IHooks + /** + * @notice Hook executed when pool is registered + * @dev Return true if registration was successful + * @dev Return false to revert the registration of the pool + * @dev Vault address can be accessed with msg.sender + * @param factory Address of the pool factory + * @param pool Address of the pool + * @return success True if the hook allowed the registration, false otherwise + */ function onRegister( address factory, address pool, TokenConfig[] memory, LiquidityManagement calldata ) external view override returns (bool) { - // This hook implements a restrictive approach, where we check if the factory is an allowed factory and if - // the pool was created by the allowed factory. Since we only use onComputeDynamicSwapFee, this might be an - // overkill in real applications because the pool math doesn't play a role in the discount calculation. + // Only pools deployed by an allowed factory may register return factory == _allowedFactory && IBasePoolFactory(factory).isPoolFromFactory(pool); } + /** + * @notice Returns flags informing which hooks are implemented in the contract. + * @return hookFlags Flags indicating which hooks the contract supports + */ + function getHookFlags() external pure override returns (IHooks.HookFlags memory hookFlags) { + // Support the `onComputeDynamicSwapFeePercentage` hook + hookFlags.shouldCallComputeDynamicSwapFee = true; + } + + /** + * @notice Called before `onBeforeSwap` if the pool has dynamic fees. + * @param params Swap parameters (see IBasePool.PoolSwapParams for struct definition) + * @param staticSwapFeePercentage Value of the static swap fee, for reference + * @return success True if the pool wishes to proceed with settlement + * @return dynamicSwapFee Value of the swap fee + */ function onComputeDynamicSwapFee( IBasePool.PoolSwapParams calldata params, - address, + address, // pool uint256 staticSwapFeePercentage - ) external view override returns (bool, uint256) { - // If the router is not trusted, does not apply the veBAL discount because getSender() may be manipulated by a malicious router. + ) external view override returns (bool success, uint256 dynamicSwapFee) { + // If the router is not trusted, do not apply a fee discount if (params.router != _trustedRouter) { return (true, staticSwapFeePercentage); } + // Find the user's address address user = IRouterCommon(params.router).getSender(); - // If user has veBAL, apply a 50% discount to the current fee (divides fees by 2) + // If the user owns veBAL, apply a 50% discount to the swap fee if (_veBAL.balanceOf(user) > 0) { return (true, staticSwapFeePercentage / 2); } + // Otherwise, do not apply the discount return (true, staticSwapFeePercentage); } } diff --git a/packages/foundry/script/Deploy.s.sol b/packages/foundry/script/Deploy.s.sol index 7dd86dea..1f7d1433 100644 --- a/packages/foundry/script/Deploy.s.sol +++ b/packages/foundry/script/Deploy.s.sol @@ -1,27 +1,30 @@ //SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; - +import { ScaffoldHelpers } from "./ScaffoldHelpers.sol"; import { DeployMockTokens } from "./DeployMockTokens.s.sol"; import { DeployConstantSum } from "./DeployConstantSum.s.sol"; import { DeployConstantProduct } from "./DeployConstantProduct.s.sol"; +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; /** * @title Deploy Script * @notice Import all deploy scripts here so that scaffold can exportDeployments() * @dev Run this script with `yarn deploy` */ -contract DeployScript is DeployMockTokens, DeployConstantSum, DeployConstantProduct { +contract DeployScript is ScaffoldHelpers { function run() external virtual { // Deploy mock tokens to be used for pools and hooks contracts - (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) = deployMockTokens(); + DeployMockTokens deployMockTokens = new DeployMockTokens(); + (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) = deployMockTokens.run(); // Deploy a constant sum factory and a pool - deployConstantSum(mockToken1, mockToken2); + DeployConstantSum deployConstantSum = new DeployConstantSum(); + deployConstantSum.run(mockToken1, mockToken2); // Deploy a constant product factory, a hooks contract, and a pool - deployConstantProduct(mockToken1, mockToken2, mockVeBAL); + DeployConstantProduct deployConstantProduct = new DeployConstantProduct(); + deployConstantProduct.run(mockToken1, mockToken2, mockVeBAL); /** * This function generates the file containing the contracts Abi definitions that are carried from /foundry to /nextjs. diff --git a/packages/foundry/script/DeployConstantProduct.s.sol b/packages/foundry/script/DeployConstantProduct.s.sol index de5da367..c4908915 100644 --- a/packages/foundry/script/DeployConstantProduct.s.sol +++ b/packages/foundry/script/DeployConstantProduct.s.sol @@ -22,11 +22,11 @@ import { ConstantProductFactory } from "../contracts/pools/ConstantProductFactor * @notice Deploys a factory and hooks contract and then deploys, registers, and initializes a constant product pool */ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { - function deployConstantProduct(IERC20 token1, IERC20 token2, IERC20 veBAL) internal { + function run(IERC20 token1, IERC20 token2, IERC20 veBAL) external virtual { // Set the deployment configurations uint32 pauseWindowDuration = 365 days; - RegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); - InitializationConfig memory initConfig = getPoolInitializationConfig(token1, token2); + PoolRegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); + PoolInitializationConfig memory initConfig = getPoolInitializationConfig(token1, token2); // Start creating the transactions uint256 deployerPrivateKey = getDeployerPrivateKey(); @@ -40,8 +40,8 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { VeBALFeeDiscountHook poolHooksContract = new VeBALFeeDiscountHook( IVault(vault), address(factory), - address(veBAL), - address(router) + address(router), + IERC20(veBAL) ); console.log("VeBALFeeDiscountHook deployed at address: %s", address(poolHooksContract)); @@ -59,8 +59,14 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { ); console.log("Constant Product Pool deployed at: %s", pool); + // Approve Permit2 contract to spend tokens on behalf of deployer + approveSpenderOnToken(address(permit2), initConfig.tokens); + + // Approve Router contract to spend tokens using Permit2 + approveSpenderOnPermit2(address(router), initConfig.tokens); + // Seed the pool with initial liquidity - initializePool( + router.initialize( pool, initConfig.tokens, initConfig.exactAmountsIn, @@ -74,15 +80,14 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { /** * @dev Set all of the configurations for deploying and registering a pool here - * - * TokenConfig encapsulates the data required for the Vault to support a token of the given type. + * @notice TokenConfig encapsulates the data required for the Vault to support a token of the given type. * For STANDARD tokens, the rate provider address must be 0, and paysYieldFees must be false. * All WITH_RATE tokens need a rate provider, and may or may not be yield-bearing. */ function getPoolRegistrationConfig( IERC20 token1, IERC20 token2 - ) internal view returns (RegistrationConfig memory regConfig) { + ) internal view returns (PoolRegistrationConfig memory config) { string memory name = "Constant Product Pool"; // name for the pool string memory symbol = "CPP"; // symbol for the BPT bytes32 salt = keccak256(abi.encode(block.number)); // salt for the pool deployment via factory @@ -90,7 +95,7 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { bool protocolFeeExempt = false; address poolHooksContract = address(0); // zero address if no hooks contract is needed - TokenConfig[] memory tokenConfig = new TokenConfig[](2); // An array of descriptors for the tokens the pool will manage. + TokenConfig[] memory tokenConfig = new TokenConfig[](2); // An array of descriptors for the tokens the pool will manage tokenConfig[0] = TokenConfig({ // Make sure to have proper token order (alphanumeric) token: token1, tokenType: TokenType.STANDARD, // STANDARD or WITH_RATE @@ -116,7 +121,7 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { enableDonation: false }); - regConfig = RegistrationConfig({ + config = PoolRegistrationConfig({ name: name, symbol: symbol, salt: salt, @@ -136,7 +141,7 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { function getPoolInitializationConfig( IERC20 token1, IERC20 token2 - ) internal pure returns (InitializationConfig memory poolInitConfig) { + ) internal pure returns (PoolInitializationConfig memory config) { IERC20[] memory tokens = new IERC20[](2); // Array of tokens to be used in the pool tokens[0] = token1; tokens[1] = token2; @@ -147,7 +152,7 @@ contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { bool wethIsEth = false; // If true, incoming ETH will be wrapped to WETH; otherwise the Vault will pull WETH tokens bytes memory userData = bytes(""); // Additional (optional) data required for adding initial liquidity - poolInitConfig = InitializationConfig({ + config = PoolInitializationConfig({ tokens: InputHelpers.sortTokens(tokens), exactAmountsIn: exactAmountsIn, minBptAmountOut: minBptAmountOut, diff --git a/packages/foundry/script/DeployConstantSum.s.sol b/packages/foundry/script/DeployConstantSum.s.sol index 686f2ed2..559d914f 100644 --- a/packages/foundry/script/DeployConstantSum.s.sol +++ b/packages/foundry/script/DeployConstantSum.s.sol @@ -10,7 +10,6 @@ import { import { IRateProvider } from "@balancer-labs/v3-interfaces/contracts/vault/IRateProvider.sol"; import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; import { PoolHelpers } from "./PoolHelpers.sol"; import { ScaffoldHelpers, console } from "./ScaffoldHelpers.sol"; @@ -21,18 +20,18 @@ import { ConstantSumFactory } from "../contracts/pools/ConstantSumFactory.sol"; * @notice Deploys, registers, and initializes a Constant Sum Pool */ contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { - function deployConstantSum(IERC20 token1, IERC20 token2) internal { + function run(IERC20 token1, IERC20 token2) external virtual { // Set the deployment configurations uint32 pauseWindowDuration = 365 days; - RegistrationConfig memory regConfig = getRegistrationConfig(token1, token2); - InitializationConfig memory initConfig = getInitializationConfig(token1, token2); + PoolRegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); + PoolInitializationConfig memory initConfig = getPoolInitializationConfig(token1, token2); // Start creating the transactions uint256 deployerPrivateKey = getDeployerPrivateKey(); vm.startBroadcast(deployerPrivateKey); // Deploy a constant sum factory contract - ConstantSumFactory factory = new ConstantSumFactory(IVault(vault), pauseWindowDuration); + ConstantSumFactory factory = new ConstantSumFactory(vault, pauseWindowDuration); console.log("Constant Sum Factory deployed at: %s", address(factory)); // Deploy a pool and register it with the vault @@ -49,8 +48,14 @@ contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { ); console.log("Constant Sum Pool deployed at: %s", pool); + // Approve Permit2 contract to spend tokens on behalf of deployer + approveSpenderOnToken(address(permit2), initConfig.tokens); + + // Approve Router contract to spend tokens using Permit2 + approveSpenderOnPermit2(address(router), initConfig.tokens); + // Seed the pool with initial liquidity - initializePool( + router.initialize( pool, initConfig.tokens, initConfig.exactAmountsIn, @@ -68,10 +73,10 @@ contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { * For STANDARD tokens, the rate provider address must be 0, and paysYieldFees must be false. * All WITH_RATE tokens need a rate provider, and may or may not be yield-bearing. */ - function getRegistrationConfig( + function getPoolRegistrationConfig( IERC20 token1, IERC20 token2 - ) internal view returns (RegistrationConfig memory regConfig) { + ) internal view returns (PoolRegistrationConfig memory config) { string memory name = "Constant Sum Pool"; // name for the pool string memory symbol = "CSP"; // symbol for the BPT bytes32 salt = keccak256(abi.encode(block.number)); // salt for the pool deployment via factory @@ -105,7 +110,7 @@ contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { enableDonation: false }); - regConfig = RegistrationConfig({ + config = PoolRegistrationConfig({ name: name, symbol: symbol, salt: salt, @@ -122,10 +127,10 @@ contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { * @dev Set the pool initialization configurations here * @notice this is where the amounts of tokens to be initially added to the pool are set */ - function getInitializationConfig( + function getPoolInitializationConfig( IERC20 token1, IERC20 token2 - ) internal pure returns (InitializationConfig memory poolInitConfig) { + ) internal pure returns (PoolInitializationConfig memory config) { IERC20[] memory tokens = new IERC20[](2); // Array of tokens to be used in the pool tokens[0] = token1; tokens[1] = token2; @@ -136,7 +141,7 @@ contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { bool wethIsEth = false; // If true, incoming ETH will be wrapped to WETH; otherwise the Vault will pull WETH tokens bytes memory userData = bytes(""); // Additional (optional) data required for adding initial liquidity - poolInitConfig = InitializationConfig({ + config = PoolInitializationConfig({ tokens: InputHelpers.sortTokens(tokens), exactAmountsIn: exactAmountsIn, minBptAmountOut: minBptAmountOut, diff --git a/packages/foundry/script/DeployMockTokens.s.sol b/packages/foundry/script/DeployMockTokens.s.sol index 4e58bb76..dfebe5c8 100644 --- a/packages/foundry/script/DeployMockTokens.s.sol +++ b/packages/foundry/script/DeployMockTokens.s.sol @@ -14,7 +14,7 @@ import { MockVeBAL } from "../contracts/mocks/MockVeBAL.sol"; * @notice Deploys mock tokens for use with pools and hooks */ contract DeployMockTokens is ScaffoldHelpers { - function deployMockTokens() internal returns (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) { + function run() external virtual returns (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) { uint256 deployerPrivateKey = getDeployerPrivateKey(); vm.startBroadcast(deployerPrivateKey); diff --git a/packages/foundry/script/PoolHelpers.sol b/packages/foundry/script/PoolHelpers.sol index 51cf9d87..1e8e24d4 100644 --- a/packages/foundry/script/PoolHelpers.sol +++ b/packages/foundry/script/PoolHelpers.sol @@ -9,17 +9,15 @@ import { import { IRouter } from "@balancer-labs/v3-interfaces/contracts/vault/IRouter.sol"; import { IPermit2 } from "permit2/src/interfaces/IPermit2.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol"; +import { IRouter } from "@balancer-labs/v3-interfaces/contracts/vault/IRouter.sol"; /** - * A collection of addresses and helper functions for deploying pools + * @title Pool Helpers + * @notice Helpful types, interface instances, and functions for deploying pools on Balancer v3 */ contract PoolHelpers { - // BalancerV3 Sepolia addresses (5th testnet release) - address internal vault = 0x92B5c1CB2999c45804A60d6529D77DeEF00fb839; - address internal router = 0xa12Da7dfD0792a10a5b05B575545Bd685798Ce35; - address internal permit2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; - - struct RegistrationConfig { + struct PoolRegistrationConfig { string name; string symbol; bytes32 salt; @@ -31,7 +29,7 @@ contract PoolHelpers { LiquidityManagement liquidityManagement; } - struct InitializationConfig { + struct PoolInitializationConfig { IERC20[] tokens; uint256[] exactAmountsIn; uint256 minBptAmountOut; @@ -39,24 +37,10 @@ contract PoolHelpers { bytes userData; } - /** - * @notice Approves the vault to spend tokens and then initializes the pool - */ - function initializePool( - address pool, - IERC20[] memory tokens, - uint256[] memory exactAmountsIn, - uint256 minBptAmountOut, - bool wethIsEth, - bytes memory userData - ) internal { - // Approve Permit2 to spend account tokens - approveSpenderOnToken(address(permit2), tokens); - // Approve Router to spend account tokens using Permit2 - approveSpenderOnPermit2(address(router), tokens); - // Initialize pool with the tokens that have been permitted - IRouter(router).initialize(pool, tokens, exactAmountsIn, minBptAmountOut, wethIsEth, userData); - } + // BalancerV3 Sepolia addresses (6th testnet release) + IVault internal vault = IVault(0x92B5c1CB2999c45804A60d6529D77DeEF00fb839); + IRouter internal router = IRouter(0xa12Da7dfD0792a10a5b05B575545Bd685798Ce35); + IPermit2 internal permit2 = IPermit2(0x000000000022D473030F116dDEE9F6B43aC78BA3); /** * Sorts the tokenConfig array into alphanumeric order @@ -94,7 +78,7 @@ contract PoolHelpers { uint160 maxAmount = type(uint160).max; uint48 maxExpiration = type(uint48).max; for (uint256 i = 0; i < tokens.length; ++i) { - IPermit2(permit2).approve(address(tokens[i]), spender, maxAmount, maxExpiration); + permit2.approve(address(tokens[i]), spender, maxAmount, maxExpiration); } } } diff --git a/packages/foundry/test/VeBALFeeDiscountHook.t.sol b/packages/foundry/test/VeBALFeeDiscountHook.t.sol index bbdce7a7..24bc21c6 100644 --- a/packages/foundry/test/VeBALFeeDiscountHook.t.sol +++ b/packages/foundry/test/VeBALFeeDiscountHook.t.sol @@ -23,6 +23,7 @@ import { PoolFactoryMock } from "@balancer-labs/v3-vault/contracts/test/PoolFact import { RouterMock } from "@balancer-labs/v3-vault/contracts/test/RouterMock.sol"; import { VeBALFeeDiscountHook } from "../contracts/hooks/VeBALFeeDiscountHook.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract VeBALFeeDiscountHookTest is BaseVaultTest { using FixedPoint for uint256; @@ -48,7 +49,7 @@ contract VeBALFeeDiscountHookTest is BaseVaultTest { // lp will be the owner of the hook. Only LP is able to set hook fee percentages. vm.prank(lp); address veBalFeeHook = address( - new VeBALFeeDiscountHook(IVault(address(vault)), address(factoryMock), address(veBAL), trustedRouter) + new VeBALFeeDiscountHook(IVault(address(vault)), address(factoryMock), trustedRouter, IERC20(veBAL)) ); vm.label(veBalFeeHook, "VeBAL Fee Hook"); return veBalFeeHook; diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index c513effa..8e0ef77f 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -1865,14 +1865,14 @@ const deployedContracts = { internalType: "address", }, { - name: "veBAL", + name: "trustedRouter", type: "address", internalType: "address", }, { - name: "trustedRouter", + name: "veBAL", type: "address", - internalType: "address", + internalType: "contract IERC20", }, ], stateMutability: "nonpayable", @@ -2417,12 +2417,12 @@ const deployedContracts = { ], outputs: [ { - name: "", + name: "success", type: "bool", internalType: "bool", }, { - name: "", + name: "dynamicSwapFee", type: "uint256", internalType: "uint256", }, @@ -2519,19 +2519,7 @@ const deployedContracts = { ], }, ], - inheritedFunctions: { - getHookFlags: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onAfterAddLiquidity: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onAfterInitialize: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onAfterRemoveLiquidity: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onAfterSwap: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onBeforeAddLiquidity: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onBeforeInitialize: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onBeforeRemoveLiquidity: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onBeforeSwap: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onComputeDynamicSwapFee: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - onRegister: "lib/balancer-v3-monorepo/pkg/vault/contracts/BaseHooks.sol", - }, + inheritedFunctions: {}, }, }, } as const; From a6f15ed494db3cb080be98794efe93704cc195dd Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Wed, 14 Aug 2024 16:49:25 -0700 Subject: [PATCH 5/7] Update hooks page design --- .../app/hooks/_components/HooksCards.tsx | 38 +++++++++---------- packages/nextjs/app/hooks/page.tsx | 10 ++++- .../nextjs/contracts/deployedContracts.ts | 12 +++--- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/packages/nextjs/app/hooks/_components/HooksCards.tsx b/packages/nextjs/app/hooks/_components/HooksCards.tsx index 6ddcfda2..55920dd3 100644 --- a/packages/nextjs/app/hooks/_components/HooksCards.tsx +++ b/packages/nextjs/app/hooks/_components/HooksCards.tsx @@ -36,26 +36,26 @@ export const HooksCards = ({ hooks }: { hooks: HookDetails[] }) => { return ( <> -
- {hooks.map(hook => ( -
setActiveModal(hook.id)} + {hooks.map(hook => ( +
setActiveModal(hook.id)} + > +
{hook.title}
+ -
-
-

{hook.title}

- - - -
- {/*
Created By {hook.created_by}
*/} -
-
{hook.description}
-
- ))} -
+ + {hook.github.slice(0, 40)}... + +
{hook.category}
+
{hook.created_by}
+
+ ))} {activeModal && ( setActiveModal(null)}> diff --git a/packages/nextjs/app/hooks/page.tsx b/packages/nextjs/app/hooks/page.tsx index c2147832..20b76b11 100644 --- a/packages/nextjs/app/hooks/page.tsx +++ b/packages/nextjs/app/hooks/page.tsx @@ -39,7 +39,15 @@ const Hooks: NextPage = async () => { .

- {hooks ? :
Error fetching hooks data!
} +
+
+
Name
+
Repo URL
+
Category
+
Created By
+
+ {hooks ? :
Error fetching hooks data!
} +
); }; diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 8e0ef77f..2cec3129 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -7,7 +7,7 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; const deployedContracts = { 31337: { MockToken1: { - address: "0x8e8cB505973E04200554Bd98741086C7Eca9f42a", + address: "0x290F385a98e707275366648817403E415a808a63", abi: [ { type: "constructor", @@ -365,7 +365,7 @@ const deployedContracts = { }, }, MockToken2: { - address: "0xC2D1A7c03C0459a8d0Ee885283CE828DE5fFf617", + address: "0x3D10F2021266d0d83090046fDF0b8790779C2A82", abi: [ { type: "constructor", @@ -723,7 +723,7 @@ const deployedContracts = { }, }, MockVeBAL: { - address: "0x906e3a6d1baf80e3e3fa3D57A5DA73099Da86C4c", + address: "0xd213c4cC9Bd38bc7dC8877e5f53955c3E5F5F416", abi: [ { type: "constructor", @@ -1081,7 +1081,7 @@ const deployedContracts = { }, }, ConstantSumFactory: { - address: "0x68c87F9fB214Bb4856a13c9123f9b0624944D1A6", + address: "0x90e1d376163cb8287ae4fF1f15CbD4F594DF6201", abi: [ { type: "constructor", @@ -1465,7 +1465,7 @@ const deployedContracts = { }, }, ConstantProductFactory: { - address: "0x2a374E85Ca5F1af906De5CdDa3658219e8759097", + address: "0x98Ae3884f844035F02d1eEbE94E54C25bCb53794", abi: [ { type: "constructor", @@ -1849,7 +1849,7 @@ const deployedContracts = { }, }, VeBALFeeDiscountHook: { - address: "0xb33ca895101aB93835fd846d8C23FBdBC29d5843", + address: "0x7798AD4e898a948FFCf426fb2aAdffbD01087085", abi: [ { type: "constructor", From aa868a9229aba75d2bb6fc58e8784220deb70c0b Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Thu, 15 Aug 2024 08:37:16 -0700 Subject: [PATCH 6/7] Rename deploy scripts for clarity --- ...kTokens.s.sol => 00_DeployMockTokens.s.sol} | 0 ...antSum.s.sol => 01_DeployConstantSum.s.sol} | 0 ...ct.s.sol => 02_DeployConstantProduct.s.sol} | 0 packages/foundry/script/Deploy.s.sol | 18 ++++++++---------- 4 files changed, 8 insertions(+), 10 deletions(-) rename packages/foundry/script/{DeployMockTokens.s.sol => 00_DeployMockTokens.s.sol} (100%) rename packages/foundry/script/{DeployConstantSum.s.sol => 01_DeployConstantSum.s.sol} (100%) rename packages/foundry/script/{DeployConstantProduct.s.sol => 02_DeployConstantProduct.s.sol} (100%) diff --git a/packages/foundry/script/DeployMockTokens.s.sol b/packages/foundry/script/00_DeployMockTokens.s.sol similarity index 100% rename from packages/foundry/script/DeployMockTokens.s.sol rename to packages/foundry/script/00_DeployMockTokens.s.sol diff --git a/packages/foundry/script/DeployConstantSum.s.sol b/packages/foundry/script/01_DeployConstantSum.s.sol similarity index 100% rename from packages/foundry/script/DeployConstantSum.s.sol rename to packages/foundry/script/01_DeployConstantSum.s.sol diff --git a/packages/foundry/script/DeployConstantProduct.s.sol b/packages/foundry/script/02_DeployConstantProduct.s.sol similarity index 100% rename from packages/foundry/script/DeployConstantProduct.s.sol rename to packages/foundry/script/02_DeployConstantProduct.s.sol diff --git a/packages/foundry/script/Deploy.s.sol b/packages/foundry/script/Deploy.s.sol index 1f7d1433..c66434ce 100644 --- a/packages/foundry/script/Deploy.s.sol +++ b/packages/foundry/script/Deploy.s.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.24; import { ScaffoldHelpers } from "./ScaffoldHelpers.sol"; -import { DeployMockTokens } from "./DeployMockTokens.s.sol"; -import { DeployConstantSum } from "./DeployConstantSum.s.sol"; -import { DeployConstantProduct } from "./DeployConstantProduct.s.sol"; +import { DeployMockTokens } from "./00_DeployMockTokens.s.sol"; +import { DeployConstantSum } from "./01_DeployConstantSum.s.sol"; +import { DeployConstantProduct } from "./02_DeployConstantProduct.s.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; /** * @title Deploy Script - * @notice Import all deploy scripts here so that scaffold can exportDeployments() + * @dev Import & run deploy scripts here so that contract Abis are carried to /nextjs * @dev Run this script with `yarn deploy` */ contract DeployScript is ScaffoldHelpers { - function run() external virtual { + function run() external virtual export { // Deploy mock tokens to be used for pools and hooks contracts DeployMockTokens deployMockTokens = new DeployMockTokens(); (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) = deployMockTokens.run(); @@ -25,12 +25,10 @@ contract DeployScript is ScaffoldHelpers { // Deploy a constant product factory, a hooks contract, and a pool DeployConstantProduct deployConstantProduct = new DeployConstantProduct(); deployConstantProduct.run(mockToken1, mockToken2, mockVeBAL); + } - /** - * This function generates the file containing the contracts Abi definitions that are carried from /foundry to /nextjs. - * These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example. - * This function should be called last. - */ + modifier export() { + _; exportDeployments(); } } From 4df059d13384284a4f401c8077f8f6d547167390 Mon Sep 17 00:00:00 2001 From: Matthew Pereira Date: Thu, 15 Aug 2024 09:28:02 -0700 Subject: [PATCH 7/7] Update README with deploy script changes --- README.md | 82 ++++++++++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 84d02c85..849b02e9 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,17 @@ A full stack prototyping tool for building on top of Balancer v3. Accelerate the ### ๐Ÿชง Table Of Contents -0. [Environment Setup ๐Ÿง‘โ€๐Ÿ’ป](#0-environment-setup-) -1. [Create a Custom Pool ๐ŸŒŠ](#1-create-a-custom-pool-) -2. [Create a Pool Factory ๐Ÿญ](#2-create-a-pool-factory-) -3. [Create a Pool Hook ๐Ÿช](#3-create-a-pool-hook-) -4. [Deploy the Contracts ๐Ÿšข](#4-deploy-the-contracts-) -5. [Test the Contracts ๐Ÿงช](#5-test-the-contracts-) +- [๐Ÿง‘โ€๐Ÿ’ป Environment Setup](#0-environment-setup-) +- [๐ŸŒŠ Create a Custom Pool](#1-create-a-custom-pool-) +- [๐Ÿญ Create a Pool Factory](#2-create-a-pool-factory-) +- [๐Ÿช Create a Pool Hook](#3-create-a-pool-hook-) +- [๐Ÿšข Deploy the Contracts](#4-deploy-the-contracts-) +- [๐Ÿงช Test the Contracts](#5-test-the-contracts-) -## 0. Environment Setup ๐Ÿง‘โ€๐Ÿ’ป +## ๐Ÿง‘โ€๐Ÿ’ป Environment Setup -[![image](https://github.com/user-attachments/assets/2d0d5c6d-647d-4782-8d7a-9076b39319b9)](https://www.youtube.com/watch?v=2lInvpCt2o4) + + ### ๐Ÿ“œ Requirements @@ -144,7 +145,7 @@ const scaffoldConfig = { -## 1. Create a Custom Pool ๐ŸŒŠ +## ๐ŸŒŠ Create a Custom Pool Your journey begins with planning the custom computation logic for the pool, which defines how an AMM exchanges one asset for another. @@ -162,7 +163,7 @@ Your journey begins with planning the custom computation logic for the pool, whi - To get started, edit the`ConstantSumPool.sol` contract directly or make a copy -## 2. Create a Pool Factory ๐Ÿญ +## ๐Ÿญ Create a Pool Factory After designing a pool contract, the next step is to prepare a factory contract because Balancer's off-chain infrastructure uses the factory address as a means to identify the type of pool, which is important for integration into the UI, SDK, and external aggregators @@ -180,7 +181,7 @@ After designing a pool contract, the next step is to prepare a factory contract - To get started, edit the`ConstantSumFactory.sol` contract directly or make a copy -## 3. Create a Pool Hook ๐Ÿช +## ๐Ÿช Create a Pool Hook Next, consider further extending the functionality of the custom pool contract with a hooks contract. If your custom pool does not need a hooks contract, use the zero address during pool registration @@ -198,33 +199,39 @@ Next, consider further extending the functionality of the custom pool contract w - To get started, edit the `VeBALFeeDiscountHook.sol` contract directly or make a copy -## 4. Deploy the Contracts ๐Ÿšข +## ๐Ÿšข Deploy the Contracts -The deploy scripts are all located in the [foundry/script/](https://github.com/balancer/scaffold-balancer-v3/tree/main/packages/foundry/script) directory and are prefixed with a number based on the order the order they're intended to be run. The mock tokens, factories, and hooks contracts must be deployed before the pools. On the frontend, the [Pools](http://localhost:3000/pools) page will automatically add a button above the search bar for any pools deployed using the latest factory contract +The deploy scripts are all located in the [foundry/script/](https://github.com/balancer/scaffold-balancer-v3/tree/main/packages/foundry/script) directory. All deploy scripts should be run inside of `Deploy.s.sol` so that the `export` modifier can automate the transfer of deployed contract info to `nextjs/contracts/depoloyedContracts.ts` -### ๐Ÿ› ๏ธ Adjust the Deploy Scripts +### ๐Ÿ‘ฏ Follow the Pattern -#### `00_DeploySetup.s.sol` +To add a new deploy script, import it into `Deploy.s.sol`, create a new instance of it, and run it -Deploy mock tokens, factory contracts, and hooks contracts to be used by pools +``` +function run() external virtual export { + DeployYourContract deployYourContract = new DeployYourContract(); + deployYourContract.run(); +} +``` -- Set the `pauseWindowDuration` for the factory contracts -- Set the mock token names, symbols, and supply -- Set any hooks contracts constructor args +### ๐Ÿ› ๏ธ Examine the Example Deploy Scripts -#### `01_DeployConstantSumPool.s.sol` +#### `00_DeployMockTokens.s.sol` -Deploy, register, and initialize a Constant Sum Pool +1. Deploys mock tokens that are used to register and initialize pools +2. Deploys a mock token used for the example `VeBALFeeDiscountHook` contract -- Set the pool registration config in the `getRegistrationConfig()` function -- Set the pool initialization config in the `getInitializationConfig()` function +#### `01_DeployConstantSum.s.sol` -#### `02_DeployConstantProductPool.s.sol` +1. Deploys a `ConstantSumFactory` +2. Deploys and registers a `ConstantSumPool` +3. Initializes the `ConstantSumPool` using mock tokens -Deploy, register, and initialize a Constant Product Pool +#### `02_DeployConstantProduct.s.sol` -- Set the pool registration config in the `getRegistrationConfig()` function -- Set the pool initialization config in the `getInitializationConfig()` function +1. Deploys a `ConstantProductFactory` +2. Deploys and registers a `ConstantProductPool` +3. Initializes the `ConstantProductPool` using mock tokens ### ๐Ÿ“ก Broadcast the Transactions @@ -234,28 +241,9 @@ To run all the deploy scripts yarn deploy ``` -To run only the `DeploySetup` script - -```bash -yarn deploy:setup -``` - -To run only the `DeployConstantSumPool` script - -```bash -yarn deploy:sum -``` - -To run only the `DeployConstantProductPool` script - -```bash -yarn deploy:product -``` - ๐Ÿ›ˆ To deploy to the live sepolia testnet, add the `--network sepolia` flag -๐Ÿ›ˆ To modify the yarn commands, edit the "scripts" section of the [/foundry/package.json](https://github.com/balancer/scaffold-balancer-v3/blob/main/packages/foundry/package.json) -## 5. Test the Contracts ๐Ÿงช +## ๐Ÿงช Test the Contracts The [balancer-v3-monorepo](https://github.com/balancer/balancer-v3-monorepo) provides testing utility contracts like [BaseVaultTest](https://github.com/balancer/balancer-v3-monorepo/blob/main/pkg/vault/test/foundry/utils/BaseVaultTest.sol). Therefore, the best way to begin writing tests for custom factory, pool, and hook contracts is to utilize the patterns and methods established by the source code.