-
Notifications
You must be signed in to change notification settings - Fork 15
Description
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:
- The genesis cryptoswap invariant amm contracts:
a. tricrypto2 (genesis)
b. twocrypto (genesis) - TricryptoNGWETH (1st gen)
- TwocryptoNG (second gen)
- 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:
- Replace Bubble sort with dumb sorting
- Bespoke cube root algorithm that costs 2000 gas on average. Implemented in Snekmate as well.
- Replace expensive geometric mean with simple geometric mean
- Use unsafe math operations wherever it is safe to do so. Old implementation -> new implementation with explanation for why we can do unsafe maths
- Replace newton_y for mathematically verified analytical solution with fallback to newton method for edge cases.
- 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.
- 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):
- Native token transfers
- Gulping of tokens (i.e. when the
self.balances
can be updated with a read ofcoin.balanceOf(self)
). - exchange_extended, which is exchanging after calling an external callback first).
- Admin fees collected in LP tokens.
- exposed claim_admin_fees
- 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:
- An xcp oracle to measure the amount of liquidity in the pool
- fees are collected in individual tokens and not lp tokens.
- Claiming individual tokens means LP token supply does not go up
- stricter conditions to claiming fees
a. claim sparingly
b. do not claim if virtual price goes below 1e18 - 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 theself._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
- 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.
- 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