Skip to content

Concentrated Liquidity Pool

Overview

Concentrated Liquidity (from UniswapV3) enhances the traditional automated market maker (AMM) model. It allows liquidity providers (LPs) to concentrate their funds in specific price ranges within a pool, rather than evenly distributing liquidity across the entire trading range in v2.

Concentrated liquidity curve

Concepts

Tick

Tick refers to a specific price point within a price range. The entire price range of a pool is divided into discrete intervals, and each interval is defined by tickLower, tickUpper.

// From ICLPoolManager.sol
struct ModifyLiquidityParams {
    // the lower and upper tick of the position
    int24 tickLower;
    int24 tickUpper;
    // how to modify the liquidity
    int256 liquidityDelta;
    // a value to set if you want unique liquidity positions at the same range
    bytes32 salt;
}
 
/// @dev see more at CLPoolManager
function modifyLiquidity(PoolKey memory key, ICLPoolManager.ModifyLiquidityParams memory params, bytes calldata hookData);

See below on examples on computing price from tick:

price = 1.0001 ** tick 

Example 1: CAKE/WETH pool:

// token0: CAKE (18 decimals)
// token1: WETH (18 decimals)
// tick: -68554 (as of 12 March 2024)
 
price: 1.0001 ** -68554 = 0.00105411128
// this also imply 1 CAKE = 0.00105411128 WETH 

Example 2: WETH/USDT pool with different token decimals pool:

// token0: WETH (18 decimals)
// token1: USDT (6 decimals)
// tick:  -193256 (as of 12 March 2024)
 
price: 1.0001 ** -193256 = 4.04965646e-9
// this also imply 1 WETH = 4.04965646e-9 USDT 
// However WETH is 18 decimals and USDT is 6 decimal, we have to multiply by 12 decimals
ratio of WETH/USDT with decimals: = 4.04965646e-9 * (10**18/10**6): 1 WETH = 4049.65646 USDT

Tick Spacing

Tick spacing define the minimum price movement between two adjacent ticks within a pool. This is one of the parameter in PoolKey.

Keep in mind that there are trade off. While smaller tick spacing allow for more precise positioning of liquidity, it might come with higher gas cost potentially. Larger tick spacing could be cheaper on gas but comes with higher slippage in trade execution potentially.

Tick spacingPrice movement between tick
10.01%
100.1%
500.5%
1001%
Example
  • tickSpacing is 10: adjacent tick to 1000 is 990 and 1010.
  • tickSpacing is 100: adjacent tick to 1000 is 900 and 1100

sqrtPriceX96

This uint160 value represent square root price ratio of token0 to token1. Its a binary fixed point number Q64.96 which means 64 bits of integer and 96 bits as decimal.

Hence

sqrtPriceX96 = sqrt(price) * 2**96
 
// shifting price to the LHS result in the below:
price = (sqrtPriceX96 / 2**96) ** 2

See below on examples on computing price ratio from sqrtPriceX96:

Example 1: CAKE/WETH pool:

// token0: CAKE (18 decimals)
// token1: WETH (18 decimals)
// sqrtPriceX96: 2574020484831874748518739167 (as of 12 March 2024)
 
// Price ratio of token0 (CAKE) and token1 (WETH):
price = (2574020484831874748518739167 / 2**96) **2 = 0.00105551602
 
CAKE to WETH: 1 CAKE = 0.00105551602 WETH 
WETH to CAKE: 1 / 0.00105551602: 1 WETH = 947.40 CAKE 
 
// CAKE is around $4.3 and ETH is $4100. so 947.40 CAKE = 4073 USDC

Example 2: WETH/USDT pool with different token decimals pool:

// token0: WETH (18 decimals)
// token1: USDT (6 decimals)
// sqrtPriceX96: 5046499860369450237927407 (as of 12 March 2024)
 
// Price ratio of token0 (WETH) in term of token1 (USDT): 4.0571e-9 ETH for 1 USDC
price = (5046499860369450237927407 / 2**96) **2 = 4.0571e-9
 
WETH to USDC: 4.0571e-9 / (10**6/10**18): 1 WETH = 4057 USDT
USDT to WETH: 4.0571e-9 / (10**18/10**6): 1 USDT = 4.0571e-21 WETH 

Liqudity delta

Liquidity delta, an int value refers to the differences in liquidity at modifyLiquidity. When its positive, it means user is adding liquidity, conversely when its negative, it means user is removing liquidity. Do refer to LiquidityAmounts.sol on calculating the liquidity.