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

Cryptoswap Third Gen #10

Open
14 tasks
bout3fiddy opened this issue Mar 6, 2024 · 2 comments
Open
14 tasks

Cryptoswap Third Gen #10

bout3fiddy opened this issue Mar 6, 2024 · 2 comments
Assignees
Labels
feature New feature or request

Comments

@bout3fiddy
Copy link
Collaborator

bout3fiddy commented Mar 6, 2024

Background

TricryptoNGWETH is the first optimised implementation of the old 3-coin cryptoswap AMM, allowing native token transfers. Its immediate upgrade (almost a year after its launch) removes some of the features and adds new ones.

The different implementations of Curve's CryptoSwap invariant AMM are noted in the following:

  1. The genesis cryptoswap invariant amm contracts:
    a. tricrypto2 (genesis)
    b. twocrypto (genesis)
  2. TricryptoNGWETH (1st gen)
  3. TwocryptoNG (second gen)
  4. TricryptoNG (second gen)

There are significant improvements from the genesis cryptoswap invariant AMM contract to the 1st gen (NG, or next-gen). Gas costs are reduced by half between the genesis and the first gen implementations. This was a labour of love, requiring development work in the compiler, dev tools (titanoboa was built to build tricryptong), coordination with etherscan, coordination with math researchers to optimise math in tricrypto, come up with better cube roots, auditors coming up with their optimisations etc. The optimisations are listed in the following:

  1. Replace Bubble sort with dumb sorting
  2. Bespoke cube root algorithm that costs 2000 gas on average. Implemented in Snekmate as well.
  3. Replace expensive geometric mean with simple geometric mean
  4. Use unsafe math operations wherever it is safe to do so. Old implementation -> new implementation with explanation for why we can do unsafe maths
  5. Replace newton_y for mathematically verified analytical solution with fallback to newton method for edge cases.
  6. Bespoke and very cheap calculation of partial derivatives of x w.r.t y, which allows the calculation of state prices. This was a contribution from Taynan Richards of ChainSecurity, which replaced the old and initially proposed version.
  7. Introduce Blueprint contracts!. This allowed factory deployed contracts to have immutables, since blueprint contracts are not like minimal proxies where immutables are not possible whatsoever. The verification pipeline of blueprint-deployed contracts still needs to be fixed. Still, when it was first deployed, it was only possible to verify the contract when Etherscan added features to read the first few bytes of the bytecode and classify the contract as a blueprint.

The implementation of state prices allowed the creation of very good oracles that power today's curve stablecoin. State prices, as opposed to last traded prices (the widely prevalent industry standard), significantly reduce the impact of price manipulation.

Cryptoswap (like everything Curve has) is an ongoing process of improvement. The features added in the second iteration of NG are simply features that come out of a natural progression of improving contracts after user feedback, experiences with speaking to auditors, etc. No known vulnerabilities in the first NG implementation prompted the second iteration of cryptoswap NG contracts.

Some of the features removed from the first gen (in the second-gen) are (not an exhaustive list):

  1. Native token transfers
  2. Gulping of tokens (i.e. when the self.balances can be updated with a read of coin.balanceOf(self)).
  3. exchange_extended, which is exchanging after calling an external callback first).
  4. Admin fees collected in LP tokens.
  5. exposed claim_admin_fees
  6. commit-apply scheme for parameters. New version applies parameters simply which is quicker to do (in one tx after governance approves).

The second-gen adds several new features including:

  1. An xcp oracle to measure the amount of liquidity in the pool
  2. fees are collected in individual tokens and not lp tokens.
  3. Claiming individual tokens means LP token supply does not go up
  4. stricter conditions to claiming fees
    a. claim sparingly
    b. do not claim if virtual price goes below 1e18
  5. exchange_received: swap tokens donated to the pool.The advantage of the new implementation is that if tokens in the pool are rebasing, there is no self.balances[i] = coins[i].balanceOf(self) in the self._claim_admin_fees() method like the old contract does

With that in mind, there are new features and more improvements that Cryptoswap contracts could accommodate.

Improvements Suggested

1. Rebasing token support

The second-gen cryptoswap NG contracts do not gulp rebases: if the amm contract holds rebasing tokens, the rebases are not absorbed by the pool contract and are simply available as: rebase_balance[i] = coins[i].balanceOf(self) - self.balances[i]. These could be recovered by the LPs somehow and added to their LP token share. This is something to consider: can we add support for pairs like stETH <> USDM where both tokens in the pool are rebasing and are very tightly pegged to their underlying collateral's value (at least historically as of writing this feature)?

