smithery.ai

Balancer V3 Pool Registration

This skill should be used when the user asks about "register pool Balancer", "pool initialization", "TokenConfig", "PoolRoleAccounts", "LiquidityManagement", "BasePoolFactory", "pool configuration", or needs to understand how pools are registered and initialized in Balancer V3.

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version0.1.0

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 10,221 B
  • docs SUMMARY.md 315 B

History

  1. First recorded snapshot · 1 installs

SKILL.md

Balancer V3 Pool Registration & Initialization

This skill covers how pools are registered with the Vault and initialized with liquidity.

Pool Lifecycle

┌──────────────────────────────────────────────────────────────┐
│                    POOL LIFECYCLE                            │
├──────────────────────────────────────────────────────────────┤
│ 1. DEPLOY:  Factory deploys pool contract                    │
│ 2. REGISTER: Factory calls vault.registerPool()              │
│ 3. INITIALIZE: Router calls vault.initialize() with liquidity│
│ 4. ACTIVE: Pool ready for swaps and liquidity operations     │
└──────────────────────────────────────────────────────────────┘

Pool Registration

registerPool Function

function registerPool(
    address pool,
    TokenConfig[] memory tokenConfig,
    uint256 swapFeePercentage,
    uint32 pauseWindowEndTime,
    bool protocolFeeExempt,
    PoolRoleAccounts calldata roleAccounts,
    address poolHooksContract,
    LiquidityManagement calldata liquidityManagement
) external;

TokenConfig

struct TokenConfig {
    IERC20 token;
    TokenType tokenType;        // STANDARD or WITH_RATE
    IRateProvider rateProvider; // Required for WITH_RATE tokens
    bool paysYieldFees;         // Yield fees charged on this token
}

enum TokenType {
    STANDARD,   // No rate provider (1:1 scaling)
    WITH_RATE   // Has rate provider for wrapped/yield tokens
}

Token Requirements:

  • 2-8 tokens per pool
  • Max 18 decimals
  • Tokens must be sorted by address
  • No duplicate tokens
  • No rebasing tokens
  • No fee-on-transfer tokens

PoolRoleAccounts

struct PoolRoleAccounts {
    address pauseManager;    // Can pause/unpause pool
    address swapFeeManager;  // Can set static swap fees
    address poolCreator;     // Receives pool creator fees
}

If set to address(0), permissions default to the Authorizer.

LiquidityManagement

struct LiquidityManagement {
    bool disableUnbalancedLiquidity;  // Only proportional add/remove
    bool enableAddLiquidityCustom;     // Pool implements custom add
    bool enableRemoveLiquidityCustom;  // Pool implements custom remove
    bool enableDonation;               // Allow DONATION add liquidity
}

BasePoolFactory Pattern

All pool factories extend BasePoolFactory:

abstract contract BasePoolFactory {
    IVault private immutable _vault;
    uint32 private immutable _pauseWindowDuration;

    // Deploy pool and register with Vault
    function _create(bytes memory constructorArgs, bytes32 salt) internal returns (address pool) {
        pool = Create2.deploy(0, salt, abi.encodePacked(creationCode, constructorArgs));
    }

    function _registerPoolWithVault(
        address pool,
        TokenConfig[] memory tokenConfig,
        uint256 swapFeePercentage,
        bool protocolFeeExempt,
        PoolRoleAccounts memory roleAccounts,
        address poolHooksContract,
        LiquidityManagement memory liquidityManagement
    ) internal {
        _vault.registerPool(
            pool,
            tokenConfig,
            swapFeePercentage,
            uint32(block.timestamp) + _pauseWindowDuration,
            protocolFeeExempt,
            roleAccounts,
            poolHooksContract,
            liquidityManagement
        );
    }

    function getDefaultLiquidityManagement() public pure returns (LiquidityManagement memory) {
        return LiquidityManagement({
            disableUnbalancedLiquidity: false,
            enableAddLiquidityCustom: false,
            enableRemoveLiquidityCustom: false,
            enableDonation: false
        });
    }
}

Pool Initialization

After registration, pools must be initialized with liquidity:

function initialize(
    address pool,
    address to,                    // BPT recipient
    IERC20[] memory tokens,        // Must match registration order
    uint256[] memory exactAmountsIn,
    uint256 minBptAmountOut,
    bytes memory userData
) external returns (uint256 bptAmountOut);

Initialization Flow

