@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
834 lines • 49.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getScopeRefreshIx = exports.getSetupIxs = void 0;
exports.getDepositWithLeverageSwapInputs = getDepositWithLeverageSwapInputs;
exports.getDepositWithLeverageIxs = getDepositWithLeverageIxs;
exports.getWithdrawWithLeverageSwapInputs = getWithdrawWithLeverageSwapInputs;
exports.getWithdrawWithLeverageIxs = getWithdrawWithLeverageIxs;
exports.buildWithdrawWithLeverageIxs = buildWithdrawWithLeverageIxs;
exports.getAdjustLeverageSwapInputs = getAdjustLeverageSwapInputs;
exports.getAdjustLeverageIxs = getAdjustLeverageIxs;
const web3_js_1 = require("@solana/web3.js");
const decimal_js_1 = __importDefault(require("decimal.js"));
const classes_1 = require("../classes");
const instructions_1 = require("./instructions");
const classes_2 = require("../classes");
const utils_1 = require("../utils");
const calcs_1 = require("./calcs");
const spl_token_1 = require("@solana/spl-token");
const utils_2 = require("./utils");
const CreationParameters_1 = require("@kamino-finance/kliquidity-sdk/dist/utils/CreationParameters");
async function getDepositWithLeverageSwapInputs({ owner, kaminoMarket, debtTokenMint, collTokenMint, depositAmount, priceDebtToColl, slippagePct, obligation, referrer, currentSlot, targetLeverage, selectedTokenMint, kamino, obligationTypeTagOverride, scopeRefreshConfig, budgetAndPriorityFeeIxs, quoteBufferBps, priceAinB, isKtoken, quoter, useV2Ixs, elevationGroupOverride, }) {
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
const solTokenReserve = kaminoMarket.getReserveByMint(spl_token_1.NATIVE_MINT);
const flashLoanFee = collReserve.getFlashLoanFee() || new decimal_js_1.default(0);
const selectedTokenIsCollToken = selectedTokenMint.equals(collTokenMint);
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
const collIsKtoken = await isKtoken(collTokenMint);
const strategy = collIsKtoken ? (await kamino.getStrategyByKTokenMint(collTokenMint)) : undefined;
const calcs = await getDepositWithLeverageCalcs(depositAmount, selectedTokenIsCollToken, collIsKtoken, depositTokenIsSol, priceDebtToColl, targetLeverage, slippagePct, flashLoanFee, kamino, strategy, debtTokenMint, priceAinB, debtReserve);
console.log('Ops Calcs', (0, classes_1.toJson)(calcs));
const obligationType = checkObligationType(obligationTypeTagOverride, collTokenMint, debtTokenMint, kaminoMarket);
// Build the repay & withdraw collateral tx to get the number of accounts
const klendIxs = await buildDepositWithLeverageIxs(kaminoMarket, debtReserve, collReserve, owner, obligation ? obligation : obligationType, referrer, currentSlot, depositTokenIsSol, scopeRefreshConfig, calcs, budgetAndPriorityFeeIxs, {
preActionIxs: [],
swapIxs: [],
lookupTables: [],
quote: {
priceAInB: new decimal_js_1.default(0), // not used
quoteResponse: undefined,
},
}, strategy, collIsKtoken, useV2Ixs, elevationGroupOverride);
const uniqueKlendAccounts = (0, utils_1.uniqueAccountsWithProgramIds)(klendIxs.instructions);
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.swapDebtTokenIn : calcs.singleSidedDepositKtokenOnly, debtReserve.stats.decimals).ceil();
const swapInputsForQuote = {
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
inputMint: debtTokenMint,
outputMint: collTokenMint,
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens swaps
};
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
const quotePriceCalcs = await getDepositWithLeverageCalcs(depositAmount, selectedTokenIsCollToken, collIsKtoken, depositTokenIsSol, swapQuote.priceAInB, targetLeverage, slippagePct, flashLoanFee, kamino, strategy, debtTokenMint, priceAinB, debtReserve);
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? quotePriceCalcs.swapDebtTokenIn : quotePriceCalcs.singleSidedDepositKtokenOnly, debtReserve.stats.decimals).ceil();
let expectedDebtTokenAtaBalance = new decimal_js_1.default(0);
if (collIsKtoken) {
let futureBalanceInAta = new decimal_js_1.default(0);
if (debtTokenMint.equals(spl_token_1.NATIVE_MINT)) {
futureBalanceInAta = futureBalanceInAta.add(!collIsKtoken ? quotePriceCalcs.initDepositInSol : quotePriceCalcs.initDepositInSol);
}
futureBalanceInAta = futureBalanceInAta.add(!collIsKtoken ? quotePriceCalcs.debtTokenToBorrow : quotePriceCalcs.flashBorrowInDebtTokenKtokenOnly);
expectedDebtTokenAtaBalance = await (0, utils_2.getExpectedTokenBalanceAfterBorrow)(kaminoMarket.getConnection(), debtTokenMint, owner, (0, classes_2.numberToLamportsDecimal)(futureBalanceInAta.toDecimalPlaces(debtReserve.stats.decimals), debtReserve.stats.decimals), debtReserve.state.liquidity.mintDecimals.toNumber());
}
return {
swapInputs: {
inputAmountLamports: swapInputAmountQuotePrice,
minOutAmountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? quotePriceCalcs.flashBorrowInCollToken : quotePriceCalcs.flashBorrowInDebtTokenKtokenOnly, !collIsKtoken ? collReserve.stats.decimals : debtReserve.stats.decimals),
inputMint: debtTokenMint,
outputMint: collTokenMint,
amountDebtAtaBalance: expectedDebtTokenAtaBalance,
},
flashLoanInfo: klendIxs.flashLoanInfo,
initialInputs: {
calcs: quotePriceCalcs,
swapQuote,
currentSlot,
collIsKtoken,
strategy,
obligation: obligation ? obligation : obligationType,
klendAccounts: uniqueKlendAccounts,
},
};
}
async function getDepositWithLeverageCalcs(depositAmount, selectedTokenIsCollToken, collIsKtoken, depositTokenIsSol, priceDebtToColl, targetLeverage, slippagePct, flashLoanFee, kamino, strategy, debtTokenMint, priceAinB, debtReserve) {
let calcs;
if (!collIsKtoken) {
calcs = (0, calcs_1.depositLeverageCalcs)({
depositAmount: depositAmount,
depositTokenIsCollToken: selectedTokenIsCollToken,
depositTokenIsSol,
priceDebtToColl,
targetLeverage,
slippagePct,
flashLoanFee,
});
}
else {
calcs = await (0, calcs_1.depositLeverageKtokenCalcs)({
kamino: kamino,
strategy: strategy,
debtTokenMint,
depositAmount: depositAmount,
depositTokenIsCollToken: selectedTokenIsCollToken,
depositTokenIsSol,
priceDebtToColl,
targetLeverage,
slippagePct,
flashLoanFee,
priceAinB,
});
// Rounding to exact number of decimals so this value is passed through in all calcs without rounding inconsistencies
calcs.flashBorrowInDebtTokenKtokenOnly = calcs.flashBorrowInDebtTokenKtokenOnly.toDecimalPlaces(debtReserve.state.liquidity.mintDecimals.toNumber(), decimal_js_1.default.ROUND_CEIL);
calcs.debtTokenToBorrow = calcs.debtTokenToBorrow.toDecimalPlaces(debtReserve.state.liquidity.mintDecimals.toNumber(), decimal_js_1.default.ROUND_CEIL);
calcs.singleSidedDepositKtokenOnly = calcs.singleSidedDepositKtokenOnly.toDecimalPlaces(debtReserve.state.liquidity.mintDecimals.toNumber(), decimal_js_1.default.ROUND_CEIL);
}
return calcs;
}
async function getDepositWithLeverageIxs({ owner, kaminoMarket, debtTokenMint, collTokenMint, depositAmount, priceDebtToColl, slippagePct, obligation, referrer, currentSlot, targetLeverage, selectedTokenMint, kamino, obligationTypeTagOverride, scopeRefreshConfig, budgetAndPriorityFeeIxs, quoteBufferBps, priceAinB, isKtoken, quoter, swapper, elevationGroupOverride, useV2Ixs, }) {
const { swapInputs, initialInputs } = await getDepositWithLeverageSwapInputs({
owner,
kaminoMarket,
debtTokenMint,
collTokenMint,
depositAmount,
priceDebtToColl,
slippagePct,
obligation,
referrer,
currentSlot,
targetLeverage,
selectedTokenMint,
kamino,
obligationTypeTagOverride,
scopeRefreshConfig,
budgetAndPriorityFeeIxs,
quoteBufferBps,
priceAinB,
isKtoken,
quoter,
useV2Ixs,
});
let depositSwapper;
if (!initialInputs.collIsKtoken) {
depositSwapper = swapper;
}
else {
if (kamino === undefined) {
throw Error('Ktoken use as collateral for leverage without Kamino instance');
}
depositSwapper = await (0, utils_2.getTokenToKtokenSwapper)(kaminoMarket, kamino, owner, slippagePct, swapper, priceAinB, false);
}
const swapsArray = await depositSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
if (initialInputs.collIsKtoken) {
if (initialInputs.strategy.strategy.strategyLookupTable) {
const strategyLut = await (0, utils_1.getLookupTableAccount)(kaminoMarket.getConnection(), initialInputs.strategy.strategy.strategyLookupTable);
swapsArray.forEach((swap) => {
swap.lookupTables.push(strategyLut);
});
}
else {
console.log('Strategy lookup table not found');
}
}
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
const solTokenReserve = kaminoMarket.getReserveByMint(spl_token_1.NATIVE_MINT);
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
return Promise.all(swapsArray.map(async (swap) => {
const ixs = await buildDepositWithLeverageIxs(kaminoMarket, debtReserve, collReserve, owner, initialInputs.obligation, referrer, currentSlot, depositTokenIsSol, scopeRefreshConfig, initialInputs.calcs, budgetAndPriorityFeeIxs, {
preActionIxs: [],
swapIxs: swap.swapIxs,
lookupTables: swap.lookupTables,
quote: swap.quote,
}, initialInputs.strategy, initialInputs.collIsKtoken, useV2Ixs, elevationGroupOverride);
return {
ixs: ixs.instructions,
flashLoanInfo: ixs.flashLoanInfo,
lookupTables: swap.lookupTables,
swapInputs,
initialInputs,
quote: swap.quote.quoteResponse,
};
}));
}
async function buildDepositWithLeverageIxs(market, debtReserve, collReserve, owner, obligation, referrer, currentSlot, depositTokenIsSol, scopeRefreshConfig, calcs, budgetAndPriorityFeeIxs, swapQuoteIxs, strategy, collIsKtoken, useV2Ixs, elevationGroupOverride) {
const collTokenMint = collReserve.getLiquidityMint();
const debtTokenMint = debtReserve.getLiquidityMint();
const collTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collTokenMint, owner, false, collReserve.getLiquidityTokenProgram());
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner, false, debtReserve.getLiquidityTokenProgram());
// 1. Create atas & budget ixs
const { budgetIxs, createAtasIxs, scopeRefreshIx } = await (0, exports.getSetupIxs)(owner, market, obligation, collTokenMint, collReserve, collIsKtoken, debtTokenMint, debtReserve, strategy, scopeRefreshConfig, budgetAndPriorityFeeIxs);
const fillWsolAtaIxs = [];
if (depositTokenIsSol) {
fillWsolAtaIxs.push(...(0, utils_1.getTransferWsolIxs)(owner, (0, spl_token_1.getAssociatedTokenAddressSync)(spl_token_1.NATIVE_MINT, owner), (0, classes_2.numberToLamportsDecimal)(calcs.initDepositInSol, utils_1.SOL_DECIMALS).ceil()));
}
// 2. Flash borrow & repay the collateral amount needed for given leverage
// if user deposits coll, then we borrow the diff, else we borrow the entire amount
const { flashBorrowIx, flashRepayIx } = (0, instructions_1.getFlashLoanInstructions)({
borrowIxIndex: budgetIxs.length + createAtasIxs.length + fillWsolAtaIxs.length + (scopeRefreshIx.length > 0 ? 1 : 0),
walletPublicKey: owner,
lendingMarketAuthority: market.getLendingMarketAuthority(),
lendingMarketAddress: market.getAddress(),
reserve: !collIsKtoken ? collReserve : debtReserve,
amountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.flashBorrowInCollToken : calcs.flashBorrowInDebtTokenKtokenOnly, !collIsKtoken ? collReserve.stats.decimals : debtReserve.stats.decimals),
destinationAta: !collIsKtoken ? collTokenAta : debtTokenAta,
// TODO(referrals): once we support referrals, we will have to replace the placeholder args below:
referrerAccount: market.programId,
referrerTokenState: market.programId,
programId: market.programId,
});
// 3. Deposit initial tokens + borrowed tokens into reserve
const kaminoDepositAndBorrowAction = await classes_1.KaminoAction.buildDepositAndBorrowTxns(market, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.collTokenToDeposit : calcs.collTokenToDeposit, collReserve.stats.decimals)
.floor()
.toString(), collTokenMint, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.debtTokenToBorrow : calcs.debtTokenToBorrow, debtReserve.stats.decimals)
.ceil()
.toString(), debtTokenMint, owner, obligation, useV2Ixs, undefined, 0, false, elevationGroupOverride === 0 ? false : true, // emode
{ skipInitialization: true, skipLutCreation: true }, // to be checked and created in a setup tx in the UI
referrer, currentSlot);
// 4. Swap
const { swapIxs } = swapQuoteIxs;
const swapInstructions = (0, utils_1.removeBudgetIxs)(swapIxs);
const flashBorrowReserve = !collIsKtoken ? collReserve : debtReserve;
const flashLoanInfo = {
flashBorrowReserve: flashBorrowReserve.address,
flashLoanFee: flashBorrowReserve.getFlashLoanFee(),
};
return {
flashLoanInfo,
instructions: [
...scopeRefreshIx,
...budgetIxs,
...createAtasIxs,
...fillWsolAtaIxs,
...[flashBorrowIx],
...(collIsKtoken ? swapInstructions : []),
...classes_1.KaminoAction.actionToIxs(kaminoDepositAndBorrowAction),
...(collIsKtoken ? [] : swapInstructions),
...[flashRepayIx],
],
};
}
async function getWithdrawWithLeverageSwapInputs({ owner, kaminoMarket, debtTokenMint, collTokenMint, deposited, borrowed, obligation, referrer, currentSlot, withdrawAmount, priceCollToDebt, slippagePct, isClosingPosition, selectedTokenMint, budgetAndPriorityFeeIxs, kamino, scopeRefreshConfig, quoteBufferBps, isKtoken, quoter, useV2Ixs, }) {
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
const flashLoanFee = debtReserve.getFlashLoanFee() || new decimal_js_1.default(0);
const selectedTokenIsCollToken = selectedTokenMint.equals(collTokenMint);
const collIsKtoken = await isKtoken(collTokenMint);
const strategy = collIsKtoken ? (await kamino.getStrategyByKTokenMint(collTokenMint)) : undefined;
const inputTokenIsSol = selectedTokenMint.equals(spl_token_1.NATIVE_MINT);
const calcs = (0, calcs_1.withdrawLeverageCalcs)(kaminoMarket, collReserve, debtReserve, priceCollToDebt, withdrawAmount, deposited, borrowed, currentSlot, isClosingPosition, selectedTokenIsCollToken, selectedTokenMint, obligation, flashLoanFee, slippagePct);
const klendIxs = await buildWithdrawWithLeverageIxs(kaminoMarket, debtReserve, collReserve, owner, obligation, referrer, currentSlot, isClosingPosition, inputTokenIsSol, scopeRefreshConfig, calcs, budgetAndPriorityFeeIxs, {
preActionIxs: [],
swapIxs: [],
lookupTables: [],
quote: {
priceAInB: new decimal_js_1.default(0), // not used
quoteResponse: undefined,
},
}, strategy, collIsKtoken, useV2Ixs);
const uniqueKlendAccounts = (0, utils_1.uniqueAccountsWithProgramIds)(klendIxs.instructions);
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(calcs.collTokenSwapIn, collReserve.getMintDecimals()).ceil();
const swapInputsForQuote = {
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
inputMint: collTokenMint,
outputMint: debtTokenMint,
amountDebtAtaBalance: undefined, // Only needed for ktokens deposits
};
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
const calcsQuotePrice = (0, calcs_1.withdrawLeverageCalcs)(kaminoMarket, collReserve, debtReserve, !collIsKtoken ? swapQuote.priceAInB : priceCollToDebt, withdrawAmount, deposited, borrowed, currentSlot, isClosingPosition, selectedTokenIsCollToken, selectedTokenMint, obligation, flashLoanFee, slippagePct);
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(calcsQuotePrice.collTokenSwapIn, collReserve.getMintDecimals()).ceil();
return {
swapInputs: {
inputAmountLamports: swapInputAmountQuotePrice,
minOutAmountLamports: calcsQuotePrice.repayAmount,
inputMint: collTokenMint,
outputMint: debtTokenMint,
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens deposits
},
flashLoanInfo: klendIxs.flashLoanInfo,
initialInputs: {
calcs: calcsQuotePrice,
swapQuote,
currentSlot,
collIsKtoken,
strategy,
obligation,
klendAccounts: uniqueKlendAccounts,
},
};
}
async function getWithdrawWithLeverageIxs({ owner, kaminoMarket, debtTokenMint, collTokenMint, obligation, deposited, borrowed, referrer, currentSlot, withdrawAmount, priceCollToDebt, slippagePct, isClosingPosition, selectedTokenMint, budgetAndPriorityFeeIxs, kamino, scopeRefreshConfig, quoteBufferBps, isKtoken, quoter, swapper, useV2Ixs, }) {
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
const inputTokenIsSol = selectedTokenMint.equals(spl_token_1.NATIVE_MINT);
const { swapInputs, initialInputs } = await getWithdrawWithLeverageSwapInputs({
owner,
kaminoMarket,
debtTokenMint,
collTokenMint,
deposited,
borrowed,
obligation,
referrer,
currentSlot,
withdrawAmount,
priceCollToDebt,
slippagePct,
isClosingPosition,
selectedTokenMint,
budgetAndPriorityFeeIxs,
kamino,
scopeRefreshConfig,
quoteBufferBps,
isKtoken,
quoter,
useV2Ixs,
});
let withdrawSwapper;
if (initialInputs.collIsKtoken) {
if (kamino === undefined) {
throw Error('Ktoken use as collateral for leverage without Kamino instance');
}
withdrawSwapper = await (0, utils_2.getKtokenToTokenSwapper)(kaminoMarket, kamino, owner, swapper);
}
else {
withdrawSwapper = swapper;
}
const swapsArray = await withdrawSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
if (initialInputs.collIsKtoken) {
if (initialInputs.strategy.strategy.strategyLookupTable) {
const strategyLut = await (0, utils_1.getLookupTableAccount)(kaminoMarket.getConnection(), initialInputs.strategy.strategy.strategyLookupTable);
swapsArray.forEach((swap) => {
swap.lookupTables.push(strategyLut);
});
}
else {
console.log('Strategy lookup table not found');
}
}
return Promise.all(swapsArray.map(async (swap) => {
const ixs = await buildWithdrawWithLeverageIxs(kaminoMarket, debtReserve, collReserve, owner, obligation, referrer, currentSlot, isClosingPosition, inputTokenIsSol, scopeRefreshConfig, initialInputs.calcs, budgetAndPriorityFeeIxs, {
preActionIxs: [],
swapIxs: swap.swapIxs,
lookupTables: swap.lookupTables,
quote: swap.quote,
}, initialInputs.strategy, initialInputs.collIsKtoken, useV2Ixs);
// Send ixs and lookup tables
return {
ixs: ixs.instructions,
flashLoanInfo: ixs.flashLoanInfo,
lookupTables: swap.lookupTables,
swapInputs,
initialInputs: initialInputs,
quote: swap.quote.quoteResponse,
};
}));
}
async function buildWithdrawWithLeverageIxs(market, debtReserve, collReserve, owner, obligation, referrer, currentSlot, isClosingPosition, depositTokenIsSol, scopeRefreshConfig, calcs, budgetAndPriorityFeeIxs, swapQuoteIxs, strategy, collIsKtoken, useV2Ixs) {
const collTokenMint = collReserve.getLiquidityMint();
const debtTokenMint = debtReserve.getLiquidityMint();
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner, false, debtReserve.getLiquidityTokenProgram());
// 1. Create atas & budget txns & user metadata
const { budgetIxs, createAtasIxs, scopeRefreshIx } = await (0, exports.getSetupIxs)(owner, market, obligation, collTokenMint, collReserve, collIsKtoken, debtTokenMint, debtReserve, strategy, scopeRefreshConfig, budgetAndPriorityFeeIxs);
const closeWsolAtaIxs = [];
if (depositTokenIsSol || debtTokenMint.equals(spl_token_1.NATIVE_MINT)) {
const wsolAta = (0, utils_1.getAssociatedTokenAddress)(spl_token_1.NATIVE_MINT, owner, false);
closeWsolAtaIxs.push((0, spl_token_1.createCloseAccountInstruction)(wsolAta, owner, owner, [], spl_token_1.TOKEN_PROGRAM_ID));
}
// TODO: Mihai/Marius check if we can improve this logic and not convert any SOL
// This is here so that we have enough wsol to repay in case the kAB swapped to sol after estimates is not enough
const fillWsolAtaIxs = [];
if (debtTokenMint.equals(spl_token_1.NATIVE_MINT)) {
const halfSolBalance = (await market.getConnection().getBalance(owner)) / web3_js_1.LAMPORTS_PER_SOL / 2;
const balanceToWrap = halfSolBalance < 0.1 ? halfSolBalance : 0.1;
fillWsolAtaIxs.push(...(0, utils_1.getTransferWsolIxs)(owner, (0, spl_token_1.getAssociatedTokenAddressSync)(spl_token_1.NATIVE_MINT, owner), (0, classes_2.numberToLamportsDecimal)(balanceToWrap, utils_1.SOL_DECIMALS).ceil()));
}
// 2. Prepare the flash borrow and flash repay amounts and ixs
// We borrow exactly how much we need to repay
// and repay that + flash amount fee
const { flashBorrowIx, flashRepayIx } = (0, instructions_1.getFlashLoanInstructions)({
borrowIxIndex: budgetIxs.length + createAtasIxs.length + fillWsolAtaIxs.length + (scopeRefreshIx.length > 0 ? 1 : 0),
walletPublicKey: owner,
lendingMarketAuthority: market.getLendingMarketAuthority(),
lendingMarketAddress: market.getAddress(),
reserve: debtReserve,
amountLamports: (0, classes_2.numberToLamportsDecimal)(calcs.repayAmount, debtReserve.stats.decimals),
destinationAta: debtTokenAta,
// TODO(referrals): once we support referrals, we will have to replace the placeholder args below:
referrerAccount: market.programId,
referrerTokenState: market.programId,
programId: market.programId,
});
// 3. Repay borrowed tokens and Withdraw tokens from reserve that will be swapped to repay flash loan
const repayAndWithdrawAction = await classes_1.KaminoAction.buildRepayAndWithdrawTxns(market, isClosingPosition ? utils_1.U64_MAX : (0, classes_2.numberToLamportsDecimal)(calcs.repayAmount, debtReserve.stats.decimals).floor().toString(), debtTokenMint, isClosingPosition
? utils_1.U64_MAX
: (0, classes_2.numberToLamportsDecimal)(calcs.depositTokenWithdrawAmount, collReserve.stats.decimals).ceil().toString(), collTokenMint, owner, currentSlot, obligation, useV2Ixs, undefined, 0, false, false, { skipInitialization: true, skipLutCreation: true }, // to be checked and created in a setup tx in the UI (won't be the case for withdraw anyway as this would be created in deposit)
referrer);
const swapInstructions = (0, utils_1.removeBudgetIxs)(swapQuoteIxs.swapIxs);
return {
flashLoanInfo: {
flashLoanFee: debtReserve.getFlashLoanFee(),
flashBorrowReserve: debtReserve.address,
},
instructions: [
...scopeRefreshIx,
...budgetIxs,
...createAtasIxs,
...fillWsolAtaIxs,
...[flashBorrowIx],
...classes_1.KaminoAction.actionToIxs(repayAndWithdrawAction),
...swapInstructions,
...[flashRepayIx],
...closeWsolAtaIxs,
],
};
}
async function getAdjustLeverageSwapInputs({ owner, kaminoMarket, debtTokenMint, collTokenMint, obligation, depositedLamports, borrowedLamports, referrer, currentSlot, targetLeverage, priceCollToDebt, priceDebtToColl, slippagePct, budgetAndPriorityFeeIxs, kamino, scopeRefreshConfig, quoteBufferBps, isKtoken, quoter, useV2Ixs, }) {
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
const deposited = (0, classes_1.lamportsToNumberDecimal)(depositedLamports, collReserve.stats.decimals);
const borrowed = (0, classes_1.lamportsToNumberDecimal)(borrowedLamports, debtReserve.stats.decimals);
const collIsKtoken = await isKtoken(collTokenMint);
const strategy = collIsKtoken ? (await kamino.getStrategyByKTokenMint(collTokenMint)) : undefined;
// Getting current flash loan fee
const currentLeverage = obligation.refreshedStats.leverage;
const isDepositViaLeverage = targetLeverage.gte(new decimal_js_1.default(currentLeverage));
let flashLoanFee;
if (isDepositViaLeverage) {
flashLoanFee = collReserve.getFlashLoanFee() || new decimal_js_1.default(0);
}
else {
flashLoanFee = debtReserve.getFlashLoanFee() || new decimal_js_1.default(0);
}
const { adjustDepositPosition, adjustBorrowPosition } = (0, calcs_1.calcAdjustAmounts)({
currentDepositPosition: deposited,
currentBorrowPosition: borrowed,
targetLeverage: targetLeverage,
priceCollToDebt: priceCollToDebt,
flashLoanFee: new decimal_js_1.default(flashLoanFee),
});
const isDeposit = adjustDepositPosition.gte(0) && adjustBorrowPosition.gte(0);
if (isDepositViaLeverage !== isDeposit) {
throw new Error('Invalid target leverage');
}
if (isDeposit) {
const calcs = await (0, calcs_1.adjustDepositLeverageCalcs)(kaminoMarket, owner, debtReserve, adjustDepositPosition, adjustBorrowPosition, priceDebtToColl, flashLoanFee, slippagePct, collIsKtoken);
// Build the repay & withdraw collateral tx to get the number of accounts
const klendIxs = await buildIncreaseLeverageIxs(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeRefreshConfig, collIsKtoken, {
preActionIxs: [],
swapIxs: [],
lookupTables: [],
quote: {
priceAInB: new decimal_js_1.default(0), // not used
quoteResponse: undefined,
},
}, budgetAndPriorityFeeIxs, useV2Ixs);
const uniqueKlendAccounts = (0, utils_1.uniqueAccountsWithProgramIds)(klendIxs.instructions);
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.borrowAmount : calcs.amountToFlashBorrowDebt, debtReserve.stats.decimals).ceil();
const swapInputsForQuote = {
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
inputMint: debtTokenMint,
outputMint: collTokenMint,
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens swaps
};
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
const { adjustDepositPosition: adjustDepositPositionQuotePrice, adjustBorrowPosition: adjustBorrowPositionQuotePrice, } = (0, calcs_1.calcAdjustAmounts)({
currentDepositPosition: deposited,
currentBorrowPosition: borrowed,
targetLeverage: targetLeverage,
priceCollToDebt: new decimal_js_1.default(1).div(swapQuote.priceAInB),
flashLoanFee: new decimal_js_1.default(flashLoanFee),
});
const calcsQuotePrice = await (0, calcs_1.adjustDepositLeverageCalcs)(kaminoMarket, owner, debtReserve, adjustDepositPositionQuotePrice, adjustBorrowPositionQuotePrice, swapQuote.priceAInB, flashLoanFee, slippagePct, collIsKtoken);
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcsQuotePrice.borrowAmount : calcsQuotePrice.amountToFlashBorrowDebt, debtReserve.getMintDecimals()).ceil();
let expectedDebtTokenAtaBalance = new decimal_js_1.default(0);
if (collIsKtoken) {
expectedDebtTokenAtaBalance = await (0, utils_2.getExpectedTokenBalanceAfterBorrow)(kaminoMarket.getConnection(), debtTokenMint, owner, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcsQuotePrice.borrowAmount : calcsQuotePrice.amountToFlashBorrowDebt, debtReserve.stats.decimals).floor(), debtReserve.getMintDecimals());
}
return {
swapInputs: {
inputAmountLamports: swapInputAmountQuotePrice,
minOutAmountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcsQuotePrice.adjustDepositPosition : calcsQuotePrice.amountToFlashBorrowDebt, !collIsKtoken ? collReserve.stats.decimals : debtReserve.stats.decimals),
inputMint: debtTokenMint,
outputMint: collTokenMint,
amountDebtAtaBalance: expectedDebtTokenAtaBalance,
},
flashLoanInfo: klendIxs.flashLoanInfo,
initialInputs: {
calcs: calcsQuotePrice,
swapQuote,
currentSlot,
collIsKtoken,
strategy,
obligation: obligation,
klendAccounts: uniqueKlendAccounts,
isDeposit: isDeposit,
},
};
}
else {
const calcs = (0, calcs_1.adjustWithdrawLeverageCalcs)(adjustDepositPosition, adjustBorrowPosition, flashLoanFee, slippagePct);
const klendIxs = await buildDecreaseLeverageIxs(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeRefreshConfig, collIsKtoken, {
preActionIxs: [],
swapIxs: [],
lookupTables: [],
quote: {
priceAInB: new decimal_js_1.default(0), // not used
quoteResponse: undefined,
},
}, budgetAndPriorityFeeIxs, useV2Ixs);
const uniqueKlendAccounts = (0, utils_1.uniqueAccountsWithProgramIds)(klendIxs.instructions);
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(calcs.withdrawAmountWithSlippageAndFlashLoanFee, collReserve.state.liquidity.mintDecimals.toNumber()).ceil();
const swapInputsForQuote = {
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
inputMint: collTokenMint,
outputMint: debtTokenMint,
amountDebtAtaBalance: undefined, // Only needed for ktokens deposits
};
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
const { adjustDepositPosition: adjustDepositPositionQuotePrice, adjustBorrowPosition: adjustBorrowPositionQuotePrice, } = (0, calcs_1.calcAdjustAmounts)({
currentDepositPosition: deposited,
currentBorrowPosition: borrowed,
targetLeverage: targetLeverage,
priceCollToDebt: swapQuote.priceAInB,
flashLoanFee: new decimal_js_1.default(flashLoanFee),
});
const calcsQuotePrice = (0, calcs_1.adjustWithdrawLeverageCalcs)(adjustDepositPositionQuotePrice, adjustBorrowPositionQuotePrice, flashLoanFee, slippagePct);
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(calcsQuotePrice.withdrawAmountWithSlippageAndFlashLoanFee, collReserve.getMintDecimals()).ceil();
return {
swapInputs: {
inputAmountLamports: swapInputAmountQuotePrice,
minOutAmountLamports: (0, classes_2.numberToLamportsDecimal)(calcsQuotePrice.adjustBorrowPosition.abs(), debtReserve.stats.decimals),
inputMint: collTokenMint,
outputMint: debtTokenMint,
amountDebtAtaBalance: undefined, // Only needed for ktokens deposits
},
flashLoanInfo: klendIxs.flashLoanInfo,
initialInputs: {
calcs: calcsQuotePrice,
swapQuote,
currentSlot,
collIsKtoken,
strategy,
obligation,
klendAccounts: uniqueKlendAccounts,
isDeposit,
},
};
}
}
async function getAdjustLeverageIxs({ owner, kaminoMarket, debtTokenMint, collTokenMint, obligation, depositedLamports, borrowedLamports, referrer, currentSlot, targetLeverage, priceCollToDebt, priceDebtToColl, slippagePct, budgetAndPriorityFeeIxs, kamino, scopeRefreshConfig, quoteBufferBps, priceAinB, isKtoken, quoter, swapper, useV2Ixs, }) {
const { swapInputs, initialInputs } = await getAdjustLeverageSwapInputs({
owner,
kaminoMarket,
debtTokenMint,
collTokenMint,
obligation,
depositedLamports,
borrowedLamports,
referrer,
currentSlot,
targetLeverage,
priceCollToDebt,
priceDebtToColl,
slippagePct,
budgetAndPriorityFeeIxs,
kamino,
scopeRefreshConfig,
quoteBufferBps,
priceAinB,
isKtoken,
quoter,
useV2Ixs,
});
// leverage increased so we need to deposit and borrow more
if (initialInputs.isDeposit) {
let depositSwapper;
if (initialInputs.collIsKtoken) {
if (kamino === undefined) {
throw Error('Ktoken use as collateral for leverage without Kamino instance');
}
depositSwapper = await (0, utils_2.getTokenToKtokenSwapper)(kaminoMarket, kamino, owner, slippagePct, swapper, priceAinB, false);
}
else {
depositSwapper = swapper;
}
const swapsArray = await depositSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
return Promise.all(swapsArray.map(async (swap) => {
const ixs = await buildIncreaseLeverageIxs(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, initialInputs.calcs, initialInputs.strategy, scopeRefreshConfig, initialInputs.collIsKtoken, {
preActionIxs: [],
swapIxs: swap.swapIxs,
lookupTables: swap.lookupTables,
quote: swap.quote,
}, budgetAndPriorityFeeIxs, useV2Ixs);
return {
ixs: ixs.instructions,
flashLoanInfo: ixs.flashLoanInfo,
lookupTables: swap.lookupTables,
swapInputs,
initialInputs,
quote: swap.quote.quoteResponse,
};
}));
}
else {
console.log('Decreasing leverage');
let withdrawSwapper;
if (initialInputs.collIsKtoken) {
if (kamino === undefined) {
throw Error('Ktoken use as collateral for leverage without Kamino instance');
}
withdrawSwapper = await (0, utils_2.getKtokenToTokenSwapper)(kaminoMarket, kamino, owner, swapper);
}
else {
withdrawSwapper = swapper;
}
// 5. Get swap ixs
const swapsArray = await withdrawSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
return Promise.all(swapsArray.map(async (swap) => {
const ixs = await buildDecreaseLeverageIxs(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, initialInputs.calcs, initialInputs.strategy, scopeRefreshConfig, initialInputs.collIsKtoken, {
preActionIxs: [],
swapIxs: swap.swapIxs,
lookupTables: swap.lookupTables,
quote: swap.quote,
}, budgetAndPriorityFeeIxs, useV2Ixs);
return {
ixs: ixs.instructions,
flashLoanInfo: ixs.flashLoanInfo,
lookupTables: swap.lookupTables,
swapInputs,
initialInputs,
quote: swap.quote.quoteResponse,
};
}));
}
}
/**
* Deposit and borrow tokens if leverage increased
*/
async function buildIncreaseLeverageIxs(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeRefreshConfig, collIsKtoken, swapQuoteIxs, budgetAndPriorityFeeIxs, useV2Ixs) {
const collReserve = kaminoMarket.getExistingReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getExistingReserveByMint(debtTokenMint);
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner, false, debtReserve.getLiquidityTokenProgram());
const collTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collTokenMint, owner, false, collReserve.getLiquidityTokenProgram());
// 1. Create atas & budget txns
const { budgetIxs, createAtasIxs, scopeRefreshIx } = await (0, exports.getSetupIxs)(owner, kaminoMarket, obligation, collTokenMint, collReserve, collIsKtoken, debtTokenMint, debtReserve, strategy, scopeRefreshConfig, budgetAndPriorityFeeIxs);
// 2. Create borrow flash loan instruction
const { flashBorrowIx, flashRepayIx } = (0, instructions_1.getFlashLoanInstructions)({
borrowIxIndex: budgetIxs.length + createAtasIxs.length + (scopeRefreshIx.length > 0 ? 1 : 0), // TODO: how about user metadata ixs
walletPublicKey: owner,
lendingMarketAuthority: kaminoMarket.getLendingMarketAuthority(),
lendingMarketAddress: kaminoMarket.getAddress(),
reserve: !collIsKtoken ? collReserve : debtReserve,
amountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.adjustDepositPosition : calcs.amountToFlashBorrowDebt, !collIsKtoken ? collReserve.stats.decimals : debtReserve.stats.decimals),
destinationAta: !collIsKtoken ? collTokenAta : debtTokenAta,
// TODO(referrals): once we support referrals, we will have to replace the placeholder args below:
referrerAccount: kaminoMarket.programId,
referrerTokenState: kaminoMarket.programId,
programId: kaminoMarket.programId,
});
const depositAction = await classes_1.KaminoAction.buildDepositTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(calcs.adjustDepositPosition, collReserve.stats.decimals).floor().toString(), collTokenMint, owner, obligation, useV2Ixs, undefined, 0, false, false, { skipInitialization: true, skipLutCreation: true }, referrer, currentSlot);
// 4. Borrow tokens in borrow token reserve that will be swapped to repay flash loan
const borrowAction = await classes_1.KaminoAction.buildBorrowTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(calcs.borrowAmount, debtReserve.stats.decimals).ceil().toString(), debtTokenMint, owner, obligation, useV2Ixs, undefined, 0, false, false, { skipInitialization: true, skipLutCreation: true }, // to be checked and create in a setup tx in the UI (won't be the case for adjust anyway as this would be created in deposit)
referrer, currentSlot);
const swapInstructions = (0, utils_1.removeBudgetIxs)(swapQuoteIxs.swapIxs);
const ixs = [
...scopeRefreshIx,
...budgetIxs,
...createAtasIxs,
...[flashBorrowIx],
...(collIsKtoken ? swapInstructions : []),
...classes_1.KaminoAction.actionToIxs(depositAction),
...classes_1.KaminoAction.actionToIxs(borrowAction),
...(collIsKtoken ? [] : swapInstructions),
...[flashRepayIx],
];
const flashBorrowReserve = !collIsKtoken ? collReserve : debtReserve;
const res = {
flashLoanInfo: {
flashBorrowReserve: flashBorrowReserve.address,
flashLoanFee: flashBorrowReserve.getFlashLoanFee(),
},
instructions: ixs,
};
return res;
}
/**
* Withdraw and repay tokens if leverage decreased
*/
async function buildDecreaseLeverageIxs(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeRefreshConfig, collIsKtoken, swapQuoteIxs, budgetAndPriorityFeeIxs, useV2Ixs) {
const collReserve = kaminoMarket.getExistingReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getExistingReserveByMint(debtTokenMint);
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner, false, debtReserve.getLiquidityTokenProgram());
// 1. Create atas & budget txns
const { budgetIxs, createAtasIxs, scopeRefreshIx } = await (0, exports.getSetupIxs)(owner, kaminoMarket, obligation, collTokenMint, collReserve, collIsKtoken, debtTokenMint, debtReserve, strategy, scopeRefreshConfig, budgetAndPriorityFeeIxs);
// TODO: Mihai/Marius check if we can improve this logic and not convert any SOL
// This is here so that we have enough wsol to repay in case the kAB swapped to sol after estimates is not enough
const closeWsolAtaIxs = [];
const fillWsolAtaIxs = [];
if (debtTokenMint.equals(spl_token_1.NATIVE_MINT)) {
const wsolAta = (0, utils_1.getAssociatedTokenAddress)(spl_token_1.NATIVE_MINT, owner, false);
closeWsolAtaIxs.push((0, spl_token_1.createCloseAccountInstruction)(wsolAta, owner, owner, [], spl_token_1.TOKEN_PROGRAM_ID));
const halfSolBalance = (await kaminoMarket.getConnection().getBalance(owner)) / web3_js_1.LAMPORTS_PER_SOL / 2;
const balanceToWrap = halfSolBalance < 0.1 ? halfSolBalance : 0.1;
fillWsolAtaIxs.push(...(0, utils_1.getTransferWsolIxs)(owner, wsolAta, (0, classes_2.numberToLamportsDecimal)(balanceToWrap, debtReserve.stats.decimals).ceil()));
}
// 3. Flash borrow & repay amount to repay (debt)
const { flashBorrowIx, flashRepayIx } = (0, instructions_1.getFlashLoanInstructions)({
borrowIxIndex: budgetIxs.length + createAtasIxs.length + fillWsolAtaIxs.length + (scopeRefreshIx.length > 0 ? 1 : 0),
walletPublicKey: owner,
lendingMarketAuthority: kaminoMarket.getLendingMarketAuthority(),
lendingMarketAddress: kaminoMarket.getAddress(),
reserve: debtReserve,
amountLamports: (0, classes_2.numberToLamportsDecimal)(decimal_js_1.default.abs(calcs.adjustBorrowPosition), debtReserve.stats.decimals),
destinationAta: debtTokenAta,
// TODO(referrals): once we support referrals, we will have to replace the placeholder args below:
referrerAccount: kaminoMarket.programId,
referrerTokenState: kaminoMarket.programId,
programId: kaminoMarket.programId,
});
// 4. Actually do the repay of the flash borrowed amounts
const repayAction = await classes_1.KaminoAction.buildRepayTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(decimal_js_1.default.abs(calcs.adjustBorrowPosition), debtReserve.stats.decimals).floor().toString(), debtTokenMint, owner, obligation, useV2Ixs, undefined, currentSlot, undefined, 0, false, false, { skipInitialization: true, skipLutCreation: true }, // to be checked and create in a setup tx in the UI (won't be the case for adjust anyway as this would be created in deposit)
referrer);
// 6. Withdraw collateral (a little bit more to be able to pay for the slippage on swap)
const withdrawAction = await classes_1.KaminoAction.buildWithdrawTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(calcs.withdrawAmountWithSlippageAndFlashLoanFee, collReserve.stats.decimals).ceil().toString(), collTokenMint, owner, obligation, useV2Ixs, undefined, 0, false, false, { skipInitialization: true, skipLutCreation: true }, // to be checked and create in a setup tx in the UI (won't be the case for adjust anyway as this would be created in deposit)
referrer, currentSlot);
const swapInstructions = (0, utils_1.removeBudgetIxs)(swapQuoteIxs.swapIxs);
const ixs = [
...scopeRefreshIx,
...budgetIxs,
...createAtasIxs,
...fillWsolAtaIxs,
...[flashBorrowIx],
...classes_1.KaminoAction.actionToIxs(repayAction),
...classes_1.KaminoAction.actionToIxs(withdrawAction),
...swapInstructions,
...[flashRepayIx],
...closeWsolAtaIxs,
];
const res = {
flashLoanInfo: {
flashBorrowReserve: debtReserve.address,
flashLoanFee: debtReserve.getFlashLoanFee(),
},
instructions: ixs,
};
return res;
}
const getSetupIxs = async (owner, kaminoMarket, obligation, collTokenMint, collReserve, collIsKtoken, debtTokenMint, debtReserve, strategy, scopeRefreshConfig, budgetAndPriorityFeeIxs) => {
const budgetIxs = budgetAndPriorityFeeIxs || (0, utils_1.getComputeBudgetAndPriorityFeeIxs)(3000000);
const mintsWithTokenPrograms = getTokenMintsWithTokenPrograms(collTokenMint, collReserve, debtTokenMint, debtReserve, collIsKtoken, strategy);
const createAtasIxs = (0, utils_1.createAtasIdempotent)(owner, mintsWithTokenPrograms).map((x) => x.createAtaIx);
const scopeRefreshIx = await (0, exports.getScopeRefreshIx)(kaminoMarket, collReserve, debtReserve, obligation, scopeRefreshConfig);
return {
budgetIxs,
createAtasIxs,
scopeRefreshIx,
};
};
exports.getSetupIxs = getSetupIxs;
const getScopeRefreshIx = async (market, collReserve, debtReserve, obligation, scopeRefreshConfig) => {
const allReserves = obligation && (0, classes_1.isKaminoObligation)(obligation)
? new utils_1.PublicKeySet([
...obligation.getDeposits().map((x) => x.reserveAddress),
...obligation.getBorrows().map((x) => x.reserveAddress),
collReserve.address,
debtReserve.address,
]).toArray()
: new utils_1.PublicKeySet([collReserve.address, debtReserve.address]).toArray();
const tokenIds = (0, classes_1.getTokenIdsForScopeRefresh)(market, allReserves);
const scopeRefreshIxs = [];
if (tokenIds.length > 0 && scopeRefreshConfig) {
scopeRefreshIxs.push(await scopeRefreshConfig.scope.refreshPriceListIx({
feed: scopeRefreshConfig.scopeFeed,
}, tokenIds));
}
return scopeRefreshIxs;
};
exports.getScopeRefreshIx = getScopeRefreshIx;
const checkObligationType = (obligationTypeTag, collTokenMint, debtTokenMint, kaminoMarket) => {
let obligationType;
if (obligationTypeTag === utils_1.ObligationTypeTag.Multiply) {
// multiply
obligationType = new utils_1.MultiplyObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
}
else if (obligationTypeTag === utils_1.ObligationTypeTag.Leverage) {
// leverage
obligationType = new utils_1.LeverageObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
}
else {
throw Error('Obligation type tag not supported for leverage, please use 1 - multiply or 3 - leverage');
}
return obligationType;
};
const getTokenMintsWithTokenPrograms = (collTokenMint, collReserve, debtTokenMint, debtReserve, collIsKtoken, strategy) => {
const mintsWithTokenPrograms = [
{
mint: collTokenMint,
tokenProgram: collReserve.getLiquidityTokenProgram(),
},
{
mint: debtTokenMint,
tokenProgram: debtReserve.getLiquidityTokenProgram(),
},
{
mint: collReserve.getCTokenMint(),
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
},
];
if (collIsKtoken) {
let kTokenAta;
let kTokenTokenProgram;
if (strategy.strategy.tokenAMint.equals(debtTokenMint)) {
kTokenAta = strategy.strategy.tokenBMint;
kTokenTokenProgram = strategy.strategy.tokenBTokenProgram.equals(web3_js_1.PublicKey.default)
? spl_token_1.TOKEN_PROGRAM_ID
: strategy.strategy.tokenBTokenProgram;
}
else {
kTokenAta = strategy.strategy.tokenAMint;
kTokenTokenProgram = strategy.strategy.tokenATokenProgram.equals(web3_js_1.PublicKey.default)
? spl_token_1.TOKEN_PROGRAM_ID
: strategy.strategy.tokenATokenProgram;
}
mintsWithTokenPrograms.push({
mint: kTokenAta,
tokenProgram: kTokenTokenProgram,
});
}
return mintsWithTokenPrograms;
};
//# sourceMappingURL=operations.js.map