1

Based on the formula on this page i wrote this Solidity contract with a function to get the price of a Token in term of USDC(6 digits) inside a Uniswap V3 pool:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;

import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";

contract LiquidityValueCalcV3 {

function calculatePrice(address poolAddress) external view returns (uint160 sqrtPriceX96, uint256 sqrtPriceX96Pow, uint256 priceFromSqrtX96, uint256 priceAdj, uint256 finalPrice) {
    IUniswapV3Pool pool = IUniswapV3Pool(poolAddress);
    
    (sqrtPriceX96,,,,,,) = pool.slot0();
    
    sqrtPriceX96Pow = uint256(sqrtPriceX96 * 10**12);

    priceFromSqrtX96 = sqrtPriceX96Pow / 2**96;
    
    priceFromSqrtX96 = priceFromSqrtX96**2; 

    priceAdj = priceFromSqrtX96 * 10**6; 

    finalPrice = (1 * 10**48) / priceAdj;
}
}

Tested with Polygon WETH/USDC pair: 0x45dDa9cb7c25131DF268515131f647d726f50608

return:

0: uint160: sqrtPriceX96 2010392868018209499338592130999787

1: uint256: sqrtPriceX96Pow 2010392868018209499338592130999787000000000000

2: uint256: priceFromSqrtX96 643876689299748453054950187649129

3: uint256: priceAdj 643876689299748453054950187649129000000

4: uint256: finalPrice 1553092411

OK, correct WETH price in the var finalPrice: 1553092411 (1553,092411) USDC

The problem comes when i try to use the same function on the Arbitrum network with a pair WETH/USDC, for example: 0xC31E54c7a869B9FcBEcc14363CF510d1c41fa443

return:

0: uint160: sqrtPriceX96 3123101146007058503352705

1: uint256: sqrtPriceX96Pow 3123101146007058503352705000000000000

2: uint256: priceFromSqrtX96 1553863710370084

3: uint256: priceAdj 1553863710370084000000

4: uint256: finalPrice 643557085043082587815192507

Wrong price in the finalPrice var but correct 18 digits price in priceAdj.

The result is also different with other pools, why? Is there anything extra that needs to be taken into consideration when calculating the price?

1 Answer 1

1

It all depends if token0 is ETH or USDC. It should be:

if (token0 == WETH) {
    finalPrice = 1e12 * (sqrtPriceX96/2**96)**2;
} else {
    finalPrice = 1e12/(sqrtPriceX96/2**96)**2;
}
1
  • 1
    The answer is correct, but makes it extremely likely (more than in the original example to suffer from rounding errors. For example, if the price is below 1.0, then sqrtPriceX96/2**96 becomes zero.
    – kfx
    Commented Oct 20, 2023 at 13:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.