# 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 at 19:30
``````    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;
}
``````

We can adapt code from the actual Uniswap V3 library function OracleLibrary.getQuoteAtTick(): https://github.com/Uniswap/v3-periphery/blob/v1.3.0/contracts/libraries/OracleLibrary.sol

``````function getQuoteFromSqrtRatioX96(
uint160 sqrtRatioX96, // same as sqrtPriceX96
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);
}
}
``````

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