liquity / ChickenBond

GNU General Public License v3.0
33 stars 5 forks source link

Toll #12

Open cvalkan opened 2 years ago

cvalkan commented 2 years ago

Toll: questions and directions

Problem statement

Chicken Bonds aim to build up permanent DEX liquidity over time. In order to achieve that, the system needs to divert a portion of the LQTY (the "toll") from its treasury to an AMM, while ensuring that bonds remain profitable (which may also affect the sLQTY payout and the top-up needed in case of a chicken-up). This is difficult as long as the system is oblivious to the current market price of sLQTY. A static fee may turn out to be too low or too high.

Assuming that the price premium will change over time (probably with a tendency to drop), it would make sense to dynamically adjust the toll based on the premium, i.e. charge more when the gains are high and vice versa. To that end, we either need an oracle or a good approximation for the sLQTY/LQTY price. Given that at least initially the sLQTY/LQTY liquidity will be low, the price could be manipulated fairly easily. Using a TWAP may help, but cannot prevent manipulation completely. A longer TWAP period means a more secure, but also more outdated price feed.

The fair price defined as the reserve ratio is hard to manipulate, as long as bonders want to artificially reduce it before they chicken in/up (to reduce the toll), which is only possible if they can make other bonders chicken in/up or out. On the other hand, no matter how we define the fair price, it will remain a rough approximation and may not accurately reflect the market price. So, the toll may again end up too low or too high, and in the worst case make bonding unprofitable so that the system gets stuck.

In the following, we analyze potential directions and possibilities.

Basis for calculating the toll

The toll is basically a percentage rate applied to a base amount, which can be defined in different ways:

Basis Pros Cons
Initial bond simple late chicken-ups don't contribute more to the permanent DEX liquidity; users may have an incentive to exploit this by staying bonded for a long time
Resulting bond (incl. top-up) late chicken-ups contribute more to the permanent DEX liquidity; can be combined with PID and individual tolls bonding may become unprofitable; bonder may need to provide LP tokens for chickening up (unless we use Bancor v3)
Net profit efficient and fair difficult to determine/estimate the sLQTY price; manipulation risks

Toll as a percentage of the initial bond

By determining the toll based on the initial bond (without the top-up), the system may not be able to acquire as much DEX liquidity compared to its acquired LQTY reserve, since the top-up may become much larger than the initial bond amount if users tend to chicken up late.

However, it's a relatively straightforward approach and by taking the reserve ratio into account for the toll rate, it could even allow to hide the toll from the user by effectively merging it with the payout cap.

Toll rate

If the toll is applied to the net gain (payout_in_LQTY - resulting_bond), the rate could be a fixed percentage between 0% and 100%, e.g. 50%, ensuring that the profits are shared between the bonders and the protocol. Note however, that indirectly, the permanent DEX liquidity held by the protocol will also increase the premium, which in turn increases the net gains and the bonding APR. So, it can be seen as a win-win.

If the toll is applied to the initial or the resulting bond, things become more complicated. While in the first case, the system may miss out on the opportunity to build up enough liquidity, appyling the rate to the resulting bond (incl. topup) could make bonding unprofitable if premium = market_price - redemption value < 100% / (100% - toll_rate) - 100%.

PID controller

To mitigate these issues, we could apply a PID-controller to adjust the toll rate. One way would be to increase the toll upon chicken-in and chicken-up events and decrease it upon chicken-outs, the rationale being that chicken-ins/ups imply positive net gains, while chicken-outs can be a signal that bonding is not attractive enough. To make sure that the system can never get stuck, the toll rate could also be subject to an exponential decay over time.

The impact of a chicken-out/in/up event on the current toll rate could be weighted by the relative size of the bond in question (compared to all outstanding bonds) as well as its age. The earlier somebody chickens in or up, the more we can increase the toll rate.

A more sophisticated approach could be to leverage the fair price as an additional source of information and use the effective premium (as pointed out by @danielattilasimon) as a target. We thus want to ensure that (100% + premium) * (100% - toll_rate) - 100% > threshold by adjusting toll_rate.

Individual toll rates

Instead of applying the same toll to every bonder, we could differentiate and let the market decide. One way of doing would be to let the user set a toll rate at the beginning. The higher the toll, the steeper the accrual curve, allowing the user to optimize for the highest APR based on the current and the expected future premium. Ideally, the system ensures that setting a non-0 toll is attractive regardless of the current premium. In other words, if the premium is the same when the user chickens in/up, he would be better off than a simultaneous bonder that doesn't pay any toll.

Assuming that we would apply the individual toll to the resulting bond (after top-up) and use a linear sLQTY accrual curve, we could determine the minting rate such that it becomes very high for toll rate close to 100%. Users that choose a high toll rate may break even soon, but would need to provide a very large top up, a large part of which would become permanent DEX liquidity.

