Math

The Balancer whitepaper describes a set of formulas derived from the value function for interacting with the protocol. The formulas in the Theory section are sufficient to describe the functional specification, but they are not straightforward to implement for the EVM, in part due to a lack of mature fixed-point math libraries.

Our implementation uses a combination of a few algebraic transformations, approximation functions, and numerical hacks to compute these formulas with bounded maximum error and reasonable gas cost.

Exponentiation Approximation

Spot Price

SPio=BiWiBoWoSP^o_i = \frac{ \frac{B_i}{W_i} }{ \frac{B_o}{W_o} }

Where:

  • Bi is the balance of token i, the token being sold by the trader which is going into the pool.

  • Bo is the balance of token o, the token being bought by the trader which is coming out of the pool.

  • Wi is the weight of token i

  • Wo is the weight of token o

When we consider swap fees, we do exactly the same calculations as without fees, but using Ai(1swapFee)A_i \cdot (1-swapFee) instead of AiA_i. This strategy is referred to as charging fees "on the way in." With the swap fee, the spot price increases. It then becomes:

SPio=BiWiBoWo1(1swapFee)SP^o_i = \frac{ \frac{B_i}{W_i} }{ \frac{B_o}{W_o} } \cdot \frac{1}{(1-swapFee)}

Out-Given-In

In the Whitepaper, we derive the following formula to calculate the amount of tokens out –AoA_o– a trader gets in return for a given amount of tokens in –AiA_i, considering a Balancer pool without any swap fees:

Ao=Bo(1(BiBi+Ai)WiWo)A_{o} = B_{o} \cdot \left(1 - \left(\frac{B_{i}}{B_{i}+A_{i}}\right)^{\frac{W_{i}}{W_{o}}}\right)

To take into account the swap fees charged by the Balancer pool, we replaceAiA_iwithAi(1swapFee)A_i \cdot (1-swapFee). This is known as charging the fees "on the way in"

Ao=Bo(1(BiBi+Ai(1swapFee))WiWo)A_{o} = B_{o} \cdot \left(1 - \left(\frac{B_{i}}{B_{i}+A_{i} \cdot (1-swapFee)}\right)^{\frac{W_{i}}{W_{o}}}\right)

In-Given-Out

In the Whitepaper, we derive the following formula for the amount of tokens in –AiA_i– a trader needs to swap to get a desired amountAoA_oof tokens out in return, considering a Balancer pool without any swap fees:

Ai=Bi((BoBoAo)WoWi1)A_{i} = B_{i} \cdot \left(\left(\frac{B_{o}}{B_{o}-A_{o}}\right)^{\frac{W_{o}}{W_{i}}}-1\right)

Since AiA_i is the amount the user has to swap to get a desired amount out AoA_o, all we have to do to include swap fees is divide the formula above by (1swapFee)(1-swapFee). This is because we know the fee charged on the way in will multiply that amountAiA_i by (1swapFee)(1-swapFee). This will cross out both terms (1swapFee)(1-swapFee) and the amount out will be AoA_o as desired:

Ai=Bi((BoBoAo)WoWi1)1(1swapFee)A_{i} = B_{i} \cdot \left(\left(\frac{B_{o}}{B_{o}-A_{o}}\right)^{\frac{W_{o}}{W_{i}}}-1\right) \cdot \frac{1}{(1-swapFee)}

All-Asset Deposit/Withdrawal

Anyone can be issued Balancer pool tokens (provided the pool is finalized) by depositing proportional amounts of each of the assets contained in the pool. So, for each token k in the pool, the amounts of token kDkD_k– that need to be deposited for someone to get PissuedP_{issued}pool tokens are:

Dk=(Psupply+PissuedPsupply1)BkD_k = \left(\frac{P_{supply}+P_{issued}}{P_{supply}}-1\right) \cdot B_k

Conversely, if a user wants to redeem their pool tokens to get their proportional share of each of the underlying tokens in the pool, the amounts of token k –AkA_k– a user gets for redeeming PredeemedP_{redeemed}pool tokens will be:

Ak=(1PsupplyPredeemedPsupply)BkA_k = \left(1-\frac{P_{supply}-P_{redeemed}}{P_{supply}}\right) \cdot B_k

All Balancer Protocol smart contracts were coded supporting a protocol-level exit fee to be charged that goes to Balancer Labs for supporting the development of the protocol. However, after careful consideration the Balancer Labs team decided to launch the first version of Balancer without any protocol fees whatsoever. (For technical reasons, this is unlikely to change.)

