UNPKG

@marinade.finance/kamino-sdk

Version:
219 lines 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RaydiumService = void 0; const web3_js_1 = require("@solana/web3.js"); const raydium_client_1 = require("../raydium_client"); const decimal_js_1 = __importDefault(require("decimal.js")); const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); const utils_1 = require("../utils"); const axios_1 = __importDefault(require("axios")); const CreationParameters_1 = require("../utils/CreationParameters"); const programId_1 = require("../raydium_client/programId"); const raydium_1 = require("../utils/raydium"); class RaydiumService { _connection; _cluster; constructor(connection, cluster) { this._connection = connection; this._cluster = cluster; } async getRaydiumWhirlpools() { return (await axios_1.default.get(`https://api.hubbleprotocol.io/raydium/ammPools`)).data; } async getRaydiumPoolLiquidityDistribution(pool, keepOrder = true, lowestTick, highestTick) { let raydiumLiqDistribution = (await axios_1.default.get(`https://api.hubbleprotocol.io/raydium/positionLine/${pool.toString()}`)).data; const poolState = await raydium_client_1.PoolState.fetch(this._connection, pool); if (!poolState) { throw Error(`Raydium pool state ${pool} does not exist`); } let poolPrice = raydium_sdk_1.SqrtPriceMath.sqrtPriceX64ToPrice(poolState.sqrtPriceX64, poolState.mintDecimals0, poolState.mintDecimals1); let liqDistribution = { currentPrice: poolPrice, currentTickIndex: poolState.tickCurrent, distribution: [], }; raydiumLiqDistribution.data.forEach((entry) => { let tickIndex = (0, raydium_1.priceToTickIndexWithRounding)(entry.price); if ((lowestTick && tickIndex < lowestTick) || (highestTick && tickIndex > highestTick)) { return; } // if the prevoious entry has the same tick index, add to it if (liqDistribution.distribution.length > 0 && liqDistribution.distribution[liqDistribution.distribution.length - 1].tickIndex === tickIndex) { liqDistribution.distribution[liqDistribution.distribution.length - 1].liquidity = liqDistribution.distribution[liqDistribution.distribution.length - 1].liquidity.add(new decimal_js_1.default(entry.liquidity)); } else { let priceWithOrder = new decimal_js_1.default(entry.price); if (!keepOrder) { priceWithOrder = new decimal_js_1.default(1).div(priceWithOrder); } const liq = { price: new decimal_js_1.default(priceWithOrder), liquidity: new decimal_js_1.default(entry.liquidity), tickIndex, }; liqDistribution.distribution.push(liq); } }); return liqDistribution; } getStrategyWhirlpoolPoolAprApy = async (strategy, pools) => { const position = await raydium_client_1.PersonalPositionState.fetch(this._connection, strategy.position); if (!position) { throw Error(`Position ${strategy.position} does not exist`); } const poolState = await raydium_client_1.PoolState.fetch(this._connection, strategy.pool); if (!poolState) { throw Error(`Raydium pool state ${strategy.pool} does not exist`); } if (!pools) { ({ data: pools } = await this.getRaydiumWhirlpools()); } if (!pools || pools.length === 0) { throw Error(`Could not get Raydium amm pools from Raydium API`); } const raydiumPool = pools.filter((d) => d.id === position.poolId.toString()).shift(); if (!raydiumPool) { throw Error(`Could not get find Raydium amm pool ${strategy.pool} from Raydium API`); } const poolInfo = (await raydium_sdk_1.AmmV3.fetchMultiplePoolInfos({ connection: this._connection, // @ts-ignore poolKeys: [raydiumPool], batchRequest: true, chainTime: new Date().getTime() / 1000, }))[strategy.pool.toString()].state; const priceRange = (0, utils_1.getStrategyPriceRangeRaydium)(position.tickLowerIndex, position.tickUpperIndex, Number(poolState.tickCurrent.toString()), Number(strategy.tokenAMintDecimals.toString()), Number(strategy.tokenBMintDecimals.toString())); if (priceRange.strategyOutOfRange) { return { ...priceRange, rewardsApy: [], rewardsApr: [], feeApy: utils_1.ZERO, feeApr: utils_1.ZERO, totalApy: utils_1.ZERO, totalApr: utils_1.ZERO, }; } const params = { poolInfo, aprType: 'day', positionTickLowerIndex: position.tickLowerIndex, positionTickUpperIndex: position.tickUpperIndex, }; const { apr, feeApr, rewardsApr } = raydium_sdk_1.AmmV3.estimateAprsForPriceRangeMultiplier(params); const totalApr = new decimal_js_1.default(apr).div(100); const fee = new decimal_js_1.default(feeApr).div(100); const rewards = rewardsApr.map((reward) => new decimal_js_1.default(reward).div(100)); return { totalApr, totalApy: (0, utils_1.aprToApy)(totalApr, 365), feeApr: fee, feeApy: (0, utils_1.aprToApy)(fee, 365), rewardsApr: rewards, rewardsApy: rewards.map((x) => (0, utils_1.aprToApy)(x, 365)), ...priceRange, }; }; getRaydiumPositionAprApy = async (poolPubkey, priceLower, priceUpper, pools) => { const poolState = await raydium_client_1.PoolState.fetch(this._connection, poolPubkey); if (!poolState) { throw Error(`Raydium pool state ${poolPubkey} does not exist`); } if (!pools) { ({ data: pools } = await this.getRaydiumWhirlpools()); } if (!pools || pools.length === 0) { throw Error(`Could not get Raydium amm pools from Raydium API`); } const raydiumPool = pools.filter((d) => d.id === poolPubkey.toString()).shift(); if (!raydiumPool) { throw Error(`Could not get find Raydium amm pool ${poolPubkey.toString()} from Raydium API`); } const poolInfo = (await raydium_sdk_1.AmmV3.fetchMultiplePoolInfos({ connection: this._connection, // @ts-ignore poolKeys: [raydiumPool], batchRequest: true, chainTime: new Date().getTime() / 1000, }))[poolPubkey.toString()].state; let tickLowerIndex = raydium_sdk_1.TickMath.getTickWithPriceAndTickspacing(priceLower, poolState.tickSpacing, poolState.mintDecimals0, poolState.mintDecimals1); let tickUpperIndex = raydium_sdk_1.TickMath.getTickWithPriceAndTickspacing(priceUpper, poolState.tickSpacing, poolState.mintDecimals0, poolState.mintDecimals1); const priceRange = (0, utils_1.getStrategyPriceRangeRaydium)(tickLowerIndex, tickUpperIndex, Number(poolState.tickCurrent.toString()), raydiumPool.mintDecimalsA, raydiumPool.mintDecimalsB); if (priceRange.strategyOutOfRange) { return { ...priceRange, rewardsApy: [], rewardsApr: [], feeApy: utils_1.ZERO, feeApr: utils_1.ZERO, totalApy: utils_1.ZERO, totalApr: utils_1.ZERO, }; } const params = { poolInfo, aprType: 'day', positionTickLowerIndex: tickLowerIndex, positionTickUpperIndex: tickUpperIndex, }; const { apr, feeApr, rewardsApr } = raydium_sdk_1.AmmV3.estimateAprsForPriceRangeMultiplier(params); const totalApr = new decimal_js_1.default(apr).div(100); const fee = new decimal_js_1.default(feeApr).div(100); const rewards = rewardsApr.map((reward) => new decimal_js_1.default(reward).div(100)); return { totalApr, totalApy: (0, utils_1.aprToApy)(totalApr, 365), feeApr: fee, feeApy: (0, utils_1.aprToApy)(fee, 365), rewardsApr: rewards, rewardsApy: rewards.map((x) => (0, utils_1.aprToApy)(x, 365)), ...priceRange, }; }; async getGenericPoolInfo(poolPubkey, pools) { const poolState = await raydium_client_1.PoolState.fetch(this._connection, poolPubkey); if (!poolState) { throw Error(`Raydium pool state ${poolPubkey} does not exist`); } if (!pools) { ({ data: pools } = await this.getRaydiumWhirlpools()); } if (!pools || pools.length === 0) { throw Error(`Could not get Raydium amm pools from Raydium API`); } const raydiumPool = pools.filter((d) => d.id === poolPubkey.toString()).shift(); if (!raydiumPool) { throw Error(`Could not get find Raydium amm pool ${poolPubkey.toString()} from Raydium API`); } let poolInfo = { dex: 'RAYDIUM', address: new web3_js_1.PublicKey(poolPubkey), tokenMintA: poolState.tokenMint0, tokenMintB: poolState.tokenMint1, price: new decimal_js_1.default(raydiumPool.price), feeRate: new decimal_js_1.default(raydiumPool.ammConfig.tradeFeeRate).div(new decimal_js_1.default(CreationParameters_1.FullPercentage)), volumeOnLast7d: new decimal_js_1.default(raydiumPool.week.volume), tvl: new decimal_js_1.default(raydiumPool.tvl), tickSpacing: new decimal_js_1.default(raydiumPool.ammConfig.tickSpacing), // todo(Silviu): get real amount of positions positions: new decimal_js_1.default(0), }; return poolInfo; } async getPositionsCountByPool(pool) { const positions = await this._connection.getProgramAccounts(programId_1.PROGRAM_ID, { commitment: 'confirmed', filters: [ { dataSize: raydium_sdk_1.PositionInfoLayout.span }, { memcmp: { bytes: pool.toBase58(), offset: raydium_sdk_1.PositionInfoLayout.offsetOf('poolId') } }, ], }); return positions.length; } } exports.RaydiumService = RaydiumService; //# sourceMappingURL=RaydiumService.js.map