@renec-foundation/redex-sdk
Version:
Typescript SDK to interact with Orca's Whirlpool program.
77 lines (76 loc) • 4.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.simulateSwap = void 0;
const common_sdk_1 = require("@orca-so/common-sdk");
const anchor_1 = require("@project-serum/anchor");
const tick_array_sequence_1 = require("./tick-array-sequence");
const swap_manager_1 = require("./swap-manager");
const public_1 = require("../../types/public");
const errors_1 = require("../../errors/errors");
/**
* Figure out the quote parameters needed to successfully complete this trade on chain
* @param param
* @returns
* @exceptions
*/
function simulateSwap(params) {
const { aToB, whirlpoolData, tickArrays, tokenAmount, sqrtPriceLimit, otherAmountThreshold, amountSpecifiedIsInput, } = params;
if (sqrtPriceLimit.gt(new anchor_1.BN(public_1.MAX_SQRT_PRICE)) || sqrtPriceLimit.lt(new anchor_1.BN(public_1.MIN_SQRT_PRICE))) {
throw new errors_1.WhirlpoolsError("Provided SqrtPriceLimit is out of bounds.", errors_1.SwapErrorCode.SqrtPriceOutOfBounds);
}
if ((aToB && sqrtPriceLimit.gt(whirlpoolData.sqrtPrice)) ||
(!aToB && sqrtPriceLimit.lt(whirlpoolData.sqrtPrice))) {
throw new errors_1.WhirlpoolsError("Provided SqrtPriceLimit is in the opposite direction of the trade.", errors_1.SwapErrorCode.InvalidSqrtPriceLimitDirection);
}
if (tokenAmount.eq(common_sdk_1.ZERO)) {
throw new errors_1.WhirlpoolsError("Provided tokenAmount is zero.", errors_1.SwapErrorCode.ZeroTradableAmount);
}
const tickSequence = new tick_array_sequence_1.TickArraySequence(tickArrays, whirlpoolData.tickSpacing, aToB);
// Ensure 1st search-index resides on the 1st array in the sequence to match smart contract expectation.
if (!tickSequence.isValidTickArray0(whirlpoolData.tickCurrentIndex)) {
throw new errors_1.WhirlpoolsError("TickArray at index 0 does not contain the Whirlpool current tick index.", errors_1.SwapErrorCode.TickArraySequenceInvalid);
}
const swapResults = (0, swap_manager_1.computeSwap)(whirlpoolData, tickSequence, tokenAmount, sqrtPriceLimit, amountSpecifiedIsInput, aToB);
if (amountSpecifiedIsInput) {
if ((aToB && otherAmountThreshold.gt(swapResults.amountB)) ||
(!aToB && otherAmountThreshold.gt(swapResults.amountA))) {
throw new errors_1.WhirlpoolsError("Quoted amount for the other token is below the otherAmountThreshold.", errors_1.SwapErrorCode.AmountOutBelowMinimum);
}
}
else {
if ((aToB && otherAmountThreshold.lt(swapResults.amountA)) ||
(!aToB && otherAmountThreshold.lt(swapResults.amountB))) {
throw new errors_1.WhirlpoolsError("Quoted amount for the other token is above the otherAmountThreshold.", errors_1.SwapErrorCode.AmountInAboveMaximum);
}
}
const { estimatedAmountIn, estimatedAmountOut } = remapAndAdjustTokens(swapResults.amountA, swapResults.amountB, aToB);
const numOfTickCrossings = tickSequence.getNumOfTouchedArrays();
if (numOfTickCrossings > public_1.MAX_SWAP_TICK_ARRAYS) {
throw new errors_1.WhirlpoolsError(`Input amount causes the quote to traverse more than the allowable amount of tick-arrays ${numOfTickCrossings}`, errors_1.SwapErrorCode.TickArrayCrossingAboveMax);
}
const touchedArrays = tickSequence.getTouchedArrays(public_1.MAX_SWAP_TICK_ARRAYS);
return {
estimatedAmountIn,
estimatedAmountOut,
estimatedEndTickIndex: swapResults.nextTickIndex,
estimatedEndSqrtPrice: swapResults.nextSqrtPrice,
estimatedFeeAmount: swapResults.totalFeeAmount,
amount: tokenAmount,
amountSpecifiedIsInput,
aToB,
otherAmountThreshold,
sqrtPriceLimit,
tickArray0: touchedArrays[0],
tickArray1: touchedArrays[1],
tickArray2: touchedArrays[2],
};
}
exports.simulateSwap = simulateSwap;
function remapAndAdjustTokens(amountA, amountB, aToB) {
const estimatedAmountIn = aToB ? amountA : amountB;
const estimatedAmountOut = aToB ? amountB : amountA;
return {
estimatedAmountIn,
estimatedAmountOut,
};
}