wrapFactor: penalizing pairs of equivalent tokens in liquidity mining

TL,DR

Proposal to apply a wrapFactor = 0.1 to the liquidity of every pair of equivalent tokens when calculating liquidity mining rewards, in an effort to attract useful liquidity to the protocol.

Motivation

One of the goals of a liquidity mining program is to attract valuable liquidity to the protocol. Valuable/useful liquidity usually:

  • provides good trading conditions for takers (low slippage in popular trading pairs, etc),
  • stimulates integrations with other Ethereum dapps and protocols,
  • unlocks novel use cases,
  • etc.

But there is also liquidity that adds very little value. One such case is when there are pairs of equivalent tokens in a pool, i.e. when the two tokens in a pair are just different representations of the same asset. This can be identified by the fact that straightforward actions like depositing/minting one token to a contract - and/or withdrawing/redeeming one token from a contract - results in the other token, with some equivalency in balance being mostly guaranteed. These actions of (un)wrapping them don’t add much friction, so the utility of trading that pair is very low.

Examples of pairs of equivalent tokens are:

  • WETH (wrapped ETH) & cETH (the voucher for withdrawing ETH lent to Compound),
  • USDC & aUSDC (the voucher for withdrawing USDC lent to Aave).

When a significant amount of liquidity is added to such pairs, BAL rewards are “taken away” from other LPs who provide more useful liquidity, since LPs compete pro-rata for the same finite amount of BAL rewards. The screenshot below shows an example of an arguably useless pool (zero trading volume) with very strong liquidity ($2.5M) and optimized parameters for maximizing its rewards (50/50 ratio & low fee).

The Proposal

There would be a list of groups of equivalent tokens, and if a pair in a pool matches any possible pair combination of tokens within a group, a constant wrapFactor (a positive value smaller than one) is applied to the liquidity of that pair.

The liquidity of a pair gets multiplied by this wrapFactor, and other factors still apply (e.g. the ratioFactor for that pair). When finally calculating overall pool liquidity, other factors such as the feeFactor also still apply. In other words, the wrapFactor is not a substitute to any other factor already in place.

An example of how the list of groups of equivalent tokens could look like:

{
  [WETH, cETH, aETH, ...], // ETH group
  [DAI, cDAI, aDAI, rDAI, CHAI, ...], // DAI group
  ...
}

Hopefully the equivalency criteria is objective enough that it shouldn’t be too hard to construct this list. If and when more subjective cases appear, the community can discuss them and update the list as frequently as necessary.

An Example

For a pool consisting of WETH / cETH / aETH / DAI / cUSDC:

  • the wrapFactor is applied to all pairs of equivalent tokens:
    • WETH/cETH,
    • WETH/aETH,
    • cETH/aETH;
  • for all remaining pairs no wrapFactor is applied (or wrapFactor = 1):
    • WETH/DAI,
    • WETH/cUSDC,
    • cETH/DAI,
    • cETH/cUSDC,
    • aETH/DAI,
    • aETH/cUSDC.

Even though a pair like aETH/cUSDC would probably have no organic trade demand, it’s still useful for arbitrage and an LP on that pair remains subject to impermanent loss (so it’d be less likely an attempt at gaming liquidity mining).

Choosing a Value

The ideal value for wrapFactor has been discussed on discord.

The community seems to mostly agree that the value 0 (effectively blacklisting equivalent pairs, making them non-eligible for BAL mining) would be too harsh. It’s still early days of the protocol and we should try to limit how opinionated we are regarding novel use cases for liquidity (e.g. we know some arb bots prefer to trade ETH/WETH on Uniswap-V1 instead of simply wrapping ETH directly, as this trading could make their code more generic/robust).

wrapFactor becomes more ineffective the higher it is, so it makes sense to introduce a low value (arbitrarily, for now) and reassess/fine-tune this value in the future if necessary, according to the results achieved.

At the moment of this post this is how the community reacted to a few possibilities, which are of course non-exhaustive:


According to community sentiment, the current proposal is to start with wrapFactor = 0.1 (i.e. reducing by 90% the BAL rewards calculated for equivalent pairs).

Further Considerations

Regarding tokens that are not exactly equivalent, but do have strong correlation: they still provide significantly useful liquidity to the protocol (price discovery, arbitrage, multihop trading). Examples are:

  • DAI & USDC,
  • WBTC & renBTC.

These pairs are especially useful in the context of multihop trading, which is coming live soon on Balancer. Say I want to buy MKR with USDC: the MKR/USDC pair is currently illiquid, but going through DAI as an intermediate token might lead to a good trade (USDC->DAI->MKR) since both USDC/DAI and DAI/MKR pairs are very liquid. Multihop - which is abstracted away for traders - arguably increases utility of the protocol, and leverages liquidity in pairs of tokens highly demanded for trading.

One rule of thumb we could use to identify equivalency is this: tokens are not equivalent when they have different custodians for backed assets, or when their peg is defended by distinct mechanisms. In other words, the peg of one of them can fail without the others failing.

For example, all these different BTC-pegged tokens are not equivalent to each other: WBTC, tBTC, renBTC, sBTC, pBTC, imBTC. But all lending vouchers for WBTC would be equivalent to each other: WBTC, cWBTC, aWBTC.

4 Likes

This is a proposal (just the initial state, for the week starting June 15th) for the list of groups of equivalent tokens:

{
  [WETH, aETH, cETH, iETH (iearn), iETH (Fulcrum), PETH], // ETH group
  [DAI, aDAI, cDAI, dDAI, iDAI, yDAI, rDAI, CHAI] // DAI group
  [USDC, aUSDC, cUSDC, dUSDC, iUSDC, yUSDC] // USDC group
}

And also:

Glossary:

3 Likes

Thanks @followthechain for summarizing this proposal formally here.

I wrote some python code to show in practice how it would work numerically. For example, the following pools would have the following final factors (tokens A, B and C are not considered equivalent to any other token, so they don’t have a penalty for being equivalent when paired with other tokens, unlike for example a pair like cDAI + aDAI would):

[0.75, 0.25], [‘A’, ‘B’] => 0.75
[0.75, 0.25], [‘cDAI’, ‘aDAI’] => 0.075
[0.49, 0.49, 0.02], [‘A’, ‘B’, ‘C’] => 0.9359
[0.49, 0.49, 0.02], [‘cDAI’, ‘aDAI’, ‘DAI’] => 0.0936
[0.49, 0.49, 0.02], [‘cDAI’, ‘aDAI’, ‘C’] => 0.1572
[0.49, 0.49, 0.02], [‘cDAI’, ‘B’, ‘DAI’] => 0.9041

The code can be found here: https://gist.github.com/FernandoMartinelli/c95603767092c5237c4643aef5faaf4b

This proposal has been welcomed and no objections have been raised by the community. It will be used from the third week of BAL liquidity mining onwards. The third week starts tomorrow, Monday Jun 15th at 00:00 UTC.

PS: synthetic tokens like sETH are not considered equivalent to their underlying because there is a floating peg between them and the underlying. Therefore, having pools with synthetics and their underlying tokens has been deemed by the community as useful liquidity. This is different from tokens that can be just wrapped into one another (like DAI and CHAI, cDAI etc) which this proposal aims to penalize.

2 Likes