Whitepaper: Uniswap v3 Core

TLDR:

  • Uniswap v3 introduces architectural changes to implement non-fungible liquidity positions concentrated along price curves, discretized into price tick ranges for increased capital efficiency, and more customizable liquidity.
  • v3 also implements a new geometric mean price oracle for improved accuracy and usability.
  • It also introduces additional flexibility for governance on how fees are structured, calculated, and allocated.

Citation

Adams, H. Zinsmeister, N. Salem, M. Keefer, R. Robinson, D. (2021). Uniswap v3 Core.

Background

  • AMMs: Generally constant product markets that implement pools of asset pairs with which users can trade or add/remove liquidity.
  • CFMMs: A smart contract that allows for the exchange of coins and derivative assets. It employs a convex function (x * y = k) which maps asset quantities to implied prices abiding by the principle of supply and demand.
  • Non-Fungible Tokens (NFTs): non-divisible and unique tokens that are often implemented through token standards, such as ERC-721 or ERC-1155.
  • Concentrated Liquidity: Refers to liquidity positions that can be bounded within price tick ranges along an AMM price curve.
  • Governance: The processes used by decentralized protocols to collect signals, make decisions, and enforce policies.
  • Liquidity Position: represents a user’s liquidity supplied to a AMM price curve.
  • Limit Order: an order to buy or sell an asset at or better than a specified price.
  • Range: A price range upon which trades may be executed (AMMs) and/or orders may be placed (order books).
  • Range Order: is a liquidity position on very small price ranges.
  • Price Oracle: Contracts which read in information off-chain (eg. prices) and feed them on-chain to be used by other contracts.
  • Price Accumulators: are contracts used by oracles to aggregate prices and keep track of changes in cumulative time-prices (usually by block).
  • Virtual reserves: Concentrated liquidity positions with smaller reserves that act like CFMM pools with larger reserves within that range.

