Concentrated liquidity is more capital efficient because with increased concentration, the same amount of tokens invested creates greater depth of liquidity.
From Uniswap's blog:
By concentrating their liquidity, LPs can provide the same liquidity depth as v2 within specified price ranges while putting far less capital at risk.
An informal way how to define capital efficiency is to see it as the ratio between the capital invested and the value generated.
- Situation A: $1 generates 1 units of value.
- Situation B: $1 generates 2 units of value.
The capital in situation B is used in 2 times more efficient way.
The main function liquidity pools is to let trading to happen.
All else being equal, a pool is more attractive for traders if it has deeper liquidity, because deeper liquidity -> reduced price impact for trades. It means that value (efficiency) of capital is greater if it is used to achieve greater depth of liquidity in the pool.
Some math-based analysis follows.
Exactly how inefficient are v2 pools? Uniswap v2 is a traditional constant-product automated market maker (AMM). The liquidity L is defined with the help of the formula
x * y = L^2,
where x
and y
are the amounts of assets in the pool. Let's say the initial price of ETH is P0 = $2000
, and that someone puts 1 ETH and 2000 DAI in the pool. In this case the value of L
is sqrt(2000)
or approximately 44.7.
Now for a different price P
the amount of ETH in the pool is sqrt(P0 / P)
, for instance for P = $8000
the pool has 0.5 ETH and for P = $500
it has 2 ETH. This means that 50% of the pool's capital is reserved for ETH prices below $500 and above $8000. Moreover, 10% of the pool's capital is reserved for prices 100x different from the current price, that is, above $200,000 and below $10 per ETH. Sure, these prices are not impossible, but is it really sensible to allocate as much as 10% of capital for these extreme scenarios?
The consequence of the capital being so spread out is that the price impact of trades in v2 pools is high unless the amount of capital is huge.
In v3, LPs can set the price range [Pa, Pb]
of each position, where Pa
is the minimum price and Pb
the maximum price. The virtual liquidity of such a v3 position / pool is defined as:
For instance, if someone believes that ETH is going to trade in the $500-$8000 range they can set these range endpoints and be 2x more capital efficient. Verify this in code:
L = sqrt(2000) # v2 liquidity value for 1 ETH + 2000 DAI position
P = 2000 # initial/current price
Pa = 500 # range min price
Pb = 8000 # range max price
# amount of ETH to match the v2 liquidity
x = L * (sqrt(Pb) - sqrt(P)) / (sqrt(Pb) * sqrt(P))
# amount of DAI to match the v2 liquidity
y = L * (sqrt(P) - sqrt(Pa))
The result is x=0.5
(ETH) and y=1000
(DAI) as expected. 2x less ETH and DAI needed to achieve the same liquidity depth!
Expanding this further:
[P / 4, P * 4] price range -> 2x capital efficiency
[P / 2, P * 2] price range -> 3.41x capital efficiency
[P / 1.2, P * 1.2] price range -> 11.48x capital efficiency
[P / 1.1, P * 1.1] price range -> 21.49x capital efficiency
[P / 1.05, P * 1.05] price range -> 41.49x capital efficiency
[P / 1.01, P * 1.01] price range -> 201.5x capital efficiency
Meaning that for stable pairs, v3 pools can easily be hundreds of times more capital efficient than v2.
For more experimentation, the Uniswap's blog also have a nice interactive calculator at the end of the "Capital Efficiency" section.
In Uniswap V3, the formula for calculating the price from a given tick is the following:
By looking up Uniswap V3's codebase, we find that the price is represented by the variable sqrtPriceX96
of type uint160
. Where:
And:
By using both formulas above and plugging in the maximum tick value of 887272
, we find the following:
We know that in Solidity, the conventional way of representing the value of ∞ would be to use the maximum integer value allowed by a type. The max number we could obtain with a uint160
(i.e. the type of sqrtPriceX96
) is:
Therefore, we conclude that the chosen maximum tick of 887272
is just enough to produce a sqrtPriceX96
that is still lower than the maximum value allowed by the type uint160
. And most likely, the minimum tick value of -887272
was chosen to represent a price of zero for symmetry.
Best Answer
A tick is initialized (i.e. active) if it's an endpoint of a position deployed in the pool.
Only ticks that are divisible by the pool's tick spacing can be initialized. For instance, the in 0.3% pool only ticks that are divisible by 60 can be position endpoints. (In the 0.05% pools: divisible by 10; in the 1% pools: divisible by 200.)
Uninitialized ticks still may contain liquidity. For instance, most ticks in the middle of a liquidity position are uninitialized, even though they do and contain liquidity for swapping. This includes ticks that are in the middle of a position and are divisible by 60 (or 10, or 200), unless they are the endpoints of some other position.
All uninitialized ticks have
liquidityNet
andliquidityGross
values equal to zero. (See the v3 whitepaper for the definition of these variables.) An initialized tick may haveliquidityNet
equal to zero - for example, when it's the upper tick of one position with liquidityL
, and the lower tick of another position with the same amount of liquidityL
, sinceL - L = 0
. However, an initialized never hasliquidityGross
equal to zero. WhenevenliquidityGross
of an active tick becomes zero dues to a position being closes, the tick is un-initialized.