[Ethereum] Computing the Uniswap V3 pair price from Q64.96 number

blockchainsolidityuniswap

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

Best Answer

    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.

Related Topic