# Introduction

Early decentralized exchange (DEX) proposals took their inspiration from classical exchange markets and made use of order books to match sell and buy orders. Although these proposals achieved to be non-custodial exchanges, they turned out to be not very good in practice. The main reason for this is that an order book has a linear increase in storage and often even polynomial increase in computation with respect to the number of orders (see [1] , p. 2). This in turn — when implemented as smart contracts — caused far too high costs in fees making these solutions infeasible. Several approaches came up which run the order book offchain to reduce costs. This line of research continues to grow further using for example advanced cryptography (StarkDex) or exploiting batch ring trades (Gnosis).

A complementary approach to offchain order books for decentralized exchanges uses the concept of automated market makers (AMMs). The great advantage of such protocols are that they only require constant space and time interactions – unlike order books –, making non-custodial exchanges feasible.

In this post we look at the basics of the following three AMM projects: Uniswap, Balancer, and Curve. We shed some light on what they have in common, and try to understand in which aspects they are different from each other. The exposition takes a simplified view considering only trading markets with two tokens. This demonstrates already the essential points without getting lost in greater complexity. For those who want to understand the general case we provide links to further literature discussing the general case in even more depth.

# The Formulas Behind Uniswap, Balancer, and Curve

In all three protocols there are two **main agents** involved. First, there are **liquidity providers** who deposit an amount of token t_{1} and a corresponding amount of token t_{2} to reserve pools R_{1} and R_{2}. Secondly, there are **traders** who buy an amount Δ_{1} of token t_{1} for a specified amount Δ_{2} of token t_{2} (always assuming Δ_{1} ≤ R_{1}). And, it is exactly the job of the automated market maker to define the price for t_{1} expressed in t_{2}. This is achieved by the following very general pattern:

**CORE PRINCIPAL**: Suppose a trader wants to buy Δ_{1} tokens t_{1}. We describe the market maker in terms of a *trading function* ψ (as in [1]). Such a trading function takes as input the actual reserve sizes R_{1}, R_{2}, as well as the trading amounts Δ_{1}, Δ_{2}, and maps these arguments to the value ψ(R_{1}, R_{2},Δ_{1},Δ_{2}). The terminology of constant function market maker (CFMM) stems from the constraint that the value of ψ has to be the same before and after the trade, i.e.

_{2}the trader has to pay for buying Δ

_{1}tokens t

_{1}, and the smart contract accepts the trade only when the equation (1) holds true. After each trade the reserves become updated to R

_{1}← R

_{1}– Δ

_{1}, and R

_{2}← R

_{2}+ Δ

_{2}.

**PRICE IMPACT FUNCTION**: Each trade of an amount of Δ_{1} tokens t_{1} has an impact on its price, since the reserve sizes are changing. In practice, if there is a significant difference between the price of the AMM and an external reference market, an arbitrage dealer will take this opportunity which balances the AMM price. The price impact of a trade of selling Δ_{1} tokens t_{1} is (mathematically speaking) the derivative of Δ_{2} considered as a function in Δ_{1}, i.e.

*marginal price*(infinitesimal small trade) of token t

_{1}is just m := g(0).

## Trading Functions and Marginal Prices

In this section we present the trading functions of Uniswap, Balancer and Curve, and their price impact functions. After passing through some mathematical formulas, we demonstrate in an example, how these different choices can be interpreted.

**UNISWAP**: The trading function of Uniswap is the product of the updated reserves

and the constraint (1) takes the form of

The price in t_{2} can be calculated by bringing all other terms of equation (2) to the right: Δ_{2} = (R_{1} * R_{2}) / (R_{1} – Δ_{1}) – R_{2}. The price impact function of buying Δ_{1} tokens is then

As a special case, we get the marginal price m_{u} = g_{u}(0) = R_{2}/R_{1} for Uniswap.

**BALANCER:** The trading function of Balancer is the weighted product of the updated reserves

where w_{i} is in the interval (0, 1) and must satisfy w_{1} + w_{2} = 1. The constraint (1) then reads as

Similarly as above, the price in t_{2} can be calculated by bringing all remaining terms of equation (3) to the right-hand side:

The price impact of buying of Δ_{1} tokens is then

As a special case, we get the marginal price m_{b} = g_{b}(0) = w_{1}/w_{2} * R_{2}/R_{1}.

**Remark**: The weights w_{1}, w_{2} have an interpretation in terms of the total market value. Namely, when considering the two token market value in one or the other token, w_{1} reflects the share of token t_{1} and w_{2} reflects the share of token t_{2} (see [4]). When we choose w_{1} = w_{2} = 1/2, then we discover the Uniswap case as a specialization of Balancer.

**CURVE**: The trading function of Curve is a linear combination of the sum and the product of the updated reserves

with α, β ≥ 0. Again, but this time with some more effort, one can find (see [1])

where k = ψ_{c}(R_{1};R_{2}; 0; 0). The price impact of buying Δ_{1} tokens is a bit more complicated to derive, but once done some work, one finds

As a special case, we get the marginal price m_{c} = g_{c}(0) = (α + β (R_{1}^{2}R_{2})^{-1})/ (α + β (R_{1}R_{2}^{2})^{-1}).

**EXAMPLE**. Each trade in a CFMM affects the price of the traded token, and the trade size even impacts the price in the same trade (“slippage”). This change in price depends heavily on the trading function of the market maker. Figure 1 shows the price impact functions we derived above for Uniswap, Balancer, and Curve. In this example we assume the reserves to be equal, namely R_{1}= R_{2} = 10000. The marginal price of Uniswap is g_{u}(0) = 1, for Balancer g_{b}(0) = w_{1}/w_{2}, and for Curve the marginal price is g_{c}(0) = 1. It becomes immediately visible that Curve’s AMM has for lower trade volumes more stable prices, making it attractive for traders between stable coins (where R_{1} = R_{2}). Approaching the reserve size R_{1} Curve’s price impact function rapidly increases as well, but only when it is very close to the reserve size.

