Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toll #12

Open
cvalkan opened this issue Feb 2, 2022 · 14 comments
Open

Toll #12

cvalkan opened this issue Feb 2, 2022 · 14 comments

Comments

@cvalkan
Copy link
Contributor

cvalkan commented Feb 2, 2022

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
Copy link
Contributor

bingen commented Feb 3, 2022

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:

  • We should try to make it “path independent”, i.e., so that it’s the same to chicken in all at once and doing it in small consecutive batches.
  • It may have a divergent effect: if market price is below fair price, people won’t chicken in to avoid a higher toll, keeping the premium and therefore the fair price high; but if the market price is higher, then people would chicken in to benefit from low toll, reducing the premium and so the fair price even more.

@bingen
Copy link
Contributor

bingen commented Feb 3, 2022

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
Copy link
Contributor

bingen commented Feb 3, 2022

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
Copy link
Contributor Author

cvalkan commented Feb 3, 2022

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
Copy link
Contributor

bingen commented Feb 3, 2022

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
Copy link
Contributor

bingen commented Feb 4, 2022

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
Copy link
Contributor Author

cvalkan commented Feb 4, 2022

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
Copy link
Contributor

bingen commented Feb 8, 2022

The equivalent formula above can be further simplified to:

fixed_toll_rate * (1 - redemption_value / market_price)

@bingen
Copy link
Contributor

bingen commented Feb 8, 2022

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
Copy link
Contributor

bingen commented Feb 8, 2022

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
Copy link
Contributor

bingen commented Feb 8, 2022

Where:
Screenshot_20220208_130729

@bingen
Copy link
Contributor

bingen commented Feb 11, 2022

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:

  • Would LP tokens be kept in the pending bonds bucket, so if users finally chicken out they can recover them too and not lose money? Another option would be that they provide LP tokens when they chicken in/up
  • How to value LP tokens and prevent sandwich attacks
  • The issuance boost should be dynamic too, because of this:

Assuming that the price premium will change over time (probably with a tendency to drop),

@bingen
Copy link
Contributor

bingen commented Feb 11, 2022

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
Copy link
Contributor

bingen commented Feb 14, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants