UNPKG

@orca-so/whirlpool-sdk

Version:

Whirlpool SDK for the Orca protocol.

252 lines (251 loc) 14.7 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.convertPositionDataToUserPositionData = exports.convertWhirlpoolDataToPoolData = void 0; const web3_js_1 = require("@solana/web3.js"); const tiny_invariant_1 = __importDefault(require("tiny-invariant")); const decimal_utils_1 = require("../utils/public/decimal-utils"); const address_1 = require("../utils/address"); const tick_util_1 = require("../utils/whirlpool/tick-util"); const collect_fees_1 = require("../quotes/collect-fees"); const collect_rewards_1 = require("../quotes/collect-rewards"); const whirlpool_client_sdk_1 = require("@orca-so/whirlpool-client-sdk"); const __1 = require(".."); function convertWhirlpoolDataToPoolData(ctx, poolAddresses, refresh) { var _a, _b, _c, _d, _e, _f; return __awaiter(this, void 0, void 0, function* () { if (refresh) { const pools = yield ctx.accountFetcher.listPools(poolAddresses, true); const allTokenAccounts = new Set(); const allMintInfos = new Set(); const allTickArrays = []; pools.forEach((pool, index) => { const poolAddress = poolAddresses[index]; if (pool && poolAddress) { allTokenAccounts.add(pool.tokenVaultA.toBase58()); allTokenAccounts.add(pool.tokenVaultB.toBase58()); allMintInfos.add(pool.tokenMintA.toBase58()); allMintInfos.add(pool.tokenMintB.toBase58()); allTickArrays.push(tick_util_1.TickUtil.getPDAWithSqrtPrice(pool.sqrtPrice, pool.tickSpacing, poolAddress, ctx.program.programId).publicKey.toBase58()); pool.rewardInfos.forEach(({ vault, mint }) => { if (!mint.equals(web3_js_1.PublicKey.default) && !vault.equals(web3_js_1.PublicKey.default)) { allTokenAccounts.add(vault.toBase58()); allMintInfos.add(mint.toBase58()); } }); } }); yield Promise.all([ ctx.accountFetcher.listTokenInfos(Array.from(allTokenAccounts), true), ctx.accountFetcher.listMintInfos(Array.from(allMintInfos), false), ctx.accountFetcher.listTickArrays(allTickArrays, true), ]); } const result = {}; for (const address of poolAddresses) { const poolId = (0, address_1.toPubKey)(address).toBase58(); const pool = yield ctx.accountFetcher.getPool(address, false); if (!pool) { console.error(`error - pool not found`); continue; } const amountA = (_a = (yield ctx.accountFetcher.getTokenInfo(pool.tokenVaultA, false))) === null || _a === void 0 ? void 0 : _a.amount; const amountB = (_b = (yield ctx.accountFetcher.getTokenInfo(pool.tokenVaultB, false))) === null || _b === void 0 ? void 0 : _b.amount; const decimalsA = (_c = (yield ctx.accountFetcher.getMintInfo(pool.tokenMintA, false))) === null || _c === void 0 ? void 0 : _c.decimals; const decimalsB = (_d = (yield ctx.accountFetcher.getMintInfo(pool.tokenMintB, false))) === null || _d === void 0 ? void 0 : _d.decimals; if (!amountA || !amountB || decimalsA === undefined || decimalsB === undefined) { console.error(`error - amount or decimals not found`); continue; } const feePercentage = decimal_utils_1.DecimalUtil.fromNumber(pool.feeRate, 6); const protocolFeePercentage = decimal_utils_1.DecimalUtil.fromNumber(pool.protocolFeeRate, 4); const rewards = []; for (const { mint, vault, emissionsPerSecondX64, growthGlobalX64 } of pool.rewardInfos) { let amount = undefined; let decimals = undefined; if (!mint.equals(web3_js_1.PublicKey.default) && !vault.equals(web3_js_1.PublicKey.default)) { amount = (_e = (yield ctx.accountFetcher.getTokenInfo(vault, false))) === null || _e === void 0 ? void 0 : _e.amount; decimals = (_f = (yield ctx.accountFetcher.getMintInfo(mint, false))) === null || _f === void 0 ? void 0 : _f.decimals; } rewards.push({ mint, vault, vaultAmount: amount, decimalVaultAmount: decimals && amount ? decimal_utils_1.DecimalUtil.fromU64(amount, decimals) : undefined, emissionsPerSecondX64, growthGlobalX64, emissionsPerSecond: decimals ? decimal_utils_1.DecimalUtil.adjustDecimals((0, whirlpool_client_sdk_1.fromX64)(emissionsPerSecondX64), decimals) : undefined, }); } result[poolId] = { address: (0, address_1.toPubKey)(address), tokenMintA: pool.tokenMintA, tokenMintB: pool.tokenMintB, stable: pool.tickSpacing === whirlpool_client_sdk_1.TickSpacing.Stable, feeRate: pool.feeRate, protocolFeeRate: pool.protocolFeeRate, liquidity: pool.liquidity, sqrtPrice: pool.sqrtPrice, tickCurrentIndex: pool.tickCurrentIndex, protocolFeeOwedA: pool.protocolFeeOwedA, protocolFeeOwedB: pool.protocolFeeOwedB, tokenVaultAmountA: amountA, tokenVaultAmountB: amountB, rewards, feeGrowthGlobalAX64: pool.feeGrowthGlobalA, feeGrowthGlobalBX64: pool.feeGrowthGlobalB, // Derived helper fields feePercentage, protocolFeePercentage, price: (0, __1.sqrtPriceX64ToPrice)(pool.sqrtPrice, decimalsA, decimalsB), decimalProtocolFeeOwedA: decimal_utils_1.DecimalUtil.fromU64(pool.protocolFeeOwedA, decimalsA), decimalProtocolFeeOwedB: decimal_utils_1.DecimalUtil.fromU64(pool.protocolFeeOwedB, decimalsB), decimalTokenVaultAmountA: decimal_utils_1.DecimalUtil.fromU64(amountA, decimalsA), decimalTokenVaultAmountB: decimal_utils_1.DecimalUtil.fromU64(amountB, decimalsB), tokenDecimalsA: decimalsA, tokenDecimalsB: decimalsB, }; } return result; }); } exports.convertWhirlpoolDataToPoolData = convertWhirlpoolDataToPoolData; function convertPositionDataToUserPositionData(ctx, walletAddress, refresh) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { const positionAddresses = yield getUserPositions(ctx, walletAddress, refresh); const result = {}; for (const address of positionAddresses) { const positionId = (0, address_1.toPubKey)(address).toBase58(); const position = yield ctx.accountFetcher.getPosition(address, refresh); if (!position) { console.error(`error - position not found`); continue; } const whirlpool = yield ctx.accountFetcher.getPool(position.whirlpool, refresh); if (!whirlpool) { console.error(`error - whirlpool not found`); continue; } const [tickLowerAddress, tickUpperAddress] = tick_util_1.TickUtil.getLowerAndUpperTickArrayAddresses(position.tickLowerIndex, position.tickUpperIndex, whirlpool.tickSpacing, position.whirlpool, ctx.program.programId); const tickArrayLower = yield ctx.accountFetcher.getTickArray(tickLowerAddress, false); const tickArrayUpper = yield ctx.accountFetcher.getTickArray(tickUpperAddress, false); if (!tickArrayLower || !tickArrayUpper) { console.error(`error - tick array not found`); continue; } const tickLower = tick_util_1.TickUtil.getTick(tickArrayLower, position.tickLowerIndex, whirlpool.tickSpacing); const tickUpper = tick_util_1.TickUtil.getTick(tickArrayUpper, position.tickUpperIndex, whirlpool.tickSpacing); const quoteParam = { whirlpool, position, tickLower, tickUpper }; const feesQuote = (0, collect_fees_1.getCollectFeesQuoteInternal)(quoteParam); const decimalsA = (_a = (yield ctx.accountFetcher.getMintInfo(whirlpool.tokenMintA, false))) === null || _a === void 0 ? void 0 : _a.decimals; const decimalsB = (_b = (yield ctx.accountFetcher.getMintInfo(whirlpool.tokenMintB, false))) === null || _b === void 0 ? void 0 : _b.decimals; if (decimalsA === undefined || decimalsB === undefined) { console.error(`error - decimals not found`); continue; } const decimalFeeOwedA = decimal_utils_1.DecimalUtil.fromU64(feesQuote.feeOwedA, decimalsA); const decimalFeeOwedB = decimal_utils_1.DecimalUtil.fromU64(feesQuote.feeOwedB, decimalsB); const rewardsQuote = (0, collect_rewards_1.getCollectRewardsQuoteInternal)(quoteParam); const rewards = []; for (const [index, { mint, vault }] of whirlpool.rewardInfos.entries()) { const amountOwed = rewardsQuote[index]; const decimals = !mint.equals(web3_js_1.PublicKey.default) && !vault.equals(web3_js_1.PublicKey.default) ? (_c = (yield ctx.accountFetcher.getMintInfo(mint, false))) === null || _c === void 0 ? void 0 : _c.decimals : undefined; const decimalAmountOwed = amountOwed && decimals ? decimal_utils_1.DecimalUtil.fromU64(amountOwed, decimals) : undefined; rewards.push({ mint, amountOwed, decimalAmountOwed, }); } result[positionId] = { address: (0, address_1.toPubKey)(address), poolAddress: position.whirlpool, positionMint: position.positionMint, liquidity: position.liquidity, tickLowerIndex: position.tickLowerIndex, tickUpperIndex: position.tickUpperIndex, feeOwedA: feesQuote.feeOwedA, feeOwedB: feesQuote.feeOwedB, rewards, // Derived helper fields priceLower: (0, __1.tickIndexToPrice)(position.tickLowerIndex, decimalsA, decimalsB), priceUpper: (0, __1.tickIndexToPrice)(position.tickUpperIndex, decimalsA, decimalsB), decimalFeeOwedA, decimalFeeOwedB, }; } return result; }); } exports.convertPositionDataToUserPositionData = convertPositionDataToUserPositionData; function getUserPositions(ctx, walletAddress, refresh) { return __awaiter(this, void 0, void 0, function* () { const potentialPositionAddresses = []; const userTokens = yield ctx.accountFetcher.listUserTokens(walletAddress, refresh); userTokens.forEach(({ amount, decimals, mint }) => { if (amount === "1" && decimals === 0 && !!mint) { potentialPositionAddresses.push((0, whirlpool_client_sdk_1.getPositionPda)(ctx.program.programId, (0, address_1.toPubKey)(mint)).publicKey); } }); const positions = yield ctx.accountFetcher.listPositions(potentialPositionAddresses, refresh); (0, tiny_invariant_1.default)(potentialPositionAddresses.length === positions.length, "not enough positions data"); if (refresh) { /*** Refresh pools ***/ const whirlpoolAddresses = new Set(); positions.forEach((position) => { if (position) { whirlpoolAddresses.add(position.whirlpool.toBase58()); } }); const pools = yield ctx.accountFetcher.listPools(Array.from(whirlpoolAddresses), refresh); /*** Refresh mint infos ***/ const allMintInfos = new Set(); pools.forEach((pool) => { if (pool) { allMintInfos.add(pool.tokenMintA.toBase58()); allMintInfos.add(pool.tokenMintB.toBase58()); pool.rewardInfos.forEach(({ mint, vault }) => { if (!mint.equals(web3_js_1.PublicKey.default) && !vault.equals(web3_js_1.PublicKey.default)) { allMintInfos.add(mint.toBase58()); } }); } }); /*** Refresh tick arrays ***/ const tickArrayAddresses = new Set(); for (const position of positions) { if (position) { const whirlpool = yield ctx.accountFetcher.getPool(position.whirlpool, false); if (whirlpool) { const [tickLowerAddress, tickUpperAddress] = tick_util_1.TickUtil.getLowerAndUpperTickArrayAddresses(position.tickLowerIndex, position.tickUpperIndex, whirlpool.tickSpacing, position.whirlpool, ctx.program.programId); tickArrayAddresses.add(tickLowerAddress.toBase58()); tickArrayAddresses.add(tickUpperAddress.toBase58()); } } } yield Promise.all([ ctx.accountFetcher.listMintInfos(Array.from(allMintInfos), false), ctx.accountFetcher.listTickArrays(Array.from(tickArrayAddresses), true), ]); } return potentialPositionAddresses.filter((_, index) => { return positions[index] !== null; }); }); }