# Computing the Uniswap V3 pair price from Q64.96 number

I am trying to compute a Uniswap V3 pool token price in Solidity.

I can get the square root price of Q64.96 number as `uint160` (e.g., `1234217676608908277512433764` - value of DAI/ETH pool (price at that time around 1 ETH for 4090 DAI)).

This can be retrieved via `IUniswapV3PoolState.slot0()`

As the function docstring says: "sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value"

How can I convert this number to `uint256`?

The calculated price should suggest the value of 1 ETH for 4090 DAI

Is there any other way of getting the Uniswap V3 pair price?

The answer would preferably be in solidity, but other answers are also acceptable.

Unsuccessful attempt

I tried squaring the number `1234217676608908277512433764` and then shifting it by 96, but the result was `1.922666416729829e+25` which doesn't seem too be correct.

`(1234217676608908277512433764^2) >> 96 = 1.922666416729829e+25`

The relationship between sqrtPriceX96 and price is metioned in the official doc:https://docs.uniswap.org/sdk/guides/fetching-prices

``````    sqrtPriceX96 = sqrt(price) * 2 ** 96
# divide both sides by 2 ** 96
sqrtPriceX96 / (2 ** 96) = sqrt(price)
# square both sides
(sqrtPriceX96 / (2 ** 96)) ** 2 = price
# expand the squared fraction
(sqrtPriceX96 ** 2) / ((2 ** 96) ** 2)  = price
# multiply the exponents in the denominator to get the final expression
sqrtRatioX96 ** 2 / 2 ** 192 = price
``````
• Where did `sqrtRatioX96` at the bottom come from? Nov 22, 2022 at 22:31
• `sqrtRatioX96` and `sqrtPriceX96` are interchangeable terms according to the official docs linked in this answer
– Voy
Dec 6, 2022 at 15:27
• thanks for this, good mathematical breakdown Mar 22, 2023 at 19:30
• Just a note that ABOVE link is 404 now and needs to be replaced Mar 31 at 22:02
``````function getPrice(address tokenIn, address tokenOut)
external
view
returns (uint256 price)
{
IUniswapV3Pool pool = IUniswapV3Pool(factory.getPool(tokenIn, tokenOut, FEE);
(uint160 sqrtPriceX96,,,,,,) =  pool.slot0();
return uint(sqrtPriceX96).mul(uint(sqrtPriceX96)).mul(1e18) >> (96 * 2);
}
``````

Returns spot price with 1e18 precision. Be careful to use spot price because it is a subject for a flash loan attacks. Either use TWAP price or check that price hasn't move much before using spot price. Also, I haven't tested this code for precision loss and upper/lower boundaries. Because Uniswap v3 use Q64.96 notion for decimals but it doesn't seem that practical. The output of the function is a number with e18 precision. It depends which decimal lib you use in your project.

• This does not seem to generalize well. How would this work on a pair like usdt/wbtc which is of decimals 8 and 6 respectively? Dec 25, 2022 at 13:49

TLDR: This is something that seems to work with every token (regardless of how many decimals it has) and it takes into consideration math overflow issues. Read explanation below:

``````import '@uniswap/v3-core/contracts/libraries/FullMath.sol';

function sqrtPriceX96ToUint(uint160 sqrtPriceX96, uint8 decimalsToken0)
internal
pure
returns (uint256)
{
uint256 numerator1 = uint256(sqrtPriceX96) * uint256(sqrtPriceX96);
uint256 numerator2 = 10**decimalsToken0;
return FullMath.mulDiv(numerator1, numerator2, 1 << 192);
}
``````

Regarding decimals: If you are calculating the price on a token with 18 decimal places, multiplying `sqrtPriceX96` by `1e18` before the division should work just fine, but it will break for tokens with other decimals (USDC anyone). In order to obtain the correct results you should pass `ERC20(token0).decimals()` to the above function.

Regarding math overflow: Depending on the price you convert the uint256 will overflow and you will end up with a wrong price. The safest way to do this is with the `MathFull.sol` library from Uniswap v3 which accounts for overflowing.

Another way to calculate the price is by taking advantage of the relationship between `liquidity`, `sqrtPricex96` and token amounts.

``````import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@uniswap/v3-core/contracts/libraries/FixedPoint96.sol';
import '@uniswap/v3-core/contracts/libraries/FullMath.sol';
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol';

function calculatePriceFromLiquidity(
uint24 fee,
) public view returns (uint256) {
IUniswapV3Pool pool = IUniswapV3Pool(IUniswapV3Factory(factory).getPool(token0, token1, fee));
(uint160 sqrtPriceX96, , , , , , ) = pool.slot0();

uint256 amount0 = FullMath.mulDiv(pool.liquidity(), FixedPoint96.Q96, sqrtPriceX96);

uint256 amount1 = FullMath.mulDiv(pool.liquidity(), sqrtPriceX96, FixedPoint96.Q96);

return (amount1 * 10**ERC20(token0).decimals()) / amount0;
}
``````
• This is wrong/misleading, if the active liquidity in a pool is 0 then your function would attempt to divide by 0. Liquidity is irrelevant to calculating price, the only reason your function returns the correct price(provided liquidity != 0) is because your function can be reduced to the same formula as many of the other answers listed here: (sqrtPriceX96 * sqrtPriceX96 * 1e18)/(2^96 * 2 ^ 96) = (sqrtPriceX96*sqrtPriceX96 * 1e18)/(2^192) Dec 2, 2023 at 14:07

We can adapt code from the actual Uniswap v3-periphery library function OracleLibrary.getQuoteAtTick. Instead of having the function accept the `tick` and then convert the `tick` to `sqrtRatioX96` using `TickMath.getSqrtRatioAtTick(tick)`, we modify it to directly accept the `sqrtRatioX96` as shown below:

``````/**
* @dev Calculates the amount of quote token received for a given amount of base token
* based on the square root of the price ratio (sqrtRatioX96).
*
* @param sqrtRatioX96 The square root of the price ratio(in terms of token1/token0) between two tokens, encoded as a Q64.96 value.
* @param baseAmount The amount of the base token for which the quote is to be calculated. Specify 1e18 for a price(quoteAmount) with 18 decimals of precision.
* @param inverse Specifies the direction of the price quote. If true then baseAmount must be the amount of token1, if false then baseAmount must be the amount for token0
*
* @return quoteAmount The calculated amount of the quote token for the specified baseAmount
*/
function getQuoteFromSqrtRatioX96(
uint160 sqrtRatioX96,
uint128 baseAmount,
bool inverse
) internal pure returns (uint256 quoteAmount) {
// Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
if (sqrtRatioX96 <= type(uint128).max) {
uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
quoteAmount = !inverse
? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)
: FullMath.mulDiv(1 << 192, baseAmount, ratioX192);
} else {
uint256 ratioX128 = FullMath.mulDiv(
sqrtRatioX96,
sqrtRatioX96,
1 << 64
);
quoteAmount = !inverse
? FullMath.mulDiv(ratioX128, baseAmount, 1 << 128)
: FullMath.mulDiv(1 << 128, baseAmount, ratioX128);
}
}
``````

