Whitepaper: Uniswap v3 Core


  • 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.


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


  • 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.


  • 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.


  • 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.

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?


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.


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?


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).

1 Like

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?

1 Like