UNPKG

@kamino-finance/kliquidity-sdk

Version:

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

115 lines (100 loc) 3.8 kB
import { Address, getAddressEncoder, getProgramDerivedAddress } from '@solana/kit'; import { encodeUtf8 } from './bytes'; import Decimal from 'decimal.js'; import { U64_MAX } from '../constants/numericalValues'; import { BinArray } from '../@codegen/meteora/accounts'; import { Bin } from '../@codegen/meteora/types'; import { ProgramDerivedAddress } from '@solana/addresses/dist/types/program-derived-address'; const BASIS_POINT_MAX = 10000; const MAX_BIN_ARRAY_SIZE = 70; const addressEncoder = getAddressEncoder(); export function getPriceOfBinByBinId(binId: number, tickSpacing: number): Decimal { const binStepNum = new Decimal(tickSpacing).div(new Decimal(BASIS_POINT_MAX)); return new Decimal(1).add(new Decimal(binStepNum)).pow(new Decimal(binId)); } export function getBinIdFromPrice(price: Decimal, tickSpacing: number, min: boolean): number { const binStepNum = new Decimal(tickSpacing).div(new Decimal(BASIS_POINT_MAX)); const binId = price.log().dividedBy(new Decimal(1).add(binStepNum).log()); return (min ? binId.floor() : binId.ceil()).toNumber(); } export function getPriceOfBinByBinIdWithDecimals( binId: number, tickSpacing: number, decimalsA: number, decimalsB: number ): Decimal { return getPriceOfBinByBinId(binId, tickSpacing) .mul(new Decimal(10).pow(decimalsA)) .div(new Decimal(10).pow(decimalsB)); } export function getBinIdFromPriceWithDecimals( price: Decimal, tickSpacing: number, min: boolean, decimalsA: number, decimalsB: number ): number { const scaledPrice = price.mul(new Decimal(10).pow(decimalsB)).div(new Decimal(10).pow(decimalsA)); return getBinIdFromPrice(scaledPrice, tickSpacing, min); } export function getPriceFromQ64Price(price: Decimal, decimalsA: number, decimalsB: number): Decimal { const scaledPrice = price.mul(new Decimal(10).pow(decimalsA)).div(new Decimal(10).pow(decimalsB)); return scaledPrice.div(new Decimal(U64_MAX)); } export function getBinArrayLowerUpperBinId(binArrayIndex: number): [number, number] { const lowerBinId = binArrayIndex * MAX_BIN_ARRAY_SIZE; const upperBinId = lowerBinId + MAX_BIN_ARRAY_SIZE - 1; return [lowerBinId, upperBinId]; } export function getBinFromBinArray(binIndex: number, binArray: BinArray): Bin | null { const [lowerBinId] = getBinArrayLowerUpperBinId(Number(binArray.index)); const offset = binIndex - lowerBinId; if (offset >= 0 && offset < binArray.bins.length) { return binArray.bins[offset]; } return null; } export function getBinFromBinArrays(binIndex: number, binArrays: BinArray[]): Bin | null { for (let i = 0; i < binArrays.length; i++) { const bin = getBinFromBinArray(binIndex, binArrays[i]); if (bin) { return bin; } } return null; } export function binIdToBinArrayIndex(binId: bigint): bigint { const idx = binId / BigInt(MAX_BIN_ARRAY_SIZE); const mod = binId % BigInt(MAX_BIN_ARRAY_SIZE); return binId < 0n && mod !== 0n ? idx - 1n : idx; } export async function deriveBinArray( lbPair: Address, index: bigint, programId: Address ): Promise<ProgramDerivedAddress> { let binArrayBytes: Uint8Array; if (index < 0n) { const mask = (1n << 64n) - 1n; const encoded = (~-index + 1n) & mask; const buf = new Uint8Array(8); const dv = new DataView(buf.buffer); dv.setBigUint64(0, encoded, true); binArrayBytes = buf; } else { const buf = new Uint8Array(8); const dv = new DataView(buf.buffer); dv.setBigUint64(0, index, true); binArrayBytes = buf; } const pda = await getProgramDerivedAddress({ seeds: [encodeUtf8('bin_array'), addressEncoder.encode(lbPair), binArrayBytes], programAddress: programId, }); return pda; } export type MeteoraPosition = { Address: Address; amountX: Decimal; amountY: Decimal; };