To further simplify getting the price we can define the following function.

``````/**
* @dev Returns the fixed-point price for a specified sqrtRatioX96, denoted in terms of token1/token0.
* This function simplifies the process of obtaining the price from sqrtRatioX96 by using a standard
* base amount (1e18) and setting the price as non-inverted (token1/token0).
*
* @param sqrtRatioX96 The square root of the price ratio between two tokens, encoded as a Q64.96 value.
*
* @return priceU18 The calculated price in terms of token1/token0, with 18 decimal places of precision.
*/
function getPriceFromSqrtRatioX96(uint160 sqrtRatioX96) internal pure returns (uint256 priceU18) {
// if we specified inverted = true, then we'd get the price in terms of token0/token1
// whereas the UniswapV3Pool sqrtRatioX96 is in terms of token1/token0
return getQuoteFromSqrtRatioX96(sqrtRatioX96, 1e18, false);
}
``````

I created a rust lib that simply returns the price and abstracts the calculations away. Feel free to use it https://github.com/FredCoen/uniswap-utilities

Had to write code for this exact purpose but with both decimal numbers variable, this did the trick for me:

`````` function getPrice(uint160 sqrtRatioX96, uint dec0, uint dec1)
external
pure
returns (uint256 price)
{

uint256 dec = dec1<=dec0 ? (18-dec1)+dec0 :dec0;
uint256 numerator1 =uint256(sqrtRatioX96) *uint256(sqrtRatioX96);
uint256 numerator2 =10**dec;
price = FullMath.mulDiv(numerator1, numerator2, 1 << 192);
}
``````
``````// Get the two token prices of the pool
// PoolInfo is a dictionary object containing the 4 variables needed
// {"SqrtX96" : slot0.sqrtPriceX96.toString(), "Pair": pairName, "Decimal0": Decimal0, "Decimal1": Decimal1}
// to get slot0 call factory contract with tokens and fee,
// then call the pool slot0, sqrtPriceX96 is returned as first dictionary variable
// var FactoryContract =  new ethers.Contract(factory, IUniswapV3FactoryABI, provider);
// var V3pool = await FactoryContract.getPool(token0, token1, fee);
// var poolContract =  new ethers.Contract(V3pool, IUniswapV3PoolABI, provider);
// var slot0 = await poolContract.slot0();

function GetPrice(PoolInfo){
let sqrtPriceX96 = PoolInfo.SqrtX96;
let Decimal0 = PoolInfo.Decimal0;
let Decimal1 = PoolInfo.Decimal1;

const buyOneOfToken0 = ((sqrtPriceX96 / 2**96)**2) / (10**Decimal1 / 10**Decimal0).toFixed(Decimal1);

console.log("price of token0 in value of token1 : " + buyOneOfToken0.toString());
console.log("price of token1 in value of token0 : " + buyOneOfToken1.toString());
console.log("");
// Convert to wei