liquity / ChickenBond

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

LUSD Chicken Bonds: gas costs & questions #10

Open RickGriff opened 2 years ago

RickGriff commented 2 years ago

External contracts

Yearn LUSD vault: https://yearn.finance/#/vault/0x378cb52b00F9D0921cb46dFc099CFf73b42419dC

Yearn Curve-LUSD vault: https://etherscan.io/address/0x5fA5B62c8AF877CB37031e0a3B2f34A78e3C56A6

Curve 3pool: https://etherscan.io/address/0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA

B.Protocol BAMM: https://etherscan.io/address/0x0d3AbAA7E088C2c82f54B2f47613DA438ea8C598

Estimated gas costs

See gas costs sheet: https://docs.google.com/spreadsheets/d/1oui7k1IrJ2Z8JxAo-SQCQ18ydVl3qMCa_c5T0oUqrrw/edit?usp=sharing

Chicken Bonds system actions Sub-actions Gas cost Total gas cost
Bond (to SP, Yearn) CB state updates 50000 260000
LUSD.approve 50000
LUSD.transferFrom 50000
YearnLUSD.deposit 110000
Bond (to SP, BProtocol) CB state updates 50000 455000
LUSD.approve 50000
LUSD.transferFrom 50000
BProtocol.deposit 305000
Bond (to Curve) CB state updates 50000 450000
LUSD.approve 50000
LUSD.transferFrom 50000
Curve.add_liquidity 190000
YearnCurveLUSD.deposit 110000
Chicken Out (from SP, Yearn) CB state updates 50000 515000
YearnLUSD.withdraw 415000
LUSD.transfer 50000
Chicken Out (from SP, BProtocol) CB state updates 50000 530000
BProtocol.withdraw 430000
LUSD.transfer 50000
Chicken Out (from Curve) CB state updates 50000 1010000
YearnCurveLUSD.withdraw 740000
Curve.remove_liquidity 170000
LUSD.transfer 50000
Chicken up (to SP, Yearn) CB state updates 50000 360000
LUSD.approve 50000
LUSD.transferFrom 50000
YearnLUSD.deposit 110000
sLUSD.mint 50000
sLUSD.transfer 50000
Chicken up (to SP, BProtocol) CB state updates 50000 555000
LUSD.approve 50000
LUSD.transferFrom 50000
BProtocol.deposit 305000
sLUSD.mint 50000
sLUSD.transfer 50000
Chicken up (to Curve) CB state updates 50000 490000
LUSD.approve 50000
LUSD.transferFrom 50000
Curve.add_liquidity 190000
YearnCurveLUSD.deposit 50000
sLUSD.mint 50000
sLUSD.transfer 50000
Redeem CB state updates 50000 1525000
sLUSD.transfer 50000
sLUSD.burn 50000
YearnLUSD.withdraw 415000
YearnCurveLUSD.withdraw 740000
Curve.remove_liquidity 170000
LUSD.transfer 50000
Shift LUSD: SP -> Curve CB state updates 50000 765000
YearnLUSD.withdraw 415000
Curve.add_liquidity 190000
YearnCurveLUSD.deposit 110000
Shift LUSD: Curve -> SP CB state updates 50000 1070000
YearnCurveLUSD.withdraw 740000
Curve.remove_liquidity 170000
YearnLUSD.deposit 110000
Chicken-in CB state updates 50000 150000
sLUSD.mint 50000
sLUSD.transfer 50000

Need to exchange tokens

  1. Staking yields: LUSD auto-compounds (LUSD earns LQTY, LQTY swapped for LUSD) in Yearn LUSD vault. No swap required.

  2. Funding the Curve AMM: Single-sided deposit when LUSD > 1 (however, performs a swap under the hood).

  3. AMM yields: LUSD-3CRV auto-compounds. The LP token earns CRV/CVX, which are swapped back to LP token by the Yearn LUSD-Curve vault. No swap required.

  4. Fund a sLUSD/LUSD pool: Incentivize 3rd parties through charging a small fee on chicken ins/ups and pay it as rewards for the pool. Or, take a cut of LUSD and sLUSD when bonders chicken in/up. No swap required.

