UNPKG

@marinade.finance/kamino-sdk

Version:
185 lines (164 loc) 6.13 kB
import Decimal from 'decimal.js'; import { PositionRange, RebalanceFieldInfo, RebalanceFieldsDict } from '../utils/types'; import { DefaultLowerPercentageBPSDecimal, DefaultUpperPercentageBPSDecimal, FullBPSDecimal, } from '../utils/CreationParameters'; import { RebalanceRaw } from '../kamino-client/types'; import { RebalanceTypeLabelName } from './consts'; import { Dex, readBigUint128LE } from '../utils'; import { upsertManyRebalanceFieldInfos } from './utils'; import { sqrtPriceX64ToPrice } from '@orca-so/whirlpool-sdk'; import BN from 'bn.js'; import { getPriceRangeFromPriceAndDiffBPS } from './math_utils'; export const PricePercentageRebalanceTypeName = 'pricePercentage'; export function getPricePercentageRebalanceFieldInfos( poolPrice: Decimal, lowerPercentageBPS: Decimal, upperPercentageBPS: Decimal, enabled: boolean = true ): RebalanceFieldInfo[] { let rebalanceType: RebalanceFieldInfo = { label: RebalanceTypeLabelName, type: 'string', value: PricePercentageRebalanceTypeName, enabled, }; let lowerBpsRebalanceFieldInfo: RebalanceFieldInfo = { label: 'lowerRangeBps', type: 'number', value: lowerPercentageBPS, enabled, }; let upperBpsRebalanceFieldInfo: RebalanceFieldInfo = { label: 'upperRangeBps', type: 'number', value: upperPercentageBPS, enabled, }; let { lowerPrice, upperPrice } = getPositionRangeFromPercentageRebalanceParams( poolPrice, lowerPercentageBPS, upperPercentageBPS ); let lowerRangeRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceLower', type: 'number', value: lowerPrice!, enabled: false, }; let upperRangeRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceUpper', type: 'number', value: upperPrice!, enabled: false, }; return [ rebalanceType, lowerBpsRebalanceFieldInfo, upperBpsRebalanceFieldInfo, lowerRangeRebalanceFieldInfo, upperRangeRebalanceFieldInfo, ]; } export function getPositionRangeFromPercentageRebalanceParams( price: Decimal, lowerPercentageBPS: Decimal, upperPercentageBPS: Decimal ): PositionRange { return getPriceRangeFromPriceAndDiffBPS(price, lowerPercentageBPS, upperPercentageBPS); } export function getDefaultPricePercentageRebalanceFieldInfos(price: Decimal): RebalanceFieldInfo[] { let fieldInfos = getPricePercentageRebalanceFieldInfos( price, DefaultLowerPercentageBPSDecimal, DefaultUpperPercentageBPSDecimal ); return fieldInfos; } export function readPricePercentageRebalanceParamsFromStrategy(rebalanceRaw: RebalanceRaw): RebalanceFieldInfo[] { let paramsBuffer = Buffer.from(rebalanceRaw.params); let lowerBpsRebalanceFieldInfo: RebalanceFieldInfo = { label: 'lowerRangeBps', type: 'number', value: new Decimal(paramsBuffer.readUint16LE(0)), enabled: true, }; let upperBpsRebalanceFieldInfo: RebalanceFieldInfo = { label: 'upperRangeBps', type: 'number', value: new Decimal(paramsBuffer.readUint16LE(2)), enabled: true, }; return [lowerBpsRebalanceFieldInfo, upperBpsRebalanceFieldInfo]; } export function readRawPricePercentageRebalanceStateFromStrategy(rebalanceRaw: RebalanceRaw): RebalanceFieldInfo[] { let stateBuffer = Buffer.from(rebalanceRaw.state); let lowerRangeRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceLower', type: 'number', value: new Decimal(readBigUint128LE(stateBuffer, 0).toString()), enabled: false, }; let upperRangeRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceUpper', type: 'number', value: new Decimal(readBigUint128LE(stateBuffer, 16).toString()), enabled: false, }; return [lowerRangeRebalanceFieldInfo, upperRangeRebalanceFieldInfo]; } export function readPricePercentageRebalanceStateFromStrategy( dex: Dex, tokenADecimals: number, tokenBDecimals: number, rebalanceRaw: RebalanceRaw ): RebalanceFieldInfo[] { let stateBuffer = Buffer.from(rebalanceRaw.state); let lowerSqrtPriceX64 = new Decimal(readBigUint128LE(stateBuffer, 0).toString()); let upperSqrtPriceX64 = new Decimal(readBigUint128LE(stateBuffer, 16).toString()); let lowerPrice: Decimal, upperPrice: Decimal; if (dex == 'ORCA') { lowerPrice = sqrtPriceX64ToPrice(new BN(lowerSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals); upperPrice = sqrtPriceX64ToPrice(new BN(upperSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals); } else if (dex == 'RAYDIUM') { lowerPrice = sqrtPriceX64ToPrice(new BN(lowerSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals); upperPrice = sqrtPriceX64ToPrice(new BN(upperSqrtPriceX64.toString()), tokenADecimals, tokenBDecimals); } else { throw new Error(`Unknown DEX ${dex}`); } let lowerRangeRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceLower', type: 'number', value: lowerPrice, enabled: false, }; let upperRangeRebalanceFieldInfo: RebalanceFieldInfo = { label: 'rangePriceUpper', type: 'number', value: upperPrice, enabled: false, }; return [lowerRangeRebalanceFieldInfo, upperRangeRebalanceFieldInfo]; } export function deserializePricePercentageRebalanceFromOnchainParams( price: Decimal, rebalanceRaw: RebalanceRaw ): RebalanceFieldInfo[] { let params = readPricePercentageRebalanceParamsFromStrategy(rebalanceRaw); let lowerRangeBPS = new Decimal(params.find((param) => param.label == 'lowerRangeBps')?.value!); let upperRangeBPS = new Decimal(params.find((param) => param.label == 'upperRangeBps')?.value!); return getPricePercentageRebalanceFieldInfos(price, lowerRangeBPS, upperRangeBPS); } export function deserializePricePercentageRebalanceWithStateOverride( dex: Dex, tokenADecimals: number, tokenBDecimals: number, price: Decimal, rebalanceRaw: RebalanceRaw ) { const stateFields = readPricePercentageRebalanceStateFromStrategy(dex, tokenADecimals, tokenBDecimals, rebalanceRaw); let fields = deserializePricePercentageRebalanceFromOnchainParams(price, rebalanceRaw); return upsertManyRebalanceFieldInfos(fields, stateFields); }