UNPKG

@orca-so/whirlpool-sdk

Version:

Whirlpool SDK for the Orca protocol.

65 lines (64 loc) 2.96 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.estimateAprsForPriceRange = exports.ZERO_APR = void 0; const web3_js_1 = require("@solana/web3.js"); const decimal_js_1 = __importDefault(require("decimal.js")); const public_1 = require("../../constants/public"); const remove_liquidity_1 = require("../../position/quotes/remove-liquidity"); const decimal_utils_1 = require("./decimal-utils"); exports.ZERO_APR = { fee: 0, rewards: [0, 0, 0], }; function estimateAprsForPriceRange(pool, // TODO: should this actually be fetched/shared? // There's a weird in/out/in dependency here on prices/fees tokenPrices, fees24h, tickLowerIndex, tickUpperIndex) { const { liquidity, sqrtPrice, tokenMintA, tokenMintB, tokenDecimalsA, tokenDecimalsB, tickCurrentIndex, } = pool; const tokenPriceA = tokenPrices[tokenMintA.toBase58()]; const tokenPriceB = tokenPrices[tokenMintB.toBase58()]; if (!fees24h || !tokenPriceA || !tokenPriceB || tickLowerIndex >= tickUpperIndex) { return exports.ZERO_APR; } // Value of liquidity if the entire liquidity were concentrated between tickLower/Upper // Since this is virtual liquidity, concentratedValue should actually be less than totalValue const { minTokenA, minTokenB } = (0, remove_liquidity_1.getRemoveLiquidityQuote)({ positionAddress: web3_js_1.PublicKey.default, tickCurrentIndex, sqrtPrice, tickLowerIndex, tickUpperIndex, liquidity, slippageTolerance: public_1.ZERO_SLIPPAGE, }); const tokenValueA = getTokenValue(minTokenA, tokenDecimalsA, tokenPriceA); const tokenValueB = getTokenValue(minTokenB, tokenDecimalsB, tokenPriceB); const concentratedValue = tokenValueA.add(tokenValueB); const feesPerYear = new decimal_js_1.default(fees24h).mul(365); const feeApr = feesPerYear.div(concentratedValue).toNumber(); const rewards = pool.rewards.map((reward) => estimateRewardApr(reward, concentratedValue, tokenPrices)); return { fee: feeApr, rewards }; } exports.estimateAprsForPriceRange = estimateAprsForPriceRange; const SECONDS_PER_YEAR = 60 * // SECONDS 60 * // MINUTES 24 * // HOURS 365; // DAYS function estimateRewardApr(reward, concentratedValue, tokenPrices) { const { mint, emissionsPerSecond } = reward; const rewardTokenPrice = tokenPrices[mint.toBase58()]; if (!emissionsPerSecond || !rewardTokenPrice) { return 0; } return emissionsPerSecond .mul(SECONDS_PER_YEAR) .mul(rewardTokenPrice) .div(concentratedValue) .toNumber(); } function getTokenValue(tokenAmount, tokenDecimals, tokenPrice) { return decimal_utils_1.DecimalUtil.adjustDecimals(new decimal_js_1.default(tokenAmount.toString()), tokenDecimals).mul(tokenPrice); }