Potential Manipulations/Exploits

LUSD price could be manipulated (with a lot of capital). This could be done with the following aims:

Potential attack vector: sandwiching the Curve LP deposit, i.e. action 2).

Profitability: likely very low, as it’s very hard to move the price by a significant %. And deposits to Curve will be small compared to the size of the pool.

TODO - check realistic numbers for attacks.

Potential mitigation: we can use a TWAP based on Chainlink LUSD-USD or Curve spot price information to make manipulation more costly.

Shifting LUSD between SP <> Curve: Are there any manipulations possible in the LUSD shifting functionality? It's a public function that can take minimum token quantity params as protection against price slippage / manipulation. However, sandwich attacks would extract value from the system not the caller. An attacker could sandwich their own LUSD shift with trades, and extract value from the system. Again, check profitability numbers.

POL

All POL is acquired, and none is permanent (since redemptions draw from both the SP and the Curve pool)

Further questions

Do we need to siphon off permanent liquidity, given that the primary goal is LUSD price stabilization (rather than acquiring POL)?

Should chicken-outs pull from the original pool the bonder's deposit was sent to, or rather pull from the pool that helps the protocol most, based on LUSD price?

Could redemptions pull from the pool that most helps the LUSD price?

Could redemptions send 3crv (rather than LUSD) from the Curve pool when LUSD trades at > 1?

Could chicken-outs send 3crv (rather than LUSD)?

Price feedback control: Will bonding happen when we most need it, i.e. when LUSD > 1? Can we incentivize that?

Economic incentives

Will this system be attractive enough LUSD holders? Will the implied sLUSD yield be greater than the naked Stability Pool yield? One one hand the overall average yield is lower (due to using a mix of Curve and Stability Pool), but the yield per sLUSD is also amplified due to open bonds. Possible solution: launch with SP deposits only, and start making Curve deposits later.

Is there always a premium, as in LQTY Chicken Bonds? Given DEX liquidity is subject to redemptions, the premium seems to depend purely on the ratio of pending LUSD to acquired LUSD.

cvalkan commented 2 years ago

Thank you very much for the thorough analysis @RickGriff!

It's surprising that BProtocol.deposit is almost 3x as expensive as YearnLUSD.deposit.

Or, take a cut of LUSD and sLUSD when bonders chicken in/up. No swap required.

Although no swap is required, depositing the two tokens to an AMM like Uniswap could still be vulnerable to price manipulation attacks, couldn't it?

All POL is acquired, and none is permanent (since redemptions draw from both the SP and the Curve pool)

If we charge redemption fees and keep them separate, we could have at least some permanent POL contributing to the price premium.

Do we need to siphon off permanent liquidity, given that the primary goal is LUSD price stabilization (rather than acquiring POL)?

While I don't see acquiring permanent POL as a goal in and by itself, it would be good to know how long the acquired liquidity would last, i.e. when people would start redeeming.

Should chicken-outs pull from the original pool the bonder's deposit was sent to, or rather pull from the pool that helps the protocol most, based on LUSD price?

Would that mean that the bonder could get back nominally more/less than the deposited amount, or that he could get back e.g. USDC instead of LUSD?

In general, I expect chicken-out's to be rare and redemptions to (hopefully) only happen in the far future, so I'm not sure how much we should optimize for those cases.

Is there always a premium, as in LQTY Chicken Bonds? Given DEX liquidity is subject to redemptions, the premium seems to depend purely on the ratio of pending LUSD to acquired LUSD.

Yes, unless we could build up some premium through redemption fees.

Price feedback control: Will bonding happen when we most need it, i.e. when LUSD > 1? Can we incentivize that?

Not sure about this. In particular, if we launch with SP deposits only, bonding may even result in a higher LUSD price in the short term. Perhaps we should look at this as a mid-term or long-term solution than a quick peg fix.