Methodology

  • Concentrated Liquidity

    • In Uniswap V1 and V2, LPs provide uniform liquidity across entire price range (0,infinity) using the CFMM (x * y = k).
    • V3 uses the concept of virtual reserves
    • Positions only need enough liquidity to cover price movement of one asset to an upper bound and the other asset to a lower bound (range).
    • When the price exits a position’s range, that position’s liquidity is no longer active and no longer earns fees and its liquidity is composed entirely of a single asset because the reserves of the other asset must have been entirely depleted.
    • The following equation can be used to determine the amount of real reserves provided for a given position, the amount of liquidity (L) is known.
    • Conveniently, this happens to be equal to the square root of k (the CFMM variable).
    • Liquidity providers can approximate any desired liquidity distribution by aggregating smaller price ranges
    • Range Orders
      • A range order is a liquidity position on very small price ranges.
      • This is different from a limit order in that 1) there is a minimum size to ranges and 2) when a position has been crossed, it must be withdrawn and if price crosses back in that range, the position will be reversed and traded back.
  • Architectural Changes

    • Multiple Pools Per Pair
      • In v1 and v2, every pair is a single liquidity pool with a uniform 0.3% fee. While this default fee worked well for many tokens, it was probably too high for some pools (e.g. stable-stable pairs) and too low for others (high-volatility or low-volume tokens).
      • v3 introduces multiple pools for each pair, with their own governance-customizable swap fees (default 0.05%, 0.3%, or 1%).
    • Non-fungible Liquidity
      • Non-compounding Fees
        • Fees in v1 and v2 were continuously reinvested in the pool as liquidity. In v3, liquidity positions are non-equivalent to each other since they occur on different price ranges and with different distributions of liquidity. Due to the non-fungible nature of liquidity positions, this cannot be done in v3 so fees are stored separately, and held as nominal tokens.
      • Removal of Native Liquidity Tokens
        • In v1 and v2, LP tokens in a pool are also ERC-20 tokens. The Uniswap philosophy is that there should not be one “canonical” ERC-20 implementation as it discourages the creation of new token wrappers.
        • In v3, anyone can create an ERC-20 wrapper for a liquidity position but they will have to write the logic describing how to handle, distribute, or reinvest fees collected; or else write an ERC-721 to wrap the position + fees as an NFT. This cannot be done uniformly in v3, since, as previously mentioned, liquidity positions are no longer fungible.
  • Governance

    • None of the core contract operations can be halted by the UNI-controlled factory contract, thereby minimizing the impact of potential governance attacks
    • Like v2, the v3 protocol fee can be turned on via governance. In v3, each pool has a parameter that can be set for % of swap fees that are allocated to the protocol, ¼, ⅕, ⅙, …etc. up to 1/10. Governance can add new fee tiers, add new price ranges to curves, and transfer ownership to a new address.
  • Oracle Upgrades

    • Oracle Observations
      • In v3, users no longer need to externally track oracle values.
      • v2 tracked the price at the beginning of the last block a trade occurred in. v3 stores the previous 65,536 checkpoints (first interaction with a pool in a block) and allows users to query an interpolated price for any historical timestamp within the checkpointed time period. This provides users improved flexibility in the methodology they are able to use to track prices.
    • Geometric Mean Price Oracle
      • v2 has two price accumulators for price of token0 in terms of token1 and vice versa since arithmetic mean prices cannot simply be inverted to get the other token price. v3 stores the geometric mean price so it does not need to track separate accumulators for both tokens. Also, since it stores log base 1.0001 of the price, it can be stored in a smaller number of bits. This means a relatively simple formula can be used to estimate the geometric mean TWAP from any period t1 to t2.
    • Liquidity Oracle
      • v3 also adds a liquidity accumulator, which can be used by contracts to choose which fee-tier pool to use oracles from.
  • Implementing Concentrated Liquidity

    • Ticks and Ranges
      • Ticks mark ranges where LPs can provide liquidity and are demarcated by a lower and upper price tick. Ticks are all 1.0001 to an integer power, which means each tick is .01% away from the next tick.
      • Under the hood, these ticks are tracked as a square root of a price for efficiency of storage. When a pool is created, a variable “tickSpacing” is defined, which limits the precision of ticks in exchange for gas cost savings. The contract tracks state variables at 3 levels (per-pool, per-tick, and per-position).
    • Global State
      • Price and Liquidity
        • v2 tracks reserve balances (x and y). v3 tracks liquidity (L) and the square root of a price ratio (√𝑃) that would be computed from virtual reserves.
        • The fact that only one of L or √𝑃 changes at a time within a tick helps to avoid some rounding errors. √𝑃 is used instead of P because it simplifies using the following formula that describes the relationship between liquidity, change in token reserves, and change in square root of price.
        • The current tick index (nearest below current price) is also tracked in global state.
      • Fees
        • The protocol fee is tracked as two variables: “feeGrowthGlobal0” and “feeGrowthGlobal1”, representing the total fees earned per liquidity over the history of the contract in the two tokens that fees are earned in. Accumulated uncollected protocol fees are also stored in two variables and can be collected by governance.
      • Swapping Within a Single Tick
        • If trades are small enough that the price does not move past a tick, then v3 functions like a CFMM pool (x * y = k). The amount of token x in virtual reserves when token y is traded is represented by the following formula:
        • v3 tracks liquidity (L) and square root of price (√𝑃) instead of actual reserves. Instead of deriving x and y and then calculating execution price, it is simpler to directly compute price or reserves from L and √𝑃 using the following formulas:
        • However, if the change in √𝑃 would push the trade past the next tick price, these formulas will not work and the contract will first calculate the portion of the trade up to the next tick, and then compute the next tick range separately.
      • Initialized Tick Bitmap
        • The pool contract tracks a “tickBitmap” of initialized ticks, as uninitialized ones are skipped in the trade logic. When initialized, ticks are checked by the contracts and use gas.
    • Tick-Indexed State
      • Every tick tracks the amount of liquidity needed to be added or removed when the tick is crossed (only changed when LPs add/remove L).
      • Since change in liquidity is tracked as a net value, the contract also tracks gross liquidity to determine which price ticks need to be initialized because they are in use (even if net liquidity is zero).
      • The pool also tracks how many fees were accumulated within a given range for each token.
      • The fee-growth variables are not meaningfully comparable between ticks as ticks may be initialized at different times. This does not affect per-position accounting, as positions only need to know the growth in a given range since the position was last touched.
      • The contract also stores the time spent outside of a tick, and is not used by the contract but tracked for the convenience of external contracts to know how long a position has been active.
      • Crossing a Tick
        • Within a tick, v3 functions like a CFMM but when it crosses a tick, the contract has to fetch the change in liquidity to update the global liquidity to ensure no LP is insolvent. In order to track time and fees within a tick, the contract needs to update the tick state values when the tick is crossed.
    • Position-Indexed State
      • The contract maps users to positions and tracks liquidity (√𝑥𝑦) for each position within a tick range. Unlike v2 pool shares, the units for liquidity do not change as fees are accumulated. The liquidity value does not reflect fees accumulated since last contract interaction (uncollected fees). Uncollected fees can be computed from the “feeGrowthInside” variables stored on the position for a given range.
      • The “setPosition” function allows LPs to update their positions. It takes a tick range and an amount of liquidity. It first computes uncollected fees and the amount of fees collected is credited to the user and netted against virtual liquidity amounts added or removed. Then, it updates the position’s liquidity by the net amount as well as modifying the net liquidity for the price tick.