Another approach would be to take the age of the bond into account: the toll rate applied to the resulting bond could decrease over time, e.g. by starting at 100% and halving every day, while the sLQTY is linearly accruing.

bingen commented 2 years ago

The fair price defined as the reserve ratio is hard to manipulate, as long as bonders want to artificially reduce it before they chicken in/up (to reduce the toll), which is only possible if they can make other bonders chicken in/up or out.

If the fair price was good enough, this would be an interesting path. Some comments about it:

bingen commented 2 years ago

if premium = market_price - redemption value < 100% / (100% - toll_rate) - 100%

What’s the rationale for this? The way I see it, we want to check if:

bond * (1 - toll_rate) * market_price / redemption_value < bond

Simplifying and re-arranging:

1 - toll_rate < redemption_value / market_price
bingen commented 2 years ago

the permanent DEX liquidity held by the protocol will also increase the premium, which in turn increases the net gains and the bonding APR. So, it can be seen as a win-win.

That’s an interesting angle, although it would depend on the revenue generated by the AMM.

cvalkan commented 2 years ago

bond * (1 - toll_rate) * market_price / redemption_value < bond

Sorry, you're right. The premium must be defined as a fraction market_price / redemption_value rather than a difference.

bingen commented 2 years ago

I think this needs to be redefined:

If the toll is applied to the net gain (payout_in_LQTY - resulting_bond), the rate could be a fixed percentage between 0% and 100%, e.g. 50%

Let’s say bond amount is 100 LQTY, backing ratio is 5x, so 20 sLQTY can be claimed, and the toll rate is 50%. If the market price was 16 (quite reasonable), then net gain would be 20*16 - 100 = 220 and therefore the toll would be 110 LQTY, which is impossible for a bond of 100 LQTY (letting chicken ups aside to simplify).

bingen commented 2 years ago

I tried to convert the toll on the net gain to a toll on the bond amount:

net_gain = bond_amount * (market_price / redemption_value - 1)

We want a reduced_bond_amount such that:

reduced_bond_amount * market_price / redemption_value - bond_amount = net_gain * (1 - fixed_toll_rate)

And rearranging, we get:

reduced_bond_amount = bond_amount * redemption_price / market_price * [(market_price / redemption_value - 1)(1 - fixed_toll_rate) + 1]

And therefore the equivalent toll_rate on the bond amount would be:

1 - redemption_price / market_price * [(market_price / redemption_value - 1)(1 - fixed_toll_rate) + 1]

To be more precise, redemption_value should be the maximum between redemption_value and 1 / (issuance_rate * bond_time).

It would be the orange line here: https://www.desmos.com/calculator/qaeyicbaur

cvalkan commented 2 years ago

Thank you for the clarification and the formulae @bingen. My definition of the toll was ill-defined. Here's a spreadsheet where I derived the same result as Bingen, just not as elegantly ;)

bingen commented 2 years ago

The equivalent formula above can be further simplified to:

fixed_toll_rate * (1 - redemption_value / market_price)
bingen commented 2 years ago

As pointed out by @danielattilasimon , the formula above is static for the chicken in point, assuming it’s always when reaching the cap. To account for any possible accrued sLQTY value we need to modify it: The accrued value at any time is bond_amount * issued_proportion

net_gain = bond_amount * (issued_proportion * market_price - 1)

We want a reduced_bond_amount such that:

reduced_bond_amount * issued_proportion * market_price - bond_amount = net_gain * (1 - fixed_toll_rate)

And rearranging, we get:

reduced_bond_amount = bond_amount * [1 + fixed_toll_rate * (1 - 1/(issued_proportion * market_price)]

And therefore the equivalent toll_rate on the bond amount would be:

fixed_toll_rate * (1 - 1/(issued_proportion * market_price)

As this can become negative for small accrued amount, this formula should be capped at zero lower bound.

bingen commented 2 years ago

There was still a mistake where extra bonded amount was not taken into account. The final formula, applied on the final bond amount (after chickening up if it’s the case), would be:

Screenshot_20220208_175711

bingen commented 2 years ago

Where: Screenshot_20220208_130729

bingen commented 2 years ago

I like the approach of not having toll at all, but allowing users to provide LP tokens along the bonds to speed up their sLQTY issuance rate. Some issues with this approach:

bingen commented 2 years ago

Another issue could be that the boost is not successful enough, so the system doesn’t build too much liquidity, which is the main purpose.

Providing the LP at the end instead of on bonding reminds me of chicken up, where users provide extra funds in order to maximize gains. So I guess we could tie the LP tokens to chicken ups, forcing that a certain amount is provided as LP tokens.

Maybe we could even completely replace chicken ups by this new version where the extra amount is all LP tokens.

bingen commented 2 years ago

Maybe we could even completely replace chicken ups by this new version where the extra amount is all LP tokens.

As @cvalkan pointed out, this would break the backing ratio invariant if the unless the extra amount is limited to an equivalent of the toll.