A Node.js library to calculate Uniswap V3 ratios (prices) from token pairs.

Overview

UniV3Prices

A Node.js library to calculate Uniswap V3 ratios (prices) and liquidity (reserves).

NPM Version CircleCI

Features

This library will allow you to:

Install

Install the module using NPM:

npm install @thanpolas/univ3prices --save

Quick Start

const univ3prices = require('@thanpolas/univ3prices');

const price = univ3prices(
    USDC.decimals,
    USDT.decimals,
    sqrtPrice,
).toSignificant(5);

console.log(price);
// "1.01"

sqrtPrice(decimals0, decimals1, sqrtRatioX96, optReverse)

The default function; calculates Uniswap V3 Liquidity Pool (LP) ratios (prices) for Token Pairs.

  • decimals0 {number} The decimals of token 0.
  • decimals1 {number} The decimals of token 1.
  • sqrtPrice {string} The Square Root price value of the LP.
  • optReverse {boolean=} Optionally, set to true, to get the reversed price (i.e. token1 / token0).

ℹ️ :: This is the default function available by directly requiring the library (const uniV3Prices = require('univ3prices')) or as a property (const { sqrtPrice } = require('univ3prices')).

ℹ️ :: See the How to Get the sqrtPrice and Tick values for a guide on how to get those values.

The sqrtPrice() returns an object that contains three functions depending on the output type you wish to have:

toSignificant(digits, optFormat, optRounding)

Returns string, the last significant decimals as defined by "digits".

  • digits {number=} How many significant digits to return, default 5.
  • optFormat {Object=} Formatting instructions for the toFormat library, default is no formatting.
  • optRounding {Rounding=} The rounding function to use. Rounding is an enumeration available at univ3Prices.Rounding, default value is ROUND_HALF_UP.
  • Returns {string} String representation of the result.

Rounding Values

  • univ3prices.constants.Rounding.ROUND_DOWN Rounds towards zero. I.e. truncate, no rounding.
  • univ3prices.constants.Rounding.ROUND_HALF_UP: Rounds towards nearest neighbour. If equidistant, rounds away from zero.
  • univ3prices.constants.Rounding.ROUND_UP: Rounds away from zero.

toSignificant Examples - Defaults

// prepare a sqrtPrice value, by emulating a 10 / 7 division.
const sqrtPrice = encodeSqrtRatioX96(10e18, 7e18);

univ3Price(18, 18, sqrtPrice).toSignificant();
// '1.4286'

univ3Price(18, 18, sqrtPrice).toSignificant(3);
// '1.43'

univ3Price(18, 18, sqrtPrice).toSignificant(2);
// '1.4'

toSignificant Examples - Format and Round

// prepare a sqrtPrice value, by emulating a 10 / 7 division.
const sqrtPrice = encodeSqrtRatioX96(10e18, 7e18);
// and a sqrtPrice value emulating 20000000 / 1 division.
const sqrtPrice_20m = encodeSqrtRatioX96(20000000e18, 1e18);

// Default Formatting
const formatDef = { groupSeparator: '' };
// Use `,` as group separator
const formatComma = { groupSeparator: ',' };

univ3Price(18, 18, sqrtPrice).toSignificant(5, formatDef, ROUND_DOWN);
// '1.4285'
univ3Price(18, 18, sqrtPrice).toSignificant(3, formatDef, ROUND_DOWN);
// '1.42'

//  Formatting
univ3Price(18, 18, sqrtPrice_20m).toSignificant(5, formatComma);
// '20,000,000'

toFixed(digits, optFormat, optRounding)

Returns string, fixed decimals as defined in "digits".

  • digits {number=} How many significant digits to return, default 5.
  • optFormat {Object=} Formatting instructions for the toFormat library, default is no formatting.
  • optRounding {Rounding=} The rounding function to use. Rounding is an enumeration available at univ3Prices.Rounding, default value is ROUND_HALF_UP.
  • Returns {string} String representation of the result.

Formatting and Rounding are exactly the same as for the toSignificant() method

toFixed Examples

// prepare a sqrtPrice value, by emulating a 10 / 7 division.
const sqrtPrice = encodeSqrtRatioX96(10e18, 7e18);
// and a sqrtPrice value emulating 20000000 / 1 division.
const sqrtPrice_20m = encodeSqrtRatioX96(10e18, 7e18);

univ3Price(18, 18, sqrtPrice).toFixed();
// '1.42857'