Applicability

  • Concentrated liquidity positions allow for improved capital efficiency, more customizability, and preserved technical efficiency for liquidity provider positions.
  • The swap fee is more customizable in v3 (0.05%, .3%, 1%, or additional) via governance. The share of the swap fee allocated to the protocol is more customizable via governance as well in v3.
  • The v3 price oracles allow users to query historical TWAP values (up to ~9 days) with flexible time slices rather than needing to store their own.
10 Likes

This is an interesting series of enhancements and optimizations on Uniswap’s classic constant product pools.

When a swap is made against a pool how much additional complexity do the new calculations add? Does the contract route a swap to the best range orders or does the user specify which range orders they want to swap against? Are there any gas savings as a result of the new approach?

There is also talk about Uniswap being deployed on Optimism, are there any details on how that will work? Will it fragment Uniswap liquidity?

6 Likes

Absolutely, this is a tradeoff that needs to be explored: how do you provide capital efficiency without sacrificing and ultimately fragmenting liquidity. In theory, the idea is that virtual reserves allow you to approximate larger reserve balances to cancel out the expected reduced liquidity at any particular price range.

Additionally, there is a described tradeoff between precise position management and gas cost. The idea is supposed to be that in the near future this will be mitigated and made more efficient through leverage of optimism. As I understand it, implementing an L2 solution is not supposed to fragment liquidity. Will require some further exploration in my opinion.

5 Likes

I am trying to figure out if the price fees automatically accommodate for gas fees in real-time, or if it uses the ticks from previous trades to infer the fee on a transaction? It seems like if it is the former, it could be spammed in an attack to slow up trades, and if it is the latter then gas fee fluctuation could affect trades and liquidity over time in a negative trend. Did I miss something?

4 Likes

Trade fees are static % of trade volume. They can be changed upon governance vote.

The exact spacing (think degree of precision) of price ticks can also be changed (though there are gas costs to that).

3 Likes

But wouldn’t the trade fees have to take into account the actual gas cost of the transaction as part of the fee, or does the transaction then have the gas fees paid separately by another pool? I am trying to figure out how the automated trades happen with gas fees fluctuating in the marketplace constantly if the liquidity trade fees are fixed percentages of trade volume. Does it just assume that the trader pays the gas fees separately on each transaction? I’m assuming these are all on chain transactions that would necessitate gas fees just for executing the trade beyond the fee charged by Uniswap?

I did a quick search and there was an article in February in Cointelegraph that discusses the network gas fees rendering Uniswap effectively unusable for small traders: DEXs becoming unusable? How to navigate record gas fees ahead of Eth2 (cointelegraph.com).

Is 3.0 attempting to solve that, or is this tool effectively going to be only compartmentalized to large-scale traders because of network fees in your opinion?

3 Likes

Traders pay gas fees. Trade fees are additional. v3 does not change the trading gas cost (or at least doesn’t appear to) on the trader’s side. The potential gas impact of v3 comes for those adding or removing liquidity (as well as some minor nuances in how the contract internally calculates prices).

However, if optimism is implemented that has the potential to materially reduce gas costs, though it is a bit separate from the core v3 spec.

5 Likes

Thanks for this clarification! This makes me wonder if miners having effective control over protocol implementation makes it more difficult to move towards solutions that reduce fees that are associated with miner payment.

On the one hand, I am excited by the prospect of non-fungible liquidity pools. On the other hand, the systems still being restrained by gas fees makes me concerned that the miners will ultimately be the ones getting the most out of v3 due to their disproportionate influence over the network’s ordering of trades.

4 Likes

Use Cases are micro-interviews created by SCRF’s research team. They’re intended to provide context for laypeople about important developments in blockchain research, and for our researchers to ask questions.

