Pool Maths Reference

Explore our GitHub repositoryopen in new window containing reference mathematical implementations, in Javascript and Python, for supported Balancer pool types. Designed to assist developers and integrators in understanding the underlying swap calculations, these implementations can be imported as a packages into your project or serve as a reference for your own implementation.

Supported Pool Types

Weighted Pool

Pools that swap tokens by enforcing a Constant Weighted Product invariant.

Stable Pool

Pools that swap tokens by enforcing a Stable Math invariant, based on Curve.

Stable Surge Pool

Stable Pools that use the Stable Surge Hook, a dynamic fee implementation that increases fees on transactions that unbalance the pool. The pool itself is exactly the same - a standard Stable Pool. The only difference is the hook, which is attached to the pool by the factory.

Liquidity Bootstrapping Pool

Liquidity Bootstrapping pools have linearly changing weights but use weighted math to determine prices.

projectTokenIndex
currentTime
startTime
endTime
projectTokenStartWeight
projectTokenEndWeight
    function getLBPoolDynamicData() external view override returns (LBPoolDynamicData memory data) {
        data.balancesLiveScaled18 = _vault.getCurrentLiveBalances(address(this));
        data.normalizedWeights = _getNormalizedWeights();
        data.staticSwapFeePercentage = _vault.getStaticSwapFeePercentage((address(this)));
        data.totalSupply = totalSupply();

        PoolConfig memory poolConfig = _vault.getPoolConfig(address(this));
        data.isPoolInitialized = poolConfig.isPoolInitialized;
        data.isPoolPaused = poolConfig.isPoolPaused;
        data.isPoolInRecoveryMode = poolConfig.isPoolInRecoveryMode;
        data.isSwapEnabled = _isSwapEnabled();
    }

    struct LBPoolDynamicData {
    uint256[] balancesLiveScaled18;
    uint256[] normalizedWeights;
    uint256 staticSwapFeePercentage;
    uint256 totalSupply;
    bool isPoolInitialized;
    bool isPoolPaused;
    bool isPoolInRecoveryMode;
    bool isSwapEnabled;
    }

    /// @inheritdoc ILBPool
    function getLBPoolImmutableData() external view override returns (LBPoolImmutableData memory data) {
        data.tokens = _vault.getPoolTokens(address(this));
        data.projectTokenIndex = _projectTokenIndex;
        data.reserveTokenIndex = _reserveTokenIndex;

        (data.decimalScalingFactors, ) = _vault.getPoolTokenRates(address(this));
        data.isProjectTokenSwapInBlocked = _blockProjectTokenSwapsIn;
        data.startTime = _startTime;
        data.endTime = _endTime;

        data.startWeights = new uint256[](_TWO_TOKENS);
        data.startWeights[_projectTokenIndex] = _projectTokenStartWeight;
        data.startWeights[_reserveTokenIndex] = _reserveTokenStartWeight;

        data.endWeights = new uint256[](_TWO_TOKENS);
        data.endWeights[_projectTokenIndex] = _projectTokenEndWeight;
        data.endWeights[_reserveTokenIndex] = _reserveTokenEndWeight;
    }
    struct LBPoolImmutableData {
    IERC20[] tokens;
    uint256[] decimalScalingFactors;
    uint256[] startWeights;
    uint256[] endWeights;
    uint256 startTime;
    uint256 endTime;
    uint256 projectTokenIndex;
    uint256 reserveTokenIndex;
    bool isProjectTokenSwapInBlocked;
    }
  • API Support: Pool will show as LIQUIDITY_BOOTSTRAPPING type and immutable params are available:

A sample graphql query is below returning information about a LBP and docs on the GqlPoolLiquidityBootstrapping is available at https://api-v3.balancer.fi/open in new window.

query {
  poolGetPool(id: "0x812C1217EA39c5242eD1C6D1015EbeD31261E28A", chain: BASE) {
    id
    ... on GqlPoolLiquidityBootstrapping {
      address
      startTime
      endTime
      isProjectTokenSwapInBlocked
      lbpOwner
      projectTokenIndex
      projectToken
      reserveToken
      reserveTokenIndex
      projectTokenStartWeight
      reserveTokenStartWeight
      projectTokenEndWeight
      reserveTokenEndWeight
    }
  }
}

Gyro 2-CLP

Gyroscope two-token pools that concentrate liquidity in a fungible manner, and can have uncorrelated assets.

paramsAlpha
paramsBeta
function getGyro2CLPPoolDynamicData() external view returns (Gyro2CLPPoolDynamicData memory data);

struct Gyro2CLPPoolDynamicData {
    uint256[] balancesLiveScaled18;
    uint256[] tokenRates;
    uint256 staticSwapFeePercentage;
    uint256 totalSupply;
    uint256 bptRate;
    bool isPoolInitialized;
    bool isPoolPaused;
    bool isPoolInRecoveryMode;
}

