Storage Formats

Price Storage Format and conversion

You may encounter price in a lot of places

It is stored as sqrt of the real price (jetton0 in terms of jetton1) that is packed in 160 bits of Fixed Point Q64.96 (96 bits of the fractional part) Example how to pack price from virtual reserves. Same could be used if you have a price and want to pack it.

export function encodePriceSqrt(reserve1: bigint, reserve0: bigint): bigint 
{
    BigNumber.set({DECIMAL_PLACES: 60})
    let result = BigNumber(reserve1.toString())
        .div(reserve0.toString())
        .sqrt()
        .multipliedBy(new BigNumber(2).pow(96))
        .integerValue(3);
    return BigInt(result.toFixed(0));
}

export function encodePriceSqrt(price: number): bigint 
{
    BigNumber.set({DECIMAL_PLACES: 60})
    let result = BigNumber(price.toString())
        .sqrt()
        .multipliedBy(new BigNumber(2).pow(96))
        .integerValue(3);
    return BigInt(result.toFixed(0));
}

Example how to invert price

// Don't use this in production. It's quite imprecise.
export function invertPriceSqrtX96(sqrtPriceX96: bigint): bigint {
    return 2n ** (96n+96n) / sqrtPriceX96
}

Unpack the price

// Core to unpack to readable format (note: this loses precision)
export function getApproxFloatPrice(priceSqrt: bigint) : number {
let result = BigNumber(priceSqrt.toString())
    .div(BigNumber(2).pow(48))
    .pow(2)
    .div(BigNumber(2).pow(96))
    return Number(result.toPrecision(8));
}

Also note that if you request the price from the contract it there is a special case to handle. If the price moves outside of all active liquidity ranges it could take values MIN_SQRT_RATIO = 4295128739 MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 To check for validity of the price you may check if current liquidity equals to zero. Current liquidity is also returned by getPoolStateAndConfiguration

Last updated