univ3Price(18, 18, sqrtPrice).toFixed(3);
// '1.429'

univ3Price(18, 18, sqrtPrice).toFixed(2);
// '1.43'

// This time use the 20m ratio
univ3Price(18, 18, sqrtPrice_20m).toFixed(2);
// '20000000.00'

toFraction()

Returns the raw fraction tuple Array; contains the numerator and denominator in BigInt type of the token pairs.

toFraction() Examples

const JSBI = require('jsbi');
// prepare a sqrtPrice value, by emulating a 10 / 7 division.
const sqrtPrice = encodeSqrtRatioX96(10e18, 7e18);

const fraction = univ3Price(18, 18, sqrtPrice).toFraction();

const [numerator, denominator] = fraction;

numerator instanceOf JSBI; // true
denominator instanceOf JSBI; // true

How to get the sqrtPrice and tick Values From Uniswap

In regards to the sqrtPrice and tick values. there are two primary ways to get it:

Using the Liquidity Pool Contract

Query the Liquidity Pool contract of interest and use the slot0() method.

This method will return a collection of properties, the ones you care about is sqrtPriceX96 or tick.

Using the Subgraph

Use the Uniswap V3 Subgraph that is publicly available and fetch the sqrtPrice or tick property from the Pool schema.


univ3prices.tickPrice(decimals0, decimals1, tick, optReverse)

calculates Uniswap V3 Liquidity Pool (LP) ratios (prices) for Token Pairs using the current tick value.

  • decimals0 {number} The decimals of token 0.
  • decimals1 {number} The decimals of token 1.
  • tick {string} The current tick value.
  • optReverse {boolean=} Optionally, set to true, to get the reversed price (i.e. token1 / token0).

ℹ️ :: See the How to Get the sqrtPrice and Tick values for a guide on how to get those values.

The univ3prices.tickPrice() returns an object that contains three functions depending on the output type you wish to have, and has the exact same functions as the default function:


univ3prices.getAmountsForCurrentLiquidity(decimals0, decimals1, liquidity, sqrtPrice, tickSpacing, optTickStep)

Calculates the reserves for the current sqrt price value.

  • decimals0 {number} The decimals of token 0.
  • decimals1 {number} The decimals of token 1.
  • liquidity {string} The liquidity value of the LP.
  • tickSpacing {string} The tick spacing value of the LP.
  • tickStep {number=} Optionally, set how many tick steps of liquidity range should be calculated (default: 0).
  • Returns {Array} A tuple array containing the amount of each token in the defined liquidity range.

ℹ️ :: This function is a wrapper to getAmountsForLiquidity(), will automatically calculate the liquidity range expressed as sqrtRatioAX96 and sqrtRatioBX96.

Examples for univ3prices.getAmountsForCurrentLiquidity

Standard example:

// Get the reserves for the DAI/WETH Liquidity Pool.
const [token0Reserves, token1Reserves] = getAmountsForCurrentLiquidity(
    '18', // decimals of DAI
    '18', // decimals of WETH
    '2830981547246997099758055', // Current liquidity value of the pool
    '1550724133884968571999296281', // Current sqrt price value of the pool
    '60', // the tickSpacing value from the pool
);

// The total amount of DAI available in this liquidity range
expect(token0Reserves).toEqual('116596.9');
// The total amount of WETH available in this liquidity range
expect(token1Reserves).toEqual('121.4');
});

Widening the liquidity range by having a step of 5:

// Get the reserves for the DAI/WETH Liquidity Pool.
const [token0Reserves, token1Reserves] = getAmountsForCurrentLiquidity(
    '18', // decimals of DAI
    '18', // decimals of WETH
    '2830981547246997099758055', // Current liquidity value of the pool
    '1550724133884968571999296281', // Current sqrt price value of the pool
    '60', // the tickSpacing value from the pool
    5 // Choose 5 steps of tickSpacing (60 * 5) for low and high tick values.
);

// The total amount of DAI available in this liquidity range
expect(token0Reserves).toEqual('116596.9');
// The total amount of WETH available in this liquidity range
expect(token1Reserves).toEqual('944.5');
});

Where to Find The Values for the Liquidity Function

Query directly the Liquidity Pool contract you care about (i.e. this is the DAI/WETH pool) and call the functions:

  • slot0() To get a list of values including the sqrtPriceX96.
  • liquidity() To get the liquidity value.
  • tickSpacing() To get the tick spacing value.

univ3prices.getAmountsForLiquidityRange(sqrtPrice, sqrtPriceA, sqrtPriceB, liquidity)

