UNPKG

@renec-foundation/redex-sdk

Version:

Typescript SDK to interact with Orca's Whirlpool program.

225 lines (224 loc) 10.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TickArrayUtil = exports.TickUtil = void 0; const common_sdk_1 = require("@orca-so/common-sdk"); const tiny_invariant_1 = __importDefault(require("tiny-invariant")); const public_1 = require("../../types/public"); const pda_utils_1 = require("./pda-utils"); var TickSearchDirection; (function (TickSearchDirection) { TickSearchDirection[TickSearchDirection["Left"] = 0] = "Left"; TickSearchDirection[TickSearchDirection["Right"] = 1] = "Right"; })(TickSearchDirection || (TickSearchDirection = {})); /** * A collection of utility functions when interacting with Ticks. * @category Whirlpool Utils */ class TickUtil { constructor() { } /** * Get the offset index to access a tick at a given tick-index in a tick-array * * @param tickIndex The tick index for the tick that this offset would access * @param arrayStartIndex The starting tick for the array that this tick-index resides in * @param tickSpacing The tickSpacing for the Whirlpool that this tickArray belongs to * @returns The offset index that can access the desired tick at the given tick-array */ static getOffsetIndex(tickIndex, arrayStartIndex, tickSpacing) { return Math.floor((tickIndex - arrayStartIndex) / tickSpacing); } /** * Get the startIndex of the tick array containing tickIndex. * * @param tickIndex * @param tickSpacing * @param offset can be used to get neighboring tick array startIndex. * @returns */ static getStartTickIndex(tickIndex, tickSpacing, offset = 0) { const realIndex = Math.floor(tickIndex / tickSpacing / public_1.TICK_ARRAY_SIZE); const startTickIndex = (realIndex + offset) * tickSpacing * public_1.TICK_ARRAY_SIZE; const ticksInArray = public_1.TICK_ARRAY_SIZE * tickSpacing; const minTickIndex = public_1.MIN_TICK_INDEX - ((public_1.MIN_TICK_INDEX % ticksInArray) + ticksInArray); (0, tiny_invariant_1.default)(startTickIndex >= minTickIndex, `startTickIndex is too small - - ${startTickIndex}`); (0, tiny_invariant_1.default)(startTickIndex <= public_1.MAX_TICK_INDEX, `startTickIndex is too large - ${startTickIndex}`); return startTickIndex; } /** * Get the nearest (rounding down) valid tick index from the tickIndex. * A valid tick index is a point on the tick spacing grid line. */ static getInitializableTickIndex(tickIndex, tickSpacing) { return tickIndex - (tickIndex % tickSpacing); } static getNextInitializableTickIndex(tickIndex, tickSpacing) { return TickUtil.getInitializableTickIndex(tickIndex, tickSpacing) + tickSpacing; } static getPrevInitializableTickIndex(tickIndex, tickSpacing) { return TickUtil.getInitializableTickIndex(tickIndex, tickSpacing) - tickSpacing; } /** * Get the previous initialized tick index within the same tick array. * * @param account * @param currentTickIndex * @param tickSpacing * @returns */ static findPreviousInitializedTickIndex(account, currentTickIndex, tickSpacing) { return TickUtil.findInitializedTick(account, currentTickIndex, tickSpacing, TickSearchDirection.Left); } /** * Get the next initialized tick index within the same tick array. * @param account * @param currentTickIndex * @param tickSpacing * @returns */ static findNextInitializedTickIndex(account, currentTickIndex, tickSpacing) { return TickUtil.findInitializedTick(account, currentTickIndex, tickSpacing, TickSearchDirection.Right); } static findInitializedTick(account, currentTickIndex, tickSpacing, searchDirection) { var _a; const currentTickArrayIndex = tickIndexToInnerIndex(account.startTickIndex, currentTickIndex, tickSpacing); const increment = searchDirection === TickSearchDirection.Right ? 1 : -1; let stepInitializedTickArrayIndex = searchDirection === TickSearchDirection.Right ? currentTickArrayIndex + increment : currentTickArrayIndex; while (stepInitializedTickArrayIndex >= 0 && stepInitializedTickArrayIndex < account.ticks.length) { if ((_a = account.ticks[stepInitializedTickArrayIndex]) === null || _a === void 0 ? void 0 : _a.initialized) { return innerIndexToTickIndex(account.startTickIndex, stepInitializedTickArrayIndex, tickSpacing); } stepInitializedTickArrayIndex += increment; } return null; } static checkTickInBounds(tick) { return tick <= public_1.MAX_TICK_INDEX && tick >= public_1.MIN_TICK_INDEX; } static isTickInitializable(tick, tickSpacing) { return tick % tickSpacing === 0; } /** * * Returns the tick for the inverse of the price that this tick represents. * Eg: Consider tick i where Pb/Pa = 1.0001 ^ i * inverse of this, i.e. Pa/Pb = 1 / (1.0001 ^ i) = 1.0001^-i * @param tick The tick to invert * @returns */ static invertTick(tick) { return -tick; } } exports.TickUtil = TickUtil; /** * A collection of utility functions when interacting with a TickArray. * @category Whirlpool Utils */ class TickArrayUtil { /** * Get the tick from tickArray with a global tickIndex. */ static getTickFromArray(tickArray, tickIndex, tickSpacing) { const realIndex = tickIndexToInnerIndex(tickArray.startTickIndex, tickIndex, tickSpacing); const tick = tickArray.ticks[realIndex]; (0, tiny_invariant_1.default)(!!tick, `tick realIndex out of range - start - ${tickArray.startTickIndex} index - ${tickIndex}, realIndex - ${realIndex}`); return tick; } /** * Return a sequence of tick array pdas based on the sequence start index. * @param tick - A tick in the first tick-array of your sequence * @param tickSpacing - Tick spacing for the whirlpool * @param numOfTickArrays - The number of TickArray PDAs to generate * @param programId - Program Id of the whirlpool for these tick-arrays * @param whirlpoolAddress - Address for the Whirlpool for these tick-arrays * @returns TickArray PDAs for the sequence` */ static getTickArrayPDAs(tick, tickSpacing, numOfTickArrays, programId, whirlpoolAddress, aToB) { let arrayIndexList = [...Array(numOfTickArrays).keys()]; if (aToB) { arrayIndexList = arrayIndexList.map((value) => -value); } return arrayIndexList.map((value) => { const startTick = TickUtil.getStartTickIndex(tick, tickSpacing, value); return pda_utils_1.PDAUtil.getTickArray(programId, whirlpoolAddress, startTick); }); } /** * Return a string containing all of the uninitialized arrays in the provided addresses. * Useful for creating error messages. * * @param tickArrayAddrs - A list of tick-array addresses to verify. * @param fetcher - {@link AccountFetcher} * @param refresh - If true, always fetch the latest on-chain data * @returns A string of all uninitialized tick array addresses, delimited by ",". Falsy value if all arrays are initialized. */ static getUninitializedArraysString(tickArrayAddrs, fetcher, refresh) { return __awaiter(this, void 0, void 0, function* () { const taAddrs = common_sdk_1.AddressUtil.toPubKeys(tickArrayAddrs); const tickArrayData = yield fetcher.listTickArrays(taAddrs, refresh); // Verify tick arrays are initialized if the user provided them. if (tickArrayData) { const uninitializedIndices = TickArrayUtil.getUninitializedArrays(tickArrayData); if (uninitializedIndices.length > 0) { const uninitializedArrays = uninitializedIndices .map((index) => taAddrs[index].toBase58()) .join(", "); return uninitializedArrays; } } return null; }); } static getUninitializedArraysPDAs(ticks, programId, whirlpoolAddress, tickSpacing, fetcher, refresh) { return __awaiter(this, void 0, void 0, function* () { const startTicks = ticks.map((tick) => TickUtil.getStartTickIndex(tick, tickSpacing)); const removeDupeTicks = [...new Set(startTicks)]; const tickArrayPDAs = removeDupeTicks.map((tick) => pda_utils_1.PDAUtil.getTickArray(programId, whirlpoolAddress, tick)); const fetchedArrays = yield fetcher.listTickArrays(tickArrayPDAs.map((pda) => pda.publicKey), refresh); const uninitializedIndices = TickArrayUtil.getUninitializedArrays(fetchedArrays); return uninitializedIndices.map((index) => { return { startIndex: removeDupeTicks[index], pda: tickArrayPDAs[index], }; }); }); } /** * Evaluate a list of tick-array data and return the array of indices which the tick-arrays are not initialized. * @param tickArrays - a list of TickArrayData or null objects from AccountFetcher.listTickArrays * @returns an array of array-index for the input tickArrays that requires initialization. */ static getUninitializedArrays(tickArrays) { return tickArrays .map((value, index) => { if (!value) { return index; } return -1; }) .filter((index) => index >= 0); } } exports.TickArrayUtil = TickArrayUtil; function tickIndexToInnerIndex(startTickIndex, tickIndex, tickSpacing) { return Math.floor((tickIndex - startTickIndex) / tickSpacing); } function innerIndexToTickIndex(startTickIndex, tickArrayIndex, tickSpacing) { return startTickIndex + tickArrayIndex * tickSpacing; }