Uniswap has become a very popular alternative to classic order-book-type exchanges and has become a common way of measuring the relative price between two on-chain coins (contracts which attempt to do this are often called ‘price oracles’). What is somewhat surprising is that, while Uniswap’s basic idea is very simple, the practical results are quite good: out in the “real world,” Uniswap seems to accurately estimate the relative price of two assets, when compared to much larger exchanges. Uniswap’s stability is also surprising as it appears unaffected by bad actors who might attempt to manipulate the price for their own personal gain.
These results may be intuitive to users of Uniswap that have seen them bear out in the wild. However, for the skeptic who views this as merely the result of favorable circumstances, our analysis creates a mathematical framework for the conditions under which Uniswap is a good oracle. We recently published our analysis of Uniswap in this paper (which was accepted into Cryptoeconomic Systems 2020), and wanted to share some of the results with a broader audience ahead of the conference.
Uniswap is a particular instance of a constant-product automated market maker (often simply, a constant-product AMM). The idea is the following: we have a contract (or exchange) that has some reserve for token “A” (containing R such tokens) and some reserve for token “B” (containing R’ such tokens). An agent who wants to buy Δ’ coins of token “B” must put in enough of coin “A” such that the product of the reserves remains constant. In other words, if the agent wants to buy Δ’ coins of token “B” from the reserves, then the agent must put in Δ coins of token “A” into the reserves such that the product of the new reserves is the same as the product of the old reserves:
Equation (1) can then easily be used to derive the quantities we will use throughout. For example, the Uniswap price, mᵤ, of coin “A” with respect to coin “B” is defined as the marginal price of purchasing coin “A” with some amount of coin “B,”
Equivalently, this is the average price of buying an infinitesimally small amount of coin “A” with “B”, which we can plot as the slope of the price at Δ = 0:
In the next section, we will connect the marginal Uniswap price to the true market price (spoiler alert: in the fee-less case, under common assumptions, they are equal).
Note: As of right now, the constant product formula, equation (1), does not include any trading fees. For simplicity, we will assume the fee-less case in the remainder of the blog post (with references to the case with fees as side-notes or when needed), but most of the statements we will make here hold pretty much as expected in the case with fees.
Arbitrage and what it tells us
In order to say anything about what the price of Uniswap should be relative to the price of a reference market, we need to assume something about how these markets interact. A very common and simple way of doing this in mathematical finance is to say that there is no arbitrage. In other words, we will assume it is impossible to “make free money” by only trading between these two markets without taking on any risk. Because of this, we can show that, if mᵤ ≠ m, where m is the reference market price, then necessarily there is a small enough trade where an agent can make positive profit, which would then imply, under this hypothesis that mᵤ = m.
To show this, let’s assume that mᵤ > m, then, by definition of mᵤ, there exists a small enough input of coin “A”, say Δ, such that
where Δ’ is the output of coin “B” given Δ of coin “A”. Similarly, there exists a small enough trade for the market such that mΔ ≈ Δ’’, but, since Δ’’ < Δ’ (as mᵤ > m), we can easily make a profit by trading Δ’’ for Δ in the open market, and then trading Δ for Δ’ in Uniswap, which means that we make a positive profit as Δ’’– Δ’ > 0. Note that this derivation, while not fully rigorous, follows essentially the same proof as the mathematically air-tight one (with some careful accounting for error terms). Since we can make a similar claim whenever mᵤ < m, we then conclude that mᵤ = m under the no arbitrage condition.
This implies that, if we assume no arbitrage and no exchange fee, then the Uniswap market price must equal the true market price! Of course, the no-arbitrage assumption only approximately holds in practice, so Uniswap may diverge slightly from the true market price, especially within a block or over a small number of blocks. A more detailed analysis shows that, under many market models, the true market price will be very close to the Uniswap price, which is confirmed by an agent-based simulation. For more details, see §2.
Note: A similar (but weaker) statement holds in the case with trading fees:
γm ≤ mᵤ ≤ γ⁻¹m, where (1-γ) is the percentage trading fee. As before, see §2.
Nice properties of Uniswap
Uniswap also has several nice properties, which strengthen our belief that it is likely to be a good oracle in practice. More specifically, (a) it is impossible to drain Uniswap of its reserves by only trading coins within the market itself, and (b) adding liquidity to the market does the right thing in that it decreases trading costs for a given coin while increasing the cost to manipulate the oracle.
Reserves are bounded from below
It is not difficult to show that there is no set of trades which could ever deplete Uniswap of its coins. Since k = R’R, then, by the AM-GM inequality we get
which immediately implies that the sum of the possible reserves is bounded from below by the square root of the product, k. Since, by definition, k is always constant after every trade, then the sum of the reserves is always bounded away from zero.
Adding liquidity decreases trading costs
There are a few ways of proving this fact, but the simplest is to note that, given an input Δ of coin “A”, we get
Using the fact that R = mᵤR’, by no-arbitrage, then the output of coin B is equal to
which is increasing in R’, for a fixed marginal price mᵤ. (Note that the denominator is decreasing as R’ increases.) So, the higher the available reserves, the larger the output amount will be for a given input amount. This is intuitive for many users of the Uniswap protocol, who see smaller slippage on more liquid pools.
Manipulation is expensive (when making large changes)
In fact, it turns out that the cost of manipulating the Uniswap price to any fixed amount scales linearly with the reserves and the number of blocks, which can be expensive in many practical cases, though we note that very small or short-term perturbations to the price are relatively cheap.
For now, let’s say that an attacker wishes to manipulate the price of Uniswap mᵤ to some amount p > m, where m is the market price, then the cost of this single action (say, for a single block) is at least,
(For a derivation, see appendix E.) If we assume that p ≥ (1+ε)m with ε>0, then since C(p) is increasing in p whenever p > m, we get that the cost is at least
for which we know that
where K is at least 1/(32√2). Finding this lower bound for C(ε) is a little tricky, but the argument is in appendix E. The bounds, as stated, are tight up to a constant factor, but the constant K given here is a very weak lower bound (and so this particular choice should only serve as a rule of thumb, rather than as a hard number).
The fact that the cost scales linearly with the reserve amounts, R, really drives home the importance of large liquidity pools for robustness. On the other hand, since the cost scales quadratically when ε is small, it is possible for an attacker to slightly manipulate the price reported in Uniswap for long periods of time without much expense. For example, if a reserve pool has R = 1,000 ETH, an attacker can manipulate the price by ε = 1% for around C(.01) ≈ .025 ETH per block (the lower bound is considerably weaker here, giving that C(.01) ≥ .002 ETH).
Note that this manipulation is possible in practice, and, as such, we will warn that no protocol should rely on very fine changes in price reported by these oracles, or prices reported over very short periods of time. That being said, manipulation quickly becomes expensive when attempting significant changes to the price, which is one of the reasons we suspect that no large manipulation of Uniswap markets has been observed.
Though relatively simple, Uniswap seems to have nice theoretical properties, which suggest its stability in practice as both a decentralized market and a price oracle. Additionally, the statements above do highlight the importance of having large reserve pools in Uniswap, as all results depend on this in one way or another.
As before, the above is only a small part of the statements derived in the complete paper — anyone interested in the details and proofs should take a look there!
After the bZx attack on 02/15/20, which exploited a bug in the bZx smart contract logic to drain the contract of funds, we would like to reiterate the importance of the conditions for the results above. As far as we can tell, this didn’t rely on oracle manipulation, but did involve the use of multiple transactions executed with in a single block.
In particular, if an attack can be carried out in a single block, then manipulation has a very small price (the price of manipulation is essentially just the trading fee) and so is quite feasible in most cases, since the bounds given above do not apply. This underscores the importance of the warnings we gave at the end of the Manipulation is expensive section: (a) it is probably unwise for a contract to depend on small changes in the Uniswap price (which are quite cheap, as shown), and (b) a contract should not depend on the price reported by Uniswap over a very short period of time.