0

I am trying to query token's prices from Uniswap. I have found the official documentation of Uniswap but it is still not clear for me, as it returns an object that I cannot formulate into an actual price. I am trying to use typescript for this following the example.

Here is the code I am using:

import { ethers } from "ethers";
import { Pool } from "@uniswap/v3-sdk";
import { Token } from "@uniswap/sdk-core";
import { abi as IUniswapV3PoolABI } from "@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json";

interface Immutables {
  factory: string;
  token0: string;
  token1: string;
  fee: number;
  tickSpacing: number;
  maxLiquidityPerTick: ethers.BigNumber;
}

interface State {
  liquidity: ethers.BigNumber;
  sqrtPriceX96: ethers.BigNumber;
  tick: number;
  observationIndex: number;
  observationCardinality: number;
  observationCardinalityNext: number;
  feeProtocol: number;
  unlocked: boolean;
}

const provider = new ethers.providers.JsonRpcProvider(
  "https://mainnet.infura.io/v3/<MYINFURIAURL>"
);
const poolAddress = "0x4e68ccd3e89f51c3074ca5072bbac773960dfa36";
const poolContract = new ethers.Contract(
  poolAddress,
  IUniswapV3PoolABI,
  provider
);

async function getPoolImmutables() {
  const [factory, token0, token1, fee, tickSpacing, maxLiquidityPerTick] =
    await Promise.all([
      poolContract.factory(),
      poolContract.token0(),
      poolContract.token1(),
      poolContract.fee(),
      poolContract.tickSpacing(),
      poolContract.maxLiquidityPerTick(),
    ]);

  const immutables: Immutables = {
    factory,
    token0,
    token1,
    fee,
    tickSpacing,
    maxLiquidityPerTick,
  };
  return immutables;
}

async function getPoolState() {
  const [liquidity, slot] = await Promise.all([
    poolContract.liquidity(),
    poolContract.slot0(),
  ]);

  const PoolState: State = {
    liquidity,
    sqrtPriceX96: slot[0],
    tick: slot[1],
    observationIndex: slot[2],
    observationCardinality: slot[3],
    observationCardinalityNext: slot[4],
    feeProtocol: slot[5],
    unlocked: slot[6],
  };

  return PoolState;
}

async function main() {
  const [immutables, state] = await Promise.all([
    getPoolImmutables(),
    getPoolState(),
  ]);

  const TokenA = new Token(3, immutables.token0, 6, "ETH", "Ether coin");

  const TokenB = new Token(3, immutables.token1, 18, "USDT", "USD Tether");

  const poolExample = new Pool(
    TokenA,
    TokenB,
    immutables.fee,
    state.sqrtPriceX96.toString(),
    state.liquidity.toString(),
    state.tick
  );

  const token0Price = poolExample.token0Price;
  const token1Price = poolExample.token1Price;

  console.log(`${JSON.stringify(TokenA)}`);
  console.log(`${JSON.stringify(TokenB)}`);

  console.log(`ETH price: ${JSON.stringify(token0Price)}`);
  console.log(`USDT price: ${JSON.stringify(token1Price)}`);
}

main();

It returns me this for the two last logs:

ETH price: {"numerator":[705566737,8761776,105637858,994326226,700219462,14069],"denominator":[0,0,0,0,0,0,4096],"baseCurrency":{"chainId":3,"decimals":6,"symbol":"ETH","name":"Ether coin","isNative":false,"isToken":true,"address":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"},"quoteCurrency":{"chainId":3,"decimals":18,"symbol":"USDT","name":"USD Tether","isNative":false,"isToken":true,"address":"0xdAC17F958D2ee523a2206206994597C13D831ec7"},"scalar":{"numerator":[1000000],"denominator":[660865024,931322574]}}

How do I turn this object into an actual number in typescript?

Also one thing that is not clear, are these the prices of the coins in this pool right? It is odd that there is a "traded pair" and there are two prices for the two tokens being traded against each other. Or is this how they represent the bid/ask gap?

Thanks

5
  • Look at the Fraction library in the Uniswap SDK. They use JSBI (big integers) internally to represent the values.
    – kfx
    Jan 10, 2022 at 11:38
  • I have checked the docs for the lib you mentioned. Using token1Price.toSignificant(5) to get the value from the objects it returns for token1: 330560000000000000000. Which is even if it would be off by some order of magnitudes, it is different from what I see for ETH USDT pool on the Uniswap price. Is there an additional trick to extract the price?
    – geo10
    Jan 10, 2022 at 13:35
  • 330560000000000000000 looks a sensible start to me, but some postprocessing is needed. "0.00033056" would be a correct price for USDT in terms of ETH right now, as 1 divided by 0.00033056 is 3035 USDT per ETH.
    – kfx
    Jan 10, 2022 at 14:10
  • I appreciate your input. console.log(token0 price: ${(1 / Number(token0Price.toSignificant(10)))/1000000000000000000000000}); and console.log(token1 price: ${(1 / Number(token1Price.toSignificant(10)))*1000000000000000000000000}); give me actually sensible numbers, BUT they seem to be off based on the Uniswap sites price. Eg: this returns 3035 as you said, but on Uniswap this pair is at 3020 which is big difference considering prices.
    – geo10
    Jan 10, 2022 at 16:10
  • There are multiple USDT/ETH pools, make sure to look at the right one for price.
    – kfx
    Jan 11, 2022 at 17:26

1 Answer 1

0

The easiest way is to use the Price object's .toSignificant(decimalsToPrint) method:

const token0ToToken1Ratio: string = poolContract.token0Price.toSignificant(18);

When converting to/from other objects like CurrencyAmount, you need to convert it to a BigInt. This is necessary because the data protocol doesn't support decimal numbers, so they multiply all the numbers by Token.decimals. It's best to use ethers.utils.parseUnits(token0ToToken1Ratio, token0.decimals) to convert from the format we read the crypto values in (like 1.0 ETH) to the value that is used internally on the blockchain (like 1 * 10**18 ETH). To convert it from the blockchain BigInt type to human readable string, use ethers.utils.formatUnits(token0Price, token0.decimals).

Your Answer

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

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