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

Protocol Design #1

Open
norswap opened this issue Mar 5, 2022 · 13 comments
Open

Protocol Design #1

norswap opened this issue Mar 5, 2022 · 13 comments

Comments

@norswap
Copy link
Contributor

norswap commented Mar 5, 2022

Here's the MVP approach from the README:

Users can create an order, or can take the opposite side of an existing order. An order consist of the expiry date for contract and the order, contract "value" (i.e the collateral, and max amount to loose), if the position is long or short, and asset (ETH/ERC20).

Order matching is done inside the contract. For the MVP version all orders are 1:1, but in the future support for difference ratio based on market conditions would make sense (if the entire market is crashing going long should yield higher payout than going short).

Both user has to deposit the value of the contract as collateral. To make things a bit simpler, I think it makes sense to value all contracts in ETH. At the expiration of the payout is done based on changes in the underlying asset against ETH. We will use ChainLink for price history. Users can also never loose more than what they put up as collateral.

So this design has a few issues (entirely my fault, since I suggested it):

  • Taking the long position is less attractive than buying the real asset, because the max upside +100%.
  • Shorting is generally unattractive in crypto because of high volatility and the max profit while shorting is 100% while the max loss is unlimited. Some stopgaps can be taken to sweeten the pot, like letting the contract price fluctuate above the asset price, but that further reduces the upside of the long side.
  • The contract must be "settled" at some point (i.e. both sides paid according to the current asset price). This means that either we need expiry dates, which fragment liquidity, or you must allow for both party to break the contract at any time (not great).

