@kamino-finance/kliquidity-sdk
Version:
Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol
292 lines • 12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReferencePriceType = exports.Dex = exports.RebalanceParamOffset = exports.ProportionalMintingMethod = exports.DollarBasedMintingMethod = void 0;
exports.sleep = sleep;
exports.dexToNumber = dexToNumber;
exports.numberToDex = numberToDex;
exports.numberToReferencePriceType = numberToReferencePriceType;
exports.getStrategyConfigValue = getStrategyConfigValue;
exports.buildStrategyRebalanceParams = buildStrategyRebalanceParams;
exports.doesStrategyHaveResetRange = doesStrategyHaveResetRange;
exports.numberToDriftDirection = numberToDriftDirection;
exports.numberToStakingRateSource = numberToStakingRateSource;
exports.numberToAutodriftStep = numberToAutodriftStep;
exports.numberToRebalanceType = numberToRebalanceType;
exports.getUpdateStrategyConfigIx = getUpdateStrategyConfigIx;
exports.collToLamportsDecimal = collToLamportsDecimal;
exports.lamportsToNumberDecimal = lamportsToNumberDecimal;
exports.readBigUint128LE = readBigUint128LE;
exports.readPriceOption = readPriceOption;
exports.rebalanceFieldsDictToInfo = rebalanceFieldsDictToInfo;
exports.isVaultInitialized = isVaultInitialized;
exports.sqrtPriceToPrice = sqrtPriceToPrice;
exports.stripTwapZeros = stripTwapZeros;
exports.percentageToBPS = percentageToBPS;
exports.keyOrDefault = keyOrDefault;
exports.optionGetValue = optionGetValue;
exports.optionGetValueOrUndefined = optionGetValueOrUndefined;
exports.optionGetValueOrDefault = optionGetValueOrDefault;
const kit_1 = require("@solana/kit");
const bytes_1 = require("./bytes");
const decimal_js_1 = __importDefault(require("decimal.js"));
const types_1 = require("../@codegen/kliquidity/types");
const instructions_1 = require("../@codegen/kliquidity/instructions");
const raydiumBridge_1 = require("./raydiumBridge");
const priceReferenceTypes_1 = require("./priceReferenceTypes");
const numericalValues_1 = require("../constants/numericalValues");
const raydiumSdkCompat_1 = require("./raydiumSdkCompat");
const pubkeys_1 = require("../constants/pubkeys");
const system_1 = require("@solana-program/system");
const whirlpools_core_1 = require("@orca-so/whirlpools-core");
exports.DollarBasedMintingMethod = new decimal_js_1.default(0);
exports.ProportionalMintingMethod = new decimal_js_1.default(1);
exports.RebalanceParamOffset = new decimal_js_1.default(256);
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
exports.Dex = ['ORCA', 'RAYDIUM', 'METEORA'];
exports.ReferencePriceType = [priceReferenceTypes_1.PoolPriceReferenceType, priceReferenceTypes_1.TwapPriceReferenceType];
function dexToNumber(dex) {
for (let i = 0; i < exports.Dex.length; i++) {
if (exports.Dex[i] === dex) {
return i;
}
}
throw new Error(`Unknown DEX ${dex}`);
}
function numberToDex(num) {
const dex = exports.Dex[num];
if (!dex) {
throw new Error(`Unknown DEX ${num}`);
}
return dex;
}
function numberToReferencePriceType(num) {
const referencePriceType = exports.ReferencePriceType[num];
if (!referencePriceType) {
throw new Error(`Strategy has invalid reference price type set: ${num}`);
}
return referencePriceType;
}
function getStrategyConfigValue(value) {
const buf = new Uint8Array(128);
const dv = new DataView(buf.buffer);
dv.setBigUint64(0, BigInt(value.toString()), true);
return [...buf];
}
function buildStrategyRebalanceParams(params, rebalance_type, tokenADecimals, tokenBDecimals) {
const buf = new Uint8Array(128);
const dv = new DataView(buf.buffer);
if (rebalance_type === types_1.RebalanceType.Manual) {
// Manual has no params
}
else if (rebalance_type === types_1.RebalanceType.PricePercentage) {
dv.setUint16(0, params[0].toNumber(), true);
dv.setUint16(2, params[1].toNumber(), true);
}
else if (rebalance_type === types_1.RebalanceType.PricePercentageWithReset) {
dv.setUint16(0, params[0].toNumber(), true);
dv.setUint16(2, params[1].toNumber(), true);
dv.setUint16(4, params[2].toNumber(), true);
dv.setUint16(6, params[3].toNumber(), true);
}
else if (rebalance_type === types_1.RebalanceType.Drift) {
dv.setInt32(0, params[0].toNumber(), true);
dv.setInt32(4, params[1].toNumber(), true);
dv.setInt32(8, params[2].toNumber(), true);
dv.setBigUint64(12, BigInt(params[3].toString()), true);
dv.setUint8(20, params[4].toNumber());
}
else if (rebalance_type === types_1.RebalanceType.TakeProfit) {
// TODO: fix this for meteora
const lowerPrice = raydiumSdkCompat_1.RaydiumSqrtPriceMath.priceToSqrtPriceX64(params[0], tokenADecimals, tokenBDecimals);
const upperPrice = raydiumSdkCompat_1.RaydiumSqrtPriceMath.priceToSqrtPriceX64(params[1], tokenADecimals, tokenBDecimals);
(0, bytes_1.writeU128LE)(dv, 0, (0, raydiumBridge_1.fromBN)(lowerPrice));
(0, bytes_1.writeU128LE)(dv, 16, (0, raydiumBridge_1.fromBN)(upperPrice));
dv.setUint8(32, params[2].toNumber());
}
else if (rebalance_type === types_1.RebalanceType.PeriodicRebalance) {
dv.setBigUint64(0, BigInt(params[0].toString()), true);
dv.setUint16(8, params[1].toNumber(), true);
dv.setUint16(10, params[2].toNumber(), true);
}
else if (rebalance_type === types_1.RebalanceType.Expander) {
dv.setUint16(0, params[0].toNumber(), true);
dv.setUint16(2, params[1].toNumber(), true);
dv.setUint16(4, params[2].toNumber(), true);
dv.setUint16(6, params[3].toNumber(), true);
dv.setUint16(8, params[4].toNumber(), true);
dv.setUint16(10, params[5].toNumber(), true);
dv.setUint8(12, params[6].toNumber());
}
else if (rebalance_type === types_1.RebalanceType.Autodrift) {
dv.setUint32(0, params[0].toNumber(), true);
dv.setInt32(4, params[1].toNumber(), true);
dv.setInt32(8, params[2].toNumber(), true);
dv.setUint16(12, params[3].toNumber(), true);
dv.setUint8(14, params[4].toNumber());
dv.setUint8(15, params[5].toNumber());
dv.setUint8(16, params[6].toNumber());
}
else {
throw 'Rebalance type not valid ' + rebalance_type;
}
return [...buf];
}
function doesStrategyHaveResetRange(rebalanceTypeNumber) {
const rebalanceType = numberToRebalanceType(rebalanceTypeNumber);
return rebalanceType === types_1.RebalanceType.PricePercentageWithReset || rebalanceType === types_1.RebalanceType.Expander;
}
function numberToDriftDirection(value) {
if (value == 0) {
return types_1.DriftDirection.Increasing;
}
else if (value == 1) {
return types_1.DriftDirection.Decreasing;
}
else {
throw new Error(`Invalid drift direction ${value.toString()}`);
}
}
function numberToStakingRateSource(value) {
if (value == 0) {
return types_1.StakingRateSource.Constant;
}
else if (value == 1) {
return types_1.StakingRateSource.Scope;
}
else {
throw new Error(`Invalid staking rate source ${value.toString()}`);
}
}
function numberToAutodriftStep(value) {
if (value == 0) {
return types_1.RebalanceAutodriftStep.Uninitialized;
}
else if (value == 1) {
return types_1.RebalanceAutodriftStep.Autodrifting;
}
else {
throw new Error(`Invalid autodrift step ${value.toString()}`);
}
}
function numberToRebalanceType(rebalance_type) {
if (rebalance_type == 0) {
return types_1.RebalanceType.Manual;
}
else if (rebalance_type == 1) {
return types_1.RebalanceType.PricePercentage;
}
else if (rebalance_type == 2) {
return types_1.RebalanceType.PricePercentageWithReset;
}
else if (rebalance_type == 3) {
return types_1.RebalanceType.Drift;
}
else if (rebalance_type == 4) {
return types_1.RebalanceType.TakeProfit;
}
else if (rebalance_type == 5) {
return types_1.RebalanceType.PeriodicRebalance;
}
else if (rebalance_type == 6) {
return types_1.RebalanceType.Expander;
}
else if (rebalance_type == 7) {
return types_1.RebalanceType.Autodrift;
}
else {
throw new Error(`Invalid rebalance type ${rebalance_type.toString()}`);
}
}
async function getUpdateStrategyConfigIx(signer, globalConfig, strategy, mode, amount, programId, newAccount = pubkeys_1.DEFAULT_PUBLIC_KEY) {
return (0, instructions_1.getUpdateStrategyConfigInstruction)({
adminAuthority: signer,
newAccount,
globalConfig,
strategy,
systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
mode,
value: new Uint8Array(getStrategyConfigValue(amount)),
}, { programAddress: programId });
}
function collToLamportsDecimal(amount, decimals) {
const factor = new decimal_js_1.default(10).pow(decimals);
return amount.mul(factor);
}
function lamportsToNumberDecimal(amount, decimals) {
const factor = new decimal_js_1.default(10).pow(decimals);
return new decimal_js_1.default(amount).div(factor);
}
function readBigUint128LE(buf, offset) {
const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
return (0, bytes_1.readU128LE)(dv, offset);
}
function readPriceOption(buf, offset) {
const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
if (dv.getUint8(offset) == 0) {
return [offset + 1, new decimal_js_1.default(0)];
}
const value = dv.getBigUint64(offset + 1, true);
const exp = dv.getBigUint64(offset + 9, true);
return [offset + 17, new decimal_js_1.default(value.toString()).div(new decimal_js_1.default(10).pow(exp.toString()))];
}
function rebalanceFieldsDictToInfo(rebalanceFields) {
const rebalanceFieldsInfo = [];
for (const key in rebalanceFields) {
const value = rebalanceFields[key];
rebalanceFieldsInfo.push({
label: key,
type: 'number',
value: value,
enabled: false,
});
}
return rebalanceFieldsInfo;
}
function isVaultInitialized(vault, decimals) {
return vault !== pubkeys_1.DEFAULT_PUBLIC_KEY && decimals > 0n;
}
function sqrtPriceToPrice(sqrtPrice, dexNo, decimalsA, decimalsB) {
const dex = numberToDex(dexNo);
if (dex == 'ORCA') {
return new decimal_js_1.default((0, whirlpools_core_1.sqrtPriceToPrice)(sqrtPrice, decimalsA, decimalsB));
}
if (dex == 'RAYDIUM') {
return raydiumSdkCompat_1.RaydiumSqrtPriceMath.sqrtPriceX64ToPrice((0, raydiumBridge_1.toBN)(sqrtPrice), decimalsA, decimalsB);
}
if (dex == 'METEORA') {
const price = new decimal_js_1.default(sqrtPrice.toString());
return price.div(new decimal_js_1.default(numericalValues_1.U64_MAX));
}
throw new Error(`Got invalid dex number ${dex}`);
}
// Zero is not a valid TWAP component as that indicates the SOL price
function stripTwapZeros(chain) {
return chain.filter((component) => component > 0);
}
function percentageToBPS(pct) {
return pct * 100;
}
function keyOrDefault(key, defaultKey) {
if (key === pubkeys_1.DEFAULT_PUBLIC_KEY) {
return defaultKey;
}
return key;
}
// Extract value from Option if Some, otherwise return null
function optionGetValue(option) {
return (0, kit_1.isSome)(option) ? option.value : null;
}
// Extract value from Option if Some, otherwise return undefined
function optionGetValueOrUndefined(option) {
return (0, kit_1.isSome)(option) ? option.value : undefined;
}
// Extract value from Option if Some, otherwise return provided default
function optionGetValueOrDefault(option, defaultValue) {
return (0, kit_1.isSome)(option) ? option.value : defaultValue;
}
//# sourceMappingURL=utils.js.map