Uniswap is a decentralized exchange that uses an algorithm instead of an order book to determine prices between two assets. Users buy and sell tokens without an intermediary, or they can provide liquidity, earning yield by staking their own capital to create a pool of tokens to be traded between buyers and sellers.

The first version of Uniswap was simple and efficient. The second version, released in 2020, expanded the system to directly trade pairs of ERC-20 tokens, and quickly became the most popular DeFi platform with $34B+ of volume traded in March according to Coin Gecko.

The third version of Uniswap (v3) will be released on May 5th. It allows liquidity providers to implement non-fungible liquidity positions concentrated at custom price ranges. The Uniswap team claims the new design will boost capital efficiency and provide more customizable liquidity.

Questions

The Research Team collected some questions about Uniswap’s latest update:

When a swap is made against a pool how much additional complexity do price-tick and position-specific calculations add? What calculations need to be performed in contract logic to execute a swap now? Are there gas savings or additional costs as a result of the new approach?

Do the gas costs of price-tick logic and operations get passed on to traders when executing swaps now? Does this in any way impact LP returns if there are gas spikes when a liquidity position becomes activated?

Does v3 effectively require LPs to use bots in order to maintain competitive yield? Will LPs perform the same, better, or worse in v3, and in what ways does this depend on how tightly they manage their liquidity? Will it be expensive or feasible for them to re-balance these positions?

v3 has been advertised as up to 4000x more capital efficient. Where does this number come from? Will this be true for most users or lower on average? How does this efficiency translate for trader experience? Is there a cost to more capital efficiency (eg. more variable yield)?

6 Likes

When a swap is made against a pool how much additional complexity do price-tick and position-specific calculations add?

Tick crossings cost on the order of ~20-40k gas. The expectation (back-tested on v2 data), is that the average trade will cross 0-2 ticks. Per-position costs are only imposed on individual position owners.

What calculations need to be performed in contract logic to execute a swap now? Are there gas savings or additional costs as a result of the new approach?

Logical complexity is quite high, swaps are now executing within a while loop. Each iteration of the while loop can cause a move from the current price until (at most) the next tick with at least one position referencing it. However, because of storage efficiencies and gas golfing, on a net basis, a typical swap is expected to cost 100-150k gas.

Do the gas costs of price-tick logic and operations get passed on to traders when executing swaps now?

Yes.

Does v3 effectively require LPs to use bots in order to maintain competitive yield? Will LPs perform the same, better, or worse in v3, and in what ways does this depend on how tightly they manage their liquidity? Will it be expensive or feasible for them to re-balance these positions?

This is a very complex question that depends heavily on market conditions. In general, the expectation is that LPs will be able to earn a reasonable risk-adjusted return, with the possibility of a small premium for those LPs actively managing their liquidity. Of course it’s generally true that tighter positions lead to higher fees at any given moment, but across time, they come with increased price exposure. Rebalancing costs vary fairly dramatically, but are on the order of 150-500k gas.

v3 has been advertised as up to 4000x more capital efficient. Where does this number come from? Will this be true for most users or lower on average? How does this efficiency translate for trader experience? Is there a cost to more capital efficiency (eg. more variable yield)?

See https://twitter.com/haydenzadams/status/1380217938867843072.

9 Likes

Thanks for the speedy response there Noah.

Logical complexity is quite high, swaps are now executing within a while loop. Each iteration of the while loop can cause a move from the current price until (at most) the next tick with at least one position referencing it. However, because of storage efficiencies and gas golfing, on a net basis, a typical swap is expected to cost 100-150k gas.

How does this compare to v2?

Tick crossings cost on the order of ~20-40k gas. The expectation (back-tested on v2 data), is that the average trade will cross 0-2 ticks. Per-position costs are only imposed on individual position owners.

Given that virtual liquidity operates like higher amounts of real liquidity (according to the core paper), would the expectation be that the back-tested 0-2 ticks will be closer to 0-1 ticks in v3 since liquidity will probably be more tightly concentrated?

My intuition is the more heavily concentrated liquidity is a bit more expensive to manage for LPs, but provides them higher capital efficiency in exchange and it creates slightly more gas cost but also more price stability for traders. Is this the general synthesis?

6 Likes

How does this compare to v2?

~Best-case v2 swaps are 101876 gas, ~best-case v3 swaps are 105743 gas. Note that this isn’t quite apples-to-apples though, because of Berlin.

