Thank you to Chanho Suh, my colleague at Curve Research, for the peer review
This Edition May 25th, 2023; 1st Edition Mar. 17, 2023
Abstract
We consolidate Curve's V1 and V2 whitepapers and elaborate on concepts introduced in the original papers' corresponding sections.
Introduction
Welcome! First things first: I assume that you have high school-level math knowledge, with only a little 1st-year university math required. You’ll also want to have a basic understanding of DeFi and DEXes. If you’ve completed at least a math-heavy Bachelor’s degree, I highly recommend you reason through the Curve V1 whitepaper (6 pages) and afterward the Curve V2 whitepaper (5 pages) on your own, only referring to this paper when you want more thorough explanation.
If this writeup’s length discourages you, read anyway: you may find that you’re the kind of twisted person who enjoys a challenge. If you aren’t eager to learn about Curve but are invested in StakeDAO, REDACTED, yearn, Convex, or Curve itself, you may be putting money in what you don’t understand. Not that I fault you for it; you’re just good at aping. Please view this as your chance to mitigate risk by knowing what Curve’s value proposition is. All journeys feel hard to start, but you often find that you were always capable. Again, refer to this paragraph’s first sentence for good measure.
Necessary DeFi and math concepts have been compiled in the Glossary. We go over the following terms: Automated Market Maker (AMM), Concentrated Liquidity, Derivative, Equilibrium, Exponential Moving Average (EMA) Oracle, Hypersurface, Impermanent Loss (IL), Invariant (Liquidity Equation, Bonding Curve), Mean-Reversion, Monotonic, and Newton’s Method.
If you’re using LLMs to summarize this paper, you’d need to cross-check the output, which might defeat the purpose of using the LLM.
Let’s first discuss where Curve began—Stableswap. Think “stable prices after swapping”.
Stableswap
As we’ve seen, exchanges like Uniswap V2 use the , or constant-product, invariant to maintain liquidity even if prices shift significantly. Before concentrated liquidity, however, stablecoins were facing price stability and liquidity issues; in addition, stablecoin LPs earned few fees. That’s why, in 2019, Curve founder Michael Egorov sought to build “Stableswap”, an efficient, stablecoin-oriented AMM with lower slippage than Uniswap at the time (V2).
The Constant-Price Invariant
Imagine a constant-price system. We can swap stablecoins -for- with no price impact. We generalize this behaviour for any number of tokens, giving us a “linear” constant-price invariant. For example, we get for two tokens. Let denote the balance of token deposited:
For any two stablecoins, the exchange rate between both tokens would be , equal to the derivative , where . However, we can’t maintain a price of exactly if the reserves of any of the tokens start to run out.
The Constant-Product Invariant
We generalize the constant-product equation for any number of tokens:
Figure 1: Stableswap (Blue) in Between Constant-Price and Uniswap Invariants (Curve)
Stableswap is a “middle ground” between having perfectly constant prices and having slippage in exchange for adaptable liquidity. In the figure above, the desired Stableswap invariant is “flat” when the reserves of X and Y are balanced, meaning the price remains constant at close to 1.0. If reserves go out of balance, there is still liquidity offered with slippage.
Figure 2: Price Slippage Under Uniswap and Stableswap (Curve)
As we swap more of one token for the other, both invariants experience considerable slippage due to providing liquidity while the pool is heavily imbalanced. However, as figure 2 above tells us, Stableswap's slippage outside of the 1.0 price zone, having a steeper slope, is initially worse than Uniswap's before it improves. Visually, the longer the straight line part in figure 3 below, the harder the graph has to curve under imbalance, which results in a wider depeg.
The Stableswap Invariant
Inspired by both graphs above, we want a “straight-line" constant-price part to have more influence when reserves are balanced, but as the portfolio becomes more imbalanced, we want the curved constant-product part to take over.
Assume we start a pool with stablecoins with equal balances in it. If and only if the pool is balanced, do the following two statements hold:
(Balanced Constant-Price Invariant)
(Balanced Constant-Product Invariant)
where the invariant is the total balance of the pool when all the coins’ prices are equal at $1. If each coin has equal reserves, each reserve is equal to the average amount , so the constant-product invariant is the product of multiplied by itself times.
But what happens when the reserves become imbalanced? That’s where we introduce an “amplification coefficient” parameter . A higher extends the range where Stableswap looks like the straight-line constant-price invariant above for longer. A lower means Stableswap looks more like the curved Uniswap invariant in figure 1 above.
Figure 3: Stableswap (Red) Approximating a Straight Line as Approaches and a Curve as Approaches (Balancer)
We say that our constant-price invariant that experiences close to zero slippage corresponds to having infinite leverage because it's like there's an infinite reserve of coins that keep replenishing the token balances after swaps such that there is no price impact. On the other hand, leverage gives us our regular constant-product invariant that experiences significant slippage but offers liquidity when there is imbalance.
Let (“chi”) denote the leverage we apply to our Stableswap invariant. As such, we want the constant-price invariant as and the constant-product invariant when . We add the Balanced Constant-Price and the Balanced Constant-Product Invariants to each other to reflect Stableswap’s two parts. We apply leverage to the constant-price part to help “flatten” the graph by multiplying by .
(Leveraged Invariant)
We multiply the constant-price term by to also get two terms with in them because we want to account for the fact that could be much larger than . As planned, if our leverage , , and we only have the constant-product term . In contrast, as , , and is very small in comparison since the number of stablecoins does not grow when grows, which makes the constant-price invariant more dominant.
However, this invariant relies on the fact that the reserves of each token are equal, and liquidity is only supported close to the ideal price of . We alter to make it dynamic: when the portfolio is perfectly balanced, is equal to the amplification coefficient ; however, when the portfolio becomes imbalanced, starts to fall off to .
(Dynamic Leverage Coefficient)
and cancel each other out when the token reserves are balanced, leaving only , but how do we know that this new decreases towards as the pool becomes imbalanced? When the pool is balanced, all token balances are the same, so .
Assuming you can swap stablecoins 1:1, say that a balanced pool is started with of token 1 and of token 2. If you deposit 5 of token 1 and take out 5 of token 2, we have that
In this case, , so . Clearly, for any , so here. We can mathematically describe imbalance using the ratio for any two tokens and : the closer is to 1, the more balanced the pool is, and the further away is from 1 towards either 0 or ∞, the less balanced the pool is.
Let’s plug some numbers. We have three scenarios where both token 1 and token 2 have starting balances of 20, 10, and 6; we deposit 5 of token 1 and take out 5 of token 2.
We see that as the imbalance represented by increased, got closer to 0 since grew relative to , so is working as intended. In fact, going to 0 implies that the slippage outside our invariant's flat region is at first faster than in Uniswap's, as Uniswap's doesn't reach 0 unless all deposits are removed from the pool.
We sub in into our leveraged invariant:
Divide both sides by , and then multiply both sides by , and we’re done:
(The Stableswap Invariant)
In the first term on the left-hand side of the equation, we got rid of and because they were working against our amplification coefficient that keeps prices constant. And there we have it. Our Stableswap invariant, using , maintains stable prices when reserves are reasonably balanced, otherwise providing liquidity under the constant-product curve with slippage proportional to .
During trades, we solve for the output amount net of a flat fee, and after deposits or withdrawals, we charge a small LP token rate. Existing LPs profit from both fees. Sharing a common result, swaps, deposits, and withdrawals all cause us to iteratively recalculate prices. However, swaps, ignoring the slight fee, mostly keep constant, while adding or removing liquidity have considerable impact on . Since governs liquidity depth, we need both higher and balanced to allow larger swaps without slippage.
Take the 4pool, composed of DAI, USDC, USDT, and Terra’s depegged UST, as a cautionary tale. On May 7, 2022, an $84.5M USDC swap and withdrawal imbalanced the share of UST to kick off UST’s then-1.5% depeg to $0.985. UST then went on to make up over 99% of remaining 4pool reserves, trading for ~$0.02-$0.03 as of the time of writing.
So to drive the point home, 's leverage comes with risk: the higher is, the faster slippage works once we exit the straight part of the curve. Imagine the market panics and values USDC/USDT at 0.90, but we value it at 1.0. If the pool then becomes heavily imbalanced but we increase , we're doubling down on mean-reversion around a 1:1 exchange rate. Given that arbitrageurs barely maintain a $1 price at the edge of the flat region, a pool with a higher —a longer flat part—requires greater LP deposits to reachieve balance. Who would cover the difference if there's no more easy arbitrage to commit?
Thus, when the peg rapidly slips and doesn't return, we might throw in the towel by decreasing , marking-to-market our assets to reflect loss. Our paper profit shifts accordingly with , so we've essentially made impermanent loss permanent. Thankfully, it then becomes easier for 1. the peg to recover, and 2. the pool to eventually balance, undoing part of the IL caused by imbalance, including reductions in .
Wow, that was a long ride. Don’t worry, we’re done with the math now.
Sike! We haven’t even touched upon Curve V2’s invariant, which includes non-stablecoin and non-pegged assets!
To enable greater liquidity, Curve V2 pools store volatile tokens which aren’t necessarily “pegged” to each other at a strict ratio like USDT, ETH, and WBTC, which compose the tricrypto2 pool.
We track a balances vector , where is the balance of token with different tokens in the pool.
We maintain a price scaling vector , where is token ’s market price relative to token ’s, with regardless of swapping activity. If we let denote the USD, then all other will track token 's price in USD, so if token starts at $50 and its price increases 10% afterwards, . V2's dynamic price scale thus differs from Stableswap's, where we almost always assume that all .
From the whitepaper, we’re given a way to convert "transformed balances” into “real balances” through a transformation :
(Real Balances)
Each transformed balance gets divided by to give the real balance , or the current amount of token in the pool.
(Transformed Balances)
We take a real balance and scale it by to give , the value of the token present denominated in token . All should be approximately equal for a pool in equilibrium, which means having roughly equal USD amounts of each token deposited since the USD is crypto’s de facto unit of account. For instance, each of the three tricrypto2 pool assets makes up a third of dollar-denominated liquidity, establishing equilibrium.
We represent our desired invariant as the hypersurface
After swaps, deposits and withdrawals, pools will resist causing massive price movements while aiming to periodically align the dollar value—or token 0 value—of respective token deposits to be equal. In addition, using implies there’s ~0 price deviation if you deposited or withdrew assets at a dollar-wise balanced ratio.
For consistency, say our transformed balances vector represents the equalized dollar-amount deposits of each token during pool balance. During and after the pool’s creation, let
We peg to the pool’s initial state where each token starts out with dollars’ worth deposited, so our pool knows how much each token is initially worth relative to the others. We want that for any value of
signifying that our current liquidity curve should barely shift after swaps if deposits remain constant and balanced. We see this price-preserving property in Stableswap thanks to its dynamic leverage coefficient . V2 redefines imbalance as having unequal dollar amounts of each token in between each price update. Every price "repeg" equalizes the dollar balances of each token, creating a new liquidity curve with a new, balanced equilibrium point.
The invariant is constant for a particular liquidity curve, being equal to the sum of all transformed deposits in a state of equilibrium. is the number of different tokens in the pool.
Since is expressed in terms of , finding a solution to the invariant above becomes trivial.
The Cryptoswap Invariant
It’s time to explicitly define our liquidity equation! We repurpose the Stableswap invariant:
(The Cryptoswap Invariant)
However, we slightly modify our leverage coefficient :
(Decaying Dynamic Leverage Coefficient)
If Stableswap is a combination of constant-price and constant-product invariants, then Cryptoswap is a combination of Stableswap and constant-product invariants. denotes how imbalanced the pool is, for becomes smaller relative to as the pool grows imbalanced. is our regular amplification coefficient. ("gamma") controls the length of flat zone, which is inverse to how tightly our part-Stableswap, part-constant product invariant hugs a purely constant-product curve that uses the same equilibrium point—more on that later.
If the reserves are balanced:
giving us our Stableswap invariant.
If the reserves are imbalanced:
causing our invariant to adopt constant-product behaviour with worse slippage than pure constant-product.
As becomes smaller relative to as the pool grows imbalanced, decreases as imbalance increases. Thus,
decreases due to having a bigger denominator. has a linear relationship with , so essentially has a square relationship with . Therefore, decreases by a square factor as decreases due to greater imbalance, since is a constant. Furthermore, drops off even faster.
Therefore, the “leverage” factor is more sensitive to reserve imbalances, causing a quicker exit from the stable price zone in Cryptoswap than in Stableswap. Cryptoswap compensates for the fact that it is working with assets more volatile than stablecoins.
The constant is also meant to help compensate for volatility: shortens our invariant's flat region in exchange for easing 's slippage outside of it. To visualize 's role, we might imagine Cryptoswap contained within a miniscule range between two constant-product invariants. When reserves become imbalanced from trading or LP volume, we repeg , which shifts our invariant while transforming its curvature. The rebalanced result lies inside the boundaries.
Figure 4: Cryptoswap (Orange) Given Room to Shift in Between Two Constant-Product Invariants (Dashed) While Approximating Stableswap (Blue) (Curve)
Thus, the smaller is— that is, the closer our imagined boundaries are—the smaller is, and the faster decreases, and the faster we emulate the constant-product invariant to provide liquidity. In this sense, a lower expresses that we give up on a stable more quickly so that our curve doesn't snap back to constant-product as hard. A lower diminishes IL by pacifying our post-flat region slippage whenever we fail to mean-revert to the current price scale.
Figure 5: Enabling Cryptoswap (Red) to Offer Stable Prices for a Volatile Asset for a Shorter Range Compared to Stableswap (Green) (Kurt Barry)
We'd then repeg the price scale, creating a new liquidity curve. We distinguish the two user activities that affect : swapping, and adding or removing liquidity. To change our liquidity curve, we solve the Cryptoswap equation for after swaps for token and for and after repegs, deposits, or withdrawals.
Solving the Invariant
We define Cryptoswap as and express the dynamic leverage coefficient as a function . After rearranging the terms to be on one side of an equation, we have
(Solvable Cryptoswap Form)
At regular intervals, we solve against either or using Newton's method. The "best" starting points for and are included below:
However, beware: isn’t monotonic, so it could “change direction”, thereby creating a potentially unlimited number of suboptimal solutions that would be gas-costly to calculate and store. Or, the curve could become flat at any point, causing Newton's method to fail to proceed.
According to Curve contributor Fiddy, Curve’s math functions usually require fewer than 10 Newton’s method iterations because they estimate optimal and . However, the number of iterations can vary widely, sometimes being as high as 24+. We find solutions that deviate from the previous iteration within only two decimal places (Curve’s Math contract, line 121), but if we can’t after 255 iterations, we give up to limit gas costs (lines 160 and 194).
With that in mind, we’re motivated to initialize and so that Newton’s method can reliably find solutions to , taking ~60k gas per or solved (line 102) not ~35k like the whitepaper states. For reference, that’s about three times the 21k gas base cost of sending someone ETH.
Computing D With Leverage
We solve for when repegs, deposits, and withdrawals occur, updating if a deposit or withdrawal is imbalanced dollar-wise. Our new is based on the rebalanced equilibrium point characterized by each updated . We illustrate solving for new below. You might need to zoom in.
Figure 6: Solving Against Using Newton’s Method, Given (Curve)
Starting from at the orange cross, we steadily iterate towards the solution, marking each step with a green dot. As we can see, we usually need three iterations at most to find a sufficiently precise answer, but we can end up taking many more steps, as shown in the bottom two graphs. While holding and constant, we start solving from the “best” :
, our maximum leverage. If current is balanced enough given , we can satisfy while our new invariant upholds the widest flat part possible. If not, we iteratively reduce and . The token vs. token vs. token … graph incrementally "unflattens", shortening its stable region, but adapting pure constant-product's gentler slippage at the edges.
Think of it this way: if we make an imbalanced deposit prevalued at $1M, we want our solved to be as close to 1M higher as possible after price slippage. We stop solving when converges, setting a rebalanced equilibrium point .
counts profit in V1 where , but when bounces around in V2, might not decrease to mark IL. Not a good sign. We'll come up with a precise profit measure in Quantification of a Repegging Loss below.
The above aside, we’ve tested and confirmed that this is safe for convergence.
Computing Without Leverage
As opposed to what affects , - swaps involve adding the user's token input to , calculating the exchange rate , solving for a new that keeps constant with , and outputting an amount of token net of a fee. We then feed the trade price to our oracle, which affects all down the line.
Again, we must navigate cautiously. If we didn’t initialize properly in Figure 7 below, we may have ended up crossing that “mountain”. In that case, we likely would've failed to find a solution after iterating too many times, marked by the red triangles. Otherwise, we could've found a suboptimal solution far away from the optimal marked by the purple arrows, which would incur excessive slippage.
Therefore, while holding constant, we want to begin solving from the "best" :
where because far outweighs .
We initially apply close to no leverage. In this sense, solving for is "opposite" to solving for . Keeping the same, . Therefore, starting from small , increases every iteration to bring up from the negatives to , reaching our swap-reduced solution . We correspondingly increment higher until the curvature fits our altered balance.
After you add token , dictates based on balance how much changes relative to . Even though stays mostly constant, our post-swap and alter where we are on the current curve. Generally, if the swap made all get closer to , the exchange rate stabilizes as we enter the flat part, and vice versa. When swaps further imbalance, slippage compounds. Fortunately, slippage works both ways: for a short region containing the flat zone and its curving edges, inputting low-supply tokens improves balance a lot faster.
Each time liquidity transforms our curve, Stableswap gets recentered around the balanced region, while bootleg constant-product governs the imbalanced region—revisit figure 5. So, when we calculate new curves, the degree of balance within price-determined dictates how the liquidity curve behaves locally, with total liquidity determining the depth of said behaviour.
To visualize recentering, have a fun table surfing video (Figure 8: A Visual Representation of Stableswap Recentering): the students on the floor constantly “recenter” around the girl on the table, who represents pool prices, to keep her stable but mobile for consecutive short distances. Of course, we need dollar-denominated balance to offer stable prices, and we suffer IL whenever we recenter.
Safe Parameters
To find out the limits of our invariant, Curve’s team used fuzzing, which is an automated way to test software by throwing extreme, invalid, or random data at a program to see how it performs or breaks, and test results validated our mathematical reasoning.
For safe convergence of :
USD is 1 quadrillion, or 1,000 trillion, dollars—more than the entire wealth of the world.
While not likely, a newly calculated can outsize total deposits by up to 200 times if total liquidity is growing quickly, like when apes are piling into a pool that has just been deployed.
For safe convergence of :
As a convention, V2 pool smart contracts store "" as .
We don’t want our deposits to grow too big.
In this case, it’d be hard to maintain liquidity with such extreme imbalance between token and token ; plus, deposits could also become too large.
For safe convergence of both and :
Again, this sets the range our invariant can bend in.
Quantification of a Repegging Loss
In V2, is dynamically volatile, so we want a dynamic mean-reversion strategy in order to make profit. To enact such, pools regularly concentrate, or "flatten", liquidity around every new price scale.
Realistically, concentrated liquidity is a bet: by briefly offering zero slippage, LPs earn consistent fees IL-free when prices mean-revert to a stable average. But, when imbalance forces recentering, LPs uniformly take amplified IL from subpar constant-product's slippage.
We illustrate the curve-warping repegging effect below.
Pre-swap, we have , where , and . Assuming no frontrunning or arbitrage, we swap $400 of for ~$343 of and nuke 's price down to 0.6.
We travel along the green curve to reach the orange recentered . Reflecting heavy imbalance, it lies distant from the old blue inside the stable zone where the green curve hugs the dashed blue line. Only by covering the repegging loss with external deposits could we return to the blue point where and.
To envision curve warping, let's say that each particular creates a "-family" of curves that share flat and curved parts. These parts are respectively parallel to each other and distinct from—e.g. non-parallel to—those of other -families. We shift between curves in a family by depositing or withdrawing at a dollar-balanced ratio. In that case, then increases or decreases without affecting the curvature.
In V1, almost any increase to creates profit. Stableswap rarely morphs because all normally stay at 1. However, Figure 9's crisscrossing straight lines demonstrate that, in V2, the flat part will relocate nonparallel to the previous flat part and adjust length, switching the invariant's family. Therefore, since constant-sum creates all flat parts, comparing across -families to measure profit is, geometrically, comparing apples to oranges. This is why doesn't accurately track repegging loss from curve to curve.
As such, we want a unique measure of pool value that accounts for V2's particular form of IL. We quantify pool value using a simple constant-product invariant. We disregard “noise” from any differences between and the market price of each token. The one-dimensional value of our pool is given as the geometric average of the real balances:
(Pool Value Without Noise)
Overall, curvy hugs Cryptoswap better and replicates its transformations better than , flat as a board and short. Hence, comparing across -families is the geometrical apples-to-apples comparison that we need to make to quantify pool value. and Cryptoswap share , where and are lower at any other point along due to slippage. The exponent restrains 's volatility.
Algorithm for Repegging
Profit Measure
To quantify profit, we first track at every repeg. After depositing into a new, empty pool, we initialize the LP token supply as . The proportion of LP tokens you own determines the proportion of liquidity you can withdraw. On each deposit, we grow the LP token supply by nearly the same percentage that deposits grew by, after deducting a deposit fee.
To measure the value of an LP token independent of when an LP joined the pool, we introduce the virtual price:
(Virtual Price)
In other words, a pool’s virtual price is the pool value available per LP token. We incorporate the virtual price to measure LP profit, which we label . When a pool receives liquidity for the first time, we initialize the virtual price and as 1.0, denoting neither profit nor loss. increases from virtual price increases, when LPs own more tokens worth more money than before.
(Profit Measure)
Creating profit, could increase disproportionately high relative to the LP token supply through swap and deposit fees and external liquidity incentives. We profit only if we reasonably preserve balance, though. The more concentrated the swap or deposit is in token , the higher the fee taken in token or LP tokens, respectively. The older the LP, the longer their ownership share "compounds" due to fees, so older LPs receive a bigger proportion of the fees than newer LPs.
Naturally, we need a placeholder to mark losses to from repegs, admin fees, and or changes. If a price update causes to fall below half of , wiping out half or more of accumulated profit, we revert it to preserve the remainder. As a result, our leftover transformed balances will stay at the same price.
This impedes potential cascading losses by momentarily allowing withdrawals at stable prices. The lower profit goes, the lower the threshold to temporarily suspend , which bolsters this line of defense.
Doubly, price manipulation becomes more expensive, taking more trade volume over a longer period. This buys time for arbitrageurs to narrow spreads between Curve pools and external exchanges, which tames further arbitrage via mean-reversion and thus blunts losses. Countering the loss, all resultingly heightened activity generates greater fees. We might compare arbitrageurs to a mafia protecting the businesses that it extorts.
Nonetheless, we should diminish the "noise" between and the market, lest we invite recurring "leveraged" losses. Two ways we can do so are: 1. attracting deep liquidity with $CRV; and 2. "optimising" pool parameters like , , the oracle time, or the admin fee. Also, under imbalance, we raise fee rates to offset repegging loss while aiming to slow the frequency of further-destabilizing trading.
Internal Oracle
To log price movement, pools take an internal exponential moving average (EMA) of price points over a specified period. Informed by trades or imbalanced withdrawals or deposits, the latest prices influence the EMA value the most, but we still end up with smoothed-out data that’s more reliable. Let be the last reported -coin price vector from seconds ago. Our weight factor has a half-time of seconds, typically 600, and the oracle price is given as:
(N-Price EMA Oracle)
where was the most recent average that we replaced.
We store the oracle price and the price peg on-chain, while we calculate the last reported price after swaps, deposits, and withdrawals. First, we derive from , which our current-family's curvature determines. Then, we incorporate into the latest EMA. Lastly, we shift current toward to create new, which updates . Every time repegs, we increase or decrease each toward by multiplying it by a value slightly above or below 1.0; however, for simplicity, the difference won’t be exactly (). We move prices in increments of , the price change step:
(Price Adjustment in Log Space)
Well, that looks scary as hell. Let's break it down. The percentage difference between the latest token oracle reading and the price scale that we're replacing makes up a fraction of how far every oracle price has deviated from every previous price in absolute terms, given by the distance formula . We multiply that fraction by our step and add 1 to get a multiple above or below 1 that we should adjust up or down by, relative to all token price changes. Obviously, pools will aim to readjust to prices that accommodate high-liquidity regions of the curve without creating losses, as the Curve docs state.
Concentrated Liquidity
Let's piece together Cryptoswap's concentrated liquidity design. Most crucially, we leverage , centering a no-slippage zone around . Adding deposits deepens liquidity net of the curve transformation's IL because Newton's method solves to differ as little as possible from its ideal result. Because imbalance is inevitable, we allow a dynamic fee, elaborated below, to both cushion profit and slow departure from the flat part. Placing another backstop, we repeg only if is more than double the IL. We thus want to subdue repegging cost beforehand, so we lower noise with $CRV incentives and pool parameter optimization. Moreover, our oracle averages prices out for greater stickiness within consistent ranges. As a result, Curve concentrates liquidity around the current price.
Dynamic Fees
Finally, some money-making talk. LPs charge a swap fee so that there's enough profit to cover IL. Intuitively, the higher the imbalance, the higher the fee; greater loss needs greater fees to offset!
The swap fee ranges between two constants and , with . In the "middle" of the stable zone, starts at and increases “out” to after imbalance.
(Dynamic Fee Within a Range)
If transformed reserves are balanced dollar-wise:
If transformed reserves become imbalanced dollar-wise:
given that is similarly close to like the in our Cryptoswap invariant. For example, within a % margin of error. Thus, as , .
When imbalance persistently worsens, grows faster than decreases by at least a power of . Consequently, near-parabolically drops to , bringing the fee up to with haste.
Another way to think about it: the fee grows based on how far the internal oracle is from . If the internal price has "run away" from where we recentered too fast, we stand to face major repegging loss, so we jack up fees to defend our profits.
In contrast to the swap fee, the deposit-withdrawal fee only applies if a deposit or withdrawal is imbalanced in dollar terms. It's intended to equal the swap fee under the assumption that the pool is balanced at time of deposit and at time of withdrawal.
V1 vs. V2
At the end of this long journey, weary traveler, I hope the following ideas were “the friends you made along the way”. Regarding Stableswap: we concentrate liquidity around a 1:1 peg, usually at a price of $1. We maintain it until extreme imbalance occurs, during which we depeg under subpar constant-product's slippage. Said slippage scales with our leverage , and changing lowers our profit, which constant-price counts because Stableswap's so flat.
Regarding Cryptoswap: we concentrate liquidity around the current price scale, albeit for necessarily shorter regions. As a result, approximates our curvier invariant better than does, which is why we track profit with . That is, better measures the repegging loss linked to curve warping, which changes in , , or produce. Our moving average oracle smoothes out and can suspend it to preserve ; separately, we scale fees after imbalance. To rebalance, our invariant equalizes all , but liquidity concentration depth persists through the curve's transformation because we initialize Newton's method well when solving for .
We’re done. Whether you read linearly or in scrambled fashion, thank you for your attention. I hope, by exploring concepts deeper, readers gleaned the subtle magic behind Curve’s system. Another fruit bundled in your mind’s handbasket: savour it well!
Glossary
Automated Market Maker (AMM)
The set of smart contracts Curve V1 and V2 use to algorithmically pool liquidity, calculate prices, minimize slippage, route multi-step trades, and, for V2, to ensure LPs are exposed to all assets equally under equilibrium.
Concentrated Liquidity
A mechanism that adds depth to liquidity around a price range such that it takes sustained trade volume in said price range to cause slippage by shifting equilibrium. When mean-reversion occurs, concentrated liquidity means no slippage for traders, and no IL for LPs—a win-win. The downside is: concentrated liquidity amplifies slippage when we run out of it. Further reading (Section 2 and Figure 3)
Derivative
If you were to draw a line in the direction a tiny point on a curve was heading in, the slope of that line would be the derivative. In an AMM, its invariant’s derivative at the current equilibrium point tells where the exchange rate between two tokens is and where it’s “going to go” after a trade involving given amounts of both tokens occurs. Further reading: V1 Formula, V2 formula not yet public
Equilibrium
In general, equilibrium point is the variable price an AMM enforces between a pair of tokens based on current reserves of each. For Curve V1, equilibrium will usually reside around $1 despite considerable imbalance. For V2, equilibrium is the “balance” denoted by a pool having equal dollar amounts of each token, achieved by changing prices, altering the true amount of any token stored, or by combining these two events to a variable degree.
Exponential Moving Average (EMA) Oracle
Curve V2’s internal oracle takes an average of a fixed number of the most recent price data points. Each point in this “moving” average has half as much weight every half-time—as in chemistry’s half-life—occurring every seconds, where the scaling factor will exponentially reduce an observation’s weight through repeated multiplication as time goes on. We then end up with smoother price data that still emphasizes the most recent prices. If the most recent price was reported seconds ago, we update the current EMA:
In a Curve V2 pool holding tokens, our invariant is geometrically represented by a hypersurface, an -dimensional surface in ()-dimensional price space formed by the dimensions of our token balances vector plus one dimension of our invariant function . Hypersurfaces like V2’s invariant are implicitly defined by single equations such as . Further reading
Impermanent Loss (IL)
LPs face impermanent loss at any time if their AMM liquidity is worth less money, even including rewards, than what it would’ve been if they had just held their tokens. Note the difference between a real paper loss, where the deposits are worth less than what the LP bought them for, and IL, where the LP had worse returns by providing liquidity rather than simply holding. Generally, after an LP deposits assets at a given exchange rate among them, they face worse IL the further prices deviate from said exchange rate. Further reading: formula, in-depth
Invariant (Liquidity Equation, Bonding Curve)
An invariant formula always satisfies some mathematical property. AMMs like Uniswap originally used the constant-product invariant, where and are the balances of two tokens and is a constant. The ratio between balances determines the exchange rate at equilibrium, and the invariant’s derivative smoothly determines how the exchange rate will change after swaps, deposits, or withdrawals.
Constant-Product Invariant (Gnosis DAO)
However, this invariant incurs slippage no matter how small the trade, so Curve’s V1 and V2 invariants seek to enable less slippage, incorporating the constant-product invariant when necessary. Further reading
Mean-Reversion
In liquid markets, asset prices tend to average out by stabilizing into a range or reversing course after a strong move in either direction. Such mean-reversion allows AMMs to organically "undo" some imbalance—and thus IL—while collecting fees in both directions. Further reading
Monotonic
A function that either doesn’t increase or doesn’t decrease at all is monotonic. Respectively, its first derivative is strictly or , and it doesn’t change sign over the function’s entire domain. Curve’s multidimensional invariant isn’t monotonic, meaning any of its partial first derivatives can become several times as it changes sign several times. Newton’s Method doesn’t work if the first derivative is , which can stop us from finding roots to Curve’s hypersurface as we lack perfect formulas for every situation. Further reading
Newton’s Method
A method to iteratively approximate a root to in the th dimension without needing an exact solution to the equation. Starting from a point, we take the tangent line at that point using the derivative, intersect it with the th axis, and repeat the process with the new value at until we find a sufficiently precise root. However, Newton’s Method can fail in several ways: first, if is “flat” at any such that but , the iterative process stops as the tangent can’t intersect the th axis. Second, we can approach a suboptimal root, which could cause excessive slippage in our invariant. Third, we can end up in a loop where we alternate our search among multiple roots, but never reach any of them due to ’s “shape”. Further reading: definition, failures