But fear not, I have an alternative design that I'm super exicted about. It's based on a protocol-issued stablecoin (or at least pseudo-stable), which acts a bit like a poker chip (let's call it $C for the purpose of this explanation). To enter any position, a user has to enter it with $C.

So if an asset has price 100$, the long side must enter with 100 $C, and so does the short side. The protocol mints $C on demand in exchange for 1$. In exchange they receive one synthetic token. Imagine the asset is ETH, they would receive one $cfdETH (long) or one $scfdETH (short). In the contract, their $C would be locked in two distinct pools: the long pool and the short pool.

When an oracle update comes in, saying that the price of ETH increases 10%, then 10% of the $C locked on the short side is transferred to the long side. And vice-versa when the price decreases.

The synthetic assets give a claim to the underlying pool. So if there the total supply of $cfdETH is 100, and you own one, then you have a claim on 1% of the $C locked on the long side of the pool, which you can redeem at any time.

This works perfectly well when the long side and the short side are perfectly balanced (i.e. the same amount of $C locked on each side), but that's unlikely to be the case. First because of the long bias (although there could a short bias when the market dumps), and second because this equilibrium is constantly shifting.

Take the 10% ETH price increase as an example. It leaves the pool unbalanced at 110 $C vs 90 $C.

The solution is to mint $C out of thin air to make everybody whole. Of course, this is an inflation and stability concern, because we're now minting unbacked $C.

One thing we can do is to encourage users to naturally balance the pools. One way we can do that is to claim less than our fair share of the pool.

Let's take an extreme example. The price of ETH is 100$. There are 10 people on the long side, but only one person on the short side. We thus have a 1000/100 $C imbalance. The protocol has to "mint" 900 $C on the short side to make the pool balanced.
One way to conceptualize this is that the protocol takes the role of a normal user on the short side, excepted it gets all its $C for free. So in this case, it would get 9 $scfdETH.

Imagine the price goes down to 90$. The protocol would normally be entitled to a gain of 9*10 = 90$C. What if instead, we credited an disproportional amount of this gain to the lone shorter?

There's many formulas we could use to this, and figuring this out is future work, but for now let's assume the protocol only claims 30% of the gains. So it gains 9*0.3*10 = 27$C while the lone shorter gets 10 + 9*10*0.7 = 73 $C. More than 7x his "normal" 10$C payout!

The risk/reward imbalance should cause people to rush in to balance the pool until the "premium" (730% in the example above) is a fair risk premium for the risk of shorting. This should be especially true since there is a way to hedge and arbitrage: long the asset (possibly by buying it on another chain, but possibly on this protocol), short it on the protocol. If the asset goes up, you're neutral, but if the value goes down, then you're making more on the short side than you're losing on the long side. Risk-free profit!

So in practice, since the protocol backstops the value with newly minted $C, and assuming the presence of smart arbitrators, the pools should be pretty balanced, which minimizes the emission of new $C, which should remove the concern about runaway inflation.

There is still a concern about the stability of $C price: will it keep peg to 1$? How do you redeem your $C for other stables?

The basic idea is that as long as demand for $C exceeds supply (i.e. people redeeming), the price will remain a 1$ (it will never exceed 1$ since the protocol is willing to mint for 1$). If it ever goes in the other direction (which is inevitable over the lifetime of a project, then there is a risk of depeg).

My suggestion here would be to implement an "exit queue": anybody can queue their $C to be sold, and in this case, the protocol will use this pool of $C to supply to new users instead of minting new $C. (Note we can't use the protocol treasury for the same purpose, since some $C was minted out of thin air — the total $C supply is only partially backed.)

This can still be a big problem if the queue grows too much or too fast. I'd fix this via a protocol token (let's call it $CFD for now). If the queue grows beyond a certain threshold, people that own $C can mint $CFD at a small discount to the market price. This allows them to exit by acquiring the token at a discounted price (and potentially dumping it immediately). Because this creates an arbitrage, the effect should be that arbitrageurs should start acquiring $C in order to purchase discounted $CFD and make a profit. So this should move the queue along.

(Alternatively, and this is probably a better approach, we could avoid minting $CFD, and just offering a discount on a $C-$CFD AMM purchase. This would have the stabilizing benefit that if the exit queue gets too full, demand for $CFD will be stimulated. It goes without saying that this all requires more thinking / modelling.)

This means that $CFD will go down in value when the TVL decreases. However, $CFD holders benefit when the TVL increases: when the queue is empty, the protocol mints $C in exchanged for other stablecoins, and those go straight to the protocol's treasury. And the treasury essentially provides a floor on the $CFD price.

In addition, the protocol should probably take some small fees (0.3%?), probably when entering and exiting synthetic positions.

Addendum: we also need to think about MEV — in particular, a user should only be allowed to effectively enter a pool following an oracle update. Otherwise, users could front-run oracle updates, piling into a position when they already know that the price will increase, and exit immediately after.

Addendum 2: the minting model means that the pools need to be permissioned — we can't allow an asset whose price could be too easily manipulated, because that creates an obvious attack to extract $C from the system. This is not too great: the initial idea was to enable to long/short ANY asset, and now we need to assess the reputability of the assets we allow. I think there are things to be done here, which is basically to create permissionless mini-copies of the protocol for specific assets (so they would have their $Cprime stable), and bridge them to the main one with something that can act as a breaker (e.g. an AMM pool that the deployer of the new asset supplies initial liquidity for). But that's FUTURE work.

Addendum 3: we can't really long/short ANY asset, because we're limited with things covered by oracles (Chainlink list here). In the future, it will be possible to read the L1 state from Optimism, so I think we'll be able to use that to get more price feeds and even things like Uniswap TWAMM, etc...

Would love feedback on this. Anybody to poke holes in the design?

@2xic
Copy link
Owner

2xic commented Mar 5, 2022

Good catch regarding the flaws in the design for the mvp 👍

Regarding the new design, I have a few questions, but will start with these 3:

Question 1

In the example of the 10 people going long, and one going short. Then the protocol would step in to stabilize the pools, but what would happen if the lone shorter exited his short ? Can the protocol be in a position alone ?
(It's more of an theoretical question, and I assume people would seize the opportunity to do an arbitrage so that the protocol would never be left in a position alone for too long. )

Question 2

In the example of the 10 people going long, and the lone shorter. The protocol has then minted 900 $c. If people start to naturally enter in on the short side, shouldn't we burn the tokens minted to have a more "natural" balance and limit inflation ?
Then the protocol does not have to mint more tokens on the long side because of the new liquidity on the short side. Or am I missing something here ?

Question 3

Example :
Current price of ETH is 100$. One user is long, and one user is short. So the long user bought one $cfdETH, and the short user bought one $scfdETH. Both pools will then have 100 $c locked up.

The price of ETH drops by 10%, so the balance of the pools will be adjusted. 10% is moved from the long pool inside the short pool (balance of long pool : 90 and short pool 110), and the protocol will mint 20 $c and put it into the long pool.

Then both user want to withdraw.

You mentioned the following :

The synthetic assets give a claim to the underlying pool. So if there the total supply of $cfdETH is 100, and you own one, then you have a claim on 1% of the $C locked on the long side of the pool, which you can redeem at any time.

So I do understand that the synthetic asset give claim to underlying pool, but I still don't fully understand how we know how much each user is entitled to after the mint.

So two questions here

  1. How do we know how much each user is entitled to after such a re-balance ?
  2. What happens to the newly minted 20 $c when a withdrawal happens ? Does it get burned, or does it go back to the protocol in some way ?

@norswap
Copy link
Contributor Author

norswap commented Mar 6, 2022

Excellent questions!

I'm afraid the answers ended up longer than the initial explanation 😅, but some very valuable thinking was made as a result.

In the example of the 10 people going long, and one going short. Then the protocol would step in to stabilize the pools, but what would happen if the lone shorter exited his short ? Can the protocol be in a position alone ?
(It's more of an theoretical question, and I assume people would seize the opportunity to do an arbitrage so that the protocol would never be left in a position alone for too long. )

Yes the protocol can go in alone. The only difference in this case is that it "takes" 100% of the gains instead of the reduced portion. The gains are taken when "exiting" the pool (which happens when a user enters). This ties in to your second question...

In the example of the 10 people going long, and the lone shorter. The protocol has then minted 900 $c. If people start to naturally enter in on the short side, shouldn't we burn the tokens minted to have a more "natural" balance and limit inflation ?
Then the protocol does not have to mint more tokens on the long side because of the new liquidity on the short side. Or am I missing something here ?

Yes, the protocol should burn the $C token when it exits a pool because a real user enters. More accurately, it should burn the principal, but send the profit to the treasury. So imagine it entered with 900 $C, owning 9 $scfdETH out of 10. If the price goes down to 90$, it gains 27 $C (0.3 * 9 * 10 $C).

If another users wants to enter the short side, buying one $scfdETH at 110 $C, then the protocol must exit 110 $C worth. Note that at this point, the short side of the pool is worth 1100 $C (1000 $C base + 10% profit), so 1 $cfdETH is worth 1100/10 = 110 $C!

This is a mistake I made above where I conflated the $cfdETH and $scfdETH price with the asset price. This only works in simple scenarios like when the long side is more popular (protocol is short) and strictly increasing in value!

In reality, the value of $cfdETH and $scfdETH is fixed by their ownership of the underlying pool. So if the price goes up, the size of the short pool decreases, which brings the $scfdETH value down (and then the protocol enters at this reduced price to bring balance to the pool size).

Not covered above when I said "the protocol must exit 110 $C worth" is how profit redistribution works. Honestly, I hadn't really thought about the "mechanism" for it before. But I'll propose something as an answer to your next question!

  1. How do we know how much each user is entitled to after such a re-balance ?

I'll take the same example on the long side, because I find it slightly more intuitive, but the same principle applies equally on the short side.

In the 1-1 long/short scenario things are easy: the initial balance is 100-100, price goes up, so it becomes 110-90 and the protocol atomically steps in to make that 110-110. A single user has the whole ownership of the long side, while on the short side, one user own 90 while the protocol owns 90. If the long user withdraw, he'll get 110, if the short user withdraws, he'll get 90.

You can add more users without fundamentally changing this scenario. If 2 users have 1 $cfdETH on the long side, and two users have 1 $scfdETH on the short side, then you have 200-200 then 220-220 balance, and a long user (owning half the pool) still can withdraw 110 $C (as expected: the price of the underlying went up 10% so you get a 10% profit).

What if a new long user enters at 110$? Now we have 220-110 (then 220-220 with protocol intervention). Both long users own 1 $cfdETH, so half the pool, and can withdraw at that point for 110 $C (which is a 10% gain for the old user, and the initial stake for the new user). So adding new users when the price goes up and down preserves all the good properties we care about.

What if the protocol had to chip in on the long side? Say we went to 110-220, so the protocol takes a 110 $C stake for 1 $cfdETH on the long side. If the long user exits immediately, he still gets 110 $C.

Let's imagine the price goes up to 120$ and that short pool is 220 $C. Then the balance will go to 200-200. Not 240-240! The protocol never chips in on both side, so because the short pool was reduced to 200 $C, the protocol must remove 40 $C from the long side (which is now 220 + 20 profit). If we ignore profit redistribution, this should 0.33333... $cfdETH == 40 $C at a price of 120 $C.

The redistribution is actually tricky (because profits depends on the entry price for the protocol, and the protocol could have many such entry prices as it keeps minting on the unpopular side). But below is a (new!) idea on how this could work:

When you transfer 20 $C from the short to the long side, also adjust the $cfdETH balances. So at that point 20 $C is 1/6 $cfdETH. The "unincentivized" stake of the protocol is half that, so 1/12 $cfdETH. If we use the formula where the protocol only takes 30% profit, then we can split this as 3/120 + 7/120 $cfdETH. So we can transfer 7/120 $cfdETH from the protocol to a "user profit account", and 3/120 $cfdETH to a "protocol profit account".

Only then do we exit the protocol in the normal way: so exiting 40 $C = 0.333... $cfdETH. This exit should be split equally between the protocol and the protocol profit account. Those are respectively 110/120 $cfdETH and 3/120 $cfdETH at this point for a total of 113/120 $cfdETH, worth 113 $C (initial stake + 3/10 of profit).

The protocol share is thus (110/120) / (113/120) * 40 = 38.94 $C = 0.3245 $cfdETH, while the profocol profit share is (3/120) / (113/120) * 40 = 1.06 $C = 0.00885 $cfdETH.

Then, we burn the protocol part, but send the protocol profit part to the treasury.

Now, the long user wants to exit. The pool composition is 1.68435 $cfdETH split between:

  • 1 for the user
  • 7/120 for the user profit account
  • 0.5921 for the protocol (110/120 - 0.3245)
  • 0.01615 for the protocol profit account (3/120 - 0.00885)

The user is entitled to: his share of the pool, so (1/1.68435) * 200 ~= 120 $C (if you're rerunning the calculation, you'll see the importance of rounding here ^^).

But the user is enttitled also to his share of the profit account. Which is his share of (total pool - protocol part). Since he is the only user, he his entitled to 100% of the profit account, so an additional 7/120 * 120$C = 7 $C.

On the flip side, if there is a loss, multiple things are possible. We could transfer the amount corresponding to the loss back from the profit account to the protocol. This is probably a bad idea, since we only make 30% on the upside. We could transfer 30% of the loss back to the protocol. Or we could transfer nothing back, which increases protocol profit at the cost of more inflation.

Note that the protocol never needs to exit a pool side on a loss, because the $C tokens get transfered to the other side. This doesn't mean the protocol is pure profit, quite the opposite: if tokens are transferred to the other side (which by definition does not include the pool), there are tokens that will be lost if the users on that side exit (i.e. realized inflation).

  1. What happens to the newly minted 20 $c when a withdrawal happens ? Does it get burned, or does it go back to the protocol in some way ?

Kind of answered above, but to consolidate: it depends where these 20 $C go. If the price goes against the side the protocol is on, they might go to the other side, where the users can withdraw it. If the price goes in the direction of the protocol, the protocol will withdraw funds as the pools naturally balance. In this case we burn the protocol part but keep the profit part.

In general, the minted $C are not really "traceable" as they enter a pool that is then manipulated proportionally. The way to think about the money supply is about there being minting events and burning events. The protocol as outlined above will never burns more than it mints (because in the best case we just burn as much $C as we put in), but could mint considerably more than it burns. The only way we could change that is by burning the protocol "trading profits", but this probably will not change the tides (there is probably a reason that the pools are unbalanced! the protocol is bound to take the unpopular side).

@2xic
Copy link
Owner

2xic commented Mar 6, 2022

Thanks for the detailed response!

I think I understand the core parts of how you envision the protocol, and I will try to code it up!

There will probably come up some new questions / edge cases as I start coding, so I can post them here as they come up.

@norswap
Copy link
Contributor Author

norswap commented Apr 3, 2022

Two new ideas which are mostly "mods" to the existing design. They could become "pool parameters".

1. Collateralized short positions

New idea that could improve the tokenomics (by limiting $C inflation): specify a collateral ratio for the short size. i.e. to purchase a short token when the price is 100$ and the collateral ratio is 2, you'd have to pay $200. If the pools are "balanced" (under these new conditions, e.g. 1000$ on the long side and 2000$ on the short side), this would enable the price to double without the need for the protocol to step in to rebalance the pools.

This collateral overhead is similar to how shorting works for many assets today: you loan the token you want to short against stablecoins, then repay it when the price goes down. Here too, you have a loan ratio (which will generally be 30-70% depending on the volatility of the asset: you can borrow 30-70% of the value of your collateral). A loan ratio of 50% is a collateral ratio of 2.

Our protocol would still be better than loan protocols because a loan protocol charges interest for the loan! We could also be a bit more aggressive on the collateral ratio (or accept more volatile assets) because the protocol can step in if we fall below a 1:1 pool ratio.

2. Limited upside long

We could modify some long pools to have "limited upside", e.g. not more than 100% gains compared to entry price. This against limits $C inflation. In exchange for accepting this limiting upside, we would modify the oracle price for the pool by offering a discount. We could determine this discount algorithmically: if the long side is much bigger than the short side, we would reduce the discount.

@2xic
Copy link
Owner

2xic commented Apr 5, 2022

@norswap Been thinking about the withdrawal logic, and reread your post a few times, but I think there is something I'm missing (or misunderstanding).

Below is my interpretation, feel free to correct me.


Withdrawal step by step

Just to make the example as simple as possible, Alice is long, and Bob is short they both entered with the same amount of $c, and there has been 0 price movement. In other words the deposited $c is what they should have the rights to.

  1. Alice want's to exit her entire long position.
  2. Alice will deposit all her longEthCfd into the contract.
  3. Alice will not received the $c just yet, but we put the fact that Alice has the rights to x * $c in a queue
    ($x = currentLongRedeemPrice * aliceLongCfdTokenDeposit).
  4. Alice waits for the queue, or do a swap with the AMM to get a CFD token.

Non AMM (i.e waiting for the queue)

So in theory Alice could now do an AMM against the protocol, and receive CFD for a small discount for the $c that is in the queue, but let's ignore that case for now.

The way I understand it, she will not receive the $c that was queued before her position has been replaced by another user (or multiple users). For instance Carol that enters the same position (long with the same $c amount), which would result in Alice getting her $c. Carol could of could of course enter her position at a different entry price.

This far all makes sense, but correct me if I has misunderstood something this far.

AMM

What if Alice choose to instead do trade with the AMM ? This is the part I'm a bit more confused about.

When I hear AMM, I automatically think of Uniswap, but I don't think having a Uniswap like AMM design is what you had in mind. For instance because of the liquidity requirement of Uniswap that would set the price ratio of the tokens, I guess we could have some re-balancing logic to reflect the price movement and liquidity, but it doesn't sound like this is what you had in mind.

This part I'm more confused about, and would love some expanding on.


If you know about a blog post, or paper explaining the AMM design you had in mind, feel free to just link me that 😃️ (I know you have a lot to do, so I don't want to force you to write an detailed response 😅️)

@norswap
Copy link
Contributor Author

norswap commented Apr 6, 2022

Hey! So the way I envisonned it was a bit different, there are two steps in the simple case.

  1. You cash out your $longEthCfd for currentLongRedeemPrice * aliceLongCfdTokenDeposit $C.
  2. If you want to swap the $C for USDC, you enter your $C into the withdrawal queue.

If, at some point, the queue becomes too large (algorithm TBD), the protocol opens the possibility of minting new $CFD at a discount to market price (probably given by a TWAP on a $CFD-$C or $CFD-$USDC pool).

And so if the queue is already too large when Alice wants to trade her $C to $USDC, she could instead choose to mint $CFD at a discount (and maybe dump it, assuming a $CFD-$USDC pool exists — not entirely sure it should!).

BUT

I've been thinking about this recently, and I'm not sure this system is the best one.

One concern the queueing system is tricky, and open to cheesing. For instance, someone could repeatedly exit 1 $C, hence creating a lot of entries in the queue, which means buying $C would become very expensive in terms of gas, as we have to iterate through the queue.

We also need to find a good algorithm for queue length.

Increasingly, I'm starting to think we need to route everything through a custom AMM that we control.

The reason I want it to be custom is to implement special features that would help in maintaining the $C-$USDC peg. I've got quite a few ideas on this that I need to write up.

MVP

I think for a MVP, we should simply have an AMM in the repo (unless there's an obvious alternative, let's go with Uni v2 fork at first for extreme simplicity). We should be able to get a TWAP of this AMM, and we should open the possibility of minting $CFD when the TWAP price is below a configurable threshold. The discount should also be configurable.

So essentially the ERC-20 $CFD contract would have a depegMint(uint amount) function, which checks that TWAP($C) < DEPEG_LIMIT and if so lets you mint $CFD for amount $C at a price of TWAP($CFD) * CFD_DEPEG_DISCOUNT, where both DEPEG_LIMIT (e.g. 0.95) and CFD_DEPEG_DISCOUNT (e.g. also 0.95) are configurable.

Open Question (on depeg minting)

Your question spurred me to think about this depeg minting mechanism a bit more, and there a lot of things to consider.

Below is a stream-of-thought of me thinking thinking through potential attacks, incentives, etc.

We might want to add a limit to the amount that can be minted in this way to avoid economic attacks. Probably the limit should be that the total value of minted $CFD (at market price? discounted price?) should be less than totalSupply($C) - marketCap($C) (this is the "loss" due to depeg: when 1 $C == 1 $USDC, this difference is 0).

Because it's interesting, example of attacks:

  • Just mint a stupid amount of $CFD, though you would need a large amount of $C to do so. Annoyingly, using the TWAP means you could actually buy it in the same block and it wouldn't affect the TWAP... probably we need a check with the current price to see if the peg hasn't already recovered! We still want to use the TWAP to trigger the discount, because otherwise someone could artificially lower the price (by selling a lot of $C) to mint a bunch of discounted $CFD, then buy back the dumped $C to benefit from an artificial discount.

  • A bit more complex, buy discounted $CFD, sell it for more $C than you acquired it for, rebuy $CFD, rinse & repeat. This is limited because at some point the AMM $CFD price gets to the point of the discount, and there is no further profit from running this loop. However:

    • This lets a single person arb the whole discount, annoying.
    • Much worse: it doesn't actually do anything for the peg! No $C has been purchased (or just a small amount).
    • This might be a good reason why we might want a $CFD-$USDC pool and not $CFD-$C. If people sell their discounted $CFD for $C, this leads to more $C in circulation, which doesn't solve the problem. On the other hand, having $CFD being sellable only for $C could also incentivize people to hold $CFD until the peg recovers.
    • Actually I think the solution is to lock the bough $CFD for a certain period (e.g. 5 days) so it can't be sold immediately. That means that people who buy $CFD need to have conviction in the asset (since they'll be exposed to its price), this avoids arbers that just want to buy and dump.
      • I have ideas for $CFD tokenomics that involves locking for longer periods of time, so we could just sell locked $CFD instead.

Yet another solution is to let people buy $CFD for $USDC, then use all that $USDC to purchase $C in the AMM and burn the bought $C. This avoids all the above problems with putting more $C in circulation. (Of course in this case the discount must take into account the current depeg in the price paid.) This is a pretty interesting solution — it avoids the need to put a limit on minting, and avoids the issue with increasing the amount of $C in circulation with people sell $CFD. There are two things I don't love about this:

  • It doesn't reward people who have a lot of stables in $C (as you need $USDC to enter this trade), which would be something we want to encourage.
  • If people buy discounted $CFD in $USDC then sell it for $C, you still have an increasing $C supply, which I don't love.
    • I think we really want to lock the sold $CFD in any case.

FINALLY, this wouldn't even be the ony peg recovery mechanism I have in mind. I think we should have a $C vault where people can earn yield on their $C, and this yield would be earned by running arbitrage on our own synth pools + maintaining the $C peg (buy $C for USDC when below peg, sell it when over peg). But I think this is for a further development milestone :D

So, synthesizing all the above, here's a candidate design (feel free to criticize):

  • $CFD liquidity is in a $CFD-$C pool
  • We have the depegMint
    • This enables purchasing $CFD with $C at a discount, just like outlined above in the MVP section
    • We also offer a builtin-in depegMintUSDC that takes USDC, does a $C AMM buy, then uses that to purchase $CFD with $C.
    • The purchase $CFD is locked (for the MVP we can put it in an escrow account that can be accessed after 5 days — later we'd sell some form of locked $CFD where the locked nature accrues some benefits like cashflows).
    • Implement the mint limit outlined above as a safeguard (i.e. total value minted less than totalSupply($C) - marketCap($C)).
      • Keep track of the amount of $CFD minted since the peg was last reached, and compute this check dynamically each time the depegMint function is called.

@2xic
Copy link
Owner

2xic commented Apr 6, 2022

So If I understand correctly,

1

Users can always cash out $longEthCfd for currentLongRedeemPrice * aliceLongCfdTokenDeposit $C, and this withdrawal will be "instant" (there is no exit queue with this method).

This means that the protocol will then do a standard rebalance of the pools as they will be become unbalanced with this approach. (Right ? )

The way I see it, it's okay that the protocol will mint in this case (because of the rebalance), because if many people do this option and the $c depegs then people will start to use option 2 as a way to arbitrage the price and that returns it back to normal.

2

From a technical perspective, it sounds like dropping the exit queue is a good idea, and just have a custom AMM.

I will think about what you wrote about the AMM design for a few more days and then get back to you here (want to make sure I have digested what you wrote properly).


Again, thanks for always writing such detailed responses. I do appreciate it a lot because it helps better understand what you envision. After all, you have been thinking about the nuances of this project longer than I have know about it, so it really helps when you posts such detailed responses 😄

@norswap
Copy link
Contributor Author

norswap commented Apr 6, 2022

This means that the protocol will then do a standard rebalance of the pools as they will be become unbalanced with this approach. (Right ? )

That's correct!

The way I see it, it's okay that the protocol will mint in this case (because of the rebalance), because if many people do this option and the $c depegs

To be precise: minting by itself does not cause a depeg, depeg happen because more people exit than join (and we have to worry about that because there is not enough $USDC to back all the $C 1-1 — and that's indeed because we mint).

Again, thanks for always writing such detailed responses. I do appreciate it a lot because it helps better understand what you envision. After all, you have been thinking about the nuances of this project longer than I have know about it, so it really helps when you posts such detailed responses 😄

Well mostly thank you for reading and working on my idea! 🙏

@2xic
Copy link
Owner

2xic commented Apr 9, 2022

To be precise: minting by itself does not cause a depeg, depeg happen because more people exit than join (and we have to worry about that because there is not enough $USDC to back all the $C 1-1 — and that's indeed because we mint).

Yep, so the challenge is that we need to keep the pools balanced, and therefore we sometimes have to mint. This means we will have some $C not backed by any $USDC, and therefore we need some way to stabilize the $C price if it goes unstable. One of your proposed method to solve this is AMM $C-$CFD.

(Please correct me, if you disagree with anything in the last paragraph).

AMM

So, I have been thinking some about the AMM approach for stabilizing $C, and here are some structured (but a bit raw) thoughts.

Birdseye-view of the implementation

Assuming we go with forking Uniswap 2, we can basically just spin up a pool $C-$CFD pool. All variables for computing the TWAP is exposed in UniswapV2Pair.sol. We can just add a function to the $CFD token contract for minting on depeg that will get the data from the Uniswap pair pool.

I assume all other aspect of Uniswap works as before. I.e any users can be liquidity provider, and they will also earn fees by doing so (0.3 %). To prevent arbitrage, they will also have incentives to add / remove $c or $CFD from the pool to keep the price at the market price. Photosynthesis (our protocol) will not touch the pools with any it's liquidity, all liquidity is provided by the users (correct me if I misunderstood this part).

Users will be able to do a call to the depegMint or depegMintUSDC function in the $CFD contract, and mint $CFD at a discount if TWAP($C) < DEPEG_LIMIT by depositing $C/$USDC. I assume this is the only way to $CFD to enter the market to keep supply / demand stable.

All bought $CFD will be locked for 5 days. This is done to prevent the minting of $CFD to further destabilize the price.

Concerns

I think $CFD and $C will be correlated in price in the situations where $C losses it's peg. Which means having a $CFD-$C pool might not work as a way to stabilize $C. What worries me a bit by having $CFD and $C in a "closed economy" is that we don't have enough external force keeping the $C stable. Basically us trying to stabilize a protocol token with another protocol token within the same protocol is what worries me.

What you mention about allowing users to buy $CFD with $USDC is very interesting, and I think this makes a lot of sense given that it's an external assets that helps to stabilize. However, this probably requires us to have some good use-cases for the CFD token (i.e why should people buy the CFD?).

  • This brings up another challenge however, how to reward people with $C not in active use. So I will be thinking a bit more about this idea...

There should be some good incentives to have $CFD since people won't do a timelock if it results in them having a "net-loss", and they won't exchange $USDC for $CFD unless it brings some value.

Use cases for $CFD

One thing we could do is say that everyone holding $CFD will be entitled to parts of the fees earned by the protocol propositional to how many $CFD tokens one own, or that $CFD owner vote on what to do with the protocol profits.

We could maybe also put some of the treasury into a lending protocol to earn some yield to make the $USDC backing better match the market cap of $C.


These discussions makes me think about tokenomics like never before! I have probably missed something, and or might have some flaws in my thoughts. Feel free to criticize / correct anything of what I have written.

@norswap
Copy link
Contributor Author

norswap commented Apr 16, 2022

Sorry, for the delay, here are some answers.

Photosynthesis (our protocol) will not touch the pools with any it's liquidity, all liquidity is provided by the users (correct me if I misunderstood this part).

I think pragmatically speaking we'd want to pre-supply liquidity to that pool. We culd do it with some kind of DAO that receives the profits of an initial token sale, however.

I think $CFD and $C will be correlated in price in the situations where $C losses it's peg. Which means having a $CFD-$C pool might not work as a way to stabilize $C. What worries me a bit by having $CFD and $C in a "closed economy" is that we don't have enough external force keeping the $C stable. Basically us trying to stabilize a protocol token with another protocol token within the same protocol is what worries me.

I share the same concern, at least partially. The problem is that on top of the price diminishing because we're selling $CFD, people would also sell $CFD because of the depeg event (though small depegs should be a common occurrence, but let's assume a large depeg) and because they foresee the price going down.

A solution here would be to render $CFD illiquid for sellers. That's not really possible, but there are instruments we can use that behave similarly. I'll write about this below.

Finally, note that the minting part of this mechanism is that of "seigniorage shares" and is notably used by Terra to maintain UST peg. However the difference is that in seigniorage shares you also buyback the token ($CFD) when the price is above peg, in order to mint more stables and bring the price back down to peg. So you'd be a little bit more incentivized to buy the token when it is cheap, since you knew you'd benefit when the price went over peg next time.

One thing we could do is say that everyone holding $CFD will be entitled to parts of the fees earned by the protocol propositional to how many $CFD tokens one own, or that $CFD owner vote on what to do with the protocol profits.

That was my plan for $CFD, but it's still a lesser incentive than benefitting from buyback when over peg (or even better, both things together).

@norswap
Copy link
Contributor Author

norswap commented Apr 16, 2022

Alright, new design that I've been thinking about. This one has no more $CFD minting, but instead has a few "staking pools" that are used to maintain the peg.

The first pool is "the twin pool". This is a pool with two sides, one with $C and one with $USDC. The idea is that when price is under peg, $USDC is used to purchase $C in the AMM and bring the price back up. The purchased $C is immediately staked in the $C side. Vice-versa, when price is over peg, the $C is used to purchase $USDC, to bring the price of $C back down. The purchase $USDC is immediately staked in the $USDC side.

This is textbook arbitrage if you expect the peg to hold. To enforce the pool to benefit, we'd have a modified AMM implementation with "right to first arbitrage". Basically after any trade, we'd check if the price is out of peg, and if so we'd use money from the pool to bring it back to peg.

There is a concern with how large the $C side of the pool is allowed to be, and how fast people can enter it, which I'll explain after explaining the next pool level.

The next pool (which I tentatively call "the glucose pool", thanks for the name idea 😉) is pure $USDC. People in there are the one that ultimately pay a price when the token is under peg, but make profits when the token is over peg.

This pool is triggered when one side of the twin pool empties. e.g. if we go under peg and exhaust all the $USDC in that side of the twin pools, we'd use the $USDC in the glucose pool instead, to do essentially the same. Glucose pool members ($GLUCOSE holder?) have a claim to portion of the glucose pool, and so when this happens they lose money.

On the flip side, if the $C part of the pool empties, then the protocol mints new $C, and buys $USDC with it, which is deposited in the glucose pool (hence making $GLUCOSE holder money).

That might sound good, but there are two issues:

  1. People have an incentive to leave/enter the twin pools when things looks bad/good.
    Normally, the twin pools handle small depeg with no issues. But say that for whatever reason, people know there is something bad coming, some kind of panic. Then the $USDC side could be emptied, leaving the glucose pool member on the hook (they should not be allowed to leave quickly, see 2). Conversely, when above peg, it's tempting to add a lot of $C to that side of the pool, get the $USDC winnings, and repurchasing the $C slowly if desired. This canibalizes all of the glucose pool members profit.
    • My solution here would be to let people pile as much $USDC as they want, but require a 7 days warmup period for the $C to enter the pool. This avoids this kind of opportunistic "just-in-time" liquidity provisioning for the $C part of the twin pool. We could also constraint the $C part of the twin pool to be closed for new deposits as long as it's under the size of the $USDC part. Maybe we can require them to supply to same amount to both sides in this case instead?
  2. The glucose pool should be illiquid — if you enter there, you will profit or lose on supply / demand shock for $C. We should make sure you'll bear the cost of a contraction in supply if you'll also benefit for increasing supply. The solution here is simple: simple require a X days period (leaning towards 30 or 90) before processing withdrawals from the pool.
    • Note that $GLUCOSE would represent ownership of the pool, but would not be a token we would set up for trading. Other people could start trading it however — it's price would derive from the underlying pool $USDC on the downside based on expectations of future $C supply contraction. This is only possible because of the withdraw delay (otherwise $GLUCOSE should always be worth exactly what you can get from withdrawing). It's also why it can't theoretically trade for more than the share in the pool: if you think the $C supply will expand, you can just deposit $USDC in the pool without delays.

I considered and discarded a seigniorage share model instead of this glucose pool, basically because of the concern outlined in the previous comment: when you want to mint & sell $CFD is also when other people are selling it, hence accelerating the price fall.

Finally, I think we need to couple all of this with even better incentive for balanced protocol pools ($longCfdETH/$shortCfdETH). I'm thinking of "arbitrage pools" where we'd draw $C from arbitrageurs to balance the pools and emit an event indicating we did so. The arbitrageurs would listen to the event and know when it reads them that they need to hedge for a certain amount. We'd reward the arbitrageur with some amount of our token (not $GLUCOSE, but the other token that receives fee cashflow — $SUN?).

@2xic
Copy link
Owner

2xic commented May 3, 2022

Sorry for my late reply, had some work waiting for me after coming home from Devconnect (was nice seeing you btw!). Hopefully back with regular commits on this project by next week.

Finally, note that the minting part of this mechanism is that of "seigniorage shares" and is notably used by Terra to maintain UST peg. However the difference is that in seigniorage shares you also buyback the token ($CFD) when the price is above peg, in order to mint more stables and bring the price back down to peg. So you'd be a little bit more incentivized to buy the token when it is cheap, since you knew you'd benefit when the price went over peg next time.

You might already be familiar with it, but sharing it just in case - there has been some criticism against this coupon-coin design which Terra/UST also resembles. There are articles that can explain it better than me , i.e https://mirror.xyz/damsondao.eth/OVeBrmrfcWm7uKLlA2Q4W1XTVkFU3cMKfNWhgf7mQuM , but the TLDR; these stablecoins only work as long as the demand for them are constantly increasing. When the demand dries up then the price fall is usually amplified because of the coins are associated together.

That being said, the article also lays out methods Terra/UST has used to try to escape the coupon coins curse. i.e by creating a ecosystem and making it possible to spend, save, and invest UST (in addition to the new Bitcoin reserve etc). This is also relevant for $c as an additional step to make it easier for it to maintain the $USDC peg.

Alright, new design that I've been thinking about. This one has no more $CFD minting, but instead has a few "staking pools" that are used to maintain the peg.

Regarding the new design I’m generally more optimistic ( 😉 ) on this one give since it's built on $USDC instead of a protocol token for holding the peg.

Correct me if I have misunderstood something here, but the main incentives for the liquidity providers is trying to benefit if the stable-coin loosing it’s peg. I also assume they make get some shares of the fees taken by the protocol, or do they only make money based on the actions within the pools (i.e the fee for the AMM in the Twin pool) ?

Trying to get a picture of the incentives of being a liquidity provider here instead of (for instance) Uniswap. One concern is the withdraw / deposit delays added, but if we are able to provide additional value that makes those delays “worth it” we should be good. I guess this could be some native token that we payout on certain intervals, it seems like the easiest way for us to be able to provide additional value for being a liquidity provider. Will think some more about this, but feel free to post any ideas you have regarding how to incentives liquidity!

Finally, I think we need to couple all of this with even better incentive for balanced protocol pools ($longCfdETH/$shortCfdETH).

I defiantly agree on this, the less the protocol has to mint the better!

@norswap
Copy link
Contributor Author

norswap commented May 10, 2022

Oh boy, I really picked the right evening to answer this, with UST/LUNA going down in a big flaming fire 🔥

I'm aware of the criticism. The main difference is that UST is unbacked excepted by LUNA (and then much more recently by BTC, but only for ~15% of the UST market cap). Here our token would be partially backed because every $C minted when over peg would be 100% backed — only $C minted when the protocol rebalances pools are unbacked.

That still can be pretty bad if partial = 20% backed or even maybe 50% backed (hard to know), hence the importance of minimizing mints.

One solution here would be to try eliminating mints altogether and running automated hedging strategy on behalf of users supplying funds (e.g. buy ETH, buy $shortETH, profit from rewards for holding $shortETH when pool is underweight on the short side + unwind the position if the short side becomes overweight). This is a strategy employed by people to capture the funding rate on perpetual protocol, for instance.

WIth that strategy though, the question is what happens if we don't have enough funds to rebalance the pools anymore.... One answer is go towards actual perpetuals, but the funding rate probably makes this less attractive to users (and it would require a full redesign, though that's the fun part lol). More reasonable: close the overweight side for new entrants when the hedging funds pool is close to being empty. Mint $C to cover the loss, but only as a last resort. Crank up the rewards for the hedging pool to attract more capital in there.

Correct me if I have misunderstood something here, but the main incentives for the liquidity providers is trying to benefit if the stable-coin loosing it’s peg. I also assume they make get some shares of the fees taken by the protocol, or do they only make money based on the actions within the pools (i.e the fee for the AMM in the Twin pool) ?

The twin pool are not traditional liquidity pools. You'd have a "normal AMM" that the protocol itself could seed from an initial sale. Other people could enter it, and there the incentive would indeed be the fees. We could add extra incentives if needed, but I think it's probably more interesting to have the protocol be the liquidity provider there.

The twin pools come in when the normal AMM depegs. When that happened, it would call into the twin pools to do a swap to (try to) restore the peg.

So say I'm a user and I'm trying to buy 10k $C and that causes the price of $C to be meaningful over 1$ (say > 1.01$). Then the pool would first use the $C part of the twin pool to swap $C for $USDC and bring the price back to 1$ before doing the user's swap. If the price is meaningfully less than 1$, we'd do the reverse (swap $USDC from the twin pool for $C).

The incentive is indeed to benefit from depegs (over peg for the $C part of the pool, under peg for the $USDC part — but since the proceeds are staked on the other side, you end up exposed to both). In both cases, you essentially buy the other stablecoin for less than 1:1 — so the total amount of $C + $USDC in the twin pools keeps growing.

Repository owner deleted a comment Feb 23, 2024
Repository owner deleted a comment Feb 23, 2024
Repository owner deleted a comment Feb 23, 2024
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

3 participants
@norswap @2xic and others