@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
136 lines • 8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRepayWithCollSwapInputs = getRepayWithCollSwapInputs;
exports.getRepayWithCollIxs = getRepayWithCollIxs;
const spl_token_1 = require("@solana/spl-token");
const classes_1 = require("../classes");
const leverage_1 = require("../leverage");
const utils_1 = require("../utils");
const decimal_js_1 = __importDefault(require("decimal.js"));
const repay_with_collateral_calcs_1 = require("./repay_with_collateral_calcs");
async function getRepayWithCollSwapInputs({ collTokenMint, currentSlot, debtTokenMint, kaminoMarket, obligation, quoter, referrer, repayAmount, isClosingPosition, budgetAndPriorityFeeIxs, scopeRefresh, }) {
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
if (!collReserve) {
throw new Error(`Collateral reserve with mint ${collReserve} not found in market ${kaminoMarket.getAddress()}`);
}
if (!debtReserve) {
throw new Error(`Debt reserve with mint ${debtReserve} not found in market ${kaminoMarket.getAddress()}`);
}
const { repayAmountLamports, flashRepayAmountLamports } = (0, repay_with_collateral_calcs_1.calcRepayAmountWithSlippage)(kaminoMarket, debtReserve, currentSlot, obligation, repayAmount, referrer);
const debtPosition = obligation.getBorrowByReserve(debtReserve.address);
const collPosition = obligation.getDepositByReserve(collReserve.address);
if (!debtPosition) {
throw new Error(`Debt position not found for ${debtReserve.stats.symbol} reserve ${debtReserve.address} in obligation ${obligation.obligationAddress}`);
}
if (!collPosition) {
throw new Error(`Collateral position not found for ${collReserve.stats.symbol} reserve ${collReserve.address} in obligation ${obligation.obligationAddress}`);
}
const { withdrawableCollLamports } = (0, repay_with_collateral_calcs_1.calcMaxWithdrawCollateral)(kaminoMarket, collReserve.address, debtReserve.address, obligation, repayAmountLamports);
const swapQuoteInputs = {
inputAmountLamports: withdrawableCollLamports,
inputMint: collTokenMint,
outputMint: debtTokenMint,
amountDebtAtaBalance: new decimal_js_1.default(0), // only used for kTokens
};
// Build the repay & withdraw collateral tx to get the number of accounts
const klendIxs = await buildRepayWithCollateralIxs(kaminoMarket, debtReserve, collReserve, obligation, referrer, currentSlot, budgetAndPriorityFeeIxs, scopeRefresh, {
preActionIxs: [],
swapIxs: [],
lookupTables: [],
}, isClosingPosition, repayAmountLamports, withdrawableCollLamports);
const uniqueKlendAccounts = (0, utils_1.uniqueAccounts)(klendIxs);
const swapQuote = await quoter(swapQuoteInputs, uniqueKlendAccounts);
const swapQuotePxDebtToColl = swapQuote.priceAInB;
const collSwapInLamports = flashRepayAmountLamports
.div(debtReserve.getMintFactor())
.div(swapQuotePxDebtToColl)
.mul(collReserve.getMintFactor())
.ceil();
return {
swapInputs: {
inputAmountLamports: collSwapInLamports,
inputMint: collTokenMint,
outputMint: debtTokenMint,
amountDebtAtaBalance: new decimal_js_1.default(0), // only used for kTokens
},
initialInputs: {
debtRepayAmountLamports: repayAmountLamports,
flashRepayAmountLamports,
swapQuote,
currentSlot,
klendAccounts: uniqueKlendAccounts,
},
};
}
async function getRepayWithCollIxs({ repayAmount, isClosingPosition, budgetAndPriorityFeeIxs, collTokenMint, currentSlot, debtTokenMint, kaminoMarket, obligation, quoter, swapper, referrer, scopeRefresh, logger = console.log, }) {
const { swapInputs, initialInputs } = await getRepayWithCollSwapInputs({
collTokenMint,
currentSlot,
debtTokenMint,
kaminoMarket,
obligation,
quoter,
referrer,
repayAmount,
isClosingPosition,
budgetAndPriorityFeeIxs,
scopeRefresh,
});
const { debtRepayAmountLamports, flashRepayAmountLamports, swapQuote } = initialInputs;
const { inputAmountLamports: collSwapInLamports } = swapInputs;
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
logger(`Expected to swap in: ${collSwapInLamports.div(collReserve.getMintFactor())} ${collReserve.symbol}, for: ${flashRepayAmountLamports.div(debtReserve.getMintFactor())} ${debtReserve.symbol}, quoter px: ${swapQuote.priceAInB} ${debtReserve.symbol}/${collReserve.symbol}`);
const swapResponse = await swapper(swapInputs, initialInputs.klendAccounts, swapQuote);
const ixs = await buildRepayWithCollateralIxs(kaminoMarket, debtReserve, collReserve, obligation, referrer, currentSlot, budgetAndPriorityFeeIxs, scopeRefresh, swapResponse, isClosingPosition, debtRepayAmountLamports, swapInputs.inputAmountLamports);
return {
ixs,
lookupTables: swapResponse.lookupTables,
swapInputs,
initialInputs,
};
}
async function buildRepayWithCollateralIxs(market, debtReserve, collReserve, obligation, referrer, currentSlot, budgetAndPriorityFeeIxs, scopeRefresh, swapQuoteIxs, isClosingPosition, debtRepayAmountLamports, collWithdrawLamports) {
// 1. Create atas & budget txns
const budgetIxns = budgetAndPriorityFeeIxs || (0, utils_1.getComputeBudgetAndPriorityFeeIxns)(1_400_000);
const atas = [
{ mint: collReserve.getLiquidityMint(), tokenProgram: collReserve.getLiquidityTokenProgram() },
{ mint: debtReserve.getLiquidityMint(), tokenProgram: debtReserve.getLiquidityTokenProgram() },
{ mint: collReserve.getCTokenMint(), tokenProgram: spl_token_1.TOKEN_PROGRAM_ID },
];
const atasAndIxs = (0, utils_1.createAtasIdempotent)(obligation.state.owner, atas);
const [, { ata: debtTokenAta }] = atasAndIxs;
// 2. Flash borrow & repay the debt to repay amount needed
const { flashBorrowIxn, flashRepayIxn } = (0, leverage_1.getFlashLoanInstructions)({
borrowIxnIndex: budgetIxns.length + atasAndIxs.length,
walletPublicKey: obligation.state.owner,
lendingMarketAuthority: market.getLendingMarketAuthority(),
lendingMarketAddress: market.getAddress(),
reserve: debtReserve,
amountLamports: debtRepayAmountLamports,
destinationAta: debtTokenAta,
referrerAccount: market.programId,
referrerTokenState: market.programId,
programId: market.programId,
});
const requestElevationGroup = !isClosingPosition && obligation.state.elevationGroup !== 0;
// 3. Repay using the flash borrowed funds & withdraw collateral to swap and pay the flash loan
const repayAndWithdrawAction = await classes_1.KaminoAction.buildRepayAndWithdrawTxns(market, isClosingPosition ? utils_1.U64_MAX : debtRepayAmountLamports.toString(), debtReserve.getLiquidityMint(), isClosingPosition ? utils_1.U64_MAX : collWithdrawLamports.toString(), collReserve.getLiquidityMint(), obligation.state.owner, currentSlot, obligation, 0, false, requestElevationGroup, undefined, isClosingPosition, referrer, scopeRefresh);
// 4. Swap collateral to debt to repay flash loan
const { preActionIxs, swapIxs } = swapQuoteIxs;
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapIxs, []);
return [
...budgetIxns,
...atasAndIxs.map((x) => x.createAtaIx),
flashBorrowIxn,
...preActionIxs,
...classes_1.KaminoAction.actionToIxs(repayAndWithdrawAction),
...swapInstructions,
flashRepayIxn,
];
}
//# sourceMappingURL=repay_with_collateral_operations.js.map