@alcorexchange/alcor-swap-sdk
Version:
## Installation **npm** ``` npm i @alcorexchange/alcor-swap-sdk ``` **yarn** ``` yarn add @alcorexchange/alcor-swap-sdk ``` ## Usage ### Import:
167 lines (150 loc) • 5.74 kB
text/typescript
import JSBI from "jsbi";
import invariant from "tiny-invariant";
import { ONE, ZERO, MaxUint256, Q64 } from "../internalConstants";
import { mostSignificantBit } from "./mostSignificantBit";
function mulShift(val: JSBI, mulBy: string): JSBI {
return JSBI.signedRightShift(
JSBI.multiply(val, JSBI.BigInt(mulBy)),
JSBI.BigInt(128)
);
}
export abstract class TickMath {
/**
* The minimum tick that can be used on any pool.
*/
public static MIN_TICK = -443636;
/**
* The maximum tick that can be used on any pool.
*/
public static MAX_TICK: number = -TickMath.MIN_TICK;
/**
* The sqrt ratio corresponding to the minimum tick that could be used on any pool.
*/
public static MIN_SQRT_RATIO: JSBI = JSBI.BigInt("4295048017");
/**
* The sqrt ratio corresponding to the maximum tick that could be used on any pool.
*/
public static MAX_SQRT_RATIO: JSBI = JSBI.BigInt(
"79226673515401279992447579062"
);
/**
* Returns the sqrt ratio as a Q64.96 for the given tick. The sqrt ratio is computed as sqrt(1.0001)^tick
* @param tick the tick for which to compute the sqrt ratio
*/
public static getSqrtRatioAtTick(tick: number): JSBI {
invariant(
tick >= TickMath.MIN_TICK &&
tick <= TickMath.MAX_TICK &&
Number.isInteger(tick),
"TICK"
);
const absTick: number = tick < 0 ? tick * -1 : tick;
let ratio: JSBI =
(absTick & 0x1) != 0
? JSBI.BigInt("0xfffcb933bd6fad37aa2d162d1a594001")
: JSBI.BigInt("0x100000000000000000000000000000000");
if ((absTick & 0x2) != 0)
ratio = mulShift(ratio, "0xfff97272373d413259a46990580e213a");
if ((absTick & 0x4) != 0)
ratio = mulShift(ratio, "0xfff2e50f5f656932ef12357cf3c7fdcc");
if ((absTick & 0x8) != 0)
ratio = mulShift(ratio, "0xffe5caca7e10e4e61c3624eaa0941cd0");
if ((absTick & 0x10) != 0)
ratio = mulShift(ratio, "0xffcb9843d60f6159c9db58835c926644");
if ((absTick & 0x20) != 0)
ratio = mulShift(ratio, "0xff973b41fa98c081472e6896dfb254c0");
if ((absTick & 0x40) != 0)
ratio = mulShift(ratio, "0xff2ea16466c96a3843ec78b326b52861");
if ((absTick & 0x80) != 0)
ratio = mulShift(ratio, "0xfe5dee046a99a2a811c461f1969c3053");
if ((absTick & 0x100) != 0)
ratio = mulShift(ratio, "0xfcbe86c7900a88aedcffc83b479aa3a4");
if ((absTick & 0x200) != 0)
ratio = mulShift(ratio, "0xf987a7253ac413176f2b074cf7815e54");
if ((absTick & 0x400) != 0)
ratio = mulShift(ratio, "0xf3392b0822b70005940c7a398e4b70f3");
if ((absTick & 0x800) != 0)
ratio = mulShift(ratio, "0xe7159475a2c29b7443b29c7fa6e889d9");
if ((absTick & 0x1000) != 0)
ratio = mulShift(ratio, "0xd097f3bdfd2022b8845ad8f792aa5825");
if ((absTick & 0x2000) != 0)
ratio = mulShift(ratio, "0xa9f746462d870fdf8a65dc1f90e061e5");
if ((absTick & 0x4000) != 0)
ratio = mulShift(ratio, "0x70d869a156d2a1b890bb3df62baf32f7");
if ((absTick & 0x8000) != 0)
ratio = mulShift(ratio, "0x31be135f97d08fd981231505542fcfa6");
if ((absTick & 0x10000) != 0)
ratio = mulShift(ratio, "0x9aa508b5b7a84e1c677de54f3e99bc9");
if ((absTick & 0x20000) != 0)
ratio = mulShift(ratio, "0x5d6af8dedb81196699c329225ee604");
if ((absTick & 0x40000) != 0)
ratio = mulShift(ratio, "0x2216e584f5fa1ea926041bedfe98");
if ((absTick & 0x80000) != 0)
ratio = mulShift(ratio, "0x48a170391f7dc42444e8fa2");
if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio);
// back to Q64
return JSBI.greaterThan(JSBI.remainder(ratio, Q64), ZERO)
? JSBI.add(JSBI.divide(ratio, Q64), ONE)
: JSBI.divide(ratio, Q64);
}
/**
* Returns the tick corresponding to a given sqrt ratio, s.t. #getSqrtRatioAtTick(tick) <= sqrtRatioX64
* and #getSqrtRatioAtTick(tick + 1) > sqrtRatioX64
* @param sqrtRatioX64 the sqrt ratio as a Q64.96 for which to compute the tick
*/
public static getTickAtSqrtRatio(sqrtRatioX64: JSBI): number {
invariant(
JSBI.greaterThanOrEqual(sqrtRatioX64, TickMath.MIN_SQRT_RATIO) &&
JSBI.lessThan(sqrtRatioX64, TickMath.MAX_SQRT_RATIO),
"SQRT_RATIO"
);
const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX64, JSBI.BigInt(64));
const msb = mostSignificantBit(sqrtRatioX128);
let r: JSBI;
if (JSBI.greaterThanOrEqual(JSBI.BigInt(msb), JSBI.BigInt(128))) {
r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127));
} else {
r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb));
}
let log_2: JSBI = JSBI.leftShift(
JSBI.subtract(JSBI.BigInt(msb), JSBI.BigInt(128)),
JSBI.BigInt(64)
);
for (let i = 0; i < 14; i++) {
r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127));
const f = JSBI.signedRightShift(r, JSBI.BigInt(128));
log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i)));
r = JSBI.signedRightShift(r, f);
}
const log_sqrt10001 = JSBI.multiply(
log_2,
JSBI.BigInt("255738958999603826347141")
);
const tickLow = JSBI.toNumber(
JSBI.signedRightShift(
JSBI.subtract(
log_sqrt10001,
JSBI.BigInt("3402992956809132418596140100660247210")
),
JSBI.BigInt(128)
)
);
const tickHigh = JSBI.toNumber(
JSBI.signedRightShift(
JSBI.add(
log_sqrt10001,
JSBI.BigInt("291339464771989622907027621153398088495")
),
JSBI.BigInt(128)
)
);
return tickLow === tickHigh
? tickLow
: JSBI.lessThanOrEqual(
TickMath.getSqrtRatioAtTick(tickHigh),
sqrtRatioX64
)
? tickHigh
: tickLow;
}
}