4

I'm trying to figure out how to convert a uniswap ratio into wei (and eventually ether).

The uniswap docs commonly mention sqrtPriceX96:

A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)

However, I can't figure out how to convert it into wei (and eventually ether).

Here is my C# Code:

BigInteger sqrRtPrice = BigInteger.Parse("1407006288156847466476392762276105");
var tt = (sqrRtPrice * sqrRtPrice) * (BigInteger)(1e18) / (BigInteger)(1e18) / BigInteger.Pow(((BigInteger)2), 192);
var eth = Nethereum.Util.UnitConversion.Convert.FromWei(tt);

In this example, eth becomes 0.000000000315379099 which is close to what Uniswap says 0.000315432, but I don't understand why mine is off by 6 decimal places. Both tokens in the pool I'm looking at (WETH-DAI) are 18 decimals long. I'm trying to convert Uniswap sqrtPriceX96 to the price I see on the Uniswap display, but I don't understand why I'm a few decimal places off.

I got my current formula from here, but I also tried the formula here and had the same problem.

3 Answers 3

1

sqrtPriceX96 is represented as token1 over token0 or rather how much token1 is needed for 1 token0.

Because solidity uses fixed point numbers there are no decimal places used.

This is a must read on the topic https://uniswap.org/blog/uniswap-v3-math-primer.

Token 1 is determined by which token contract address base16 value is greater.

For example WETH/USDC on Ethereum https://etherscan.io/address/0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8

>>> 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 > 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
True

WETH has 18 decimals of precision, USDC has 6.


Price is reported in the slot0 call avaialble on all Uniswap V3 pools.

[ slot0 method Response ]
  sqrtPriceX96   uint160 :  1837769053120899173775504701779545

In solidity to get price you would do

FullMath.mulDiv(
    uint256(_sqrtRatioX96) * uint256(_sqrtRatioX96),
    10 ** _decimal0,
    1 << 192
);

In nodejs you would do

const returnPrice = async (poolContract, decimals0) => {
  const sqrtPriceX96 = (await poolContract.slot0())[0];
  return sqrtPriceX96
    .pow(BigNumber.from("2"))
    .mul(BigNumber.from("10").pow(decimals0))
    .div(BigNumber.from("2").pow(BigNumber.from("192")));
};

In python you would do

one_token0 = round(decimal.Decimal(sqrtPriceX96 * sqrtPriceX96 * ((10**decimal_token0) / (10**decimal_token1)) / (2 ** 192)), decimal_token1)

Also there are some helpful documents in the Discord if you haven't met the wonderful Rachel.


Example

>>> one_token0 = round(decimal.Decimal(sqrtPriceX96 * sqrtPriceX96 * ((10**6) / (10**18)) / (2 ** 192)), 18)
>>> one_token0
Decimal('0.000538050080273366') # how much WETH for 1 USDC

>>> one_token1 = 1 / one_token0
>>> one_token1
Decimal('1858.563053260640816896359652') # how much USDC for 1 WETH

The first returned value is in 18 decimal precision. Gwei you would multiple by 1e9 and Wei you would multiply by 1e18.


I'm not sure your sqrtPrice is correct. Here I pull the WETH-DAI 5 bips pool (both tokens are 18 decimals of precision as you note). https://etherscan.io/address/0x60594a405d53811d3bc4766596efd80fd545a270#readContract.

[ slot0 method Response ]
  sqrtPriceX96   uint160 :  1837867657081239291626318498

>>> one_token0 = round(decimal.Decimal(sqrtPriceX96 * sqrtPriceX96 * ((10**18) / (10**18))
 / (2 ** 192)), 18)
>>> one_token0
Decimal('0.000538107819075710')

>>> one_token1
Decimal('1858.363630020591262902910979')

If things still don't make sense let me know.

0

sqrtPriceX96 is the number which is the ratio between pool tokens. it does not represent any value. as you shared a quote from docs

A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)

0

Here's how you can consistently convert UniV3 sqrtPriceX96 to price with 18 decimals in Solidity, same principle can be applied in JS. You have to covert it from square root price and adjust for decimals:

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);
}
1
  • Instead of adding the same answer to multiple question it will be better if you flag them as duplicates.
    – Ismael
    Commented Jan 28 at 5:41

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.