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. diff --git a/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol b/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol index 1f0e9c61..3ce87035 100644 --- a/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol +++ b/packages/foundry/contracts/hooks/VeBALFeeDiscountHook.sol @@ -9,63 +9,80 @@ 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"; /** - * @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 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/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/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_DeployMockTokens.s.sol b/packages/foundry/script/00_DeployMockTokens.s.sol new file mode 100644 index 00000000..dfebe5c8 --- /dev/null +++ b/packages/foundry/script/00_DeployMockTokens.s.sol @@ -0,0 +1,34 @@ +//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 { 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 ScaffoldHelpers { + function run() external virtual 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/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/01_DeployConstantSumPool.s.sol b/packages/foundry/script/01_DeployConstantSum.s.sol similarity index 74% rename from packages/foundry/script/01_DeployConstantSumPool.s.sol rename to packages/foundry/script/01_DeployConstantSum.s.sol index 7dfa8604..559d914f 100644 --- a/packages/foundry/script/01_DeployConstantSumPool.s.sol +++ b/packages/foundry/script/01_DeployConstantSum.s.sol @@ -10,42 +10,32 @@ 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 { 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 - * @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 { +contract DeployConstantSum is PoolHelpers, ScaffoldHelpers { + function run(IERC20 token1, IERC20 token2) external virtual { + // Set the deployment configurations + uint32 pauseWindowDuration = 365 days; + PoolRegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); + PoolInitializationConfig memory initConfig = getPoolInitializationConfig(token1, token2); + + // Start creating the transactions uint256 deployerPrivateKey = getDeployerPrivateKey(); + vm.startBroadcast(deployerPrivateKey); - // 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 - RegistrationConfig memory regConfig = getRegistrationConfig(token1, token2); - InitializationConfig memory initConfig = getInitializationConfig(token1, token2); + // Deploy a constant sum factory contract + ConstantSumFactory factory = new ConstantSumFactory(vault, pauseWindowDuration); + console.log("Constant Sum Factory deployed at: %s", address(factory)); - vm.startBroadcast(deployerPrivateKey); // Deploy a pool and register it with the vault - address pool = ConstantSumFactory(factory).create( + address pool = factory.create( regConfig.name, regConfig.symbol, regConfig.salt, @@ -58,8 +48,14 @@ contract DeployConstantSumPool 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, @@ -77,10 +73,10 @@ contract DeployConstantSumPool 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( - address token1, - address token2 - ) internal view returns (RegistrationConfig memory regConfig) { + function getPoolRegistrationConfig( + IERC20 token1, + IERC20 token2 + ) 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 @@ -90,13 +86,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 @@ -114,7 +110,7 @@ contract DeployConstantSumPool is PoolHelpers, ScaffoldHelpers { enableDonation: false }); - regConfig = RegistrationConfig({ + config = PoolRegistrationConfig({ name: name, symbol: symbol, salt: salt, @@ -131,13 +127,13 @@ contract DeployConstantSumPool 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( - address token1, - address token2 - ) internal pure returns (InitializationConfig memory poolInitConfig) { + function getPoolInitializationConfig( + IERC20 token1, + IERC20 token2 + ) internal pure returns (PoolInitializationConfig memory config) { 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 @@ -145,7 +141,7 @@ contract DeployConstantSumPool 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/02_DeployConstantProductPool.s.sol b/packages/foundry/script/02_DeployConstantProduct.s.sol similarity index 71% rename from packages/foundry/script/02_DeployConstantProductPool.s.sol rename to packages/foundry/script/02_DeployConstantProduct.s.sol index 6ba3de8f..c4908915 100644 --- a/packages/foundry/script/02_DeployConstantProductPool.s.sol +++ b/packages/foundry/script/02_DeployConstantProduct.s.sol @@ -11,46 +11,42 @@ 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"; +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` + * @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 run() external virtual { +contract DeployConstantProduct is PoolHelpers, ScaffoldHelpers { + function run(IERC20 token1, IERC20 token2, IERC20 veBAL) external virtual { + // Set the deployment configurations + uint32 pauseWindowDuration = 365 days; + PoolRegistrationConfig memory regConfig = getPoolRegistrationConfig(token1, token2); + PoolInitializationConfig 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 + VeBALFeeDiscountHook poolHooksContract = new VeBALFeeDiscountHook( + IVault(vault), + address(factory), + address(router), + IERC20(veBAL) ); - // 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,13 +54,19 @@ 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); + // 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, @@ -78,15 +80,14 @@ contract DeployConstantProductPool 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 getRegistrationConfig( + 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 @@ -94,7 +95,7 @@ contract DeployConstantProductPool 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 @@ -120,7 +121,7 @@ contract DeployConstantProductPool is PoolHelpers, ScaffoldHelpers { enableDonation: false }); - regConfig = RegistrationConfig({ + config = PoolRegistrationConfig({ name: name, symbol: symbol, salt: salt, @@ -137,10 +138,10 @@ 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) { + ) 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; @@ -151,7 +152,7 @@ contract DeployConstantProductPool 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/Deploy.s.sol b/packages/foundry/script/Deploy.s.sol new file mode 100644 index 00000000..c66434ce --- /dev/null +++ b/packages/foundry/script/Deploy.s.sol @@ -0,0 +1,34 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { ScaffoldHelpers } from "./ScaffoldHelpers.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 + * @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 export { + // Deploy mock tokens to be used for pools and hooks contracts + DeployMockTokens deployMockTokens = new DeployMockTokens(); + (IERC20 mockToken1, IERC20 mockToken2, IERC20 mockVeBAL) = deployMockTokens.run(); + + // Deploy a constant sum factory and a pool + DeployConstantSum deployConstantSum = new DeployConstantSum(); + deployConstantSum.run(mockToken1, mockToken2); + + // Deploy a constant product factory, a hooks contract, and a pool + DeployConstantProduct deployConstantProduct = new DeployConstantProduct(); + deployConstantProduct.run(mockToken1, mockToken2, mockVeBAL); + } + + modifier export() { + _; + exportDeployments(); + } +} 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/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/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/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 70232685..2cec3129 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: "0x290F385a98e707275366648817403E415a808a63", 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: "0x3D10F2021266d0d83090046fDF0b8790779C2A82", + 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: "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", }, + ], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "allowance", + inputs: [ { - 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", + name: "owner", 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", - }, - ], + name: "spender", + type: "address", + internalType: "address", }, ], outputs: [ { - name: "pool", - type: "address", - internalType: "address", + name: "", + type: "uint256", + internalType: "uint256", }, ], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "disable", - inputs: [], - outputs: [], - stateMutability: "nonpayable", + stateMutability: "view", }, { type: "function", - name: "getActionId", + name: "approve", inputs: [ { - name: "selector", - type: "bytes4", - internalType: "bytes4", + name: "spender", + type: "address", + internalType: "address", + }, + { + name: "value", + type: "uint256", + internalType: "uint256", }, ], outputs: [ { name: "", - type: "bytes32", - internalType: "bytes32", + type: "bool", + internalType: "bool", }, ], - stateMutability: "view", + stateMutability: "nonpayable", }, { type: "function", - name: "getAuthorizer", - inputs: [], - outputs: [ + name: "balanceOf", + inputs: [ { - name: "", + name: "account", 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: "", + type: "uint256", + internalType: "uint256", }, ], - stateMutability: "pure", + stateMutability: "view", }, { type: "function", - name: "getDefaultPoolHooksContract", + name: "decimals", inputs: [], outputs: [ { name: "", - type: "address", - internalType: "address", + type: "uint8", + internalType: "uint8", }, ], - stateMutability: "pure", + stateMutability: "view", }, { 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: [], + 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", + }, + ], + }, + { + 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: "0xd213c4cC9Bd38bc7dC8877e5f53955c3E5F5F416", abi: [ { type: "constructor", @@ -1106,369 +1080,412 @@ const deployedContracts = { transferFrom: "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol", }, }, - MockToken2: { - address: "0x68c87F9fB214Bb4856a13c9123f9b0624944D1A6", + ConstantSumFactory: { + address: "0x90e1d376163cb8287ae4fF1f15CbD4F594DF6201", 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: "view", + stateMutability: "pure", }, { type: "function", - name: "symbol", - inputs: [], + name: "getDeploymentAddress", + inputs: [ + { + name: "salt", + type: "bytes32", + internalType: "bytes32", + }, + ], outputs: [ { name: "", - type: "string", - internalType: "string", + type: "address", + internalType: "address", }, ], stateMutability: "view", }, { type: "function", - name: "totalSupply", + name: "getNewPoolPauseWindowEndTime", inputs: [], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", + type: "uint32", + internalType: "uint32", }, ], stateMutability: "view", }, { type: "function", - name: "transfer", - inputs: [ - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], + name: "getOriginalPauseWindowEndTime", + inputs: [], outputs: [ { name: "", - type: "bool", - internalType: "bool", + type: "uint32", + internalType: "uint32", }, ], - stateMutability: "nonpayable", + stateMutability: "view", }, { type: "function", - name: "transferFrom", - inputs: [ - { - name: "from", - type: "address", - internalType: "address", - }, - { - name: "to", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], + name: "getPauseWindowDuration", + inputs: [], outputs: [ { name: "", - type: "bool", - internalType: "bool", - }, - ], - stateMutability: "nonpayable", - }, - { - 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", + type: "uint32", + internalType: "uint32", }, ], - anonymous: false, + stateMutability: "view", }, { - type: "event", - name: "Transfer", - inputs: [ - { - name: "from", - type: "address", - indexed: true, - internalType: "address", - }, + type: "function", + name: "getVault", + inputs: [], + outputs: [ { - name: "to", + name: "", type: "address", - indexed: true, - internalType: "address", - }, - { - name: "value", - type: "uint256", - indexed: false, - internalType: "uint256", + internalType: "contract IVault", }, ], - anonymous: false, + stateMutability: "view", }, { - type: "error", - name: "ERC20InsufficientAllowance", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - { - name: "allowance", - type: "uint256", - internalType: "uint256", - }, + type: "function", + name: "isDisabled", + inputs: [], + outputs: [ { - name: "needed", - type: "uint256", - internalType: "uint256", + name: "", + type: "bool", + internalType: "bool", }, ], + stateMutability: "view", }, { - type: "error", - name: "ERC20InsufficientBalance", + type: "function", + name: "isPoolFromFactory", inputs: [ { - name: "sender", + name: "pool", type: "address", internalType: "address", }, + ], + outputs: [ { - name: "balance", - type: "uint256", - internalType: "uint256", - }, - { - name: "needed", - type: "uint256", - internalType: "uint256", + name: "", + type: "bool", + internalType: "bool", }, ], + stateMutability: "view", }, { - type: "error", - name: "ERC20InvalidApprover", + type: "event", + name: "FactoryDisabled", + inputs: [], + anonymous: false, + }, + { + type: "event", + name: "PoolCreated", inputs: [ { - name: "approver", + name: "pool", type: "address", + indexed: true, internalType: "address", }, ], + anonymous: false, }, { type: "error", - name: "ERC20InvalidReceiver", - inputs: [ - { - name: "receiver", - type: "address", - internalType: "address", - }, - ], + name: "Disabled", + inputs: [], }, { type: "error", - name: "ERC20InvalidSender", - inputs: [ - { - name: "sender", - type: "address", - internalType: "address", - }, - ], + name: "PoolPauseWindowDurationOverflow", + inputs: [], }, { type: "error", - name: "ERC20InvalidSpender", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - ], + name: "SenderNotAllowed", + inputs: [], + }, + { + type: "error", + 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", }, }, - MockVeBAL: { - address: "0xBcd2152CD06E3e65f88f3f21aeBDc5473d8EAef4", + ConstantProductFactory: { + address: "0x98Ae3884f844035F02d1eEbE94E54C25bCb53794", 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", @@ -1481,160 +1498,273 @@ const deployedContracts = { internalType: "string", }, { - name: "initialSupply", + 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", }, + { + 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: "allowance", + name: "disable", + inputs: [], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "getActionId", inputs: [ { - name: "owner", - type: "address", - internalType: "address", + name: "selector", + type: "bytes4", + internalType: "bytes4", }, + ], + outputs: [ { - name: "spender", - type: "address", - internalType: "address", + name: "", + type: "bytes32", + internalType: "bytes32", }, ], + stateMutability: "view", + }, + { + type: "function", + name: "getAuthorizer", + inputs: [], outputs: [ { name: "", - type: "uint256", - internalType: "uint256", + type: "address", + internalType: "contract IAuthorizer", + }, + ], + 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: "view", + stateMutability: "pure", }, { type: "function", - name: "approve", - inputs: [ - { - name: "spender", - type: "address", - internalType: "address", - }, - { - name: "value", - type: "uint256", - internalType: "uint256", - }, - ], + name: "getDefaultPoolHooksContract", + inputs: [], outputs: [ { name: "", - type: "bool", - internalType: "bool", + type: "address", + internalType: "address", }, ], - 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: "0x7798AD4e898a948FFCf426fb2aAdffbD01087085", abi: [ { type: "constructor", @@ -1839,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", @@ -2391,12 +2417,12 @@ const deployedContracts = { ], outputs: [ { - name: "", + name: "success", type: "bool", internalType: "bool", }, { - name: "", + name: "dynamicSwapFee", type: "uint256", internalType: "uint256", }, @@ -2493,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;