UNPKG

@alcorexchange/alcor-swap-sdk

Version:

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

189 lines (182 loc) 7.93 kB
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import invariant from "tiny-invariant"; import { ZERO } from "../internalConstants"; import { isSorted } from "./isSorted"; function tickComparator(a, b) { return a.id - b.id; } /**x * Utility methods for interacting with sorted lists of ticks */ export let TickList = /*#__PURE__*/function () { /** * Cannot be constructed */ function TickList() { _classCallCheck(this, TickList); } return _createClass(TickList, null, [{ key: "validateList", value: function validateList(ticks, tickSpacing) { 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 }) => accumulator + liquidityNet, ZERO); if (!(totalNet === ZERO)) console.error('ZERO_NET INVARIAN ISSUE!'); // HOTFIX ignoring for now TODO // ensure tick liquidity deltas sum to 0 // invariant( // (// ticks.reduce( // (accumulator, { liquidityNet }) => // (accumulator + liquidityNet), // ZERO // ) === // ZERO //), // "ZERO_NET" // ); invariant(isSorted(ticks, tickComparator), "SORTED"); } }, { key: "isBelowSmallest", value: function isBelowSmallest(ticks, tick) { invariant(ticks.length > 0, "LENGTH"); return tick < ticks[0].id; } }, { key: "isAtOrAboveLargest", value: function isAtOrAboveLargest(ticks, tick) { invariant(ticks.length > 0, "LENGTH"); return tick >= ticks[ticks.length - 1].id; } }, { key: "getTick", value: function getTick(ticks, id) { 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 */ }, { key: "binarySearch", value: function binarySearch(ticks, tick) { 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; // Если не нашли точное совпадение, возвращаем последний меньший индекс } }, { key: "nextInitializedTick", value: function nextInitializedTick(ticks, tick, lte) { 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]; } } }, { key: "nextInitializedTickWithinOneWord", value: function nextInitializedTickWithinOneWord(ticks, tick, lte, tickSpacing) { 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]; } } /** * Optimized version with cursor hint for sequential access (swap loops) * @param cursorHint - last known index position, -1 if unknown * @returns [tickId, initialized, newCursorIndex] */ }, { key: "nextInitializedTickWithinOneWordWithCursor", value: function nextInitializedTickWithinOneWordWithCursor(ticks, tick, lte, tickSpacing, cursorHint) { 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, -1]; if (tick >= ticks[tickCount - 1].id) return [ticks[tickCount - 1].id, true, tickCount - 1]; // Use cursor hint for O(1) lookup if valid let id; if (cursorHint >= 0 && cursorHint < tickCount) { // Linear scan from hint (swap moves monotonically) if (ticks[cursorHint].id <= tick && (cursorHint === tickCount - 1 || ticks[cursorHint + 1].id > tick)) { id = cursorHint; } else if (cursorHint > 0 && ticks[cursorHint - 1].id <= tick && ticks[cursorHint].id > tick) { id = cursorHint - 1; } else { id = this.binarySearch(ticks, tick); } } else { id = this.binarySearch(ticks, tick); } const nextInitializedTick = Math.max(minimum, ticks[id].id); return [nextInitializedTick, nextInitializedTick === ticks[id].id, id]; } else { const wordPos = compressed + 1 >> 7; const maximum = ((wordPos + 1 << 7) - 1) * tickSpacing; if (tick >= ticks[tickCount - 1].id) return [maximum, false, tickCount - 1]; if (tick < ticks[0].id) return [ticks[0].id, true, 0]; // Use cursor hint for O(1) lookup if valid let id; if (cursorHint >= 0 && cursorHint < tickCount - 1) { if (ticks[cursorHint].id <= tick && ticks[cursorHint + 1].id > tick) { id = cursorHint; } else if (cursorHint < tickCount - 2 && ticks[cursorHint + 1].id <= tick && ticks[cursorHint + 2].id > tick) { id = cursorHint + 1; } else { id = this.binarySearch(ticks, tick); } } else { id = this.binarySearch(ticks, tick); } const nextInitializedTick = Math.min(maximum, ticks[id + 1].id); return [nextInitializedTick, nextInitializedTick === ticks[id + 1].id, id]; } } }]); }();