# Wasted Liqudity

**URL:** <https://forum.balancer.fi/t/wasted-liqudity/106>\
**Category:** Liquidity Mining \[deprecated\]\
**Created:** [July 17, 2020, 10:22pm UTC](https://forum.balancer.fi/t/wasted-liqudity/106 "2020-07-17T22:22:17Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![justwanttoknowathing](https://avatars.discourse-cdn.com/v4/letter/j/6f9a4e/32.png) [@justwanttoknowathing](https://forum.balancer.fi/u/justwanttoknowathing)\
**Post date:** [July 17, 2020, 10:22pm UTC](https://forum.balancer.fi/t/wasted-liqudity/106/1 "2020-07-17T22:22:17Z")

</div>

_Liquidity-fragmentation-is-bad team here, coming at you with a detailed write up about liquidity fragmentation!_

# The basics:

## What is _liquidity fragmentation_?

Liquidity fragmentation, in general, is the unavoidable fact that assets trade on many venues and liquidity of the asset must be split between these venues. For example, eth trades on both Coinbase and Binance and the prices may differ slightly between these exchanges. Another example would be Coinbase and Balancer.

Note that this same definition can also apply _within_ Balancer itself. Eth may trade via many different pools such as ETH/BTC or ETH/USDC. This is still normal, inevitable and unavoidable liquidity fragmentation, but the next step is actual _wasted liquidity_, so…

## What is _wasted liquidity_?

Wasted liquidity is when we go one-lever deeper: on Balancer today eth doesn’t _just_ trade on _one_ ETH/BTC pools. It trades on two. And unlike the ETH/USDC pool – that, remember, is good – this second ETH/BTC pool is bad.

It’s an exact clone of the other pool. No, really, check it:

```auto
Wasted $445702 on [{'addr': '0x29...a177', 'name': ['WBTC50', 'WETH50'], 'Fee': 0.15}, {'addr': '0x80...2e9d', 'name': ['WBTC50', 'WETH50'], 'Fee': 0.15}]

```

Click through and admire the sameness:  
[https://pools.balancer.exchange/#/pool/0x294de1cde8b04bf6d25f98f1d547052f8080a177](https://pools.balancer.exchange/#/pool/0x294de1cde8b04bf6d25f98f1d547052f8080a177)  
[https://pools.balancer.exchange/#/pool/0x80b42669f3d8bba7618800efe6aed60d90f72e9d](https://pools.balancer.exchange/#/pool/0x80b42669f3d8bba7618800efe6aed60d90f72e9d)

**That** is wasted liquidity and it is one of many examples on Balancer today.

## What can we _do about it_?

Two things:

1. If you have liquidity in a wasteful pool, move it to its larger cousin. Only by working together can we defeat wasted liquidity.

2. Penalize liquidity in wasteful pools: give them fewer BAL rewards.

## What is _the catch_?

Two things:

### 1) Wasted liquidity isn’t entirely objective.

Some pools are like those two BTC/ETH pools provided as an example above, but others are _probably_ wasteful, but require a judgement call. Give it a try, does this look like a fair group to you?

```auto
{'addr': '0xa2...bd95', 'name': ['WBTC49', 'cETH49', 'COMP2'], 'Fee': 0.15},
{'addr': '0x7a...ae25', 'name': ['WBTC49', 'cETH49', 'COMP2'], 'Fee': 0.15},
{'addr': '0xab...3b3c', 'name': ['WBTC48', 'cETH50', 'COMP2'], 'Fee': 0.15},
{'addr': '0xc7...1803', 'name': ['WBTC49', 'cETH49', 'COMP2'], 'Fee': 0.15},
{'addr': '0x7c...cb71', 'name': ['WBTC50', 'cETH48', 'COMP2'], 'Fee': 0.15}

```

Those’re some awfully similar pools, but they’re not identical. Should they be penalized as one group?

### 2) Naive penalties are gameable.

It’s difficult to tell which pool, out of a group of similar pools, should be spared from penalty. Clearly one of them, but how to tell? We have two reasonable options:

1. The oldest.

2. The largest.

The drawback of choosing the oldest is precisely that it might not also be the largest. If this turned out to be so, we’d then be demanding that more liquidity move than was necessary, which is inefficient.

Choosing the largest means our choice may move around in gameable ways: what if many minnows are supplying a healthy ETH/USDC pool and a spiteful whale swoops in and creates a bigger ETH/USDC pool. Our minnows migrate to the new pool, but the whale repeats the ploy!

**Those both seem kind of bad?**

Yeah. Here’s our best path forward:

In the short-term, we go with the oldest pool. Or even just the “most popular right now” pool. The point is, we pick a winning pool out of each group and penalize the rest. New pools that would get grouped with one of these “winners” are penalized just like the existing ones.

In the longer-term, we commit to eventually deprecate our “winners” system and allow the largest pool in a given group to be the one to go unpenalized. The assumption here would be that _eventually_ Balancer would exit growth mode and could charge a small (but large enough to deter griefing) BAL cost on the creation of new pools.

# The Code:

Change `FEE_DIFF` and `ALC_DIFF` to match what you think they ought to be.

`FEE_DIFF` is how different two fees must be to no longer consider two pools “the same”. `1` is a `0.01%` difference: e.g. a `0.25%` fee pool and a `0.30%` fee pool are similar if `FEE_DIFF >= 5`.

`ALC_DIFF` is how different two matching asset allocations must be, +/- from each other, to no longer consider two pools “the same”. `1` is a `1%` difference: e.g. `BAL/ETH 80/20` and `BAL/ETH 75/25` are similar if `ALC_DIFF >= 5`.

```python
from bs4 import BeautifulSoup as bs
from requests import get

FEE_DIFF = 5
ALC_DIFF = 5

def parse(s):
    return [{'asset': i.lstrip()[0:i.lstrip().find(' ')], 'percent': int(i[i.lstrip().find(' ')+1:])} for i in s.split('%')[:-1]]

def similar(a, b):
    if abs(a['Fee'] - b['Fee'])*100 > FEE_DIFF:
        return False
    a, b = a['Assets'], b['Assets']
    return False not in [True in [i['asset'] in [j['asset'] for j in b] and abs(j['percent'] - i['percent']) <= ALC_DIFF for j in b if j['asset'] == i['asset']] for i in a]

data = []
for i in bs(get("http://www.predictions.exchange/balancer/None").text, features="lxml").find("table", id="balTable").find_all("tr"):
    try:
        addr, assets, fee, liq, _, _, _, _, _, _ = [j.text.strip() for j in i.find_all('td')]
        data.append({'Address': addr, 'Assets': parse(assets), 'Liquidity': int(liq.lstrip('$').replace(',', '')), 'Fee': float(fee.rstrip('%'))})
    except:
        pass

total_wasted = 0
counted = []
for i in data:
    grouped = [a for a in data if similar(a, i)]
    if len([j for j in counted if j in grouped]) > 0:
        continue
    liq = [a['Liquidity'] for a in grouped]
    ml = max(liq)
    tl = sum(liq)
    wasted = tl - ml
    total_wasted += wasted
    if wasted > 1:
        print('Wasted $%i on %s' % (wasted, [{'addr': i['Address'], 'name': ['%s%i' % (j['asset'], j['percent']) for j in i['Assets']], 'Fee': i['Fee']} for i in grouped]))
    counted.append(i)
print('Wasted $%i total' % total_wasted)

```

Here’s a recent snapshot with the default “5” `DIFF` values:

```auto
Wasted $445702 on [{'addr': '0x29...a177', 'name': ['WBTC50', 'WETH50'], 'Fee': 0.15}, {'addr': '0x80...2e9d', 'name': ['WBTC50', 'WETH50'], 'Fee': 0.15}]
Wasted $87678 on [{'addr': '0x5e...07d5', 'name': ['sETH50', 'WETH50'], 'Fee': 0.01}, {'addr': '0x61...a095', 'name': ['sETH55', 'WETH45'], 'Fee': 0.02}]
Wasted $9971 on [{'addr': '0x57...0fbe', 'name': ['DAI50', 'USDC50'], 'Fee': 0.05}, {'addr': '0x2b...2b4a', 'name': ['DAI50', 'USDC50'], 'Fee': 0.05}]
Wasted $7102199 on [{'addr': '0xa2...bd95', 'name': ['WBTC49', 'cETH49', 'COMP2'], 'Fee': 0.15}, {'addr': '0x7a...ae25', 'name': ['WBTC49', 'cETH49', 'COMP2'], 'Fee': 0.15}, {'addr': '0xab...3b3c', 'name': ['WBTC48', 'cETH50', 'COMP2'], 'Fee': 0.15}, {'addr': '0xc7...1803', 'name': ['WBTC49', 'cETH49', 'COMP2'], 'Fee': 0.15}, {'addr': '0x7c...cb71', 'name': ['WBTC50', 'cETH48', 'COMP2'], 'Fee': 0.15}]
Wasted $409419 on [{'addr': '0xca...c597', 'name': ['cUSDC50', 'cUSDT50'], 'Fee': 0.05}, {'addr': '0x01...6efd', 'name': ['cUSDC50', 'cUSDT50'], 'Fee': 0.05}, {'addr': '0xa1...a19e', 'name': ['cUSDC50', 'cUSDT50'], 'Fee': 0.01}]
Wasted $325043 on [{'addr': '0xc8...307d', 'name': ['PNK50', 'WETH50'], 'Fee': 0.1}, {'addr': '0x77...2148', 'name': ['PNK55', 'WETH45'], 'Fee': 0.15}]
Wasted $559616 on [{'addr': '0x94...3b79', 'name': ['cDAI50', 'cUSDT50'], 'Fee': 0.05}, {'addr': '0x4d...cc9f', 'name': ['cDAI50', 'cUSDT50'], 'Fee': 0.1}, {'addr': '0xb8...53ea', 'name': ['cDAI50', 'cUSDT50'], 'Fee': 0.01}]
Wasted $279894 on [{'addr': '0xcd...0ccd', 'name': ['TUSD50', 'USDC50'], 'Fee': 0.05}, {'addr': '0x62...3fe7', 'name': ['TUSD50', 'USDC50'], 'Fee': 0.09}]
Wasted $297578 on [{'addr': '0x59...0138', 'name': ['cUSDC50', 'cDAI50'], 'Fee': 0.05}, {'addr': '0x62...4a01', 'name': ['cUSDC50', 'cDAI50'], 'Fee': 0.05}]
Wasted $106921 on [{'addr': '0xc3...0e57', 'name': ['NMR80', 'WETH20'], 'Fee': 0.3}, {'addr': '0x87...c2e7', 'name': ['NMR75', 'WETH25'], 'Fee': 0.25}]
Wasted $9343 on [{'addr': '0x57...0a94', 'name': ['MKR50', 'WETH50'], 'Fee': 0.14}, {'addr': '0xd3...4afe', 'name': ['MKR50', 'WETH50'], 'Fee': 0.15}]
Wasted $97484 on [{'addr': '0x01...4c0d', 'name': ['GRID90', 'WETH10'], 'Fee': 0.25}, {'addr': '0x99...c061', 'name': ['GRID95', 'WETH5'], 'Fee': 0.2}]
Wasted $27127 on [{'addr': '0x80...fc36', 'name': ['aTUSD16', 'aSUSD16', 'aBUSD16', 'aUSDT16', 'LEND2', 'aUSDC16', 'aDAI16'], 'Fee': 0.0}, {'addr': '0x2f...3d7c', 'name': ['aTUSD16', 'aSUSD16', 'aBUSD16', 'aUSDT16', 'aUSDC16', 'aDAI16'], 'Fee': 0.01}]
Wasted $5391 on [{'addr': '0x82...8b34', 'name': ['WETH50', 'MFT50'], 'Fee': 0.1}, {'addr': '0x03...d490', 'name': ['WETH50', 'MFT50'], 'Fee': 0.1}]
Wasted $48758 on [{'addr': '0xe1...3221', 'name': ['TRB97', 'USDC2'], 'Fee': 0.09}, {'addr': '0xb1...81da', 'name': ['TRB97', 'USDC2'], 'Fee': 0.09}]
Wasted $9812124 total

```

# Discuss:

1. Other paths forward.
2. Things I missed.
3. What `FEE_DIFF` value would be appropriate?
4. What `ALC_DIFF` value would be appropriate?
5. What would be an appropriate factor penalty to apply to penalized pools?

---

<div class="post-metadata">

**Author:** ![5325235235235](https://avatars.discourse-cdn.com/v4/letter/5/6bbea6/32.png) [@5325235235235](https://forum.balancer.fi/u/5325235235235)\
**Post date:** [July 18, 2020, 9:27am UTC](https://forum.balancer.fi/t/wasted-liqudity/106/2 "2020-07-18T09:27:14Z")

</div>

Great proposal! I don’t have a better suggestion how to handle it.

My suggestions:  
FEE\_DIFF \<= 4  
ALC\_DIFF \<= 4  
Penalty = 50% of the BAL reward

---

<div class="post-metadata">

**Author:** ![JesusPerez\_Crypto\_Pl](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.balancer.fi/jesusperez_crypto_pl/32/22_2.png) [@JesusPerez\_Crypto\_Pl](https://forum.balancer.fi/u/JesusPerez_Crypto_Pl)\
**Post date:** [July 18, 2020, 5:45pm UTC](https://forum.balancer.fi/t/wasted-liqudity/106/3 "2020-07-18T17:45:05Z")

</div>

Really great proposal. In order to be effective, probably it will need some UX changes in order to advise when you create a new pool that there are some similar ones and that your pool will be penalized.

Other important issue is for private pools, where probably they need to be private even there are other publics that are similar. That proposal will penalize private management.

---

<div class="post-metadata">

**Author:** ![monet-supply](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.balancer.fi/monet-supply/32/102_2.png) [@monet-supply](https://forum.balancer.fi/u/monet-supply)\
**Post date:** [July 18, 2020, 7:04pm UTC](https://forum.balancer.fi/t/wasted-liqudity/106/4 "2020-07-18T19:04:14Z")

</div>

Is the liquidity from multiple similar pools really wasted? Or does it just make the router less gas efficient?

---

<div class="post-metadata">

**Author:** ![justwanttoknowathing](https://avatars.discourse-cdn.com/v4/letter/j/6f9a4e/32.png) [@justwanttoknowathing](https://forum.balancer.fi/u/justwanttoknowathing)\
**Post date:** [July 18, 2020, 7:13pm UTC](https://forum.balancer.fi/t/wasted-liqudity/106/5 "2020-07-18T19:13:43Z")

</div>

Less gas efficient, the SOR will route through multiple pools if doing so presents the best price. Do consider that “less gass efficient”, in the current gas environment, frequently means the liquidity is effectively wasted.

One of the primary things Balancer competes with other on-chain AMMs about is gas efficiency.

---

<div class="post-metadata">

**Author:** ![DefiAlert](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.balancer.fi/defialert/32/135_2.png) [@DefiAlert](https://forum.balancer.fi/u/DefiAlert)\
**Post date:** [August 2, 2020, 7:12am UTC](https://forum.balancer.fi/t/wasted-liqudity/106/6 "2020-08-02T07:12:44Z")

</div>

Signed up precisely to comment on this proposal.  
From a psychological point two many choices harm new users experience when choosing the right pool. Eventually the user might just leave for a competitor.