Single-Asset Deposit / Withdrawal

Single-Asset Deposit

In the Whitepaper, we derive the following formula for the amount of pool tokens –PissuedP_{issued}– a liquidity provider gets in return for depositing an amount AtA_tof a single token t present in the pool:

Pissued=Psupply((1+AtBt)Wt1)P_{issued} = P_{supply} \cdot \left(\left(1+\frac{A_t}{B_t}\right)^{W_t} -1\right)

Since Balancer allows for depositing and withdrawing liquidity to Balancer pools using only one of the tokens present in the pool, this could be used to do the equivalent of a swap: provide liquidity depositing token A, and immediately withdraw that liquidity in token B. Therefore a swap fee has to be charged, proportional to the tokens that would need to be swapped for an all-asset deposit.

Another justification for charging a swap fee when a liquidity provider does a single-asset deposit is that they are getting a share of a pool that contains a basket of different assets. So what they are really doing is trading one of the pool assets (the token t being deposited) for proportional shares of all the pool assets.

Since the pool already has a share of its value in token t, represented by the weightWtW_t, it only makes sense to charge a swap fee for the remaining portion of the deposit At(1Wt)A_t \cdot(1 - W_t)

The formula then becomes:

Pissued=Psupply((1+(AtAt(1Wt)swapFee)Bt)Wt1)P_{issued} = P_{supply} \cdot \left(\left(1+\frac{\left(A_t-A_t\cdot(1 - W_t)\cdot swapFee\right)}{B_t}\right)^{W_t} -1\right)

The formula above calculates the amount of pool tokens one receives in return for a deposit of a given amount of a single asset. We also allow for users to define a given amount of pool tokens they desire to get – PissuedP_{issued}– and calculate what amount of tokens t is needed – AtA_t:

At=Bt((1+PissuedPsupply)1Wt1)A_t = B_t \cdot \left(\left(1+\frac{P_{issued}}{P_{supply}}\right)^{\frac{1}{W_t}} -1\right)

Taking into account the swap fees, we have:

At=Bt((1+PissuedPsupply)1Wt1)(1Wt)swapFeeA_t = B_t \cdot \frac{\left(\left(1+\frac{P_{issued}}{P_{supply}}\right)^{\frac{1}{W_t}} -1\right)}{(1 - W_t)\cdot swapFee}

Single-Asset Withdrawal

Without considering swap fees, each withdrawal formula is simply the inverse of the corresponding deposit formula. In other words, if you deposit a given amount of token t for pool tokens and then immediately redeem these pool tokens for token t, you should receive exactly what you started off with.

The formula without considering swap fees is then:

At=Bt(1(1PredeemedPsupply)1Wt)A_t = B_t \cdot \left(1-\left(1-\frac{P_{redeemed}}{P_{supply}}\right)^\frac{1}{W_t}\right)

Where AtA_t is the amount of token t one receives when redeeming PredeemedP_{redeemed}pool tokens.

Considering swap fees, we have the following:

At=Bt(1(1PredeemedPsupply)1Wt)(1(1Wt)swapFee)A_t = B_t \cdot \left(1-\left(1-\frac{P_{redeemed}}{P_{supply}}\right)^\frac{1}{W_t}\right)\cdot \left(1-(1 - W_t)\cdot swapFee\right)

If there were an exit fee, it would be taken from the amount of tokens redeemed PredeemedP_{redeemed}but as mentioned above this fee is zero in the first version of Balancer.

Balancer also allows for a liquidity provider to choose a desired amount of token t, AtA_t, they would like to withdraw from the pool, and calculates the necessary amount of pool tokens required for that,PredeemedP_{redeemed}. The formula without considering swap fees is:

Predeemed=Psupply(1(1AtBt)Wt)P_{redeemed} = P_{supply} \cdot \left(1-\left(1-\frac{A_t}{B_t}\right)^{W_t} \right)

Where AtA_t is the amount of token t one receives when redeeming PredeemedP_{redeemed}pool tokens.

Considering swap fees, we have the following:

Predeemed=Psupply(1(1At(1(1Wt)swapFee)Bt)Wt)P_{redeemed} = P_{supply} \cdot \left(1-\left(1-\frac{\frac{A_t}{\left(1-(1 - W_t)\cdot swapFee\right)}}{B_t}\right)^{W_t} \right)