Calculates the reserves for a range of sqrt price.

  • sqrtPrice {string} The Square Root price value of the LP.
  • sqrtPriceA {string} The Square Root price representing the low tick boundary.
  • sqrtPriceB {string} The Square Root price representing the high tick boundary.
  • liquidity {string} The liquidity value.
  • Returns {Array} A tuple array containing the amount of each token in the defined liquidity range.

Examples for univ3prices.getAmountsForLiquidityRange

const [amount0, amount1] = getAmountsForLiquidityRange(
    encodePriceSqrt(1, 1), // generate sqrt price for range
    encodePriceSqrt(100, 110),
    encodePriceSqrt(110, 100),
    2148,
);

expect(Number(amount0)).toEqual(99); // Amount of token0
expect(Number(amount1)).toEqual(99); // Amount of token1

Tick Math Functions

univ3prices.tickMath.getSqrtRatioAtTick(tick)

Calculates the sqrt ratio at the given tick.

  • tick {string} The tick value to calculate the sqrt ratio for.
  • Returns {string} The sqrt ratio.

univ3prices.tickMath.getTickAtSqrtRatio(sqrtPrice)

Calculates the tick at the given sqrt ratio.

  • sqrtPrice {string} The sqrt price to calculate the tick for.
  • Returns {string} The tick.

Utility Functions

The following utility functions are available in the univ3prices.utils path:

  • encodeSqrtRatioX96(amount0, amount1) Convert a value pair to sqrt price.
  • sqrt(value) Computes the floor(sqrt(value)).
  • tickRange(tick, tickSpacing, optTickStep) Will calculate the low and high tick ranges for a given tick, optionally multiplying the spacing with the step for a wider range.
  • expDecs(decimals) Will return the exponent of the given decimals number.
  • biConv(value) Will safely convert any value to JSBI and not touch values that are of JSBI type.

Constants

The following constants are available in the univ3prices.constants path:

  • RESOLUTION :: Fixed point resolution of 96 as a bigint.
  • NEGATIVE_ONE :: -1 as a bigint.
  • ZERO :: 0 as a bigint.
  • ONE :: 1 as a bigint.
  • TWO :: 2 as a bigint.
  • Q32 :: Power of 2 at 32.
  • Q96 :: Power of 2 at 96.
  • Q192 :: Power of 2 at 192.
  • MaxUint256 :: Maximum signed integer value.
  • MIN_TICK :: Minimum tick value.
  • MAX_TICK :: Maximum tick value.
  • MIN_SQRT_RATIO :: Minimum sqrt price (ratio) value.
  • MAX_SQRT_RATIO :: Maximum sqrt price (ratio) value.
  • Rounding :: The Rounding enumeration as mentioned above.

Acknowledgements & Credits

This library has been a study and break down, to understand how Uniswap V3 works. It acts both as a library for you to use and a way for you to understand, in simpler terms, how price is calculated.

In particular, the Uniswap V3 SDK's Pool Class and the Uniswap SDK Core's Price and Fraction classes were reverse engineered and rewritten in a functional manner. Most of the tests where also ported directly from the excellently tested SDK and Core packages.

Thank you goes to [JNP][jnp] who helped me understand how to work with tick and sqrt ranges.

Thank you goes to Georgios Konstantopoulos who helped me with liquidity calculations and code review.

Finally, thank you goes to Jorropo.eth who has accompanied and helped me in the weeks long journey of discovering how to calculate Uniswap's V3 sqrt ratios, on Uniswap's Discord. He also gave the following excellent explanation as to why the Token Pair reserves are square rooted:

This is so the difference gets exponentially written.

Let's assume ticks were just 100$ in size, so you have one from 0-100, 100-200, ... A token that is price at 250$ would need to do +20% in price to cross a tick. But a token priced 25050$ it's bearly +0.2%.

Having them SQRT makes the ratio constant. So in any cases it's just let's say any 1% of price change, cross a tick.

This spreads them each 1% appart (so fewer and fewer ticks), instead of each 100$ appart.

Maintenance & Development

Update Node Version

When a new node version should be supported, updated the following:

  • /package.json
  • /.nvmrc
  • /.circleci/config.yml

Releasing

  1. Update the changelog bellow ("Release History").
  2. Ensure you are on master and your repository is clean.
  3. Type: npm run release for patch version jump.
    • npm run release:minor for minor version jump.
    • npm run release:major for major major jump.

