@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
164 lines • 10 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isBorrowingEnabled = exports.getExpectedTokenBalanceAfterBorrow = void 0;
exports.getTokenToKtokenSwapper = getTokenToKtokenSwapper;
exports.getKtokenDepositIxs = getKtokenDepositIxs;
exports.getKtokenToTokenSwapper = getKtokenToTokenSwapper;
exports.getKtokenWithdrawIxs = getKtokenWithdrawIxs;
exports.getKtokenWithdrawEstimatesAndPrice = getKtokenWithdrawEstimatesAndPrice;
exports.swapProviderToKaminoSwapProvider = swapProviderToKaminoSwapProvider;
const classes_1 = require("../classes");
const decimal_js_1 = __importDefault(require("decimal.js"));
const utils_1 = require("../utils");
const utils_2 = require("../classes/utils");
const bn_js_1 = __importDefault(require("bn.js"));
async function getTokenToKtokenSwapper(kaminoMarket, kamino, depositor, slippagePct, swapper, priceAinB, includeAtaIxns = true) {
return async (inputs, klendAccounts, quote) => {
const slippageBps = new decimal_js_1.default(slippagePct).mul('100');
const mintInDecimals = kaminoMarket.getReserveByMint(inputs.inputMint).state.liquidity.mintDecimals.toNumber();
const amountIn = (0, classes_1.lamportsToNumberDecimal)(inputs.inputAmountLamports, mintInDecimals);
console.debug('Depositing token', inputs.inputMint.toString(), ' for ', inputs.outputMint.toString(), 'ktoken');
if (inputs.amountDebtAtaBalance === undefined) {
throw Error('Amount in debt ATA balance is undefined for leverage ktoken deposit');
}
const ixWithLookup = (await getKtokenDepositIxs(kaminoMarket.getConnection(), kamino, depositor, inputs.inputMint, inputs.outputMint, amountIn, slippageBps, inputs.amountDebtAtaBalance, swapper, priceAinB, includeAtaIxns, klendAccounts, quote));
const luts = await (0, utils_1.getLookupTableAccounts)(kaminoMarket.getConnection(), ixWithLookup.lookupTablesAddresses);
return {
preActionIxs: [],
swapIxs: ixWithLookup.instructions,
lookupTables: luts,
};
};
}
async function getKtokenDepositIxs(connection, kamino, depositor, depositTokenMint, ktokenMint, amountToDeposit, slippageBps, amountExpectedDepositAtaBalance, swapper, priceAinB, includeAtaIxns = true, klendAccounts, quote) {
const kaminoStrategy = await kamino.getStrategyByKTokenMint(ktokenMint);
const tokenAMint = kaminoStrategy?.strategy.tokenAMint;
const tokenBMint = kaminoStrategy?.strategy.tokenBMint;
const priceAinBDecimal = await priceAinB(tokenAMint, tokenBMint);
if (tokenAMint.equals(depositTokenMint)) {
const bBalance = await (0, utils_1.getTokenAccountBalanceDecimal)(connection, tokenBMint, depositor);
const tokensBalances = { a: amountExpectedDepositAtaBalance, b: bBalance };
console.log('amountToDeposit', amountToDeposit);
return await kamino.singleSidedDepositTokenA(kaminoStrategy, amountToDeposit, depositor, slippageBps, undefined, swapProviderToKaminoSwapProvider(swapper, klendAccounts, quote), tokensBalances, priceAinBDecimal, includeAtaIxns);
}
else if (tokenBMint.equals(depositTokenMint)) {
const aBalance = await (0, utils_1.getTokenAccountBalanceDecimal)(connection, tokenAMint, depositor);
const tokensBalances = { a: aBalance, b: amountExpectedDepositAtaBalance };
return await kamino.singleSidedDepositTokenB(kaminoStrategy, amountToDeposit, depositor, slippageBps, undefined, swapProviderToKaminoSwapProvider(swapper, klendAccounts, quote), tokensBalances, priceAinBDecimal, includeAtaIxns);
}
else {
throw Error('Deposit token is neither A nor B in the strategy');
}
}
async function getKtokenToTokenSwapper(kaminoMarket, kamino, depositor, swapper) {
return async (inputs, klendAccounts, quote) => {
const amountInDecimals = kaminoMarket.getReserveByMint(inputs.inputMint).state.liquidity.mintDecimals.toNumber();
const amountToWithdraw = (0, classes_1.lamportsToNumberDecimal)(inputs.inputAmountLamports, amountInDecimals);
const kaminoStrategy = await kamino.getStrategyByKTokenMint(inputs.inputMint);
console.log('Withdrawing ktoken', inputs.inputMint.toString(), ' for ', inputs.outputMint.toString(), 'token');
const ixWithdraw = (await getKtokenWithdrawIxs(kamino, depositor, kaminoStrategy, amountToWithdraw));
const [estimatedAOut, estimatedBOut] = await getKtokenWithdrawEstimatesAndPrice(kamino, kaminoStrategy, amountToWithdraw);
if (inputs.outputMint.equals(kaminoStrategy.strategy.tokenAMint)) {
const { swapIxs, lookupTables } = await swapper({
inputAmountLamports: estimatedBOut,
inputMint: kaminoStrategy.strategy.tokenBMint,
outputMint: kaminoStrategy.strategy.tokenAMint,
amountDebtAtaBalance: new decimal_js_1.default(0),
}, klendAccounts, quote);
return {
preActionIxs: [],
swapIxs: [...ixWithdraw.prerequisiteIxs, ixWithdraw.withdrawIx, ...swapIxs],
lookupTables,
};
}
else if (inputs.outputMint.equals(kaminoStrategy.strategy.tokenBMint)) {
const { swapIxs, lookupTables } = await swapper({
inputAmountLamports: estimatedAOut,
inputMint: kaminoStrategy.strategy.tokenAMint,
outputMint: kaminoStrategy.strategy.tokenBMint,
amountDebtAtaBalance: new decimal_js_1.default(0),
}, klendAccounts, quote);
return {
preActionIxs: [],
swapIxs: [...ixWithdraw.prerequisiteIxs, ixWithdraw.withdrawIx, ...swapIxs],
lookupTables,
};
}
else {
throw Error('Deposit token is neither A nor B in the strategy');
}
};
}
async function getKtokenWithdrawIxs(kamino, withdrawer, kaminoStrategy, amountToWithdraw) {
return await kamino.withdrawShares(kaminoStrategy, amountToWithdraw, withdrawer);
}
async function getKtokenWithdrawEstimatesAndPrice(kamino, kaminoStrategy, amountToWithdraw) {
const sharesData = await kamino.getStrategyShareData(kaminoStrategy);
const withdrawPct = amountToWithdraw
.div((0, classes_1.lamportsToNumberDecimal)(new decimal_js_1.default(kaminoStrategy.strategy.sharesIssued.toString()), kaminoStrategy.strategy.sharesMintDecimals.toNumber()))
.toDecimalPlaces(18);
const withdrawFee = new decimal_js_1.default(10_000).sub(new decimal_js_1.default(kaminoStrategy.strategy.withdrawFee.toString()));
// TODO: Mihai/Marius improve - currently subtracting due to decimal accuracy issues compared to yvaults SC
// for both A and B op: .sub(0.000002)
const estimatedAOut = sharesData.balance.computedHoldings.invested.a
.add(sharesData.balance.computedHoldings.available.a)
.mul(withdrawPct)
.toDecimalPlaces(kaminoStrategy.strategy.tokenAMintDecimals.toNumber(), 1)
.sub(0.000002)
.mul(withdrawFee)
.div(10_000)
.toDecimalPlaces(kaminoStrategy.strategy.tokenAMintDecimals.toNumber());
const estimatedAOutDecimal = (0, utils_2.numberToLamportsDecimal)(estimatedAOut, kaminoStrategy.strategy.tokenAMintDecimals.toNumber()).floor();
const estimatedBOut = sharesData.balance.computedHoldings.invested.b
.add(sharesData.balance.computedHoldings.available.b)
.mul(withdrawPct)
.toDecimalPlaces(kaminoStrategy.strategy.tokenBMintDecimals.toNumber(), 1)
.sub(0.000002)
.mul(withdrawFee)
.div(10_000)
.toDecimalPlaces(kaminoStrategy.strategy.tokenAMintDecimals.toNumber());
const estimatedBOutDecimal = (0, utils_2.numberToLamportsDecimal)(estimatedBOut, kaminoStrategy.strategy.tokenBMintDecimals.toNumber()).floor();
console.log('a-out', estimatedAOutDecimal.toString());
console.log('b-out', estimatedBOut.toString());
return [estimatedAOutDecimal, estimatedBOutDecimal];
}
function swapProviderToKaminoSwapProvider(swapper, klendAccounts, swapQuote) {
return async (input, tokenAMint, tokenBMint, _owner, _slippage, _allKeys) => {
if (input.tokenBToSwapAmount.lt(0)) {
const swapperIxs = await swapper({
inputAmountLamports: input.tokenBToSwapAmount.abs(),
inputMint: tokenBMint,
outputMint: tokenAMint,
amountDebtAtaBalance: undefined,
}, klendAccounts, swapQuote);
return [swapperIxs.swapIxs, swapperIxs.lookupTables.map((lt) => lt.key)];
}
else if (input.tokenAToSwapAmount.lt(0)) {
const swapperIxs = await swapper({
inputAmountLamports: input.tokenAToSwapAmount.abs(),
inputMint: tokenAMint,
outputMint: tokenBMint,
amountDebtAtaBalance: undefined,
}, klendAccounts, swapQuote);
return [swapperIxs.swapIxs, swapperIxs.lookupTables.map((lt) => lt.key)];
}
else {
throw Error('Nothing to swap');
}
};
}
const getExpectedTokenBalanceAfterBorrow = async (connection, mint, owner, amountToBorrowLamports, amountToBorrowmintDecimals) => {
const initialUserTokenABalance = await (0, utils_1.getTokenAccountBalanceDecimal)(connection, mint, owner);
return initialUserTokenABalance
.add((0, classes_1.lamportsToNumberDecimal)(amountToBorrowLamports, amountToBorrowmintDecimals))
.toDecimalPlaces(amountToBorrowmintDecimals);
};
exports.getExpectedTokenBalanceAfterBorrow = getExpectedTokenBalanceAfterBorrow;
const isBorrowingEnabled = (reserve) => {
return reserve.state.config.borrowLimit.gt(new bn_js_1.default(0));
};
exports.isBorrowingEnabled = isBorrowingEnabled;
//# sourceMappingURL=utils.js.map
;