Valuing BPT

Overview

There are a variety of reasons that one might want to determine the value of a Balancer Pool Token (BPT). Ultimately, it comes down to assessing the value of the underlying tokens per BPT. Please pay attention to the warnings on this page, as they are critical for calculating values accurately.

Informational

If evaluating a BPT purely for informational purposes (e.g. displaying on a UI), the calculation is quite trivial.

On-Chain

When evaluating for mission critical operations (e.g. determining if a loan with BPT as collateral can be liquidated), however, data validity and manipulation resistance are extremely important.

Getting BPT Supply

Don't use `totalSupply` without reading this first!

Balancer Pools with pre-minted BPT will always return type(uint211).max.

There are three potential functions to query when determining the BPT supply depending on pool type. When evaluating a new pool type, ensure that you are using the correct supply function!

getActualSupply

This is the most common/current function to call. getActualSupply is used by the most recent versions of Weighted and Stable Pools. It accounts for pre-minted BPT as well as due protocol fees.

getVirtualSupply

This is used by Linear Pools and "legacy" Stable Phantom Pools. It accounts for pre-minted BPT but does not take due protocol fees into account. The omission of protocol fee calculations in Linear Pools is intentional since they do not pay protocol fees.

totalSupply

In general, totalSupply only makes sense to call for older "legacy" pools. The original Weighted and Stable Pools do not have pre-minted BPT, so they follow the typical convention of using totalSupply to account for issued pool shares.

Informational Price Evaluation

Don't use this on-chain!

This calculation is for infomational purposes only since it can be easily manipulated.

In short, BPT value is calculated by getting all underlying balances, multiplying those by their market prices, and dividing by the total supply of LP tokens.

On-Chain Price Evaluation

Check for Balancer Vault re-entrancy on ALL on-chain price evaluations!!!

When evaluating BPT price on-chain, it is CRUCIAL to verify that the Balancer Vault is not being re-entered.

The recommended method for doing this is using Balancer's VaultReentrancyLibopen in new window. Calling ensureNotInVaultContext(vault) will perform a noop call to the Vault that will fail if an attacker is attempting a read-only re-entrancy attack.

This library can be imported from version >= 3.1.2 of v2-pool-utilsopen in new window.

Weighted Pools

When calculating a Weighted Pool BPT price on-chain, it's important to use a manipulation resistant technique. The below formula uses the invariant, V, instead of balances directly. While token balances are used in the calculation of the invariant, the error is bounded by the swap fees that an attacker would have to pay to significantly imbalance a pool.

Where V is the WeightedMath invariant calculated as:

Forumla derivation hereopen in new window.

Stable Pools

The pool.getRate() function returns the exchange rate of a BPT to the underlying base asset of the pool accounting for rate providers, if they exist. A few examples:

  • The WETH/wstETH pool will return a rate relative to WETH
  • bb-a-USD will return a rate relative to USD, calculated as a weighted average of the underlying stablecoins (DAI, USDC, USDT) in the nested linear pools (bb-a-DAI, bb-a-USDC, bb-a-USDT)

Linear Pools

Linear Pools have a pool.getRate() function that return the exchange rate of a BPT to the underlying base asset (mainToken) of the pool.