UNPKG

@kamino-finance/klend-sdk

Version:

Typescript SDK for interacting with the Kamino Lending (klend) protocol

136 lines 8 kB
"use strict"; 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