UNPKG

@kamino-finance/kliquidity-sdk

Version:

Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol

141 lines (126 loc) 4.88 kB
import Decimal from 'decimal.js'; import { PositionRange, RebalanceFieldInfo, RebalanceFieldsDict } from '../utils/types'; import { FullBPSDecimal } from '../utils/CreationParameters'; import { Dex, readBigUint128LE } from '../utils'; import { sqrtPriceToPrice as orcaSqrtPriceToPrice } from '@orca-so/whirlpools-core'; import { RebalanceRaw } from '../@codegen/kliquidity/types'; import { getPriceFromQ64Price } from '../utils/meteora'; import { RaydiumSqrtPriceMath as SqrtPriceMath } from '../utils/raydiumSdkCompat'; import { toBN } from '../utils/raydiumBridge'; export const DEFAULT_LOWER_RANGE_PRICE_DIFF_BPS = new Decimal(500); export const DEFAULT_UPPER_RANGE_PRICE_DIFF_BPS = new Decimal(500); export const DEFAULT_DESTINATION_TOKEN = new Decimal(1); export const TakeProfitRebalanceTypeName = 'takeProfit'; export function getTakeProfitRebalanceFieldsInfos( lowerRangePrice: Decimal, upperRangePrice: Decimal, destinationToken: Decimal, enabled: boolean = true ): RebalanceFieldInfo[] { const rebalanceType: RebalanceFieldInfo = { label: 'rebalanceType', type: 'string', value: TakeProfitRebalanceTypeName, enabled, }; const lowerRangePriceRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceLower', type: 'number', value: lowerRangePrice, enabled, }; const upperRangePriceRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceUpper', type: 'number', value: upperRangePrice, enabled, }; const destinationTokenRebalanceFieldInfo: RebalanceFieldInfo = { label: 'destinationToken', type: 'number', value: destinationToken, enabled, }; return [ rebalanceType, lowerRangePriceRebalanceFieldInfo, upperRangePriceRebalanceFieldInfo, destinationTokenRebalanceFieldInfo, ]; } export function getPositionRangeFromTakeProfitParams( dex: Dex, tokenADecimals: number, tokenBDecimals: number, lowerSqrtPriceX64: Decimal, upperSqrtPriceX64: Decimal ): PositionRange { if (dex == 'ORCA') { const lowerPrice = new Decimal( orcaSqrtPriceToPrice(BigInt(lowerSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals) ); const upperPrice = new Decimal( orcaSqrtPriceToPrice(BigInt(upperSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals) ); return { lowerPrice, upperPrice }; } else if (dex == 'RAYDIUM') { const lowerPrice = new Decimal( orcaSqrtPriceToPrice(BigInt(lowerSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals) ); const upperPrice = new Decimal( orcaSqrtPriceToPrice(BigInt(upperSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals) ); return { lowerPrice, upperPrice }; } else if (dex == 'METEORA') { const lowerPrice = getPriceFromQ64Price(new Decimal(lowerSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals); const upperPrice = getPriceFromQ64Price(new Decimal(upperSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals); return { lowerPrice, upperPrice }; } else { throw new Error(`Unknown DEX ${dex}`); } } export function getDefaultTakeProfitRebalanceFieldsInfos(price: Decimal): RebalanceFieldInfo[] { const lowerPrice = price.mul(FullBPSDecimal.sub(DEFAULT_LOWER_RANGE_PRICE_DIFF_BPS)).div(FullBPSDecimal); const upperPrice = price.mul(FullBPSDecimal.add(DEFAULT_UPPER_RANGE_PRICE_DIFF_BPS)).div(FullBPSDecimal); return getTakeProfitRebalanceFieldsInfos(lowerPrice, upperPrice, price); } export function readTakeProfitRebalanceParamsFromStrategy( tokenADecimals: number, tokenBDecimals: number, rebalanceRaw: RebalanceRaw ) { const buf = new Uint8Array(rebalanceRaw.params); const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); const params: RebalanceFieldsDict = {}; params['lowerRangePrice'] = SqrtPriceMath.sqrtPriceX64ToPrice( toBN(readBigUint128LE(buf, 0)), tokenADecimals, tokenBDecimals ); params['upperRangePrice'] = SqrtPriceMath.sqrtPriceX64ToPrice( toBN(readBigUint128LE(buf, 16)), tokenADecimals, tokenBDecimals ); params['destinationToken'] = new Decimal(dv.getUint8(32)); return params; } export function readTakeProfitRebalanceStateFromStrategy(rebalanceRaw: RebalanceRaw) { const buf = new Uint8Array(rebalanceRaw.state); const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); const state: RebalanceFieldsDict = {}; state['step'] = new Decimal(dv.getUint8(0)); return state; } export function deserializeTakeProfitRebalanceFromOnchainParams( tokenADecimals: number, tokenBDecimals: number, rebalanceRaw: RebalanceRaw ): RebalanceFieldInfo[] { const params = readTakeProfitRebalanceParamsFromStrategy(tokenADecimals, tokenBDecimals, rebalanceRaw); return getTakeProfitRebalanceFieldsInfos( params['lowerRangePrice'], params['upperRangePrice'], params['destinationToken'] ); }