@orca-so/whirlpools-sdk
Version:
Typescript SDK to interact with Orca's Whirlpool program.
115 lines • 5.68 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeSwap = computeSwap;
const common_sdk_1 = require("@orca-so/common-sdk");
const bn_js_1 = __importDefault(require("bn.js"));
const public_1 = require("../../types/public");
const swap_math_1 = require("../../utils/math/swap-math");
const public_2 = require("../../utils/public");
const errors_1 = require("../../errors/errors");
function computeSwap(whirlpoolData, tickSequence, tokenAmount, sqrtPriceLimit, amountSpecifiedIsInput, aToB) {
let amountRemaining = tokenAmount;
let amountCalculated = common_sdk_1.ZERO;
let currSqrtPrice = whirlpoolData.sqrtPrice;
let currLiquidity = whirlpoolData.liquidity;
let currTickIndex = whirlpoolData.tickCurrentIndex;
let totalFeeAmount = common_sdk_1.ZERO;
const feeRate = whirlpoolData.feeRate;
const protocolFeeRate = whirlpoolData.protocolFeeRate;
let currProtocolFee = new bn_js_1.default(0);
let currFeeGrowthGlobalInput = aToB
? whirlpoolData.feeGrowthGlobalA
: whirlpoolData.feeGrowthGlobalB;
while (amountRemaining.gt(common_sdk_1.ZERO) && !sqrtPriceLimit.eq(currSqrtPrice)) {
let { nextIndex: nextTickIndex } = tickSequence.findNextInitializedTickIndex(currTickIndex);
let { nextTickPrice, nextSqrtPriceLimit: targetSqrtPrice } = getNextSqrtPrices(nextTickIndex, sqrtPriceLimit, aToB);
const swapComputation = (0, swap_math_1.computeSwapStep)(amountRemaining, feeRate, currLiquidity, currSqrtPrice, targetSqrtPrice, amountSpecifiedIsInput, aToB);
totalFeeAmount = totalFeeAmount.add(swapComputation.feeAmount);
if (amountSpecifiedIsInput) {
amountRemaining = amountRemaining.sub(swapComputation.amountIn);
amountRemaining = amountRemaining.sub(swapComputation.feeAmount);
amountCalculated = amountCalculated.add(swapComputation.amountOut);
}
else {
amountRemaining = amountRemaining.sub(swapComputation.amountOut);
amountCalculated = amountCalculated.add(swapComputation.amountIn);
amountCalculated = amountCalculated.add(swapComputation.feeAmount);
}
if (amountRemaining.isNeg()) {
throw new errors_1.WhirlpoolsError("Amount remaining is negative.", errors_1.SwapErrorCode.AmountRemainingOverflow);
}
if (amountCalculated.gt(common_sdk_1.U64_MAX)) {
throw new errors_1.WhirlpoolsError("Amount calculated is greater than U64_MAX.", errors_1.SwapErrorCode.AmountCalcOverflow);
}
let { nextProtocolFee, nextFeeGrowthGlobalInput } = calculateFees(swapComputation.feeAmount, protocolFeeRate, currLiquidity, currProtocolFee, currFeeGrowthGlobalInput);
currProtocolFee = nextProtocolFee;
currFeeGrowthGlobalInput = nextFeeGrowthGlobalInput;
if (swapComputation.nextPrice.eq(nextTickPrice)) {
const nextTick = tickSequence.getTick(nextTickIndex);
if (nextTick.initialized) {
currLiquidity = calculateNextLiquidity(nextTick.liquidityNet, currLiquidity, aToB);
}
currTickIndex = aToB ? nextTickIndex - 1 : nextTickIndex;
}
else {
currTickIndex = public_2.PriceMath.sqrtPriceX64ToTickIndex(swapComputation.nextPrice);
}
currSqrtPrice = swapComputation.nextPrice;
}
let { amountA, amountB } = calculateEstTokens(tokenAmount, amountRemaining, amountCalculated, aToB, amountSpecifiedIsInput);
return {
amountA,
amountB,
nextTickIndex: currTickIndex,
nextSqrtPrice: currSqrtPrice,
totalFeeAmount,
};
}
function getNextSqrtPrices(nextTick, sqrtPriceLimit, aToB) {
const nextTickPrice = public_2.PriceMath.tickIndexToSqrtPriceX64(nextTick);
const nextSqrtPriceLimit = aToB
? bn_js_1.default.max(sqrtPriceLimit, nextTickPrice)
: bn_js_1.default.min(sqrtPriceLimit, nextTickPrice);
return { nextTickPrice, nextSqrtPriceLimit };
}
function calculateFees(feeAmount, protocolFeeRate, currLiquidity, currProtocolFee, currFeeGrowthGlobalInput) {
let nextProtocolFee = currProtocolFee;
let nextFeeGrowthGlobalInput = currFeeGrowthGlobalInput;
let globalFee = feeAmount;
if (protocolFeeRate > 0) {
let delta = calculateProtocolFee(globalFee, protocolFeeRate);
globalFee = globalFee.sub(delta);
nextProtocolFee = nextProtocolFee.add(currProtocolFee);
}
if (currLiquidity.gt(common_sdk_1.ZERO)) {
const globalFeeIncrement = globalFee.shln(64).div(currLiquidity);
nextFeeGrowthGlobalInput = nextFeeGrowthGlobalInput.add(globalFeeIncrement);
}
return {
nextProtocolFee,
nextFeeGrowthGlobalInput,
};
}
function calculateProtocolFee(globalFee, protocolFeeRate) {
return globalFee.mul(new bn_js_1.default(protocolFeeRate).div(public_1.PROTOCOL_FEE_RATE_MUL_VALUE));
}
function calculateEstTokens(amount, amountRemaining, amountCalculated, aToB, amountSpecifiedIsInput) {
return aToB === amountSpecifiedIsInput
? {
amountA: amount.sub(amountRemaining),
amountB: amountCalculated,
}
: {
amountA: amountCalculated,
amountB: amount.sub(amountRemaining),
};
}
function calculateNextLiquidity(tickNetLiquidity, currLiquidity, aToB) {
return aToB
? currLiquidity.sub(tickNetLiquidity)
: currLiquidity.add(tickNetLiquidity);
}
//# sourceMappingURL=swap-manager.js.map