┌──────────────────────────────────────────────────────────────┐
│                   INITIALIZATION FLOW                        │
├──────────────────────────────────────────────────────────────┤
│ 1. Verify pool is registered but not initialized             │
│ 2. Verify tokens match registration order                    │
│ 3. Call beforeInitialize hook (if enabled)                   │
│ 4. Compute initial invariant from pool.computeInvariant()    │
│ 5. Mint initial BPT (invariant + minimum locked)             │
│ 6. Lock MINIMUM_BPT to address(0) for safety                 │
│ 7. Transfer actual BPT to recipient                          │
│ 8. Call afterInitialize hook (if enabled)                    │
│ 9. Mark pool as initialized                                  │
└──────────────────────────────────────────────────────────────┘

Minimum BPT Lock

// Protects against first-depositor attacks
uint256 internal constant _POOL_MINIMUM_TOTAL_SUPPLY = 1e6;

// During initialization:
// - Compute BPT = invariant
// - Lock MINIMUM to burn address
// - Give (BPT - MINIMUM) to depositor

Pool Configuration

After registration, pools have configuration stored:

struct PoolConfig {
    LiquidityManagement liquidityManagement;
    uint256 staticSwapFeePercentage;
    uint256 aggregateSwapFeePercentage;
    uint256 aggregateYieldFeePercentage;
    uint40 tokenDecimalDiffs;
    uint32 pauseWindowEndTime;
    bool isPoolRegistered;
    bool isPoolInitialized;
    bool isPoolPaused;
    bool isPoolInRecoveryMode;
}

Fee Configuration

// Swap fees (0.001% to 10%)
uint256 private constant _MIN_SWAP_FEE_PERCENTAGE = 0.001e16;
uint256 private constant _MAX_SWAP_FEE_PERCENTAGE = 10e16;

// Aggregate fees = protocol fee + pool creator fee
// Set via ProtocolFeeController

Creating a Pool (Factory Example)

// WeightedPoolFactory.create()
function create(
    string memory name,
    string memory symbol,
    TokenConfig[] memory tokens,
    uint256[] memory normalizedWeights,
    PoolRoleAccounts memory roleAccounts,
    uint256 swapFeePercentage,
    address poolHooksContract,
    bool enableDonation,
    bool disableUnbalancedLiquidity,
    bytes32 salt
) external returns (address pool) {
    LiquidityManagement memory liquidityManagement = getDefaultLiquidityManagement();
    liquidityManagement.enableDonation = enableDonation;
    liquidityManagement.disableUnbalancedLiquidity = disableUnbalancedLiquidity;

    pool = _create(
        abi.encode(
            WeightedPool.NewPoolParams({
                name: name,
                symbol: symbol,
                numTokens: tokens.length,
                normalizedWeights: normalizedWeights,
                version: _poolVersion
            }),
            getVault()
        ),
        salt
    );

    _registerPoolWithVault(
        pool,
        tokens,
        swapFeePercentage,
        false,  // not protocol fee exempt
        roleAccounts,
        poolHooksContract,
        liquidityManagement
    );
}

Hooks During Registration

If a hooks contract is provided:

interface IHooks {
    // Called during registration - must return true
    function onRegister(
        address factory,
        address pool,
        TokenConfig[] memory tokenConfig,
        LiquidityManagement calldata liquidityManagement
    ) external returns (bool success);

    // Returns which hooks the contract implements
    function getHookFlags() external view returns (HookFlags memory);
}

Querying Pool State

// Check registration status
function isPoolRegistered(address pool) external view returns (bool);
function isPoolInitialized(address pool) external view returns (bool);

// Get pool tokens
function getPoolTokens(address pool) external view returns (IERC20[] memory);

// Get full pool data
function getPoolData(address pool) external view returns (PoolData memory);

// Get pool configuration
function getPoolConfig(address pool) external view returns (PoolConfig memory);

Pool Type Skills

For specific pool implementations, see:

Pool Type Skill Use Case
Weighted Pool balancer-v3-weighted-pool Uncorrelated assets with custom weights
Stable Pool balancer-v3-stable-pool Correlated/pegged assets (stablecoins, LSTs)
Gyro Pools balancer-v3-gyro-pool Concentrated liquidity (2-CLP, E-CLP)
CoW Pool balancer-v3-cow-pool MEV-protected trading
RECLAMM Pool balancer-v3-reclamm-pool Regenerating concentrated liquidity with auto-adjusting price range

Reference Files

For complete implementation:

  • pkg/interfaces/contracts/vault/IVaultExtension.sol - Registration interface
  • pkg/pool-utils/contracts/BasePoolFactory.sol - Factory base class
  • pkg/pool-weighted/contracts/WeightedPoolFactory.sol - Example factory