UNPKG

@alcorexchange/alcor-swap-sdk

Version:

## Installation ​​ **npm** ``` npm i @alcorexchange/alcor-swap-sdk ``` **yarn** ``` yarn add @alcorexchange/alcor-swap-sdk ``` ## Usage ### Import:

147 lines (127 loc) 4.39 kB
import JSBI from "jsbi"; import invariant from "tiny-invariant"; import { Tick } from "../entities/tick"; import { ZERO } from "../internalConstants"; import { isSorted } from "./isSorted"; function tickComparator(a: Tick, b: Tick) { return a.id - b.id; } /**x * Utility methods for interacting with sorted lists of ticks */ export abstract class TickList { /** * Cannot be constructed */ private constructor() {} public static validateList(ticks: Tick[], tickSpacing: number) { invariant(tickSpacing > 0, "TICK_SPACING_NONZERO"); // ensure ticks are spaced appropriately invariant( ticks.every(({ id }) => id % tickSpacing === 0), "TICK_SPACING" ); const totalNet = ticks.reduce( (accumulator, { liquidityNet }) => JSBI.add(accumulator, liquidityNet), ZERO ) if (!JSBI.equal(totalNet, ZERO)) console.error('ZERO_NET INVARIAN ISSUE!') // HOTFIX ignoring for now TODO // ensure tick liquidity deltas sum to 0 // invariant( // JSBI.equal( // ticks.reduce( // (accumulator, { liquidityNet }) => // JSBI.add(accumulator, liquidityNet), // ZERO // ), // ZERO // ), // "ZERO_NET" // ); invariant(isSorted(ticks, tickComparator), "SORTED"); } public static isBelowSmallest(ticks: readonly Tick[], tick: number): boolean { invariant(ticks.length > 0, "LENGTH"); return tick < ticks[0].id; } public static isAtOrAboveLargest( ticks: readonly Tick[], tick: number ): boolean { invariant(ticks.length > 0, "LENGTH"); return tick >= ticks[ticks.length - 1].id; } public static getTick(ticks: readonly Tick[], id: number): Tick { const tick = ticks[this.binarySearch(ticks, id)]; invariant(tick.id === id, "NOT_CONTAINED"); return tick; } /** * Finds the largest tick in the list of ticks that is less than or equal to tick * @param ticks list of ticks * @param tick tick to find the largest tick that is less than or equal to tick * @private */ private static binarySearch(ticks: readonly Tick[], tick: number): number { let l = 0; let r = ticks.length - 1; while (l <= r) { const i = Math.floor((l + r) / 2); if (ticks[i].id <= tick && (i === ticks.length - 1 || ticks[i + 1].id > tick)) { return i; } if (ticks[i].id < tick) l = i + 1; else r = i - 1; } return r; // Если не нашли точное совпадение, возвращаем последний меньший индекс } public static nextInitializedTick( ticks: readonly Tick[], tick: number, lte: boolean ): Tick { if (lte) { invariant(!TickList.isBelowSmallest(ticks, tick), "BELOW_SMALLEST"); if (TickList.isAtOrAboveLargest(ticks, tick)) { return ticks[ticks.length - 1]; } const id = this.binarySearch(ticks, tick); return ticks[id]; } else { invariant(!this.isAtOrAboveLargest(ticks, tick), "AT_OR_ABOVE_LARGEST"); if (this.isBelowSmallest(ticks, tick)) { return ticks[0]; } const id = this.binarySearch(ticks, tick); return ticks[id + 1]; } } public static nextInitializedTickWithinOneWord( ticks: readonly Tick[], tick: number, lte: boolean, tickSpacing: number ): [number, boolean] { const compressed = Math.floor(tick / tickSpacing); const tickCount = ticks.length; if (lte) { const wordPos = compressed >> 7; const minimum = (wordPos << 7) * tickSpacing; if (tick < ticks[0].id) return [minimum, false]; if (tick >= ticks[tickCount - 1].id) return [ticks[tickCount - 1].id, true]; const id = this.binarySearch(ticks, tick); const nextInitializedTick = Math.max(minimum, ticks[id].id); return [nextInitializedTick, nextInitializedTick === ticks[id].id]; } else { const wordPos = (compressed + 1) >> 7; const maximum = (((wordPos + 1) << 7) - 1) * tickSpacing; if (tick >= ticks[tickCount - 1].id) return [maximum, false]; if (tick < ticks[0].id) return [ticks[0].id, true]; const id = this.binarySearch(ticks, tick); const nextInitializedTick = Math.min(maximum, ticks[id + 1].id); return [nextInitializedTick, nextInitializedTick === ticks[id + 1].id]; } } }