Given that virtual liquidity operates like higher amounts of real liquidity (according to the core paper), would the expectation be that the back-tested 0-2 ticks will be closer to 0-1 ticks in v3 since liquidity will probably be more tightly concentrated?

Good question! Yes in theory v3 will see average better execution than v2, so fewer ticks will be crossed.

My intuition is the more heavily concentrated liquidity is a bit more expensive to manage for LPs, but provides them higher capital efficiency in exchange and it creates slightly more gas cost but also more price stability for traders. Is this the general synthesis?

Yes that seems generally correct, though I think there’s an important distinction to be made w/r/t stable-stable pairs like USDC/DAI vs something like DAI/ETH.

9 Likes

Do you have insight into what the worst-case would be for each?

3 Likes

Yes that seems generally correct, though I think there’s an important distinction to be made w/r/t stable-stable pairs like USDC/DAI vs something like DAI/ETH.

I am curious how this will affect non-stables vs stables. Obviously stables will have tighter liquidity spreads probably with liquidity walls on either side of the peg. For non-stables, I expect a moving semi-normal distribution centered on current price with some degree of lag.

My intuition is that trades executed outside of the “hot” price ranges will have less liquidity and thus a higher price impact. This means that effectively they are more expensive trades. As such, trading is disincentivized outside of heavy liquidity ranges.

The exception to this should be when arbitrage with external platforms is more profitable than incurring the cost of higher price impact from trading in lower liquidity ranges. This would basically be when there are real market price movements not minor fluctuations. By extension, this should result in lower volatility around heavy liquidity concentrations.

For stables this is an obvious benefit in that it allows you to use a Uniswap pool to effectively disincentivize small peg fluctuations (though it doesn’t really stop larger price movements). For non-stables it will be very hard for LPs to know the difference between a lasting price movement and a momentary fluctuation so I expect some middle-point solution where LPs chase price but also build in a “tail” to their positions to address these fluctuations.

Basically, a very cool stochastic modeling problem to be solved here.

5 Likes

As the next generation of DeFi platforms emerge, are we seeing much divergence between the different platforms?

1 Like

In terms of AMM platforms specifically or more general?

2 Likes

I was thinking of Balancer v 2 and Uniswap v 3, but I’d be interested in your thoughts about how DeFi is shaping up after a year of explosive growth

2 Likes

AMMs have experienced a tremendous amount of volume and liquidity and there have been numerous different flavors of AMM that have sprouted up, though Uniswap maintains a large market share. I think anything further might be speculative discussion.

1 Like

On May 5, Uniswap v3 will launch on the L1 Ethereum mainnet, with an L2 deployment on Optimism set to follow shortly after.

For more research summaries and discussion about Automated Market Makers:

An Analysis of Uniswap Markets, summarized by lead SCRF researcher Vishesh Choudhry, was written in the early days of Uniswap and outlines how Constant Product Markets (the core of Uniswap) can be represented by relatively simple and elegant convex equations.

SCRF researcher Trent Davis summarizes Why Stake When You Can Borrow? which looks at how staking derivatives affects network security for Proof of Stake and Decentralized Finance. An interesting discussion about the risks involved with collateral swapping, capital flight, AAVE’s June 2020 v2 whitepaper, deflationary mechanisms such as Ethereum’s EIP-1559 proposal and the intersection between financialization and network security follows.

Davis also summarizes Automated Market Makers for Decentralized Finance which takes a look at circle/ellipse-based cost functions and considers whether they’d be a better substitute for Automated Market Makers than currently used cost functions, which are vulnerable to front-running attacks and may not abide by the principles of supply and demand.

SCRF researcher Barry Gitarts sketches out some of the unsolved issues involving Derivative AMMs, and proposes a solution for derivatives trading that involves using an oracle to observe the state of a liquidity pool, and compute the pool’s delta (the correlation between price change with the underlying and derivative asset). To read on in Issues in Derivative Automated Market Makers.

2 Likes

One of the interesting things emerging about Uniswap v3 is that we see the liquidity distributions matching the expectation of a semi-normal distribution but with less skew than might have been anticipated.


Source: info.uniswap.org

The concentration of liquidity certainly seems to be delivering on the promise of “virtual” liquidity and is theoretically providing improved capital efficiency. The primary caveat that remains to be seen is the gas cost for maintaining this efficiency going forward.

4 Likes