@kamino-finance/kliquidity-sdk
Version:
Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol
177 lines (154 loc) • 5.62 kB
text/typescript
import { LiquidityMathUtil, PersonalPositionLayout, TickArrayUtil, TickUtil } from '@raydium-io/raydium-sdk-v2/lib';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import Decimal from 'decimal.js';
export type ReturnTypeGetTickPrice = {
tick: number;
price: Decimal;
tickSqrtPriceX64: BN;
};
export type RaydiumPersonalPositionInfo = ReturnType<typeof PersonalPositionLayout.decode>;
export function decodeRaydiumPersonalPosition(data: Buffer): RaydiumPersonalPositionInfo {
return PersonalPositionLayout.decode(data);
}
// Big-endian on purpose: the on-chain CLMM program derives both protocol-position and
// tick-array PDAs with tick_index.to_be_bytes(), and all existing mainnet
// ProtocolPositionState accounts live at BE-derived addresses. raydium-sdk-v2 >= 0.2.x
// switched its own getPdaProtocolPositionAddress to little-endian, which only works for
// Raydium because the program now treats protocol_position as a deprecated unchecked
// account — but we store and read this address, so we must keep the BE derivation.
export function i32ToBytes(num: number): Uint8Array {
const arr = new ArrayBuffer(4);
new DataView(arr).setInt32(0, num, false);
return new Uint8Array(arr);
}
export function getPdaProtocolPositionAddress(
programId: PublicKey,
poolId: PublicKey,
tickLower: number,
tickUpper: number
): { publicKey: PublicKey; nonce: number } {
const [publicKey, nonce] = PublicKey.findProgramAddressSync(
[
Buffer.from('position', 'utf8'),
poolId.toBuffer(),
Buffer.from(i32ToBytes(tickLower)),
Buffer.from(i32ToBytes(tickUpper)),
],
programId
);
return { publicKey, nonce };
}
export class RaydiumSqrtPriceMath {
static sqrtPriceX64ToPrice(sqrtPriceX64: BN, decimalsA: number, decimalsB: number): Decimal {
return TickUtil.sqrtPriceX64ToPrice(sqrtPriceX64, decimalsA, decimalsB);
}
static priceToSqrtPriceX64(price: Decimal, decimalsA: number, decimalsB: number): BN {
return TickUtil.priceToSqrtPriceX64(price, decimalsA, decimalsB);
}
static getSqrtPriceX64FromTick(tick: number): BN {
return TickUtil.getSqrtPriceAtTick(tick);
}
static getTickFromPrice(price: Decimal, decimalsA: number, decimalsB: number): number {
return TickUtil.priceToTick(price, decimalsA, decimalsB);
}
static getTickFromSqrtPriceX64(sqrtPriceX64: BN): number {
return TickUtil.getTickAtSqrtPrice(sqrtPriceX64);
}
}
export class RaydiumTickMath {
static getTickWithPriceAndTickspacing(
price: Decimal,
tickSpacing: number,
mintDecimalsA: number,
mintDecimalsB: number
): number {
const tick = RaydiumSqrtPriceMath.getTickFromPrice(price, mintDecimalsA, mintDecimalsB);
const roundedTick = tick < 0 ? Math.floor(tick / tickSpacing) : Math.ceil(tick / tickSpacing);
return roundedTick * tickSpacing;
}
static roundPriceWithTickspacing(
price: Decimal,
tickSpacing: number,
mintDecimalsA: number,
mintDecimalsB: number
): Decimal {
const tick = this.getTickWithPriceAndTickspacing(price, tickSpacing, mintDecimalsA, mintDecimalsB);
return RaydiumSqrtPriceMath.sqrtPriceX64ToPrice(
RaydiumSqrtPriceMath.getSqrtPriceX64FromTick(tick),
mintDecimalsA,
mintDecimalsB
);
}
}
export class RaydiumLiquidityMath {
static addDelta(x: BN, y: BN): BN {
return LiquidityMathUtil.addDelta(x, y);
}
static getTokenAmountAFromLiquidity(sqrtPriceX64A: BN, sqrtPriceX64B: BN, liquidity: BN, roundUp: boolean): BN {
return LiquidityMathUtil.getAmountForLiquidityA(sqrtPriceX64A, sqrtPriceX64B, liquidity, roundUp);
}
static getTokenAmountBFromLiquidity(sqrtPriceX64A: BN, sqrtPriceX64B: BN, liquidity: BN, roundUp: boolean): BN {
return LiquidityMathUtil.getAmountForLiquidityB(sqrtPriceX64A, sqrtPriceX64B, liquidity, roundUp);
}
static getLiquidityFromTokenAmountA(sqrtPriceX64A: BN, sqrtPriceX64B: BN, amountA: BN, _roundUp: boolean): BN {
return LiquidityMathUtil.getLiquidityFromAmountA(sqrtPriceX64A, sqrtPriceX64B, amountA);
}
static getLiquidityFromTokenAmountB(sqrtPriceX64A: BN, sqrtPriceX64B: BN, amountB: BN): BN {
return LiquidityMathUtil.getLiquidityFromAmountB(sqrtPriceX64A, sqrtPriceX64B, amountB);
}
static getLiquidityFromTokenAmounts(
sqrtPriceCurrentX64: BN,
sqrtPriceX64A: BN,
sqrtPriceX64B: BN,
amountA: BN,
amountB: BN
): BN {
return LiquidityMathUtil.getLiquidityFromAmounts(
sqrtPriceCurrentX64,
sqrtPriceX64A,
sqrtPriceX64B,
amountA,
amountB
);
}
static getAmountsFromLiquidity(
sqrtPriceCurrentX64: BN,
sqrtPriceX64A: BN,
sqrtPriceX64B: BN,
liquidity: BN,
roundUp: boolean
): { amountA: BN; amountB: BN } {
return LiquidityMathUtil.getAmountsForLiquidity(
sqrtPriceCurrentX64,
sqrtPriceX64A,
sqrtPriceX64B,
liquidity,
roundUp
);
}
static getAmountsFromLiquidityWithSlippage(
sqrtPriceCurrentX64: BN,
sqrtPriceX64A: BN,
sqrtPriceX64B: BN,
liquidity: BN,
amountMax: boolean,
roundUp: boolean,
amountSlippage: number
): { amountSlippageA: BN; amountSlippageB: BN } {
return LiquidityMathUtil.getAmountsFromLiquidityWithSlippage(
sqrtPriceCurrentX64,
sqrtPriceX64A,
sqrtPriceX64B,
liquidity,
amountMax,
roundUp,
amountSlippage
);
}
}
export class RaydiumTickUtils {
static getTickArrayStartIndexByTick(tickIndex: number, tickSpacing: number): number {
return TickArrayUtil.getTickArrayStartIndex(tickIndex, tickSpacing);
}
}