skills/smithery.ai/cyotee-balancer-v3-pool-registration

cyotee-balancer-v3-pool-registration

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
Weekly Installs
1
First Seen
Feb 28, 2026
Installed on
mcpjam1
amp1
cline1
openclaw1
opencode1
cursor1