2. Boost

Cryptoswap invariant AMMs take half the earned profits to rebalance liquidity closer to the exponential moving average prices. This means, if the pool had some form of capability to accept donations to inflate its profits, it could absorb these donated profits to rebalance and deepen liquidity significantly. This is even more effective in pools where the tokens do not have significant volatility but are not volatile pairs (e.g., USD <> EUR forex markets, which are generally very deep).

The ability to donate was discontinued in the second generation since the removal of the gulp.

The idea would be to
a. Donate to the pool contract safely and not manipulate prices in any direction
b. call tweak_price
c. Donated profits should not go into user positions, and only be used for amm rebalancing.

This is quite tricky to achieve but increases flexibility and utility of these AMM contracts.

Additional considerations

  1. Admin fees can be made to be dynamic such that the dao only earns fees when volatility is high and earn nothing when volatility is low: this can be parametrised in such a way that the percentage of admin fees depends on the distance of fee from the lowest fee to the highest fee.
  2. rebalances can only come from donated funds for boosts, and optionally from a part of earned revenue by the pool: this can be parametrised in a way such that the amount of earned revenue that can be spent by the pool for rebalancing be parametrised. normally take 0% of earn fees such that LPs earn everything. and let the dao set which percentage should go for rebalancing.

Security considerations

  • donations must not impact spot prices or price oracles
  • users must not profit from donations
  • admin must not profit from donations
  • totalysupply of lp tokens cannot go up from donations
  • virtual price cannot go up from donations

Task List

  • Add boost
  • Audit
  • deploy implementations to factories across all chains.
  • curve-api to track the implementation
  • curve-js to allow deploying rebasing and boost supported implementation
  • curve-js to onboard the new interface so it can be displayed in the frontend
  • curve-frontend to onboard the new implementation in pool deployment
  • curve-frontend to onboard pool pages for the new implementation.

Nice to have

  • Add rebasing token support
@bout3fiddy bout3fiddy added the feature New feature or request label Mar 6, 2024
@AlbertoCentonze
Copy link
Contributor

AlbertoCentonze commented Mar 8, 2024

My rationale for not reintroducing rebase support is:

  • The amount of work that it might require and the complexity it will add to the contracts is not worth it compared to the size of the pools using it.
  • I'm not sure that the feature is adding real value to Curve and the LPs. Any sane project with a rebasing token should have a wrapped non-rebasing version (like wstETH for stETH) that can be used in the pool in order not to lose the rebases.
  • Implementing such a functionality would encourage developers to go for this approach more. It's not just about Curve, rebases are a big foot gun in the industry and I think that it is dangerous to "endorse" them.
  • If we want to give users the illusion that their swapping the rebasing token without wrapping/unwrapping it this can be achieved within the router or using a "zap" contract that would unwrap the token when buying and wrap it when selling. I think in some cases it might even end up being cheaper than adding the rebase logic in the pool. The other advantage of this approach is that only pools that need the wrap/unwrap part would pass through this "zap" contract while the other pools would keep a leaner/cheaper logic.

Very excited about the boost, a couple of questions:

  • I'm not sure boost is a good name given that we already have a boost concept for the gauges. What about rebalancing donations?
  • Is it more effective to fully subsidize the rebalancing cost so that LPs earn more fees or should we add these rebalancing donations on top of them?

@bout3fiddy
Copy link
Collaborator Author

Implementing such a functionality would encourage developers to go for this approach more. It's not just about Curve, rebases are a big foot gun in the industry and I think that it is dangerous to "endorse" them.

Curve has been a long standing supporter of rebasing markets and it's a pedigree of ours to have rebasing token support in our AMMs. But: I don't disagree. I think rebasing tokens are a small market, and we could revisit them in the future if security around the composability of rebasing tokens improves.

I'm not sure boost is a good name given that we already have a boost concept for the gauges. What about rebalancing donations?

Naming rights go to whoever writes the algorithm. We can discuss re-iterate internally.

Is it more effective to fully subsidize the rebalancing cost so that LPs earn more fees or should we add these rebalancing donations on top of them?

I think we should parameterise them: so a parameter that decides how much of earned revenue from swaps goes into the 'rebalancing funds' which is then used to rebalance?

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

No branches or pull requests

2 participants