@orca-so/whirlpools-sdk
Version:
Typescript SDK to interact with Orca's Whirlpool program.
252 lines • 11.7 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PriceMath = void 0;
const anchor_1 = require("@coral-xyz/anchor");
const common_sdk_1 = require("@orca-so/common-sdk");
const decimal_js_1 = __importDefault(require("decimal.js"));
const public_1 = require("../../types/public");
const tick_utils_1 = require("./tick-utils");
const BIT_PRECISION = 14;
const LOG_B_2_X32 = "59543866431248";
const LOG_B_P_ERR_MARGIN_LOWER_X64 = "184467440737095516";
const LOG_B_P_ERR_MARGIN_UPPER_X64 = "15793534762490258745";
class PriceMath {
static priceToSqrtPriceX64(price, decimalsA, decimalsB) {
return common_sdk_1.MathUtil.toX64(price.mul(decimal_js_1.default.pow(10, decimalsB - decimalsA)).sqrt());
}
static sqrtPriceX64ToPrice(sqrtPriceX64, decimalsA, decimalsB) {
return common_sdk_1.MathUtil.fromX64(sqrtPriceX64)
.pow(2)
.mul(decimal_js_1.default.pow(10, decimalsA - decimalsB));
}
static tickIndexToSqrtPriceX64(tickIndex) {
if (tickIndex > 0) {
return new anchor_1.BN(tickIndexToSqrtPricePositive(tickIndex));
}
else {
return new anchor_1.BN(tickIndexToSqrtPriceNegative(tickIndex));
}
}
static sqrtPriceX64ToTickIndex(sqrtPriceX64) {
if (sqrtPriceX64.gt(new anchor_1.BN(public_1.MAX_SQRT_PRICE)) ||
sqrtPriceX64.lt(new anchor_1.BN(public_1.MIN_SQRT_PRICE))) {
throw new Error("Provided sqrtPrice is not within the supported sqrtPrice range.");
}
const msb = sqrtPriceX64.bitLength() - 1;
const adjustedMsb = new anchor_1.BN(msb - 64);
const log2pIntegerX32 = signedShiftLeft(adjustedMsb, 32, 128);
let bit = new anchor_1.BN("8000000000000000", "hex");
let precision = 0;
let log2pFractionX64 = new anchor_1.BN(0);
let r = msb >= 64 ? sqrtPriceX64.shrn(msb - 63) : sqrtPriceX64.shln(63 - msb);
while (bit.gt(new anchor_1.BN(0)) && precision < BIT_PRECISION) {
r = r.mul(r);
let rMoreThanTwo = r.shrn(127);
r = r.shrn(63 + rMoreThanTwo.toNumber());
log2pFractionX64 = log2pFractionX64.add(bit.mul(rMoreThanTwo));
bit = bit.shrn(1);
precision += 1;
}
const log2pFractionX32 = log2pFractionX64.shrn(32);
const log2pX32 = log2pIntegerX32.add(log2pFractionX32);
const logbpX64 = log2pX32.mul(new anchor_1.BN(LOG_B_2_X32));
const tickLow = signedShiftRight(logbpX64.sub(new anchor_1.BN(LOG_B_P_ERR_MARGIN_LOWER_X64)), 64, 128).toNumber();
const tickHigh = signedShiftRight(logbpX64.add(new anchor_1.BN(LOG_B_P_ERR_MARGIN_UPPER_X64)), 64, 128).toNumber();
if (tickLow == tickHigh) {
return tickLow;
}
else {
const derivedTickHighSqrtPriceX64 = PriceMath.tickIndexToSqrtPriceX64(tickHigh);
if (derivedTickHighSqrtPriceX64.lte(sqrtPriceX64)) {
return tickHigh;
}
else {
return tickLow;
}
}
}
static tickIndexToPrice(tickIndex, decimalsA, decimalsB) {
return PriceMath.sqrtPriceX64ToPrice(PriceMath.tickIndexToSqrtPriceX64(tickIndex), decimalsA, decimalsB);
}
static priceToTickIndex(price, decimalsA, decimalsB) {
return PriceMath.sqrtPriceX64ToTickIndex(PriceMath.priceToSqrtPriceX64(price, decimalsA, decimalsB));
}
static priceToInitializableTickIndex(price, decimalsA, decimalsB, tickSpacing) {
return tick_utils_1.TickUtil.getInitializableTickIndex(PriceMath.priceToTickIndex(price, decimalsA, decimalsB), tickSpacing);
}
static invertPrice(price, decimalsA, decimalsB) {
const tick = PriceMath.priceToTickIndex(price, decimalsA, decimalsB);
const invTick = tick_utils_1.TickUtil.invertTick(tick);
return PriceMath.tickIndexToPrice(invTick, decimalsB, decimalsA);
}
static invertSqrtPriceX64(sqrtPriceX64) {
const tick = PriceMath.sqrtPriceX64ToTickIndex(sqrtPriceX64);
const invTick = tick_utils_1.TickUtil.invertTick(tick);
return PriceMath.tickIndexToSqrtPriceX64(invTick);
}
static getSlippageBoundForSqrtPrice(sqrtPriceX64, slippage) {
const sqrtPriceX64Decimal = common_sdk_1.DecimalUtil.fromBN(sqrtPriceX64);
const slippageNumerator = new decimal_js_1.default(slippage.numerator.toString());
const slippageDenominator = new decimal_js_1.default(slippage.denominator.toString());
const lowerBoundSqrtPriceDecimal = sqrtPriceX64Decimal
.mul(slippageDenominator.sub(slippageNumerator).sqrt())
.div(slippageDenominator.sqrt())
.toDecimalPlaces(0);
const upperBoundSqrtPriceDecimal = sqrtPriceX64Decimal
.mul(slippageDenominator.add(slippageNumerator).sqrt())
.div(slippageDenominator.sqrt())
.toDecimalPlaces(0);
const lowerBoundSqrtPrice = anchor_1.BN.min(anchor_1.BN.max(new anchor_1.BN(lowerBoundSqrtPriceDecimal.toFixed(0)), public_1.MIN_SQRT_PRICE_BN), public_1.MAX_SQRT_PRICE_BN);
const upperBoundSqrtPrice = anchor_1.BN.min(anchor_1.BN.max(new anchor_1.BN(upperBoundSqrtPriceDecimal.toFixed(0)), public_1.MIN_SQRT_PRICE_BN), public_1.MAX_SQRT_PRICE_BN);
const lowerTickCurrentIndex = PriceMath.sqrtPriceX64ToTickIndex(lowerBoundSqrtPrice);
const upperTickCurrentIndex = PriceMath.sqrtPriceX64ToTickIndex(upperBoundSqrtPrice);
return {
lowerBound: [lowerBoundSqrtPrice, lowerTickCurrentIndex],
upperBound: [upperBoundSqrtPrice, upperTickCurrentIndex],
};
}
}
exports.PriceMath = PriceMath;
function tickIndexToSqrtPricePositive(tick) {
let ratio;
if ((tick & 1) != 0) {
ratio = new anchor_1.BN("79232123823359799118286999567");
}
else {
ratio = new anchor_1.BN("79228162514264337593543950336");
}
if ((tick & 2) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79236085330515764027303304731")), 96, 256);
}
if ((tick & 4) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79244008939048815603706035061")), 96, 256);
}
if ((tick & 8) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79259858533276714757314932305")), 96, 256);
}
if ((tick & 16) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79291567232598584799939703904")), 96, 256);
}
if ((tick & 32) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79355022692464371645785046466")), 96, 256);
}
if ((tick & 64) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79482085999252804386437311141")), 96, 256);
}
if ((tick & 128) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("79736823300114093921829183326")), 96, 256);
}
if ((tick & 256) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("80248749790819932309965073892")), 96, 256);
}
if ((tick & 512) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("81282483887344747381513967011")), 96, 256);
}
if ((tick & 1024) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("83390072131320151908154831281")), 96, 256);
}
if ((tick & 2048) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("87770609709833776024991924138")), 96, 256);
}
if ((tick & 4096) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("97234110755111693312479820773")), 96, 256);
}
if ((tick & 8192) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("119332217159966728226237229890")), 96, 256);
}
if ((tick & 16384) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("179736315981702064433883588727")), 96, 256);
}
if ((tick & 32768) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("407748233172238350107850275304")), 96, 256);
}
if ((tick & 65536) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("2098478828474011932436660412517")), 96, 256);
}
if ((tick & 131072) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("55581415166113811149459800483533")), 96, 256);
}
if ((tick & 262144) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("38992368544603139932233054999993551")), 96, 256);
}
return signedShiftRight(ratio, 32, 256);
}
function tickIndexToSqrtPriceNegative(tickIndex) {
let tick = Math.abs(tickIndex);
let ratio;
if ((tick & 1) != 0) {
ratio = new anchor_1.BN("18445821805675392311");
}
else {
ratio = new anchor_1.BN("18446744073709551616");
}
if ((tick & 2) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18444899583751176498")), 64, 256);
}
if ((tick & 4) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18443055278223354162")), 64, 256);
}
if ((tick & 8) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18439367220385604838")), 64, 256);
}
if ((tick & 16) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18431993317065449817")), 64, 256);
}
if ((tick & 32) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18417254355718160513")), 64, 256);
}
if ((tick & 64) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18387811781193591352")), 64, 256);
}
if ((tick & 128) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18329067761203520168")), 64, 256);
}
if ((tick & 256) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("18212142134806087854")), 64, 256);
}
if ((tick & 512) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("17980523815641551639")), 64, 256);
}
if ((tick & 1024) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("17526086738831147013")), 64, 256);
}
if ((tick & 2048) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("16651378430235024244")), 64, 256);
}
if ((tick & 4096) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("15030750278693429944")), 64, 256);
}
if ((tick & 8192) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("12247334978882834399")), 64, 256);
}
if ((tick & 16384) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("8131365268884726200")), 64, 256);
}
if ((tick & 32768) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("3584323654723342297")), 64, 256);
}
if ((tick & 65536) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("696457651847595233")), 64, 256);
}
if ((tick & 131072) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("26294789957452057")), 64, 256);
}
if ((tick & 262144) != 0) {
ratio = signedShiftRight(ratio.mul(new anchor_1.BN("37481735321082")), 64, 256);
}
return ratio;
}
function signedShiftLeft(n0, shiftBy, bitWidth) {
let twosN0 = n0.toTwos(bitWidth).shln(shiftBy);
twosN0.imaskn(bitWidth + 1);
return twosN0.fromTwos(bitWidth);
}
function signedShiftRight(n0, shiftBy, bitWidth) {
let twoN0 = n0.toTwos(bitWidth).shrn(shiftBy);
twoN0.imaskn(bitWidth - shiftBy + 1);
return twoN0.fromTwos(bitWidth - shiftBy);
}
//# sourceMappingURL=price-math.js.map