@kamino-finance/kliquidity-sdk
Version:
Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol
160 lines • 8.51 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSOLMint = exports.DECIMALS_SOL = exports.SOL_MINTS = exports.WSOL_MINT = exports.SOL_MINT = void 0;
exports.getAssociatedTokenAddressAndAccount = getAssociatedTokenAddressAndAccount;
exports.getAssociatedTokenAddress = getAssociatedTokenAddress;
exports.createAssociatedTokenAccountInstruction = createAssociatedTokenAccountInstruction;
exports.createComputeUnitLimitIx = createComputeUnitLimitIx;
exports.getStrategyPriceRangeOrca = getStrategyPriceRangeOrca;
exports.getStrategyPriceRangeRaydium = getStrategyPriceRangeRaydium;
exports.getStrategyPriceRangeMeteora = getStrategyPriceRangeMeteora;
exports.getMeteoraPriceLowerUpper = getMeteoraPriceLowerUpper;
exports.getPriceLowerUpper = getPriceLowerUpper;
exports.getTokenNameFromCollateralInfo = getTokenNameFromCollateralInfo;
exports.getMintDecimals = getMintDecimals;
exports.solToWSol = solToWSol;
exports.getTokenAccountBalance = getTokenAccountBalance;
exports.getTokenAccountBalanceLamports = getTokenAccountBalanceLamports;
const kit_1 = require("@solana/kit");
const decimal_js_1 = __importDefault(require("decimal.js"));
const meteora_1 = require("./meteora");
const token_1 = require("@solana-program/token");
const token_2022_1 = require("@solana-program/token-2022");
const system_1 = require("@solana-program/system");
const compute_budget_1 = require("@solana-program/compute-budget");
const whirlpools_core_1 = require("@orca-so/whirlpools-core");
exports.SOL_MINT = (0, kit_1.address)('So11111111111111111111111111111111111111111');
exports.WSOL_MINT = (0, kit_1.address)('So11111111111111111111111111111111111111112');
exports.SOL_MINTS = [exports.SOL_MINT, exports.WSOL_MINT];
exports.DECIMALS_SOL = 9;
async function getAssociatedTokenAddressAndAccount(connection, mint, owner, programId = token_1.TOKEN_PROGRAM_ADDRESS) {
const ata = await getAssociatedTokenAddress(mint, owner, programId);
const account = await (0, token_2022_1.fetchMaybeToken)(connection, ata);
return [ata, account.exists ? account : null];
}
async function getAssociatedTokenAddress(mint, owner, programId = token_1.TOKEN_PROGRAM_ADDRESS, associatedTokenProgramId = token_2022_1.ASSOCIATED_TOKEN_PROGRAM_ADDRESS) {
const [ata] = await (0, token_2022_1.findAssociatedTokenPda)({
mint,
owner,
tokenProgram: programId,
}, { programAddress: associatedTokenProgramId });
return ata;
}
function createAssociatedTokenAccountInstruction(payer, associatedTokenAddress, owner, mint, programId = token_1.TOKEN_PROGRAM_ADDRESS, associatedTokenProgramId = token_2022_1.ASSOCIATED_TOKEN_PROGRAM_ADDRESS) {
return (0, token_2022_1.getCreateAssociatedTokenInstruction)({
mint,
owner,
ata: associatedTokenAddress,
payer: payer,
tokenProgram: programId,
systemProgram: system_1.SYSTEM_PROGRAM_ADDRESS,
}, { programAddress: associatedTokenProgramId });
}
function createComputeUnitLimitIx(units = 400000) {
return (0, compute_budget_1.getSetComputeUnitLimitInstruction)({ units });
}
function getStrategyPriceRangeOrca(tickLowerIndex, tickUpperIndex, strategy, poolPrice) {
const { priceLower, priceUpper } = getPriceLowerUpper(tickLowerIndex, tickUpperIndex, Number(strategy.tokenAMintDecimals.toString()), Number(strategy.tokenBMintDecimals.toString()));
const strategyOutOfRange = poolPrice.lt(priceLower) || poolPrice.gt(priceUpper);
return { priceLower, poolPrice, priceUpper, strategyOutOfRange };
}
function getStrategyPriceRangeRaydium(tickLowerIndex, tickUpperIndex, tickCurrent, tokenADecimals, tokenBDecimals) {
const { priceLower, priceUpper } = getPriceLowerUpper(tickLowerIndex, tickUpperIndex, tokenADecimals, tokenBDecimals);
const poolPrice = new decimal_js_1.default((0, whirlpools_core_1.tickIndexToPrice)(tickCurrent, tokenADecimals, tokenBDecimals));
const strategyOutOfRange = poolPrice.lt(priceLower) || poolPrice.gt(priceUpper);
return { priceLower: new decimal_js_1.default(priceLower), poolPrice, priceUpper: new decimal_js_1.default(priceUpper), strategyOutOfRange };
}
function getStrategyPriceRangeMeteora(priceLower, priceUpper, activeBinId, binStep, decimalsA, decimalsB) {
const poolPrice = (0, meteora_1.getPriceOfBinByBinIdWithDecimals)(activeBinId, binStep, decimalsA, decimalsB);
const strategyOutOfRange = poolPrice.lt(priceLower) || poolPrice.gt(priceUpper);
return { priceLower, poolPrice, priceUpper, strategyOutOfRange };
}
function getMeteoraPriceLowerUpper(tickLowerIndex, tickUpperIndex, tokenAMintDecimals, tokenBMintDecimals, binStep) {
const priceLower = (0, meteora_1.getPriceOfBinByBinIdWithDecimals)(tickLowerIndex, binStep, tokenAMintDecimals, tokenBMintDecimals);
const priceUpper = (0, meteora_1.getPriceOfBinByBinIdWithDecimals)(tickUpperIndex, binStep, tokenAMintDecimals, tokenBMintDecimals);
return { priceLower, priceUpper };
}
function getPriceLowerUpper(tickLowerIndex, tickUpperIndex, tokenAMintDecimals, tokenBMintDecimals) {
const priceLower = (0, whirlpools_core_1.tickIndexToPrice)(tickLowerIndex, Number(tokenAMintDecimals.toString()), Number(tokenBMintDecimals.toString()));
const priceUpper = (0, whirlpools_core_1.tickIndexToPrice)(tickUpperIndex, Number(tokenAMintDecimals.toString()), Number(tokenBMintDecimals.toString()));
return { priceLower, priceUpper };
}
// Collateral names come back as Uint8Array on-chain, but can degrade into plain arrays
// or keyed objects after JSON serialization through caches or APIs.
function normalizeFixedBytes(value) {
if (value == null) {
return [];
}
if (typeof value === 'string') {
return Array.from(value, (char) => char.charCodeAt(0));
}
if (value instanceof Uint8Array) {
return Array.from(value);
}
if (value instanceof ArrayBuffer) {
return Array.from(new Uint8Array(value));
}
if (ArrayBuffer.isView(value)) {
return Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
}
if (Array.isArray(value)) {
return value.map((item) => Number(item)).filter((item) => Number.isFinite(item));
}
if (typeof value === 'object') {
const record = value;
if (Array.isArray(record.data)) {
return record.data.map((item) => Number(item)).filter((item) => Number.isFinite(item));
}
return Object.entries(record)
.filter(([key]) => /^\d+$/.test(key))
.sort((a, b) => Number(a[0]) - Number(b[0]))
.map(([, item]) => Number(item))
.filter((item) => Number.isFinite(item));
}
return [];
}
// Decode the fixed-width on-chain token name and stay resilient to JSON-round-tripped byte shapes.
function getTokenNameFromCollateralInfo(collateralInfo) {
const name = typeof collateralInfo.name === 'string'
? collateralInfo.name
: String.fromCharCode(...normalizeFixedBytes(collateralInfo.name));
return name.replace(/\0/g, '');
}
const isSOLMint = (mint) => {
return exports.SOL_MINTS.filter((m) => m === mint).length > 0;
};
exports.isSOLMint = isSOLMint;
async function getMintDecimals(rpc, mint) {
if ((0, exports.isSOLMint)(mint)) {
return exports.DECIMALS_SOL;
}
const acc = await (0, token_2022_1.fetchMaybeMint)(rpc, mint);
if (!acc.exists) {
throw new Error(`Mint ${mint} not found`);
}
return acc.data.decimals;
}
function solToWSol(mint) {
if (mint === exports.SOL_MINT) {
return exports.WSOL_MINT;
}
return mint;
}
async function getTokenAccountBalance(rpc, tokenAccount) {
const tokenAccountBalance = await rpc.getTokenAccountBalance(tokenAccount).send();
if (!tokenAccountBalance.value) {
throw new Error(`Could not get token account balance for ${tokenAccount.toString()}.`);
}
return new decimal_js_1.default(tokenAccountBalance.value.uiAmountString);
}
async function getTokenAccountBalanceLamports(rpc, tokenAccount) {
const tokenAccountBalance = await rpc.getTokenAccountBalance(tokenAccount).send();
if (!tokenAccountBalance.value) {
throw new Error(`Could not get token account balance for ${tokenAccount.toString()}.`);
}
return Number(tokenAccountBalance.value.amount);
}
//# sourceMappingURL=tokenUtils.js.map