Deploy a Custom AMM Using a Factory

This section is for developers looking to deploy a custom pool contract that has already been written. If you are looking to design a custom AMM with a novel invariant, start here.

Balancer recommends that custom pools be deployed via a factory contract because our 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. Factories also provide important security benefits, mainly guaranteeing the integrity of the setup and preventing front-running. If the contract deploys and registers the factory in one operation, the pool is certain to have the desired configuration.

Although core Balancer pool factories do not do this, as they are meant to be generic and support many different use cases, including separate funding, consider also initializing through the factory (or at least in the same transaction as the create). Factories could even inspect the on-chain conditions during deployment, and revert if they are unfavorable (e.g., nested pool rates have been manipulated), further reducing the risks of front-running or other types of interference. Regarding initialization, it is also recommended to initialize ERC4626 buffers before deploying any pools with corresponding wrapped tokens. Initialization is the step that sets the proportion of underlying and wrapped tokens; thereafter, liquidity can only be added proportionally. To ensure the pools work as intended, buffers should be created and funded by sponsors prior to deploying pools designed to use them.

For maximum security, consider using a private node for sensitive / high liquidity operations, to avoid risks associated with the public mempool.

To fully set up a new custom pool so that normal liquidity operations and swaps are enabled, five required steps must be taken:

  1. Deploy a factory contract that inherits from BasePoolFactory.solopen in new window
  2. Deploy the pool contract using the factory's _create function
  3. Register the pool using the factory's _registerPoolWithVault function
  4. Use Permit2open in new window to approve the Router to spend the tokens that will be used to initialize the pool
  5. Call router.initialize()open in new window to seed the pool with initial liquidity

Tips

To see example foundry scripts for deploying a custom pool using a factory, check out Scaffold Balancer v3open in new window

Creating a Custom Pool Factory Contract

A factory contract should inherit the BasePoolFactory.solopen in new window abstract contract, which sets the table for deploying pools with CREATE3 and streamlines the registration process.

Below, we present an example custom pool factory that uses the ConstantSumPool contract from Build your custom AMM

Factory Constructor Parameters

  • IVault vault: The address of the Balancer vault
  • uint32 pauseWindowDuration: The period, starting from deployment of a factory, during which pools can be paused and unpaused, see FactoryWidePauseWindow.solopen in new window
  • bytes memory creationCode: The creation bytecode of the pool contract used by CREATE3 for deployment

Pool Deployment Parameters

  • bytes memory constructorArgs: The abi encoded constructor args for the custom pool
  • bytes32 salt: Used to compute a unique, deterministic address for each pool deployment

Pool Registration Parameters

Info

Although deploying pools via a factory contract is the recommended approach, it is not mandatory since it is possible to call vault.registerPoolopen in new window directly.

Initializing a Custom Pool

After a custom pool has been deployed and registered, the next step is to add initial liquidity to the pool, which is a three step process:

  1. Ensure the Permit2open in new window contract has been granted sufficient allowance to spend tokens on behalf of the msg.sender
  2. Transfer sufficient allowance to the Routeropen in new window with Permit2.approveopen in new window
  3. Call router.initialize()open in new window

After a pool has been initialized, normal liquidity operations and swaps are instantly enabled.