function getGyro2CLPPoolImmutableData() external view returns (Gyro2CLPPoolImmutableData memory data);

struct Gyro2CLPPoolImmutableData {
    IERC20[] tokens;
    uint256[] decimalScalingFactors;
    uint256 sqrtAlpha;
    uint256 sqrtBeta;
}

Gyro E-CLP

Elliptic CLPs, or E-CLPs, allow trading along the curve of an ellipse. Suitable for correlated assets that would be used with Stable Pools.

paramsAlpha
paramsBeta
paramsC
paramsS
paramsLambda
tauAlphaX
tauAlphaY
tauBetaX
tauBetaY
u
v
w
z
dSq
function getGyroECLPPoolDynamicData() external view returns (GyroECLPPoolDynamicData memory data);

struct GyroECLPPoolDynamicData {
  uint256[] balancesLiveScaled18;
  uint256[] tokenRates;
  uint256 staticSwapFeePercentage;
  uint256 totalSupply;
  uint256 bptRate;
  bool isPoolInitialized;
  bool isPoolPaused;
  bool isPoolInRecoveryMode;
}

function getGyroECLPPoolImmutableData() external view returns (GyroECLPPoolImmutableData memory data);

struct GyroECLPPoolImmutableData {
    IERC20[] tokens;
    uint256[] decimalScalingFactors;
    int256 paramsAlpha;
    int256 paramsBeta;
    int256 paramsC;
    int256 paramsS;
    int256 paramsLambda;
    int256 tauAlphaX;
    int256 tauAlphaY;
    int256 tauBetaX;
    int256 tauBetaY;
    int256 u;
    int256 v;
    int256 w;
    int256 z;
    int256 dSq;
}
  • API Support: Pool will show as GYROE type and immutable params are available:
query MyQuery {
  aggregatorPools(
    where: { chainIn: ARBITRUM, protocolVersionIn: 3, poolTypeIn: GYROE }
  ) {
    address
    type
    alpha
    beta
    c
    s
    lambda
    tauAlphaX
    tauAlphaY
    tauBetaX
    tauBetaY
    u
    v
    w
    z
    dSq
  }
}

QuantAMM BTFs

BTFs by QuantAMM dynamically adjust pool weights to capitalize on price movements. For example, a BTF pool can automatically increase its WBTC allocation when the BTF strategy thinks the value will rise faster than ETH. This allows LPs to earn both trading fees and profits from underlying asset appreciation through continuous, responsive, fully on-chain TradFi-style strategies.

Mainnet:
* UpdateWeightRunner: 0x21Ae9576a393413D6d91dFE2543dCb548Dbb8748
* QuantAMMWeightedPoolFactory: 0xD5c43063563f9448cE822789651662cA7DcD5773

Arbitrum:
* UpdateWeightRunner: 0x8Ca4e2a74B84c1feb9ADe19A0Ce0bFcd57e3f6F7
* QuantAMMWeightedPoolFactory: 0x62B9eC6A5BBEBe4F5C5f46C8A8880df857004295

Base:
* UpdateWeightRunner: 0x8Ca4e2a74B84c1feb9ADe19A0Ce0bFcd57e3f6F7
* QuantAMMWeightedPoolFactory: 0x62B9eC6A5BBEBe4F5C5f46C8A8880df857004295
  • Maths requires the following dynamic data:
firstFourWeightsAndMultipliers
secondFourWeightsAndMultipliers
lastUpdateTime
lastInterpolationTimePossible
function getQsecondFourWeightsAndMultipliersuantAMMWeightedPoolDynamicData() external view returns (QuantAMMWeightedPoolDynamicData memory data);

struct QuantAMMWeightedPoolDynamicData {
    uint256[] balancesLiveScaled18;
    uint256[] tokenRates;
    uint256 totalSupply;
    bool isPoolInitialized;
    bool isPoolPaused;
    bool isPoolInRecoveryMode;
    int256[] firstFourWeightsAndMultipliers;
    int256[] ;
    uint40 lastUpdateTime;
    uint40 lastInteropTime;
}

function getQuantAMMWeightedPoolImmutableData() external view returns (QuantAMMWeightedPoolImmutableData memory data);

struct QuantAMMWeightedPoolImmutableData {
  IERC20[] tokens;
  uint oracleStalenessThreshold;
  uint256 poolRegistry;
  int256[][] ruleParameters;
  uint64[] lambda;
  uint64 epsilonMax;
  uint64 absoluteWeightGuardRail;
  uint64 updateInterval;
  uint256 maxTradeSizeRatio;
}
  • API Support: Pool will show as QUANT_AMM_WEIGHTED type:
query MyQuery {
  aggregatorPools(
    where: {
      chainIn: MAINNET
      protocolVersionIn: 3
      poolTypeIn: QUANT_AMM_WEIGHTED
    }
  ) {
    address
    type
  }
}