UNPKG

@renec-foundation/redex-sdk

Version:

Typescript SDK to interact with Orca's Whirlpool program.

121 lines (120 loc) 5.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TickArraySequence = void 0; const errors_1 = require("../../errors/errors"); const public_1 = require("../../types/public"); const tick_array_index_1 = require("./tick-array-index"); /** * NOTE: differs from contract method of having the swap manager keep track of array index. * This is due to the initial requirement to lazy load tick-arrays. This requirement is no longer necessary. */ class TickArraySequence { constructor(tickArrays, tickSpacing, aToB) { this.tickSpacing = tickSpacing; this.aToB = aToB; if (!tickArrays[0] || !tickArrays[0].data) { throw new Error("TickArray index 0 must be initialized"); } // If an uninitialized TickArray appears, truncate all TickArrays after it (inclusive). this.sequence = []; for (const tickArray of tickArrays) { if (!tickArray || !tickArray.data) { break; } this.sequence.push({ address: tickArray.address, data: tickArray.data, }); } this.touchedArrays = [...Array(this.sequence.length).fill(false)]; this.startArrayIndex = tick_array_index_1.TickArrayIndex.fromTickIndex(this.sequence[0].data.startTickIndex, this.tickSpacing).arrayIndex; } isValidTickArray0(tickCurrentIndex) { const shift = this.aToB ? 0 : this.tickSpacing; const tickArray = this.sequence[0].data; return this.checkIfIndexIsInTickArrayRange(tickArray.startTickIndex, tickCurrentIndex + shift); } getNumOfTouchedArrays() { return this.touchedArrays.filter((val) => !!val).length; } getTouchedArrays(minArraySize) { let result = this.touchedArrays.reduce((prev, curr, index) => { if (curr) { prev.push(this.sequence[index].address); } return prev; }, []); // Edge case: nothing was ever touched. if (result.length === 0) { return []; } // The quote object should contain the specified amount of tick arrays to be plugged // directly into the swap instruction. // If the result does not fit minArraySize, pad the rest with the last touched array const sizeDiff = minArraySize - result.length; if (sizeDiff > 0) { result = result.concat(Array(sizeDiff).fill(result[result.length - 1])); } return result; } getTick(index) { const targetTaIndex = tick_array_index_1.TickArrayIndex.fromTickIndex(index, this.tickSpacing); if (!this.isArrayIndexInBounds(targetTaIndex, this.aToB)) { throw new Error("Provided tick index is out of bounds for this sequence."); } const localArrayIndex = this.getLocalArrayIndex(targetTaIndex.arrayIndex, this.aToB); const tickArray = this.sequence[localArrayIndex].data; this.touchedArrays[localArrayIndex] = true; if (!tickArray) { throw new errors_1.WhirlpoolsError(`TickArray at index ${localArrayIndex} is not initialized.`, errors_1.SwapErrorCode.TickArrayIndexNotInitialized); } if (!this.checkIfIndexIsInTickArrayRange(tickArray.startTickIndex, index)) { throw new errors_1.WhirlpoolsError(`TickArray at index ${localArrayIndex} is unexpected for this sequence.`, errors_1.SwapErrorCode.TickArraySequenceInvalid); } return tickArray.ticks[targetTaIndex.offsetIndex]; } /** * if a->b, currIndex is included in the search * if b->a, currIndex is always ignored * @param currIndex * @returns */ findNextInitializedTickIndex(currIndex) { const searchIndex = this.aToB ? currIndex : currIndex + this.tickSpacing; let currTaIndex = tick_array_index_1.TickArrayIndex.fromTickIndex(searchIndex, this.tickSpacing); // Throw error if the search attempted to search for an index out of bounds if (!this.isArrayIndexInBounds(currTaIndex, this.aToB)) { throw new errors_1.WhirlpoolsError(`Swap input value traversed too many arrays. Out of bounds at attempt to traverse tick index - ${currTaIndex.toTickIndex()}.`, errors_1.SwapErrorCode.TickArraySequenceInvalid); } while (this.isArrayIndexInBounds(currTaIndex, this.aToB)) { const currTickData = this.getTick(currTaIndex.toTickIndex()); if (currTickData.initialized) { return { nextIndex: currTaIndex.toTickIndex(), nextTickData: currTickData }; } currTaIndex = this.aToB ? currTaIndex.toPrevInitializableTickIndex() : currTaIndex.toNextInitializableTickIndex(); } const lastIndexInArray = Math.max(Math.min(this.aToB ? currTaIndex.toTickIndex() + this.tickSpacing : currTaIndex.toTickIndex() - 1, public_1.MAX_TICK_INDEX), public_1.MIN_TICK_INDEX); return { nextIndex: lastIndexInArray, nextTickData: null }; } getLocalArrayIndex(arrayIndex, aToB) { return aToB ? this.startArrayIndex - arrayIndex : arrayIndex - this.startArrayIndex; } /** * Check whether the array index potentially exists in this sequence. * Note: assumes the sequence of tick-arrays are sequential * @param index */ isArrayIndexInBounds(index, aToB) { // a+0...a+n-1 array index is ok const localArrayIndex = this.getLocalArrayIndex(index.arrayIndex, aToB); const seqLength = this.sequence.length; return localArrayIndex >= 0 && localArrayIndex < seqLength; } checkIfIndexIsInTickArrayRange(startTick, tickIndex) { const upperBound = startTick + this.tickSpacing * public_1.TICK_ARRAY_SIZE; return tickIndex >= startTick && tickIndex < upperBound; } } exports.TickArraySequence = TickArraySequence;