Another interesting quantity is the curvature μ of the price impact function, which is formally defined as g'(0) and satisfies g(Δ_{1}) – g(0) ≤μg(0) (assuming g to be a convex function). It describes the change of the price with respect to the marginal price. Figure 2 shows how this bound on the price change varies with respect to the volume of the market, i.e the portfolio values PV of both token reserves.

## Trading Functions with Fees

Usually fees are paid on the way in, i.e in the token t_{2}, and the percentage fee of (1 – γ) charged Δ_{2} is paid out to the liquidity providers when they withdraw their funds (see next section for more details). Hence the trading function with fee of Uniswap, Balancer, and Curve from the previous section are slightly changed to

**UNISWAP**:

**BALANCER**:

**CURVE**:

Besides these changes, the reserves are updated in the same way as for the non-fee case, i.e. R_{1} ← R_{1} – Δ_{1}, and R_{2} ← R_{2} + Δ_{2}. The marginal price reflecting the trading fee are m_{u} = 1/γ R_{2}/R_{1} (Uniswap) and m_{b} = 1/γ (w_{1}R_{2})/(R_{1} w_{2}) (Balancer). For Curve we will provide a corresponding formula in an update of this post.

# Liquidity Provider Return and Other Topics

**DEPOSIT and WITHDRAW**: When a liquidity pool is created, its initial reserve balances are in 0, i.e. R_{1} = R_{2} = 0. The first liquidity provider sets the initial price of the pool by the amount of tokens t_{1} and t_{2} she decides to send to the pool. In case of Uniswap, she is incentivized to deposit an equal value of both tokens into the pool, otherwise an arbitrage dealer will use this opportunity. In the case of Balancer, also the weights w_{1},w_{2} can be set which incentivizes to deposit exactly this share of tokens to the pool. Subsequent liquidity providers must deposit pair tokens proportional to the current price (or make some corrections to it), otherwise they run the risk of being arbitraged as well.

**LIQUIDITY PROVIDER RETURN**: Whenever a liquidity provider deposits into a pool, she receives liquidity tokens in return. These tokens represent her contribution to the actual pool size. In order to withdraw, the liquidity provider must burn the liquidity tokens which gives her back the proportion of the reserve pool. Assuming a fixed market price, the liquidity provider will collect the same amount plus a return from fees which increased the pool size. (Some minor fees for withdrawing from reserves may apply!)

There is an empirical evidence that the shape of the price impact function and the liquidity provider’s return are correlated. As shown in Figure 1, Curve’s price impact function is flat around the “mean” (i.e. when R_{1} = R_{2} in the stable coin example) while the price impact function of Uniswap increases more rapidly. This invites stable coin traders to change higher amounts between stable coins in the Curve platform, which creates a higher trading volume. Therefore, a higher return is paid to liquidity providers in Curve, which, in fact, has the highest token volume locked (see here)! See [1], section 2, for a more general discussion. In the above scenario the market price of the tokens are supposed to be constant which can be assumed for stable coin pairs in Curve. For other coins, this is usually not the case, since slippage (see below) changes the token price. Until prices are not moved back to the “original” price, this may cause an impermanent loss. This loss becomes permanent when the liquidity provider withdraws before the price moves back. For more details see here.

**NO-ARBITRAGE BOUND**: Let’s look at the no-arbitrage bound. Again, (1- γ) is the percentage fee, and let m_{p} the price of a reference market. When the marginal price of token t_{1} is smaller than the market price, i.e. m ≤ m_{p}, there is a chance of a non-zero profit. With the same reasoning for the other way around, we have no-arbitrage opportunity state in Uniswap, when γ m_{p} ≤ m_{u} ≤ 1/γ m_{p}, and for Balancer when γ m_{p} ≤ m_{b} ≤ 1/γ m_{p}.

**COST of MANIPULATION**: If we denote by C(ε) the cost in t_{2} to change the market maker price m_{u} of t_{1} to (1+ ε)m_{p}, then [2], p.7, provides the following lower bound for Uniswap in the no-fee case:

An interesting observation is that the cost is bounded form below by the reserve size R_{2}, i.e. the cost of manipulation becomes higher for markets with large liquidity pools. Similar formulas can derived for Balancer and Curve.

**SLIPPAGE and FRONT-RUNNING**: As we have seen in the example above, the current marginal prices can be changed by a large trade. This can be used to run an attack on a common trader — let’s name her Alice. By choosing a high gas fee, a malicious trader can achieve to put a buy order at price m_{1} just before the buy order of Alice who intended to buy with marginal price m_{1}, but ends up buying at a higher price m_{2}. The order of Alice goes through anyway, pushing the price up to a marginal price m_{3}. Now the malicious trader sells at m_{3} making a profit. Since this attack puts a transaction before and after the transaction of Alice, it is also called a *sandwich attack*. See here for a good explanation and counter-measures.

# References

[1] G. Angeris, A. Evans, T. Chitra; When does the tail wag the dog? Curvature and market making, 2020.

[2] G. Angeris et al.; An analysis of Uniswap markets, 2020.

[3] G. Angeris, T. Chitra; Improved Price Oracles: Constant Function Market Makers, 2020.

[4] F. Martinelli, N. Mushegian; Balancer white paper. 2019