@orca-so/whirlpools-sdk
Version:
Typescript SDK to interact with Orca's Whirlpool program.
128 lines • 5.89 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculatePricesForQuoteToken = calculatePricesForQuoteToken;
exports.isSubset = isSubset;
exports.convertAmount = convertAmount;
const common_sdk_1 = require("@orca-so/common-sdk");
const decimal_js_1 = __importDefault(require("decimal.js"));
const _1 = require(".");
const swap_quote_1 = require("../quotes/public/swap-quote");
const public_1 = require("../utils/public");
const token_extension_util_1 = require("../utils/public/token-extension-util");
const swap_utils_1 = require("../utils/swap-utils");
function checkLiquidity(pool, tickArrays, aToB, thresholdConfig, decimalsMap) {
const { amountOut, priceImpactThreshold } = thresholdConfig;
let estimatedAmountIn;
try {
({ estimatedAmountIn } = (0, swap_quote_1.swapQuoteWithParams)({
whirlpoolData: pool,
aToB,
amountSpecifiedIsInput: false,
tokenAmount: amountOut,
otherAmountThreshold: public_1.SwapUtils.getDefaultOtherAmountThreshold(false),
sqrtPriceLimit: public_1.SwapUtils.getDefaultSqrtPriceLimit(aToB),
tickArrays,
tokenExtensionCtx: token_extension_util_1.NO_TOKEN_EXTENSION_CONTEXT,
}, common_sdk_1.Percentage.fromDecimal(new decimal_js_1.default(0))));
}
catch {
return false;
}
let price, inputDecimals, outputDecimals;
if (aToB) {
price = getPrice(pool, decimalsMap);
inputDecimals = decimalsMap[pool.tokenMintA.toBase58()];
outputDecimals = decimalsMap[pool.tokenMintB.toBase58()];
}
else {
price = getPrice(pool, decimalsMap).pow(-1);
inputDecimals = decimalsMap[pool.tokenMintB.toBase58()];
outputDecimals = decimalsMap[pool.tokenMintA.toBase58()];
}
const amountOutDecimals = common_sdk_1.DecimalUtil.fromBN(amountOut, outputDecimals);
const estimatedAmountInDecimals = common_sdk_1.DecimalUtil.fromBN(estimatedAmountIn, inputDecimals);
const maxAmountInDecimals = amountOutDecimals
.div(price)
.mul(priceImpactThreshold)
.toDecimalPlaces(inputDecimals);
return estimatedAmountInDecimals.lte(maxAmountInDecimals);
}
function getMostLiquidPools(quoteTokenMint, poolMap) {
const mostLiquidPools = new Map();
Object.entries(poolMap).forEach(([address, pool]) => {
const mintA = pool.tokenMintA.toBase58();
const mintB = pool.tokenMintB.toBase58();
if (pool.liquidity.isZero()) {
return;
}
if (!pool.tokenMintA.equals(quoteTokenMint) &&
!pool.tokenMintB.equals(quoteTokenMint)) {
return;
}
const baseTokenMint = pool.tokenMintA.equals(quoteTokenMint)
? mintB
: mintA;
const existingPool = mostLiquidPools.get(baseTokenMint);
if (!existingPool || pool.liquidity.gt(existingPool.pool.liquidity)) {
mostLiquidPools.set(baseTokenMint, {
address: common_sdk_1.AddressUtil.toPubKey(address),
pool,
});
}
});
return Object.fromEntries(mostLiquidPools);
}
function calculatePricesForQuoteToken(mints, quoteTokenMint, poolMap, tickArrayMap, decimalsMap, config, thresholdConfig) {
const mostLiquidPools = getMostLiquidPools(quoteTokenMint, poolMap);
return Object.fromEntries(mints.map((mintAddr) => {
const mint = common_sdk_1.AddressUtil.toPubKey(mintAddr);
if (mint.equals(quoteTokenMint)) {
return [mint.toBase58(), new decimal_js_1.default(1)];
}
const [mintA, mintB] = public_1.PoolUtil.orderMints(mint, quoteTokenMint);
const aToB = common_sdk_1.AddressUtil.toPubKey(mintB).equals(quoteTokenMint);
const baseTokenMint = aToB ? mintA : mintB;
const poolCandidate = mostLiquidPools[common_sdk_1.AddressUtil.toString(baseTokenMint)];
if (poolCandidate === undefined) {
return [mint.toBase58(), null];
}
const { pool, address } = poolCandidate;
const tickArrays = getTickArrays(pool, address, aToB, tickArrayMap, config);
const isPoolLiquid = checkLiquidity(pool, tickArrays, aToB, thresholdConfig, decimalsMap);
if (!isPoolLiquid) {
return [mint.toBase58(), null];
}
const price = getPrice(pool, decimalsMap);
const quotePrice = aToB ? price : price.pow(-1);
return [mint.toBase58(), quotePrice];
}));
}
function getTickArrays(pool, address, aToB, tickArrayMap, config = _1.defaultGetPricesConfig) {
const { programId } = config;
const tickArrayAddresses = (0, swap_utils_1.getTickArrayPublicKeysWithStartTickIndex)(pool.tickCurrentIndex, pool.tickSpacing, aToB, programId, address);
return tickArrayAddresses.map((a) => {
return {
address: a.pubkey,
startTickIndex: a.startTickIndex,
data: tickArrayMap[a.pubkey.toBase58()],
};
});
}
function getPrice(pool, decimalsMap) {
const tokenAAddress = pool.tokenMintA.toBase58();
const tokenBAddress = pool.tokenMintB.toBase58();
if (!(tokenAAddress in decimalsMap) || !(tokenBAddress in decimalsMap)) {
throw new Error("Missing token decimals");
}
return public_1.PriceMath.sqrtPriceX64ToPrice(pool.sqrtPrice, decimalsMap[tokenAAddress], decimalsMap[tokenBAddress]);
}
function isSubset(listA, listB) {
return listA.every((itemA) => listB.includes(itemA));
}
function convertAmount(amount, price, amountDecimal, resultDecimal) {
return common_sdk_1.DecimalUtil.toBN(common_sdk_1.DecimalUtil.fromBN(amount, amountDecimal).div(price), resultDecimal);
}
//# sourceMappingURL=calculate-pool-prices.js.map