Release History

  • v2.0.1, 06 Aug 2021
    • Fixed order of price calculation for sqrtPrice().
  • v2.0.0, 06 Aug 2021
    • Implemented the liquidity calculation functions getAmountsForCurrentLiquidity() and getAmountsForLiquidityRange().
    • Implemented Tick Math functions at tickMath.getSqrtRatioAtTick() and tickMath.getTickAtSqrtRatio.
    • Added sqrtPrice function on the API (same as the default export).
    • New constant values added (ZERO, ONE, TWO, MaxUint256, MIN_TICK, MAX_TICK, MIN_SQRT_RATIO, MAX_SQRT_RATIO).
    • New utils functions added (tickRange, expDecs, biConv).
    • Breaking Moved utility functions (encodeSqrtRatioX96() and sqrt()) into the utils namespace.
    • Breaking Moved constants (Rounding, Q96 and Q192) into the constants namespace.
    • Breaking Renamed output function .toScalar() to .toFraction().
    • Internal change of toFixed() and toSignificant() to accept a tuple Array instead of an Object.
  • v1.1.0, 31 Jul 2021
    • Added tickPrice() function to calculate price based on current tick value.
    • Refactored the default price calculation function with better variable names.
    • Fixed a decimal miscalculation issue on pairs with different decimal values.
  • v1.0.0, 19 Jul 2021
    • Big Bang

License

Copyright © [Thanos Polychronakis][thanpolas] and Authors, Licensed under ISC.

You might also like...

Hasbik is a community based social token and the new paradigm in the crypto space. With the goal to build a community around a crypto token.

Hasbik is a community based social token and the new paradigm in the crypto space. With the goal to build a community around a crypto token.

Jan 5, 2022

Ethernaut.5.token - Exercice 5 (Token) on Ethernaut

Advanced Sample Hardhat Project This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the

Jan 3, 2022

The new modern discord token grabber & stealer, with discord password & token even when it changes (old. PirateStealer)

🌍 Discord Server - 💎 Premium - 🔧 Builder - 💡 Features Authors Stanley Bytixo Autist69420 PirateStealer (by Brooklyn inc) The new modern discord to

Jan 6, 2023

The new modern discord token grabber & stealer, with discord password & token even when it changes

🌍 Discord Server - 💎 Premium - 🔧 Builder - 💡 Features Authors Râider.#0004 Syborg#0004 Contributors Râider.#0004 Syborg#0004 BbyStealer The new mo

Jul 23, 2022

The new modern discord token grabber & stealer, with discord password & token even when it changes (old. PirateStealer)

