@orca-so/whirlpool-sdk
Version:
Whirlpool SDK for the Orca protocol.
65 lines (64 loc) • 2.96 kB
JavaScript
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);
}
;