Balancer Pool Token Implementation
Balancer Pool Tokens are tokens that represent ownership or shares in a Balancer pool. When users add liquidity to a Balancer pool by depositing tokens, they receive corresponding Balancer Pool Tokens in return. These tokens represent their proportional share of the liquidity pool.
Balancer Pool Tokens are dynamic in nature, meaning their value can fluctuate based on changes in the composition of the pool. They represent ownership of the assets within the pool and entitle holders to a portion of the trading fees generated by the pool, proportional to their share. Users can redeem their Balancer Pool Tokens to withdraw their share of the underlying assets from the pool.
BalancerPoolToken Contract
The BalancerPoolToken contract adheres to the ERC20 token standard by incorporating the necessary methods and properties. However, it does not directly manage the state of the token. Instead, it delegates these responsibilities to the Vault contract, which is an instance of ERC20MultiToken. This design choice centralizes the accounting and management of tokens, facilitating atomic updates to critical pool states.
Here's how the BalancerPoolToken
contract achieves this:
Inheritance: The BalancerPoolToken
contract also inherits from IERC20
, IERC20Metadata
, IERC20Permit
, IRateProvider
, EIP712
, Nonces
, ERC165
and our local VaultGuard
. This means it has all the methods and properties required by the ERC20 standard.
Delegation: The BalancerPoolToken contract doesn't manage the token state itself. Instead, it delegates this responsibility to the Vault contract. For example, the totalSupply, balanceOf, transfer, allowance, approve, and transferFrom methods all call the corresponding methods on the Vault contract.
ERC20 Events: The BalancerPoolToken contract emits the Transfer and Approval events, which are required by the ERC20 standard. These events are emitted in the emitTransfer and emitApproval methods, which can only be called by the Vault contract on the pool contract.
ERC20Permit: The BalancerPoolToken contract also implements the ERC20 Permit extension, which allows approvals to be made via signatures. This is done in the permit method, which again delegates the approval to the Vault contract.
IRateProvider: Each pool can serve as a rate provider, with a natural "BPT Rate" = pool value (= invariant) / totalSupply. However, great care must be taken when using pool tokens this way, as rates may be unpredictable or manipulable. In general, since the rate calculation does not include a "rounding hint" (as does the base invariant calculation), if there is any significant or non-linear error in the invariant, the computed value of the invariant might go down when it should go up. Weighted Pool invariants have this property, so calling
getRate
on a Weighted Pool is unsafe, and reverts unconditionally.EIP712, Nonces: These have to do with supporting permit2 and signatures, so that explicit token approvals can be avoided in many cases.
ERC165: This is not used in core pool types, but allows interface detection. See the Ethereum docs.
VaultGuard: This simply stores a reference to the Vault and defines the
onlyVault
modifier for functions that can only be called by the Vault.
By doing this, the BalancerPoolToken contract ensures that Balancer Pool Tokens (BPTs) are fully ERC20 compliant, while also allowing the Vault contract to have full control over BPT accounting. This design ensures atomic updates to critical pool state and supports composability, which is crucial for integration with other DeFi protocols.
Composability
As BPTs adhere to the ERC20 standard, they can seamlessly integrate as pool tokens in other pools. For instance, the BPT of an ERC4626 pool comprising wrapped versions of DAI, USDC, and USDT can be paired with tokens from new projects. This composability ensures the maintenance of deep and capital-efficient stable liquidity, while simultaneously creating efficient swap paths for the project token.