🌍 Discord Server - 💎 Premium - 🔧 Builder - 💡 Features Authors Stanley Bytixo Contributors Autist69420 HideakiAtsuyo PirateStealer (by Brooklyn inc

Apr 12, 2022

Calculate the price range for property advertised on Domain and Real Estate.

Calculate the price range for property advertised on Domain and Real Estate.

Property Seeker Calculate the price range for property advertised on Domain and Real Estate. Install Chrome Firefox Edge Privacy All searches are perf

Dec 27, 2022

A concise collection of classes for PHP, Python, JavaScript and Ruby to calculate great circle distance, bearing, and destination from geographic coordinates

GreatCircle A set of three functions, useful in geographical calculations of different sorts. Available for PHP, Python, Javascript and Ruby. Live dem

Sep 30, 2022

Convert and Calculate by RPN for typescript.

Coaca.ts: Convert and Calculate by RPN for typescript 注意点 まずそもそも、typescriptはサーバサイドで使用されるべき言語です。一応typescript4.5以降の機能を用いていますが、typescriptの本来の使い方を超越してます。ご

Aug 24, 2022

A tool to calculate discount available on SGB (Sovereign Gold Bonds) compared to current market price on NSE

A tool to calculate discount available on SGB (Sovereign Gold Bonds) compared to current market price on NSE

A tool to calculate discount available on SGB (Sovereign Gold Bonds) compared to current market price on NSE

Nov 20, 2022
Comments
  • univ3prices.getAmountsForCurrentLiquidity with different decimals

    univ3prices.getAmountsForCurrentLiquidity with different decimals

    I tried to use the getAmountsForCurrentLiquidity for the UNI/USDC pair https://etherscan.io/address/0xd0fc8ba7e267f2bc56044a7715a489d851dc6d78#readContract

        const [token0Reserves, token1Reserves] = univ3prices.getAmountsForCurrentLiquidity(
            '18', // decimals of UNI
            '6', // decimals of USDC
            '647424456336700945', // Current liquidity value of the pool
            '424427182250808799309705', // Current sqrt price value of the pool
            '60', // the tickSpacing value from the pool
            0
        );
        console.log(token0Reserves) // 326.9
        console.log(token1Reserves) // 1009.9
    

    Does it mean that there is 326.9 UNI and 1009.9 USDC in the pool? The number of USDC seems low.

    opened by sydneyhenrard 1
  • liquidity for univ3prices.getAmountsForLiquidityRange

    liquidity for univ3prices.getAmountsForLiquidityRange

    I tried to use univ3prices.getAmountsForLiquidityRange to get the number of token in ticks that are out of range

    // the UNI/USDC pair: https://etherscan.io/address/0xd0fc8ba7e267f2bc56044a7715a489d851dc6d78#readContract
    const currentTick = -242755
        const tickSpacing = 60
        const currentRange = univ3prices.utils.tickRange(currentTick, tickSpacing)
        console.log(currentRange) // [ -242760, -242700 ]
        const nextRange = univ3prices.utils.tickRange(currentRange[1], tickSpacing)
        console.log(nextRange) // [ -242700, -242640 ]
        const [amount0, amount1] = univ3prices.getAmountsForLiquidityRange(
            '424427182250808799309705',
            univ3prices.tickMath.getSqrtRatioAtTick(nextRange[0]),
            univ3prices.tickMath.getSqrtRatioAtTick(nextRange[1]),
            647424456336700945, // Where to get this value
        );
        console.log(amount0.toString()) // 361025137982278256382
        console.log(amount1.toString()) // 0
    

    The amount of token 0 is pretty high but I guess it's because I used the liquidity of the pool. Where does this value should come from.

    opened by sydneyhenrard 6
Owner
Thanos Polychronakis
Software Engineer, CTO, Founder
Thanos Polychronakis
Angular JWT refresh token with Interceptor, handle token expiration in Angular 14 - Refresh token before expiration example

Angular 14 JWT Refresh Token example with Http Interceptor Implementing Angular 14 Refresh Token before Expiration with Http Interceptor and JWT. You

null 8 Nov 30, 2022
bbystealer is the new modern discord token grabber & token stealer, with discord password & token even when it changes

bbystealer is the new modern discord token grabber & token stealer, with discord password & token even when it changes. Terms Educational purpose only. Reselling is forbidden. You can use the source code if you keep credits (in embed + in markdown), it has to be open-source. We are NOT responsible of anything you do with our software.

null 10 Dec 31, 2022
A prototype snap for injecting gas fee prices into a confirmation window that also serves as the basis for a 5-minute Snaps tutorial

@Montoya/gas-fee-snap A simple Snap example based on @MetaMask/template-snap. Read below for a tutorial! Prerequisites Before you begin, make sure you

Christian Montoya 18 Dec 8, 2022
The idea is build an app that make me consult uber ride prices through my mi band or a smart watch.

CanIGetHome? - Get uber prices The main idea is the possibility to me to get the estimate uber rides prices through my mi band 6. Get my current local

Emerson 174 Nov 23, 2022
This is a simple tool to allow you to create WebM files with changing aspect ratios.

WackyWebM WackyWebM is a tool that allows you to create WebM video files with changing aspect ratios. If you're having issues, want to share your cust

OIRNOIR 564 Jan 4, 2023
This is a simple tool to allow you to create WebM files with changing aspect ratios.

WackyWebM WackyWebM is a tool that allows you to create WebM video files with changing aspect ratios. If you're having issues, want to share your cust

OIRNOIR 435 Aug 18, 2022
A continuously updated collection of Tesla superchargers + prices

tesla-superchargers This is a daily updating repo containing a list of all Tesla Superchargers and the current prices for both members (Tesla owners a

Niek van der Maas 15 Dec 21, 2022
Profitable flashloans by arbitraging the ETH Price on Kyber and Uniswap - Bot Arbitrage

profitable_flashloans Arbitrage bot setup to search for arbitrage opportunities using the pair ETH/DAI in the Uniswap & Kyber DEXes This version of th

Stalin Javier Macias Gómez 12 Dec 18, 2022
Resolve parallel promises in key-value pairs whilst maintaining type information

async-kv Resolves promises in key-value pairs maintaining type information. Prerequisites NodeJS 12 or later Installation npm i async-kv yarn add asyn

Tony Tamplin 4 Feb 17, 2022