@kamino-finance/klend-sdk 5.0.2 → 5.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/classes/obligation.d.ts.map +1 -1
- package/dist/classes/obligation.js +1 -2
- package/dist/classes/obligation.js.map +1 -1
- package/dist/classes/reserve.d.ts +0 -1
- package/dist/classes/reserve.d.ts.map +1 -1
- package/dist/classes/reserve.js +3 -7
- package/dist/classes/reserve.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.js +6 -0
- package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
- package/dist/leverage/calcs.d.ts +28 -1
- package/dist/leverage/calcs.d.ts.map +1 -1
- package/dist/leverage/calcs.js +204 -8
- package/dist/leverage/calcs.js.map +1 -1
- package/dist/leverage/index.d.ts +1 -0
- package/dist/leverage/index.d.ts.map +1 -1
- package/dist/leverage/index.js +1 -0
- package/dist/leverage/index.js.map +1 -1
- package/dist/leverage/operations.d.ts +14 -241
- package/dist/leverage/operations.d.ts.map +1 -1
- package/dist/leverage/operations.js +508 -776
- package/dist/leverage/operations.js.map +1 -1
- package/dist/leverage/types.d.ts +173 -0
- package/dist/leverage/types.d.ts.map +1 -0
- package/dist/leverage/types.js +3 -0
- package/dist/leverage/types.js.map +1 -0
- package/dist/leverage/utils.d.ts +5 -5
- package/dist/leverage/utils.d.ts.map +1 -1
- package/dist/leverage/utils.js +68 -33
- package/dist/leverage/utils.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/fuzz.d.ts +3 -0
- package/dist/utils/fuzz.d.ts.map +1 -0
- package/dist/utils/fuzz.js +11 -0
- package/dist/utils/fuzz.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/obligation.ts +1 -2
- package/src/classes/reserve.ts +3 -16
- package/src/lending_operations/repay_with_collateral_operations.ts +2 -0
- package/src/leverage/calcs.ts +315 -8
- package/src/leverage/index.ts +1 -0
- package/src/leverage/operations.ts +1079 -1331
- package/src/leverage/types.ts +211 -0
- package/src/leverage/utils.ts +103 -64
- package/src/utils/constants.ts +2 -0
- package/src/utils/fuzz.ts +5 -0
- package/src/utils/index.ts +1 -0
|
@@ -3,7 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.getDepositWithLeverageSwapInputs = getDepositWithLeverageSwapInputs;
|
|
7
|
+
exports.getDepositWithLeverageIxns = getDepositWithLeverageIxns;
|
|
8
|
+
exports.getWithdrawWithLeverageSwapInputs = getWithdrawWithLeverageSwapInputs;
|
|
9
|
+
exports.getWithdrawWithLeverageIxns = getWithdrawWithLeverageIxns;
|
|
10
|
+
exports.buildWithdrawWithLeverageIxns = buildWithdrawWithLeverageIxns;
|
|
11
|
+
exports.getAdjustLeverageSwapInputs = getAdjustLeverageSwapInputs;
|
|
12
|
+
exports.getAdjustLeverageIxns = getAdjustLeverageIxns;
|
|
7
13
|
const web3_js_1 = require("@solana/web3.js");
|
|
8
14
|
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
9
15
|
const classes_1 = require("../classes");
|
|
@@ -13,157 +19,93 @@ const utils_1 = require("../utils");
|
|
|
13
19
|
const calcs_1 = require("./calcs");
|
|
14
20
|
const spl_token_1 = require("@solana/spl-token");
|
|
15
21
|
const utils_2 = require("./utils");
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
collTokenToDeposit: finalColl,
|
|
33
|
-
swapDebtTokenIn: debt,
|
|
34
|
-
swapCollTokenExpectedOut: finalColl.sub(depositAmount),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
const y = targetLeverage.mul(priceDebtToColl);
|
|
39
|
-
const x = flashLoanFee.add('1').mul(slippage.add('1')).div(priceDebtToColl);
|
|
40
|
-
const finalColl = depositAmount.div(x.sub(targetLeverage.sub('1').div(y)));
|
|
41
|
-
const flashBorrowColl = finalColl.mul(flashLoanFee.add('1'));
|
|
42
|
-
const debt = targetLeverage.sub('1').mul(finalColl).div(y);
|
|
43
|
-
return {
|
|
44
|
-
flashBorrowInCollToken: flashBorrowColl,
|
|
45
|
-
initDepositInSol,
|
|
46
|
-
debtTokenToBorrow: debt,
|
|
47
|
-
collTokenToDeposit: finalColl,
|
|
48
|
-
swapDebtTokenIn: debt.add(depositAmount),
|
|
49
|
-
swapCollTokenExpectedOut: finalColl,
|
|
50
|
-
};
|
|
22
|
+
const CreationParameters_1 = require("@kamino-finance/kliquidity-sdk/dist/utils/CreationParameters");
|
|
23
|
+
async function getDepositWithLeverageSwapInputs({ owner, kaminoMarket, debtTokenMint, collTokenMint, depositAmount, priceDebtToColl, slippagePct, obligation, referrer, currentSlot, targetLeverage, selectedTokenMint, kamino, obligationTypeTagOverride, scopeFeed, budgetAndPriorityFeeIxs, quoteBufferBps, priceAinB, isKtoken, quoter, }) {
|
|
24
|
+
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
25
|
+
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
26
|
+
const solTokenReserve = kaminoMarket.getReserveByMint(utils_1.WRAPPED_SOL_MINT);
|
|
27
|
+
const flashLoanFee = collReserve.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
28
|
+
const selectedTokenIsCollToken = selectedTokenMint.equals(collTokenMint);
|
|
29
|
+
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
|
|
30
|
+
const collIsKtoken = await isKtoken(collTokenMint);
|
|
31
|
+
const strategy = collIsKtoken ? (await kamino.getStrategyByKTokenMint(collTokenMint)) : undefined;
|
|
32
|
+
const calcs = await getDepositWithLeverageCalcs(depositAmount, selectedTokenIsCollToken, collIsKtoken, depositTokenIsSol, priceDebtToColl, targetLeverage, slippagePct, flashLoanFee, kamino, strategy, debtTokenMint, priceAinB, debtReserve);
|
|
33
|
+
console.log('Ops Calcs', (0, calcs_1.toJson)(calcs));
|
|
34
|
+
let obligationType;
|
|
35
|
+
if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Multiply) {
|
|
36
|
+
// multiply
|
|
37
|
+
obligationType = new utils_1.MultiplyObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
51
38
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const { kamino, strategy, debtTokenMint, depositAmount, depositTokenIsCollToken, depositTokenIsSol, priceDebtToColl, targetLeverage, slippagePct, flashLoanFee, priceAinB, strategyHoldings, } = props;
|
|
56
|
-
const initDepositInSol = depositTokenIsSol ? depositAmount : new decimal_js_1.default(0);
|
|
57
|
-
const slippage = slippagePct.div('100');
|
|
58
|
-
let flashBorrowInDebtToken;
|
|
59
|
-
let collTokenToDeposit;
|
|
60
|
-
let debtTokenToBorrow;
|
|
61
|
-
if (depositTokenIsCollToken) {
|
|
62
|
-
const x = slippage.add('1').div(priceDebtToColl);
|
|
63
|
-
const y = flashLoanFee.add('1').mul(priceDebtToColl);
|
|
64
|
-
const z = targetLeverage.mul(y).div(targetLeverage.sub(1));
|
|
65
|
-
flashBorrowInDebtToken = depositAmount.div(z.minus(new decimal_js_1.default(1).div(x)));
|
|
66
|
-
collTokenToDeposit = depositAmount.add(flashBorrowInDebtToken.div(x));
|
|
67
|
-
debtTokenToBorrow = flashBorrowInDebtToken.mul(new decimal_js_1.default(1).add(flashLoanFee));
|
|
68
|
-
return {
|
|
69
|
-
flashBorrowInDebtToken,
|
|
70
|
-
initDepositInSol,
|
|
71
|
-
collTokenToDeposit,
|
|
72
|
-
debtTokenToBorrow,
|
|
73
|
-
requiredCollateral: collTokenToDeposit.sub(depositAmount), // Assuming netValue is requiredCollateral, adjust as needed
|
|
74
|
-
singleSidedDeposit: flashBorrowInDebtToken,
|
|
75
|
-
};
|
|
39
|
+
else if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Leverage) {
|
|
40
|
+
// leverage
|
|
41
|
+
obligationType = new utils_1.LeverageObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
76
42
|
}
|
|
77
43
|
else {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
flashBorrowInDebtToken,
|
|
107
|
-
initDepositInSol,
|
|
108
|
-
collTokenToDeposit,
|
|
109
|
-
debtTokenToBorrow,
|
|
110
|
-
requiredCollateral: collTokenToDeposit, // Assuming collTokenToDeposit is requiredCollateral, adjust as needed
|
|
111
|
-
singleSidedDeposit,
|
|
112
|
-
};
|
|
44
|
+
throw Error('Obligation type tag not supported for leverage, please use 1 - multiply or 3 - leverage');
|
|
45
|
+
}
|
|
46
|
+
// Build the repay & withdraw collateral tx to get the number of accounts
|
|
47
|
+
const klendIxs = await buildDepositWithLeverageIxns(kaminoMarket, debtReserve, collReserve, owner, obligation ? obligation : obligationType, referrer, currentSlot, depositTokenIsSol, scopeFeed, calcs, budgetAndPriorityFeeIxs, {
|
|
48
|
+
preActionIxs: [],
|
|
49
|
+
swapIxs: [],
|
|
50
|
+
lookupTables: [],
|
|
51
|
+
}, strategy, collIsKtoken);
|
|
52
|
+
const uniqueKlendAccounts = (0, utils_1.uniqueAccounts)(klendIxs);
|
|
53
|
+
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.swapDebtTokenIn : calcs.singleSidedDepositKtokenOnly, debtReserve.stats.decimals).ceil();
|
|
54
|
+
const swapInputsForQuote = {
|
|
55
|
+
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
|
|
56
|
+
inputMint: debtTokenMint,
|
|
57
|
+
outputMint: collTokenMint,
|
|
58
|
+
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens swaps
|
|
59
|
+
};
|
|
60
|
+
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
|
|
61
|
+
const quotePriceCalcs = await getDepositWithLeverageCalcs(depositAmount, selectedTokenIsCollToken, collIsKtoken, depositTokenIsSol, swapQuote.priceAInB, targetLeverage, slippagePct, flashLoanFee, kamino, strategy, debtTokenMint, priceAinB, debtReserve);
|
|
62
|
+
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? quotePriceCalcs.swapDebtTokenIn : quotePriceCalcs.singleSidedDepositKtokenOnly, debtReserve.stats.decimals).ceil();
|
|
63
|
+
let expectedDebtTokenAtaBalance = new decimal_js_1.default(0);
|
|
64
|
+
if (collIsKtoken) {
|
|
65
|
+
let futureBalanceInAta = new decimal_js_1.default(0);
|
|
66
|
+
if (debtTokenMint.equals(utils_1.WRAPPED_SOL_MINT)) {
|
|
67
|
+
futureBalanceInAta = futureBalanceInAta.add(!collIsKtoken ? quotePriceCalcs.initDepositInSol : quotePriceCalcs.initDepositInSol);
|
|
68
|
+
}
|
|
69
|
+
futureBalanceInAta = futureBalanceInAta.add(!collIsKtoken ? quotePriceCalcs.debtTokenToBorrow : quotePriceCalcs.flashBorrowInDebtTokenKtokenOnly);
|
|
70
|
+
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());
|
|
113
71
|
}
|
|
114
|
-
};
|
|
115
|
-
exports.depositLeverageKtokenCalcs = depositLeverageKtokenCalcs;
|
|
116
|
-
const getDepositWithLeverageSwapInputs = (props) => {
|
|
117
|
-
const { depositAmount, priceDebtToColl, slippagePct, targetLeverage, kaminoMarket, selectedTokenMint, debtTokenMint, collTokenMint, } = props;
|
|
118
|
-
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
119
|
-
const selectedTokenIsCollToken = selectedTokenMint.equals(collTokenMint);
|
|
120
|
-
const solTokenReserve = kaminoMarket.getReserveByMint(utils_1.WRAPPED_SOL_MINT);
|
|
121
|
-
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
|
|
122
|
-
const flashLoanFee = debtReserve?.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
123
|
-
const calcs = (0, exports.depositLeverageCalcs)({
|
|
124
|
-
depositAmount,
|
|
125
|
-
depositTokenIsCollToken: selectedTokenIsCollToken,
|
|
126
|
-
depositTokenIsSol,
|
|
127
|
-
priceDebtToColl,
|
|
128
|
-
targetLeverage,
|
|
129
|
-
slippagePct,
|
|
130
|
-
flashLoanFee,
|
|
131
|
-
});
|
|
132
72
|
return {
|
|
133
73
|
swapInputs: {
|
|
134
|
-
inputAmountLamports:
|
|
74
|
+
inputAmountLamports: swapInputAmountQuotePrice,
|
|
135
75
|
inputMint: debtTokenMint,
|
|
136
76
|
outputMint: collTokenMint,
|
|
77
|
+
amountDebtAtaBalance: expectedDebtTokenAtaBalance,
|
|
78
|
+
},
|
|
79
|
+
initialInputs: {
|
|
80
|
+
calcs: quotePriceCalcs,
|
|
81
|
+
swapQuote,
|
|
82
|
+
currentSlot,
|
|
83
|
+
collIsKtoken,
|
|
84
|
+
strategy,
|
|
85
|
+
obligation: obligation ? obligation : obligationType,
|
|
86
|
+
klendAccounts: uniqueKlendAccounts,
|
|
137
87
|
},
|
|
138
88
|
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
priceDebtToColl,
|
|
156
|
-
targetLeverage,
|
|
157
|
-
slippagePct,
|
|
158
|
-
flashLoanFee,
|
|
159
|
-
});
|
|
160
|
-
let calcsKtoken;
|
|
161
|
-
if (collIsKtoken) {
|
|
162
|
-
calcsKtoken = await (0, exports.depositLeverageKtokenCalcs)({
|
|
89
|
+
}
|
|
90
|
+
async function getDepositWithLeverageCalcs(depositAmount, selectedTokenIsCollToken, collIsKtoken, depositTokenIsSol, priceDebtToColl, targetLeverage, slippagePct, flashLoanFee, kamino, strategy, debtTokenMint, priceAinB, debtReserve) {
|
|
91
|
+
let calcs;
|
|
92
|
+
if (!collIsKtoken) {
|
|
93
|
+
calcs = (0, calcs_1.depositLeverageCalcs)({
|
|
94
|
+
depositAmount: depositAmount,
|
|
95
|
+
depositTokenIsCollToken: selectedTokenIsCollToken,
|
|
96
|
+
depositTokenIsSol,
|
|
97
|
+
priceDebtToColl,
|
|
98
|
+
targetLeverage,
|
|
99
|
+
slippagePct,
|
|
100
|
+
flashLoanFee,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
calcs = await (0, calcs_1.depositLeverageKtokenCalcs)({
|
|
163
105
|
kamino: kamino,
|
|
164
106
|
strategy: strategy,
|
|
165
107
|
debtTokenMint,
|
|
166
|
-
depositAmount:
|
|
108
|
+
depositAmount: depositAmount,
|
|
167
109
|
depositTokenIsCollToken: selectedTokenIsCollToken,
|
|
168
110
|
depositTokenIsSol,
|
|
169
111
|
priceDebtToColl,
|
|
@@ -173,23 +115,84 @@ const getDepositWithLeverageIxns = async (props) => {
|
|
|
173
115
|
priceAinB,
|
|
174
116
|
});
|
|
175
117
|
// Rounding to exact number of decimals so this value is passed through in all calcs without rounding inconsistencies
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
118
|
+
calcs.flashBorrowInDebtTokenKtokenOnly = calcs.flashBorrowInDebtTokenKtokenOnly.toDecimalPlaces(debtReserve.state.liquidity.mintDecimals.toNumber(), decimal_js_1.default.ROUND_CEIL);
|
|
119
|
+
calcs.debtTokenToBorrow = calcs.debtTokenToBorrow.toDecimalPlaces(debtReserve.state.liquidity.mintDecimals.toNumber(), decimal_js_1.default.ROUND_CEIL);
|
|
120
|
+
calcs.singleSidedDepositKtokenOnly = calcs.singleSidedDepositKtokenOnly.toDecimalPlaces(debtReserve.state.liquidity.mintDecimals.toNumber(), decimal_js_1.default.ROUND_CEIL);
|
|
121
|
+
}
|
|
122
|
+
return calcs;
|
|
123
|
+
}
|
|
124
|
+
async function getDepositWithLeverageIxns({ owner, kaminoMarket, debtTokenMint, collTokenMint, depositAmount, priceDebtToColl, slippagePct, obligation, referrer, currentSlot, targetLeverage, selectedTokenMint, kamino, obligationTypeTagOverride, scopeFeed, budgetAndPriorityFeeIxs, quoteBufferBps, priceAinB, isKtoken, quoter, swapper, }) {
|
|
125
|
+
const { swapInputs, initialInputs } = await getDepositWithLeverageSwapInputs({
|
|
126
|
+
owner,
|
|
127
|
+
kaminoMarket,
|
|
128
|
+
debtTokenMint,
|
|
129
|
+
collTokenMint,
|
|
130
|
+
depositAmount,
|
|
131
|
+
priceDebtToColl,
|
|
132
|
+
slippagePct,
|
|
133
|
+
obligation,
|
|
134
|
+
referrer,
|
|
135
|
+
currentSlot,
|
|
136
|
+
targetLeverage,
|
|
137
|
+
selectedTokenMint,
|
|
138
|
+
kamino,
|
|
139
|
+
obligationTypeTagOverride,
|
|
140
|
+
scopeFeed,
|
|
141
|
+
budgetAndPriorityFeeIxs,
|
|
142
|
+
quoteBufferBps,
|
|
143
|
+
priceAinB,
|
|
144
|
+
isKtoken,
|
|
145
|
+
quoter,
|
|
146
|
+
});
|
|
147
|
+
let depositSwapper;
|
|
148
|
+
if (!initialInputs.collIsKtoken) {
|
|
149
|
+
depositSwapper = swapper;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
if (kamino === undefined) {
|
|
153
|
+
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
154
|
+
}
|
|
155
|
+
depositSwapper = await (0, utils_2.getTokenToKtokenSwapper)(kaminoMarket, kamino, owner, slippagePct, swapper, priceAinB, false);
|
|
156
|
+
}
|
|
157
|
+
const { swapIxs, lookupTables } = await depositSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
|
|
158
|
+
if (initialInputs.collIsKtoken) {
|
|
159
|
+
if (initialInputs.strategy.strategy.strategyLookupTable) {
|
|
160
|
+
const strategyLut = await (0, utils_1.getLookupTableAccount)(kaminoMarket.getConnection(), initialInputs.strategy.strategy.strategyLookupTable);
|
|
161
|
+
lookupTables.push(strategyLut);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
console.log('Strategy lookup table not found');
|
|
165
|
+
}
|
|
179
166
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
167
|
+
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
168
|
+
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
169
|
+
const solTokenReserve = kaminoMarket.getReserveByMint(utils_1.WRAPPED_SOL_MINT);
|
|
170
|
+
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
|
|
171
|
+
const ixs = await buildDepositWithLeverageIxns(kaminoMarket, debtReserve, collReserve, owner, initialInputs.obligation, referrer, currentSlot, depositTokenIsSol, scopeFeed, initialInputs.calcs, budgetAndPriorityFeeIxs, {
|
|
172
|
+
preActionIxs: [],
|
|
173
|
+
swapIxs: swapIxs,
|
|
174
|
+
lookupTables: lookupTables,
|
|
175
|
+
}, initialInputs.strategy, initialInputs.collIsKtoken);
|
|
176
|
+
return {
|
|
177
|
+
ixs,
|
|
178
|
+
lookupTables,
|
|
179
|
+
swapInputs,
|
|
180
|
+
initialInputs,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async function buildDepositWithLeverageIxns(market, debtReserve, collReserve, owner, obligation, referrer, currentSlot, depositTokenIsSol, scopeFeed, calcs, budgetAndPriorityFeeIxs, swapQuoteIxs, strategy, collIsKtoken) {
|
|
184
|
+
const budgetIxns = budgetAndPriorityFeeIxs || (0, utils_1.getComputeBudgetAndPriorityFeeIxns)(3000000);
|
|
185
|
+
const collTokenMint = collReserve.getLiquidityMint();
|
|
186
|
+
const debtTokenMint = debtReserve.getLiquidityMint();
|
|
187
|
+
const collTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collTokenMint, owner);
|
|
188
|
+
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner);
|
|
186
189
|
// 1. Create atas & budget txns
|
|
187
190
|
let mintsToCreateAtas;
|
|
188
191
|
if (collIsKtoken) {
|
|
189
192
|
const secondTokenAta = strategy.strategy.tokenAMint.equals(debtTokenMint)
|
|
190
193
|
? strategy.strategy.tokenBMint
|
|
191
194
|
: strategy.strategy.tokenAMint;
|
|
192
|
-
const secondTokenTokenProgarm = strategy
|
|
195
|
+
const secondTokenTokenProgarm = strategy.strategy.tokenAMint.equals(debtTokenMint)
|
|
193
196
|
? strategy.strategy.tokenBTokenProgram.equals(web3_js_1.PublicKey.default)
|
|
194
197
|
? spl_token_1.TOKEN_PROGRAM_ID
|
|
195
198
|
: strategy.strategy.tokenBTokenProgram
|
|
@@ -231,269 +234,183 @@ const getDepositWithLeverageIxns = async (props) => {
|
|
|
231
234
|
},
|
|
232
235
|
];
|
|
233
236
|
}
|
|
234
|
-
const
|
|
235
|
-
const { atas: [collTokenAta, debtTokenAta], createAtaIxs, } = await (0, utils_1.getAtasWithCreateIxnsIfMissing)(connection, user, mintsToCreateAtas);
|
|
236
|
-
// TODO: this needs to work the other way around also
|
|
237
|
-
// TODO: marius test this with shorting leverage and with leverage looping
|
|
237
|
+
const atasAndCreateIxns = (0, utils_1.createAtasIdempotent)(owner, mintsToCreateAtas);
|
|
238
238
|
const fillWsolAtaIxns = [];
|
|
239
239
|
if (depositTokenIsSol) {
|
|
240
|
-
fillWsolAtaIxns.push(...(0, utils_1.getDepositWsolIxns)(
|
|
240
|
+
fillWsolAtaIxns.push(...(0, utils_1.getDepositWsolIxns)(owner, (0, spl_token_1.getAssociatedTokenAddressSync)(utils_1.WRAPPED_SOL_MINT, owner), (0, classes_2.numberToLamportsDecimal)(calcs.initDepositInSol, utils_1.SOL_DECIMALS).ceil()));
|
|
241
241
|
}
|
|
242
|
-
//
|
|
242
|
+
// 2. Flash borrow & repay the collateral amount needed for given leverage
|
|
243
243
|
// if user deposits coll, then we borrow the diff, else we borrow the entire amount
|
|
244
244
|
const { flashBorrowIxn, flashRepayIxn } = (0, instructions_1.getFlashLoanInstructions)({
|
|
245
|
-
borrowIxnIndex: budgetIxns.length +
|
|
246
|
-
walletPublicKey:
|
|
247
|
-
lendingMarketAuthority:
|
|
248
|
-
lendingMarketAddress:
|
|
245
|
+
borrowIxnIndex: budgetIxns.length + atasAndCreateIxns.length + fillWsolAtaIxns.length,
|
|
246
|
+
walletPublicKey: owner,
|
|
247
|
+
lendingMarketAuthority: market.getLendingMarketAuthority(),
|
|
248
|
+
lendingMarketAddress: market.getAddress(),
|
|
249
249
|
reserve: !collIsKtoken ? collReserve : debtReserve,
|
|
250
|
-
amountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.flashBorrowInCollToken :
|
|
250
|
+
amountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.flashBorrowInCollToken : calcs.flashBorrowInDebtTokenKtokenOnly, !collIsKtoken ? collReserve.stats.decimals : debtReserve.stats.decimals),
|
|
251
251
|
destinationAta: !collIsKtoken ? collTokenAta : debtTokenAta,
|
|
252
|
-
referrerAccount:
|
|
253
|
-
referrerTokenState:
|
|
254
|
-
programId:
|
|
252
|
+
referrerAccount: market.programId,
|
|
253
|
+
referrerTokenState: market.programId,
|
|
254
|
+
programId: market.programId,
|
|
255
255
|
});
|
|
256
|
-
console.log('Borrowing: ', (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.debtTokenToBorrow : calcsKtoken.debtTokenToBorrow, debtReserve.stats.decimals)
|
|
257
|
-
.ceil()
|
|
258
|
-
.toString());
|
|
259
256
|
// 3. Deposit initial tokens + borrowed tokens into reserve
|
|
260
|
-
let obligationType;
|
|
261
|
-
if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Multiply) {
|
|
262
|
-
// multiply
|
|
263
|
-
obligationType = new utils_1.MultiplyObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
264
|
-
}
|
|
265
|
-
else if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Leverage) {
|
|
266
|
-
// leverage
|
|
267
|
-
obligationType = new utils_1.LeverageObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
throw Error('Obligation type tag not supported for leverage, please use 1 - multiply or 3 - leverage');
|
|
271
|
-
}
|
|
272
257
|
const scopeRefresh = scopeFeed ? { includeScopeRefresh: true, scopeFeed: scopeFeed } : undefined;
|
|
273
|
-
const kaminoDepositAndBorrowAction = await classes_1.KaminoAction.buildDepositAndBorrowTxns(
|
|
258
|
+
const kaminoDepositAndBorrowAction = await classes_1.KaminoAction.buildDepositAndBorrowTxns(market, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.collTokenToDeposit : calcs.collTokenToDeposit, collReserve.stats.decimals)
|
|
274
259
|
.floor()
|
|
275
|
-
.toString(), collTokenMint, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.debtTokenToBorrow :
|
|
260
|
+
.toString(), collTokenMint, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.debtTokenToBorrow : calcs.debtTokenToBorrow, debtReserve.stats.decimals)
|
|
276
261
|
.ceil()
|
|
277
|
-
.toString(), debtTokenMint,
|
|
262
|
+
.toString(), debtTokenMint, owner, obligation, 0, false, true, // emode
|
|
278
263
|
false, // to be checked and created in a setup tx in the UI
|
|
279
264
|
referrer, currentSlot, scopeRefresh);
|
|
280
|
-
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
...createAtaIxs,
|
|
284
|
-
...fillWsolAtaIxns,
|
|
285
|
-
...[flashBorrowIxn],
|
|
286
|
-
...kaminoDepositAndBorrowAction.setupIxs,
|
|
287
|
-
...[kaminoDepositAndBorrowAction.lendingIxs[0]],
|
|
288
|
-
...kaminoDepositAndBorrowAction.inBetweenIxs,
|
|
289
|
-
...[kaminoDepositAndBorrowAction.lendingIxs[1]],
|
|
290
|
-
...kaminoDepositAndBorrowAction.cleanupIxs,
|
|
291
|
-
...[flashRepayIxn],
|
|
292
|
-
];
|
|
293
|
-
const uniqueAccounts = new utils_1.PublicKeySet([]);
|
|
294
|
-
ixns.forEach((ixn) => {
|
|
295
|
-
ixn.keys.forEach((key) => {
|
|
296
|
-
uniqueAccounts.add(key.pubkey);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
const totalKlendAccounts = uniqueAccounts.toArray().length;
|
|
300
|
-
// return early to avoid extra swapper calls
|
|
301
|
-
if (getTotalKlendAccountsOnly) {
|
|
302
|
-
return {
|
|
303
|
-
ixns: [],
|
|
304
|
-
lookupTablesAddresses: [],
|
|
305
|
-
swapInputs: {
|
|
306
|
-
inputAmountLamports: new decimal_js_1.default('0'),
|
|
307
|
-
inputMint: web3_js_1.PublicKey.default,
|
|
308
|
-
outputMint: web3_js_1.PublicKey.default,
|
|
309
|
-
},
|
|
310
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
let depositSwapper;
|
|
314
|
-
let expectedDebtTokenAtaBalance = new decimal_js_1.default(0); // only needed for kTokens
|
|
265
|
+
// 4. Swap
|
|
266
|
+
const { swapIxs } = swapQuoteIxs;
|
|
267
|
+
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapIxs, []);
|
|
315
268
|
if (!collIsKtoken) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
const swapInputs = {
|
|
331
|
-
inputAmountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.swapDebtTokenIn : calcsKtoken.singleSidedDeposit, debtReserve.stats.decimals).ceil(),
|
|
332
|
-
inputMint: debtTokenMint,
|
|
333
|
-
outputMint: collTokenMint,
|
|
334
|
-
};
|
|
335
|
-
const [swapIxns, lookupTablesAddresses] = await depositSwapper(swapInputs.inputAmountLamports.toNumber(), swapInputs.inputMint, swapInputs.outputMint, slippagePct.toNumber(), expectedDebtTokenAtaBalance);
|
|
336
|
-
if (collIsKtoken) {
|
|
337
|
-
if (strategy?.strategy.strategyLookupTable) {
|
|
338
|
-
lookupTablesAddresses.push(strategy?.strategy.strategyLookupTable);
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
console.log('Strategy lookup table not found');
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapIxns, []);
|
|
345
|
-
if (!collIsKtoken) {
|
|
346
|
-
return {
|
|
347
|
-
ixns: [
|
|
348
|
-
...budgetIxns,
|
|
349
|
-
...createAtaIxs,
|
|
350
|
-
...fillWsolAtaIxns,
|
|
351
|
-
...[flashBorrowIxn],
|
|
352
|
-
...kaminoDepositAndBorrowAction.setupIxs,
|
|
353
|
-
...[kaminoDepositAndBorrowAction.lendingIxs[0]],
|
|
354
|
-
...kaminoDepositAndBorrowAction.inBetweenIxs,
|
|
355
|
-
...[kaminoDepositAndBorrowAction.lendingIxs[1]],
|
|
356
|
-
...kaminoDepositAndBorrowAction.cleanupIxs,
|
|
357
|
-
...swapInstructions,
|
|
358
|
-
...[flashRepayIxn],
|
|
359
|
-
],
|
|
360
|
-
lookupTablesAddresses,
|
|
361
|
-
swapInputs,
|
|
362
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
363
|
-
};
|
|
269
|
+
return [
|
|
270
|
+
...budgetIxns,
|
|
271
|
+
...atasAndCreateIxns.map((x) => x.createAtaIx),
|
|
272
|
+
...fillWsolAtaIxns,
|
|
273
|
+
...[flashBorrowIxn],
|
|
274
|
+
...kaminoDepositAndBorrowAction.setupIxs,
|
|
275
|
+
...[kaminoDepositAndBorrowAction.lendingIxs[0]],
|
|
276
|
+
...kaminoDepositAndBorrowAction.inBetweenIxs,
|
|
277
|
+
...[kaminoDepositAndBorrowAction.lendingIxs[1]],
|
|
278
|
+
...kaminoDepositAndBorrowAction.cleanupIxs,
|
|
279
|
+
...swapInstructions,
|
|
280
|
+
...[flashRepayIxn],
|
|
281
|
+
];
|
|
364
282
|
}
|
|
365
283
|
else {
|
|
366
|
-
return
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
],
|
|
380
|
-
lookupTablesAddresses,
|
|
381
|
-
swapInputs,
|
|
382
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
383
|
-
};
|
|
284
|
+
return [
|
|
285
|
+
...budgetIxns,
|
|
286
|
+
...atasAndCreateIxns.map((x) => x.createAtaIx),
|
|
287
|
+
...fillWsolAtaIxns,
|
|
288
|
+
...[flashBorrowIxn],
|
|
289
|
+
...swapInstructions,
|
|
290
|
+
...kaminoDepositAndBorrowAction.setupIxs,
|
|
291
|
+
...[kaminoDepositAndBorrowAction.lendingIxs[0]],
|
|
292
|
+
...kaminoDepositAndBorrowAction.inBetweenIxs,
|
|
293
|
+
...[kaminoDepositAndBorrowAction.lendingIxs[1]],
|
|
294
|
+
...kaminoDepositAndBorrowAction.cleanupIxs,
|
|
295
|
+
...[flashRepayIxn],
|
|
296
|
+
];
|
|
384
297
|
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const getWithdrawWithLeverageSwapInputs = (props) => {
|
|
388
|
-
const { amount, deposited, borrowed, priceCollToDebt, slippagePct, isClosingPosition, kaminoMarket, selectedTokenMint, debtTokenMint, collTokenMint, userObligation, currentSlot, } = props;
|
|
298
|
+
}
|
|
299
|
+
async function getWithdrawWithLeverageSwapInputs({ owner, kaminoMarket, debtTokenMint, collTokenMint, deposited, borrowed, obligation, referrer, currentSlot, withdrawAmount, priceCollToDebt, slippagePct, isClosingPosition, selectedTokenMint, budgetAndPriorityFeeIxs, kamino, scopeFeed, quoteBufferBps, isKtoken, quoter, }) {
|
|
389
300
|
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
390
301
|
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
391
|
-
const flashLoanFee = debtReserve
|
|
302
|
+
const flashLoanFee = debtReserve.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
392
303
|
const selectedTokenIsCollToken = selectedTokenMint.equals(collTokenMint);
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const
|
|
414
|
-
const collTokenSwapIn = selectedTokenIsCollToken ? swapAmountIfWithdrawingColl : swapAmountIfWithdrawingDebt;
|
|
304
|
+
const collIsKtoken = await isKtoken(collTokenMint);
|
|
305
|
+
const strategy = collIsKtoken ? (await kamino.getStrategyByKTokenMint(collTokenMint)) : undefined;
|
|
306
|
+
const solTokenReserve = kaminoMarket.getReserveByMint(utils_1.WRAPPED_SOL_MINT);
|
|
307
|
+
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
|
|
308
|
+
const calcs = (0, calcs_1.withdrawLeverageCalcs)(kaminoMarket, collReserve, debtReserve, priceCollToDebt, withdrawAmount, deposited, borrowed, currentSlot, isClosingPosition, selectedTokenIsCollToken, selectedTokenMint, obligation, flashLoanFee, slippagePct);
|
|
309
|
+
const klendIxs = await buildWithdrawWithLeverageIxns(kaminoMarket, debtReserve, collReserve, owner, obligation, referrer, currentSlot, isClosingPosition, depositTokenIsSol, scopeFeed, calcs, budgetAndPriorityFeeIxs, {
|
|
310
|
+
preActionIxs: [],
|
|
311
|
+
swapIxs: [],
|
|
312
|
+
lookupTables: [],
|
|
313
|
+
}, strategy, collIsKtoken);
|
|
314
|
+
const uniqueKlendAccounts = (0, utils_1.uniqueAccounts)(klendIxs);
|
|
315
|
+
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(calcs.collTokenSwapIn, collReserve.state.liquidity.mintDecimals.toNumber()).ceil();
|
|
316
|
+
const swapInputsForQuote = {
|
|
317
|
+
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
|
|
318
|
+
inputMint: collTokenMint,
|
|
319
|
+
outputMint: debtTokenMint,
|
|
320
|
+
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens deposits
|
|
321
|
+
};
|
|
322
|
+
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
|
|
323
|
+
const calcsQuotePrice = (0, calcs_1.withdrawLeverageCalcs)(kaminoMarket, collReserve, debtReserve, collIsKtoken ? swapQuote.priceAInB : priceCollToDebt, withdrawAmount, deposited, borrowed, currentSlot, isClosingPosition, selectedTokenIsCollToken, selectedTokenMint, obligation, flashLoanFee, slippagePct);
|
|
324
|
+
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(calcsQuotePrice.collTokenSwapIn, collReserve.state.liquidity.mintDecimals.toNumber()).ceil();
|
|
415
325
|
return {
|
|
416
326
|
swapInputs: {
|
|
417
|
-
inputAmountLamports:
|
|
327
|
+
inputAmountLamports: swapInputAmountQuotePrice,
|
|
418
328
|
inputMint: collTokenMint,
|
|
419
329
|
outputMint: debtTokenMint,
|
|
330
|
+
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens deposits
|
|
331
|
+
},
|
|
332
|
+
initialInputs: {
|
|
333
|
+
calcs: calcsQuotePrice,
|
|
334
|
+
swapQuote,
|
|
335
|
+
currentSlot,
|
|
336
|
+
collIsKtoken,
|
|
337
|
+
strategy,
|
|
338
|
+
obligation,
|
|
339
|
+
klendAccounts: uniqueKlendAccounts,
|
|
420
340
|
},
|
|
421
341
|
};
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
const getWithdrawWithLeverageIxns = async (props) => {
|
|
425
|
-
const { connection, budgetAndPriorityFeeIxns, user, amount, deposited, borrowed, collTokenMint, debtTokenMint, priceCollToDebt, selectedTokenMint, isClosingPosition, kaminoMarket, slippagePct, swapper, referrer, isKtoken, kamino, obligationTypeTagOverride, obligation, currentSlot, getTotalKlendAccountsOnly, scopeFeed, } = props;
|
|
342
|
+
}
|
|
343
|
+
async function getWithdrawWithLeverageIxns({ owner, kaminoMarket, debtTokenMint, collTokenMint, obligation, deposited, borrowed, referrer, currentSlot, withdrawAmount, priceCollToDebt, slippagePct, isClosingPosition, selectedTokenMint, budgetAndPriorityFeeIxs, kamino, scopeFeed, quoteBufferBps, isKtoken, quoter, swapper, }) {
|
|
426
344
|
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
427
345
|
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
428
|
-
const flashLoanFee = debtReserve?.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
429
|
-
const collIsKtoken = await isKtoken(collTokenMint);
|
|
430
346
|
const solTokenReserve = kaminoMarket.getReserveByMint(utils_1.WRAPPED_SOL_MINT);
|
|
431
|
-
const selectedTokenIsCollToken = selectedTokenMint.equals(collTokenMint);
|
|
432
347
|
const depositTokenIsSol = !solTokenReserve ? false : selectedTokenMint.equals(solTokenReserve.getLiquidityMint());
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
348
|
+
const { swapInputs, initialInputs } = await getWithdrawWithLeverageSwapInputs({
|
|
349
|
+
owner,
|
|
350
|
+
kaminoMarket,
|
|
351
|
+
debtTokenMint,
|
|
352
|
+
collTokenMint,
|
|
353
|
+
deposited,
|
|
354
|
+
borrowed,
|
|
355
|
+
obligation,
|
|
356
|
+
referrer,
|
|
357
|
+
currentSlot,
|
|
358
|
+
withdrawAmount,
|
|
359
|
+
priceCollToDebt,
|
|
360
|
+
slippagePct,
|
|
361
|
+
isClosingPosition,
|
|
362
|
+
selectedTokenMint,
|
|
363
|
+
budgetAndPriorityFeeIxs,
|
|
364
|
+
kamino,
|
|
365
|
+
scopeFeed,
|
|
366
|
+
quoteBufferBps,
|
|
367
|
+
isKtoken,
|
|
368
|
+
quoter,
|
|
369
|
+
});
|
|
370
|
+
let withdrawSwapper;
|
|
371
|
+
if (initialInputs.collIsKtoken) {
|
|
372
|
+
if (kamino === undefined) {
|
|
373
|
+
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
374
|
+
}
|
|
375
|
+
withdrawSwapper = await (0, utils_2.getKtokenToTokenSwapper)(kaminoMarket, kamino, owner, swapper);
|
|
441
376
|
}
|
|
442
377
|
else {
|
|
443
|
-
|
|
378
|
+
withdrawSwapper = swapper;
|
|
444
379
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
//
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
// 5. Get swap estimations to understand how much we need to borrow from borrow reserve
|
|
473
|
-
// prevent withdrawing more then deposited if we close position
|
|
474
|
-
const depositTokenWithdrawAmount = !isClosingPosition
|
|
475
|
-
? withdrawAmount.mul(new decimal_js_1.default(1).plus(flashLoanFee))
|
|
476
|
-
: withdrawAmount;
|
|
477
|
-
// We are swapping debt token
|
|
478
|
-
// When withdrawing coll, it means we just need to swap enough to pay for the flash borrow
|
|
479
|
-
const swapAmountIfWithdrawingColl = repayAmount
|
|
480
|
-
.mul(new decimal_js_1.default(1).plus(flashLoanFee))
|
|
481
|
-
.mul(new decimal_js_1.default(1 + slippagePct / 100))
|
|
482
|
-
.div(priceCollToDebt);
|
|
483
|
-
// When withdrawing debt, it means we need to swap just the collateral we are withdrwaing
|
|
484
|
-
// enough to cover the debt we are repaying, leaving the remaining in the wallet
|
|
485
|
-
const swapAmountIfWithdrawingDebt = withdrawAmount;
|
|
486
|
-
const collTokenSwapIn = selectedTokenIsCollToken ? swapAmountIfWithdrawingColl : swapAmountIfWithdrawingDebt;
|
|
487
|
-
const debtTokenExpectedSwapOut = collTokenSwapIn.mul(priceCollToDebt).div(new decimal_js_1.default(1 + slippagePct / 100));
|
|
488
|
-
const strategy = collIsKtoken ? await kamino?.getStrategyByKTokenMint(collTokenMint) : undefined;
|
|
489
|
-
console.log('Expecting to swap', collTokenSwapIn.toString(), 'coll for', debtTokenExpectedSwapOut.toString(), 'debt');
|
|
380
|
+
const { swapIxs, lookupTables } = await withdrawSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
|
|
381
|
+
if (initialInputs.collIsKtoken) {
|
|
382
|
+
if (initialInputs.strategy.strategy.strategyLookupTable) {
|
|
383
|
+
const strategyLut = await (0, utils_1.getLookupTableAccount)(kaminoMarket.getConnection(), initialInputs.strategy.strategy.strategyLookupTable);
|
|
384
|
+
lookupTables.push(strategyLut);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.log('Strategy lookup table not found');
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const ixs = await buildWithdrawWithLeverageIxns(kaminoMarket, debtReserve, collReserve, owner, obligation, referrer, currentSlot, isClosingPosition, depositTokenIsSol, scopeFeed, initialInputs.calcs, budgetAndPriorityFeeIxs, {
|
|
391
|
+
preActionIxs: [],
|
|
392
|
+
swapIxs,
|
|
393
|
+
lookupTables,
|
|
394
|
+
}, initialInputs.strategy, initialInputs.collIsKtoken);
|
|
395
|
+
// Send ixns and lookup tables
|
|
396
|
+
return {
|
|
397
|
+
ixs,
|
|
398
|
+
lookupTables,
|
|
399
|
+
swapInputs,
|
|
400
|
+
initialInputs: initialInputs,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
async function buildWithdrawWithLeverageIxns(market, debtReserve, collReserve, owner, obligation, referrer, currentSlot, isClosingPosition, depositTokenIsSol, scopeFeed, calcs, budgetAndPriorityFeeIxs, swapQuoteIxs, strategy, collIsKtoken) {
|
|
404
|
+
const collTokenMint = collReserve.getLiquidityMint();
|
|
405
|
+
const debtTokenMint = debtReserve.getLiquidityMint();
|
|
406
|
+
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner);
|
|
490
407
|
// 1. Create atas & budget txns & user metadata
|
|
491
408
|
let mintsToCreateAtas;
|
|
492
409
|
if (collIsKtoken) {
|
|
493
410
|
const secondTokenAta = strategy.strategy.tokenAMint.equals(debtTokenMint)
|
|
494
411
|
? strategy.strategy.tokenBMint
|
|
495
412
|
: strategy.strategy.tokenAMint;
|
|
496
|
-
const secondTokenTokenProgram = strategy
|
|
413
|
+
const secondTokenTokenProgram = strategy.strategy.tokenAMint.equals(debtTokenMint)
|
|
497
414
|
? strategy.strategy.tokenBTokenProgram.equals(web3_js_1.PublicKey.default)
|
|
498
415
|
? spl_token_1.TOKEN_PROGRAM_ID
|
|
499
416
|
: strategy.strategy.tokenBTokenProgram
|
|
@@ -535,96 +452,45 @@ const getWithdrawWithLeverageIxns = async (props) => {
|
|
|
535
452
|
},
|
|
536
453
|
];
|
|
537
454
|
}
|
|
538
|
-
const
|
|
455
|
+
const atasAndCreateIxns = (0, utils_1.createAtasIdempotent)(owner, mintsToCreateAtas);
|
|
539
456
|
const closeWsolAtaIxns = [];
|
|
540
457
|
if (depositTokenIsSol || debtTokenMint.equals(utils_1.WRAPPED_SOL_MINT)) {
|
|
541
|
-
const wsolAta = (0, utils_1.getAssociatedTokenAddress)(utils_1.WRAPPED_SOL_MINT,
|
|
542
|
-
closeWsolAtaIxns.push((0, spl_token_1.createCloseAccountInstruction)(wsolAta,
|
|
458
|
+
const wsolAta = (0, utils_1.getAssociatedTokenAddress)(utils_1.WRAPPED_SOL_MINT, owner, false);
|
|
459
|
+
closeWsolAtaIxns.push((0, spl_token_1.createCloseAccountInstruction)(wsolAta, owner, owner, [], spl_token_1.TOKEN_PROGRAM_ID));
|
|
543
460
|
}
|
|
544
|
-
const budgetIxns =
|
|
545
|
-
// TODO:
|
|
461
|
+
const budgetIxns = budgetAndPriorityFeeIxs || (0, utils_1.getComputeBudgetAndPriorityFeeIxns)(3000000);
|
|
462
|
+
// TODO: Might be worth removing as it's only needed for Ktokens
|
|
546
463
|
// This is here so that we have enough wsol to repay in case the kAB swapped to sol after estimates is not enough
|
|
547
464
|
const fillWsolAtaIxns = [];
|
|
548
465
|
if (debtTokenMint.equals(utils_1.WRAPPED_SOL_MINT)) {
|
|
549
|
-
const halfSolBalance = (await
|
|
466
|
+
const halfSolBalance = (await market.getConnection().getBalance(owner)) / web3_js_1.LAMPORTS_PER_SOL / 2;
|
|
550
467
|
const balanceToWrap = halfSolBalance < 0.1 ? halfSolBalance : 0.1;
|
|
551
|
-
fillWsolAtaIxns.push(...(0, utils_1.getDepositWsolIxns)(
|
|
468
|
+
fillWsolAtaIxns.push(...(0, utils_1.getDepositWsolIxns)(owner, (0, spl_token_1.getAssociatedTokenAddressSync)(utils_1.WRAPPED_SOL_MINT, owner), (0, classes_2.numberToLamportsDecimal)(balanceToWrap, utils_1.SOL_DECIMALS).ceil()));
|
|
552
469
|
}
|
|
553
470
|
// 2. Prepare the flash borrow and flash repay amounts and ixns
|
|
554
471
|
// We borrow exactly how much we need to repay
|
|
555
472
|
// and repay that + flash amount fee
|
|
556
473
|
const { flashBorrowIxn, flashRepayIxn } = (0, instructions_1.getFlashLoanInstructions)({
|
|
557
|
-
borrowIxnIndex: budgetIxns.length +
|
|
558
|
-
walletPublicKey:
|
|
559
|
-
lendingMarketAuthority:
|
|
560
|
-
lendingMarketAddress:
|
|
474
|
+
borrowIxnIndex: budgetIxns.length + atasAndCreateIxns.length + fillWsolAtaIxns.length,
|
|
475
|
+
walletPublicKey: owner,
|
|
476
|
+
lendingMarketAuthority: market.getLendingMarketAuthority(),
|
|
477
|
+
lendingMarketAddress: market.getAddress(),
|
|
561
478
|
reserve: debtReserve,
|
|
562
|
-
amountLamports: (0, classes_2.numberToLamportsDecimal)(repayAmount, debtReserve.stats.decimals),
|
|
479
|
+
amountLamports: (0, classes_2.numberToLamportsDecimal)(calcs.repayAmount, debtReserve.stats.decimals),
|
|
563
480
|
destinationAta: debtTokenAta,
|
|
564
|
-
referrerAccount:
|
|
565
|
-
referrerTokenState:
|
|
566
|
-
programId:
|
|
481
|
+
referrerAccount: market.programId,
|
|
482
|
+
referrerTokenState: market.programId,
|
|
483
|
+
programId: market.programId,
|
|
567
484
|
});
|
|
568
485
|
// 6. Repay borrowed tokens and Withdraw tokens from reserve that will be swapped to repay flash loan
|
|
569
|
-
const repayAndWithdrawAction = await classes_1.KaminoAction.buildRepayAndWithdrawTxns(
|
|
486
|
+
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
|
|
487
|
+
? utils_1.U64_MAX
|
|
488
|
+
: (0, classes_2.numberToLamportsDecimal)(calcs.depositTokenWithdrawAmount, collReserve.stats.decimals).ceil().toString(), collTokenMint, owner, currentSlot, obligation, 0, false, false, false, // 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)
|
|
570
489
|
isClosingPosition, referrer, { includeScopeRefresh: true, scopeFeed: scopeFeed });
|
|
571
|
-
const
|
|
490
|
+
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapQuoteIxs.swapIxs, []);
|
|
491
|
+
return [
|
|
572
492
|
...budgetIxns,
|
|
573
|
-
...
|
|
574
|
-
...fillWsolAtaIxns,
|
|
575
|
-
...[flashBorrowIxn],
|
|
576
|
-
...repayAndWithdrawAction.setupIxs,
|
|
577
|
-
...[repayAndWithdrawAction.lendingIxs[0]],
|
|
578
|
-
...repayAndWithdrawAction.inBetweenIxs,
|
|
579
|
-
...[repayAndWithdrawAction.lendingIxs[1]],
|
|
580
|
-
...repayAndWithdrawAction.cleanupIxs,
|
|
581
|
-
...[flashRepayIxn],
|
|
582
|
-
...closeWsolAtaIxns,
|
|
583
|
-
];
|
|
584
|
-
const uniqueAccs = (0, utils_1.uniqueAccounts)(klendIxns);
|
|
585
|
-
const totalKlendAccounts = uniqueAccs.length;
|
|
586
|
-
// return early to avoid extra swapper calls
|
|
587
|
-
if (getTotalKlendAccountsOnly) {
|
|
588
|
-
return {
|
|
589
|
-
ixns: [],
|
|
590
|
-
lookupTablesAddresses: [],
|
|
591
|
-
swapInputs: {
|
|
592
|
-
inputAmountLamports: new decimal_js_1.default('0'),
|
|
593
|
-
inputMint: web3_js_1.PublicKey.default,
|
|
594
|
-
outputMint: web3_js_1.PublicKey.default,
|
|
595
|
-
},
|
|
596
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
let withdrawSwapper;
|
|
600
|
-
if (collIsKtoken) {
|
|
601
|
-
if (kamino === undefined) {
|
|
602
|
-
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
603
|
-
}
|
|
604
|
-
withdrawSwapper = await (0, utils_2.getKtokenToTokenSwapper)(kaminoMarket, kamino, user, swapper);
|
|
605
|
-
}
|
|
606
|
-
else {
|
|
607
|
-
withdrawSwapper = swapper;
|
|
608
|
-
}
|
|
609
|
-
const swapInputs = {
|
|
610
|
-
inputAmountLamports: (0, classes_2.numberToLamportsDecimal)(collTokenSwapIn, collReserve.stats.decimals).ceil(),
|
|
611
|
-
inputMint: collTokenMint,
|
|
612
|
-
outputMint: debtTokenMint,
|
|
613
|
-
};
|
|
614
|
-
const [swapIxns, lookupTablesAddresses] = await withdrawSwapper(swapInputs.inputAmountLamports.toNumber(), swapInputs.inputMint, swapInputs.outputMint, slippagePct);
|
|
615
|
-
// TODO MARIUS: remove first instruction that is setBudget ixn
|
|
616
|
-
if (collIsKtoken) {
|
|
617
|
-
if (strategy?.strategy.strategyLookupTable) {
|
|
618
|
-
lookupTablesAddresses.push(strategy?.strategy.strategyLookupTable);
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
console.log('Strategy lookup table not found');
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapIxns, []);
|
|
625
|
-
const ixns = [
|
|
626
|
-
...budgetIxns,
|
|
627
|
-
...createAtaIxs,
|
|
493
|
+
...atasAndCreateIxns.map((x) => x.createAtaIx),
|
|
628
494
|
...fillWsolAtaIxns,
|
|
629
495
|
...[flashBorrowIxn],
|
|
630
496
|
...repayAndWithdrawAction.setupIxs,
|
|
@@ -636,20 +502,24 @@ const getWithdrawWithLeverageIxns = async (props) => {
|
|
|
636
502
|
...[flashRepayIxn],
|
|
637
503
|
...closeWsolAtaIxns,
|
|
638
504
|
];
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
ixns,
|
|
642
|
-
lookupTablesAddresses,
|
|
643
|
-
swapInputs,
|
|
644
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
645
|
-
};
|
|
646
|
-
};
|
|
647
|
-
exports.getWithdrawWithLeverageIxns = getWithdrawWithLeverageIxns;
|
|
648
|
-
const getAdjustLeverageSwapInputs = (props) => {
|
|
649
|
-
const { deposited, borrowed, priceCollToDebt, priceDebtToColl, slippagePct, targetLeverage, kaminoMarket, debtTokenMint, collTokenMint, } = props;
|
|
505
|
+
}
|
|
506
|
+
async function getAdjustLeverageSwapInputs({ owner, kaminoMarket, debtTokenMint, collTokenMint, obligation, depositedLamports, borrowedLamports, referrer, currentSlot, targetLeverage, priceCollToDebt, priceDebtToColl, slippagePct, budgetAndPriorityFeeIxs, kamino, scopeFeed, quoteBufferBps, isKtoken, quoter, }) {
|
|
650
507
|
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
651
508
|
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
652
|
-
const
|
|
509
|
+
const deposited = (0, classes_1.lamportsToNumberDecimal)(depositedLamports, collReserve.stats.decimals);
|
|
510
|
+
const borrowed = (0, classes_1.lamportsToNumberDecimal)(borrowedLamports, debtReserve.stats.decimals);
|
|
511
|
+
const collIsKtoken = await isKtoken(collTokenMint);
|
|
512
|
+
const strategy = collIsKtoken ? (await kamino.getStrategyByKTokenMint(collTokenMint)) : undefined;
|
|
513
|
+
// Getting current flash loan fee
|
|
514
|
+
const currentLeverage = obligation.refreshedStats.leverage;
|
|
515
|
+
const isDepositViaLeverage = targetLeverage.gte(new decimal_js_1.default(currentLeverage));
|
|
516
|
+
let flashLoanFee;
|
|
517
|
+
if (isDepositViaLeverage) {
|
|
518
|
+
flashLoanFee = collReserve.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
flashLoanFee = debtReserve.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
522
|
+
}
|
|
653
523
|
const { adjustDepositPosition, adjustBorrowPosition } = (0, calcs_1.calcAdjustAmounts)({
|
|
654
524
|
currentDepositPosition: deposited,
|
|
655
525
|
currentBorrowPosition: borrowed,
|
|
@@ -658,147 +528,187 @@ const getAdjustLeverageSwapInputs = (props) => {
|
|
|
658
528
|
flashLoanFee: new decimal_js_1.default(flashLoanFee),
|
|
659
529
|
});
|
|
660
530
|
const isDeposit = adjustDepositPosition.gte(0) && adjustBorrowPosition.gte(0);
|
|
531
|
+
if (isDepositViaLeverage !== isDeposit) {
|
|
532
|
+
throw new Error('Invalid target leverage');
|
|
533
|
+
}
|
|
661
534
|
if (isDeposit) {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
535
|
+
const calcs = await (0, calcs_1.adjustDepositLeverageCalcs)(kaminoMarket, owner, debtReserve, adjustDepositPosition, adjustBorrowPosition, priceDebtToColl, flashLoanFee, slippagePct, collIsKtoken);
|
|
536
|
+
// Build the repay & withdraw collateral tx to get the number of accounts
|
|
537
|
+
const klendIxs = await buildIncreaseLeverageIxns(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeFeed, collIsKtoken, {
|
|
538
|
+
preActionIxs: [],
|
|
539
|
+
swapIxs: [],
|
|
540
|
+
lookupTables: [],
|
|
541
|
+
}, budgetAndPriorityFeeIxs);
|
|
542
|
+
const uniqueKlendAccounts = (0, utils_1.uniqueAccounts)(klendIxs);
|
|
543
|
+
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.borrowAmount : calcs.amountToFlashBorrowDebt, debtReserve.state.liquidity.mintDecimals.toNumber()).ceil();
|
|
544
|
+
const swapInputsForQuote = {
|
|
545
|
+
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
|
|
546
|
+
inputMint: debtTokenMint,
|
|
547
|
+
outputMint: collTokenMint,
|
|
548
|
+
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens swaps
|
|
549
|
+
};
|
|
550
|
+
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
|
|
551
|
+
const { adjustDepositPosition: adjustDepositPositionQuotePrice, adjustBorrowPosition: adjustBorrowPositionQuotePrice, } = (0, calcs_1.calcAdjustAmounts)({
|
|
552
|
+
currentDepositPosition: deposited,
|
|
553
|
+
currentBorrowPosition: borrowed,
|
|
554
|
+
targetLeverage: targetLeverage,
|
|
555
|
+
priceCollToDebt: new decimal_js_1.default(1).div(swapQuote.priceAInB),
|
|
556
|
+
flashLoanFee: new decimal_js_1.default(flashLoanFee),
|
|
557
|
+
});
|
|
558
|
+
const calcsQuotePrice = await (0, calcs_1.adjustDepositLeverageCalcs)(kaminoMarket, owner, debtReserve, adjustDepositPositionQuotePrice, adjustBorrowPositionQuotePrice, swapQuote.priceAInB, flashLoanFee, slippagePct, collIsKtoken);
|
|
559
|
+
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcsQuotePrice.borrowAmount : calcsQuotePrice.amountToFlashBorrowDebt, debtReserve.state.liquidity.mintDecimals.toNumber()).ceil();
|
|
560
|
+
let expectedDebtTokenAtaBalance = new decimal_js_1.default(0);
|
|
561
|
+
if (collIsKtoken) {
|
|
562
|
+
expectedDebtTokenAtaBalance = await (0, utils_2.getExpectedTokenBalanceAfterBorrow)(kaminoMarket.getConnection(), debtTokenMint, owner, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcsQuotePrice.borrowAmount : calcsQuotePrice.amountToFlashBorrowDebt, debtReserve.stats.decimals).floor(), debtReserve.state.liquidity.mintDecimals.toNumber());
|
|
563
|
+
}
|
|
666
564
|
return {
|
|
667
565
|
swapInputs: {
|
|
668
|
-
inputAmountLamports:
|
|
566
|
+
inputAmountLamports: swapInputAmountQuotePrice,
|
|
669
567
|
inputMint: debtTokenMint,
|
|
670
568
|
outputMint: collTokenMint,
|
|
569
|
+
amountDebtAtaBalance: expectedDebtTokenAtaBalance,
|
|
570
|
+
},
|
|
571
|
+
initialInputs: {
|
|
572
|
+
calcs: calcsQuotePrice,
|
|
573
|
+
swapQuote,
|
|
574
|
+
currentSlot,
|
|
575
|
+
collIsKtoken,
|
|
576
|
+
strategy,
|
|
577
|
+
obligation: obligation,
|
|
578
|
+
klendAccounts: uniqueKlendAccounts,
|
|
579
|
+
isDeposit: isDeposit,
|
|
671
580
|
},
|
|
672
581
|
};
|
|
673
582
|
}
|
|
674
583
|
else {
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
584
|
+
const calcs = (0, calcs_1.adjustWithdrawLeverageCalcs)(adjustDepositPosition, adjustBorrowPosition, flashLoanFee, slippagePct);
|
|
585
|
+
const klendIxs = await buildDecreaseLeverageIxns(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeFeed, collIsKtoken, {
|
|
586
|
+
preActionIxs: [],
|
|
587
|
+
swapIxs: [],
|
|
588
|
+
lookupTables: [],
|
|
589
|
+
}, budgetAndPriorityFeeIxs);
|
|
590
|
+
const uniqueKlendAccounts = (0, utils_1.uniqueAccounts)(klendIxs);
|
|
591
|
+
const swapInputAmount = (0, classes_2.numberToLamportsDecimal)(calcs.withdrawAmountWithSlippageAndFlashLoanFee, collReserve.state.liquidity.mintDecimals.toNumber()).ceil();
|
|
592
|
+
const swapInputsForQuote = {
|
|
593
|
+
inputAmountLamports: swapInputAmount.mul(new decimal_js_1.default(1).add(quoteBufferBps.div(CreationParameters_1.FullBPS))),
|
|
594
|
+
inputMint: collTokenMint,
|
|
595
|
+
outputMint: debtTokenMint,
|
|
596
|
+
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens deposits
|
|
597
|
+
};
|
|
598
|
+
const swapQuote = await quoter(swapInputsForQuote, uniqueKlendAccounts);
|
|
599
|
+
const { adjustDepositPosition: adjustDepositPositionQuotePrice, adjustBorrowPosition: adjustBorrowPositionQuotePrice, } = (0, calcs_1.calcAdjustAmounts)({
|
|
600
|
+
currentDepositPosition: deposited,
|
|
601
|
+
currentBorrowPosition: borrowed,
|
|
602
|
+
targetLeverage: targetLeverage,
|
|
603
|
+
priceCollToDebt: swapQuote.priceAInB,
|
|
604
|
+
flashLoanFee: new decimal_js_1.default(flashLoanFee),
|
|
605
|
+
});
|
|
606
|
+
const calcsQuotePrice = (0, calcs_1.adjustWithdrawLeverageCalcs)(adjustDepositPositionQuotePrice, adjustBorrowPositionQuotePrice, flashLoanFee, slippagePct);
|
|
607
|
+
const swapInputAmountQuotePrice = (0, classes_2.numberToLamportsDecimal)(calcsQuotePrice.withdrawAmountWithSlippageAndFlashLoanFee, collReserve.state.liquidity.mintDecimals.toNumber()).ceil();
|
|
678
608
|
return {
|
|
679
609
|
swapInputs: {
|
|
680
|
-
inputAmountLamports:
|
|
610
|
+
inputAmountLamports: swapInputAmountQuotePrice,
|
|
681
611
|
inputMint: collTokenMint,
|
|
682
612
|
outputMint: debtTokenMint,
|
|
613
|
+
amountDebtAtaBalance: new decimal_js_1.default(0), // Only needed for ktokens deposits
|
|
614
|
+
},
|
|
615
|
+
initialInputs: {
|
|
616
|
+
calcs: calcsQuotePrice,
|
|
617
|
+
swapQuote,
|
|
618
|
+
currentSlot,
|
|
619
|
+
collIsKtoken,
|
|
620
|
+
strategy,
|
|
621
|
+
obligation,
|
|
622
|
+
klendAccounts: uniqueKlendAccounts,
|
|
623
|
+
isDeposit,
|
|
683
624
|
},
|
|
684
625
|
};
|
|
685
626
|
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
currentBorrowPosition: borrowed,
|
|
710
|
-
targetLeverage: targetLeverage,
|
|
711
|
-
priceCollToDebt: priceCollToDebt,
|
|
712
|
-
flashLoanFee: new decimal_js_1.default(flashLoanFee),
|
|
627
|
+
}
|
|
628
|
+
async function getAdjustLeverageIxns({ owner, kaminoMarket, debtTokenMint, collTokenMint, obligation, depositedLamports, borrowedLamports, referrer, currentSlot, targetLeverage, priceCollToDebt, priceDebtToColl, slippagePct, budgetAndPriorityFeeIxs, kamino, scopeFeed, quoteBufferBps, priceAinB, isKtoken, quoter, swapper, }) {
|
|
629
|
+
const { swapInputs, initialInputs } = await getAdjustLeverageSwapInputs({
|
|
630
|
+
owner,
|
|
631
|
+
kaminoMarket,
|
|
632
|
+
debtTokenMint,
|
|
633
|
+
collTokenMint,
|
|
634
|
+
obligation,
|
|
635
|
+
depositedLamports,
|
|
636
|
+
borrowedLamports,
|
|
637
|
+
referrer,
|
|
638
|
+
currentSlot,
|
|
639
|
+
targetLeverage,
|
|
640
|
+
priceCollToDebt,
|
|
641
|
+
priceDebtToColl,
|
|
642
|
+
slippagePct,
|
|
643
|
+
budgetAndPriorityFeeIxs,
|
|
644
|
+
kamino,
|
|
645
|
+
scopeFeed,
|
|
646
|
+
quoteBufferBps,
|
|
647
|
+
priceAinB,
|
|
648
|
+
isKtoken,
|
|
649
|
+
quoter,
|
|
713
650
|
});
|
|
714
|
-
let ixns = [];
|
|
715
|
-
let lookupTablesAddresses = [];
|
|
716
|
-
let swapInputs;
|
|
717
|
-
let totalKlendAccounts = 0;
|
|
718
|
-
const isDeposit = adjustDepositPosition.gte(0) && adjustBorrowPosition.gte(0);
|
|
719
|
-
if (isDepositViaLeverage !== isDeposit) {
|
|
720
|
-
throw new Error('Invalid target leverage');
|
|
721
|
-
}
|
|
722
651
|
// leverage increased so we need to deposit and borrow more
|
|
723
|
-
if (isDeposit) {
|
|
724
|
-
|
|
652
|
+
if (initialInputs.isDeposit) {
|
|
653
|
+
let depositSwapper;
|
|
654
|
+
if (initialInputs.collIsKtoken) {
|
|
655
|
+
if (kamino === undefined) {
|
|
656
|
+
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
657
|
+
}
|
|
658
|
+
depositSwapper = await (0, utils_2.getTokenToKtokenSwapper)(kaminoMarket, kamino, owner, slippagePct, swapper, priceAinB, false);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
depositSwapper = swapper;
|
|
662
|
+
}
|
|
663
|
+
const { swapIxs, lookupTables } = await depositSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
|
|
725
664
|
// TODO: marius why are we not using both adjustDepositPosition & adjustBorrowPosition
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
swapper,
|
|
738
|
-
referrer,
|
|
739
|
-
isKtoken,
|
|
740
|
-
priceAinB,
|
|
741
|
-
kamino,
|
|
742
|
-
obligationTypeTagOverride,
|
|
743
|
-
obligation: userObligation,
|
|
744
|
-
currentSlot,
|
|
745
|
-
getTotalKlendAccountsOnly,
|
|
746
|
-
scopeFeed,
|
|
747
|
-
});
|
|
748
|
-
ixns = res.ixns;
|
|
749
|
-
lookupTablesAddresses = res.lookupTablesAddresses;
|
|
750
|
-
swapInputs = res.swapInputs;
|
|
751
|
-
totalKlendAccounts = res.totalKlendAccounts;
|
|
665
|
+
const ixs = await buildIncreaseLeverageIxns(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, initialInputs.calcs, initialInputs.strategy, scopeFeed, initialInputs.collIsKtoken, {
|
|
666
|
+
preActionIxs: [],
|
|
667
|
+
swapIxs,
|
|
668
|
+
lookupTables,
|
|
669
|
+
}, budgetAndPriorityFeeIxs);
|
|
670
|
+
return {
|
|
671
|
+
ixs,
|
|
672
|
+
lookupTables,
|
|
673
|
+
swapInputs,
|
|
674
|
+
initialInputs,
|
|
675
|
+
};
|
|
752
676
|
}
|
|
753
677
|
else {
|
|
754
678
|
console.log('Decreasing leverage');
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
totalKlendAccounts = res.totalKlendAccounts;
|
|
679
|
+
let withdrawSwapper;
|
|
680
|
+
if (initialInputs.collIsKtoken) {
|
|
681
|
+
if (kamino === undefined) {
|
|
682
|
+
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
683
|
+
}
|
|
684
|
+
withdrawSwapper = await (0, utils_2.getKtokenToTokenSwapper)(kaminoMarket, kamino, owner, swapper);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
withdrawSwapper = swapper;
|
|
688
|
+
}
|
|
689
|
+
// 5. Get swap ixns
|
|
690
|
+
const { swapIxs, lookupTables } = await withdrawSwapper(swapInputs, initialInputs.klendAccounts, initialInputs.swapQuote);
|
|
691
|
+
const ixs = await buildDecreaseLeverageIxns(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, initialInputs.calcs, initialInputs.strategy, scopeFeed, initialInputs.collIsKtoken, {
|
|
692
|
+
preActionIxs: [],
|
|
693
|
+
swapIxs,
|
|
694
|
+
lookupTables,
|
|
695
|
+
}, budgetAndPriorityFeeIxs);
|
|
696
|
+
return {
|
|
697
|
+
ixs,
|
|
698
|
+
lookupTables,
|
|
699
|
+
swapInputs,
|
|
700
|
+
initialInputs,
|
|
701
|
+
};
|
|
779
702
|
}
|
|
780
|
-
|
|
781
|
-
ixns,
|
|
782
|
-
lookupTablesAddresses,
|
|
783
|
-
swapInputs,
|
|
784
|
-
totalKlendAccounts,
|
|
785
|
-
};
|
|
786
|
-
};
|
|
787
|
-
exports.getAdjustLeverageIxns = getAdjustLeverageIxns;
|
|
703
|
+
}
|
|
788
704
|
/**
|
|
789
705
|
* Deposit and borrow tokens if leverage increased
|
|
790
706
|
*/
|
|
791
|
-
|
|
792
|
-
const { connection, budgetAndPriorityFeeIxns, user, kaminoMarket, depositAmount, collTokenMint, debtTokenMint, slippagePct, priceDebtToColl, priceCollToDebt, swapper, referrer, isKtoken, priceAinB, kamino, obligationTypeTagOverride = 1, obligation, currentSlot, getTotalKlendAccountsOnly, scopeFeed, } = props;
|
|
707
|
+
async function buildIncreaseLeverageIxns(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeFeed, collIsKtoken, swapQuoteIxs, budgetAndPriorityFeeIxns) {
|
|
793
708
|
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
794
709
|
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
795
|
-
const
|
|
796
|
-
const
|
|
797
|
-
if (!priceDebtToColl || !priceCollToDebt) {
|
|
798
|
-
throw new Error('Price is not loaded. Please, reload the page and try again');
|
|
799
|
-
}
|
|
800
|
-
// TODO: why are we recalculating here again
|
|
801
|
-
const strategy = collIsKtoken ? await kamino?.getStrategyByKTokenMint(collTokenMint) : undefined;
|
|
710
|
+
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner);
|
|
711
|
+
const collTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(collTokenMint, owner);
|
|
802
712
|
// 1. Create atas & budget txns
|
|
803
713
|
const budgetIxns = budgetAndPriorityFeeIxns || (0, utils_1.getComputeBudgetAndPriorityFeeIxns)(3000000);
|
|
804
714
|
let mintsToCreateAtas;
|
|
@@ -848,105 +758,30 @@ const getIncreaseLeverageIxns = async (props) => {
|
|
|
848
758
|
},
|
|
849
759
|
];
|
|
850
760
|
}
|
|
851
|
-
const
|
|
761
|
+
const atasAndCreateIxns = (0, utils_1.createAtasIdempotent)(owner, mintsToCreateAtas);
|
|
852
762
|
// 2. Create borrow flash loan instruction
|
|
853
|
-
// used if coll is Ktoken and we borrow debt token instead
|
|
854
|
-
const amountToFashBorrowDebt = depositAmount
|
|
855
|
-
.div(priceDebtToColl)
|
|
856
|
-
.mul(new decimal_js_1.default(1 + slippagePct / 100))
|
|
857
|
-
.toDecimalPlaces(debtReserve.stats.decimals, decimal_js_1.default.ROUND_UP);
|
|
858
|
-
// .toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber());
|
|
859
763
|
const { flashBorrowIxn, flashRepayIxn } = (0, instructions_1.getFlashLoanInstructions)({
|
|
860
|
-
borrowIxnIndex: budgetIxns.length +
|
|
861
|
-
walletPublicKey:
|
|
764
|
+
borrowIxnIndex: budgetIxns.length + atasAndCreateIxns.length, // TODO: how about user metadata ixns
|
|
765
|
+
walletPublicKey: owner,
|
|
862
766
|
lendingMarketAuthority: kaminoMarket.getLendingMarketAuthority(),
|
|
863
767
|
lendingMarketAddress: kaminoMarket.getAddress(),
|
|
864
768
|
reserve: !collIsKtoken ? collReserve : debtReserve,
|
|
865
|
-
amountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ?
|
|
769
|
+
amountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? calcs.adjustDepositPosition : calcs.amountToFlashBorrowDebt, !collIsKtoken ? collReserve.stats.decimals : debtReserve.stats.decimals),
|
|
866
770
|
destinationAta: !collIsKtoken ? collTokenAta : debtTokenAta,
|
|
867
771
|
referrerAccount: kaminoMarket.programId,
|
|
868
772
|
referrerTokenState: kaminoMarket.programId,
|
|
869
773
|
programId: kaminoMarket.programId,
|
|
870
774
|
});
|
|
871
|
-
|
|
872
|
-
let obligationType;
|
|
873
|
-
if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Multiply) {
|
|
874
|
-
// multiply
|
|
875
|
-
obligationType = new utils_1.MultiplyObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
876
|
-
}
|
|
877
|
-
else if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Leverage) {
|
|
878
|
-
// leverage
|
|
879
|
-
obligationType = new utils_1.LeverageObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
880
|
-
}
|
|
881
|
-
else {
|
|
882
|
-
throw Error('Obligation type tag not supported for leverage, please use 1 - multiply or 3 - leverage');
|
|
883
|
-
}
|
|
884
|
-
const depositAction = await classes_1.KaminoAction.buildDepositTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(depositAmount, collReserve.stats.decimals).floor().toString(), collTokenMint, user, obligation ? obligation : obligationType, 0, false, false, false, // 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)
|
|
775
|
+
const depositAction = await classes_1.KaminoAction.buildDepositTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(calcs.adjustDepositPosition, collReserve.stats.decimals).floor().toString(), collTokenMint, owner, obligation, 0, false, false, false, // 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)
|
|
885
776
|
referrer, currentSlot, { includeScopeRefresh: true, scopeFeed: scopeFeed });
|
|
886
|
-
// 4.
|
|
887
|
-
const
|
|
888
|
-
.mul(new decimal_js_1.default(1).plus(flashLoanFee))
|
|
889
|
-
.mul(new decimal_js_1.default(1 + slippagePct / 100))
|
|
890
|
-
.div(priceDebtToColl);
|
|
891
|
-
const _collTokenExpectedSwapOut = depositAmount.mul(new decimal_js_1.default(1).plus(flashLoanFee));
|
|
892
|
-
// 5. Borrow tokens in borrow token reserve that will be swapped to repay flash loan
|
|
893
|
-
const borrowAction = await classes_1.KaminoAction.buildBorrowTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(borrowAmount, debtReserve.stats.decimals).ceil().toString(), debtTokenMint, user, obligation ? obligation : obligationType, 0, false, false, false, // 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)
|
|
777
|
+
// 4. Borrow tokens in borrow token reserve that will be swapped to repay flash loan
|
|
778
|
+
const borrowAction = await classes_1.KaminoAction.buildBorrowTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(calcs.borrowAmount, debtReserve.stats.decimals).ceil().toString(), debtTokenMint, owner, obligation, 0, false, false, false, // 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)
|
|
894
779
|
referrer, currentSlot, { includeScopeRefresh: true, scopeFeed: scopeFeed });
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
...createAtaIxs,
|
|
898
|
-
...[flashBorrowIxn],
|
|
899
|
-
...depositAction.setupIxs,
|
|
900
|
-
...depositAction.lendingIxs,
|
|
901
|
-
...depositAction.cleanupIxs,
|
|
902
|
-
...borrowAction.setupIxs,
|
|
903
|
-
...borrowAction.lendingIxs,
|
|
904
|
-
...borrowAction.cleanupIxs,
|
|
905
|
-
...[flashRepayIxn],
|
|
906
|
-
];
|
|
907
|
-
const uniqueAccounts = new utils_1.PublicKeySet([]);
|
|
908
|
-
klendIxns.forEach((ixn) => {
|
|
909
|
-
ixn.keys.forEach((key) => {
|
|
910
|
-
uniqueAccounts.add(key.pubkey);
|
|
911
|
-
});
|
|
912
|
-
});
|
|
913
|
-
const totalKlendAccounts = uniqueAccounts.toArray().length;
|
|
914
|
-
// return early to avoid extra swapper calls
|
|
915
|
-
if (getTotalKlendAccountsOnly) {
|
|
916
|
-
return {
|
|
917
|
-
ixns: [],
|
|
918
|
-
lookupTablesAddresses: [],
|
|
919
|
-
swapInputs: {
|
|
920
|
-
inputAmountLamports: new decimal_js_1.default('0'),
|
|
921
|
-
inputMint: web3_js_1.PublicKey.default,
|
|
922
|
-
outputMint: web3_js_1.PublicKey.default,
|
|
923
|
-
},
|
|
924
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
925
|
-
};
|
|
926
|
-
}
|
|
927
|
-
let depositSwapper;
|
|
928
|
-
let expectedDebtTokenAtaBalance = new decimal_js_1.default(0);
|
|
929
|
-
if (collIsKtoken) {
|
|
930
|
-
if (kamino === undefined) {
|
|
931
|
-
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
932
|
-
}
|
|
933
|
-
depositSwapper = await (0, utils_2.getTokenToKtokenSwapper)(connection, kaminoMarket, kamino, user, swapper, priceAinB, false);
|
|
934
|
-
expectedDebtTokenAtaBalance = await (0, utils_2.getExpectedTokenBalanceAfterBorrow)(connection, debtTokenMint, user, (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? borrowAmount : amountToFashBorrowDebt, debtReserve.stats.decimals).floor(), debtReserve.state.liquidity.mintDecimals.toNumber());
|
|
935
|
-
}
|
|
936
|
-
else {
|
|
937
|
-
depositSwapper = swapper;
|
|
938
|
-
}
|
|
939
|
-
const swapInputs = {
|
|
940
|
-
inputAmountLamports: (0, classes_2.numberToLamportsDecimal)(!collIsKtoken ? borrowAmount : amountToFashBorrowDebt, debtReserve.stats.decimals).ceil(),
|
|
941
|
-
inputMint: debtTokenMint,
|
|
942
|
-
outputMint: collTokenMint,
|
|
943
|
-
};
|
|
944
|
-
const [swapIxns, lookupTablesAddresses] = await depositSwapper(swapInputs.inputAmountLamports.toNumber(), swapInputs.inputMint, swapInputs.outputMint, slippagePct, expectedDebtTokenAtaBalance);
|
|
945
|
-
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapIxns, []);
|
|
946
|
-
const ixns = !collIsKtoken
|
|
780
|
+
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapQuoteIxs.swapIxs, []);
|
|
781
|
+
const ixs = !collIsKtoken
|
|
947
782
|
? [
|
|
948
783
|
...budgetIxns,
|
|
949
|
-
...
|
|
784
|
+
...atasAndCreateIxns.map((x) => x.createAtaIx),
|
|
950
785
|
...[flashBorrowIxn],
|
|
951
786
|
...depositAction.setupIxs,
|
|
952
787
|
...depositAction.lendingIxs,
|
|
@@ -959,7 +794,7 @@ const getIncreaseLeverageIxns = async (props) => {
|
|
|
959
794
|
]
|
|
960
795
|
: [
|
|
961
796
|
...budgetIxns,
|
|
962
|
-
...
|
|
797
|
+
...atasAndCreateIxns.map((x) => x.createAtaIx),
|
|
963
798
|
...[flashBorrowIxn],
|
|
964
799
|
...swapInstructions,
|
|
965
800
|
...depositAction.setupIxs,
|
|
@@ -970,37 +805,15 @@ const getIncreaseLeverageIxns = async (props) => {
|
|
|
970
805
|
...borrowAction.cleanupIxs,
|
|
971
806
|
...[flashRepayIxn],
|
|
972
807
|
];
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
});
|
|
976
|
-
// Create and send transaction
|
|
977
|
-
if (collIsKtoken) {
|
|
978
|
-
if (strategy?.strategy.strategyLookupTable) {
|
|
979
|
-
lookupTablesAddresses.push(strategy?.strategy.strategyLookupTable);
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
console.log('Strategy lookup table not found');
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
return {
|
|
986
|
-
ixns,
|
|
987
|
-
lookupTablesAddresses,
|
|
988
|
-
swapInputs,
|
|
989
|
-
totalKlendAccounts,
|
|
990
|
-
};
|
|
991
|
-
};
|
|
992
|
-
exports.getIncreaseLeverageIxns = getIncreaseLeverageIxns;
|
|
808
|
+
return ixs;
|
|
809
|
+
}
|
|
993
810
|
/**
|
|
994
811
|
* Withdraw and repay tokens if leverage decreased
|
|
995
812
|
*/
|
|
996
|
-
|
|
997
|
-
const { connection, budgetAndPriorityFeeIxns, user, kaminoMarket, withdrawAmount, repayAmount, collTokenMint, debtTokenMint, slippagePct, swapper, referrer, isKtoken, kamino, obligationTypeTagOverride = 1, obligation, currentSlot, getTotalKlendAccountsOnly, scopeFeed, } = props;
|
|
998
|
-
console.log('getDecreaseLeverageIxns', (0, calcs_1.toJson)({ withdrawAmount, repayAmount, collTokenMint, debtTokenMint, slippagePct }));
|
|
813
|
+
async function buildDecreaseLeverageIxns(owner, kaminoMarket, collTokenMint, debtTokenMint, obligation, referrer, currentSlot, calcs, strategy, scopeFeed, collIsKtoken, swapQuoteIxs, budgetAndPriorityFeeIxns) {
|
|
999
814
|
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
1000
815
|
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
1001
|
-
const
|
|
1002
|
-
const flashLoanFee = debtReserve?.getFlashLoanFee() || new decimal_js_1.default(0);
|
|
1003
|
-
const strategy = collIsKtoken ? await kamino?.getStrategyByKTokenMint(collTokenMint) : undefined;
|
|
816
|
+
const debtTokenAta = (0, spl_token_1.getAssociatedTokenAddressSync)(debtTokenMint, owner);
|
|
1004
817
|
// 1. Create atas & budget txns
|
|
1005
818
|
const budgetIxns = budgetAndPriorityFeeIxns || (0, utils_1.getComputeBudgetAndPriorityFeeIxns)(3000000);
|
|
1006
819
|
let mintsToCreateAtas;
|
|
@@ -1050,105 +863,42 @@ const getDecreaseLeverageIxns = async (props) => {
|
|
|
1050
863
|
},
|
|
1051
864
|
];
|
|
1052
865
|
}
|
|
1053
|
-
const
|
|
866
|
+
const atasAndCreateIxns = (0, utils_1.createAtasIdempotent)(owner, mintsToCreateAtas);
|
|
1054
867
|
// TODO: Mihai/Marius check if we can improve this logic and not convert any SOL
|
|
1055
868
|
// This is here so that we have enough wsol to repay in case the kAB swapped to sol after estimates is not enough
|
|
1056
869
|
const closeWsolAtaIxns = [];
|
|
1057
|
-
if (debtTokenMint.equals(utils_1.WRAPPED_SOL_MINT)) {
|
|
1058
|
-
const wsolAta = await (0, utils_1.getAssociatedTokenAddress)(utils_1.WRAPPED_SOL_MINT, user, false);
|
|
1059
|
-
closeWsolAtaIxns.push((0, spl_token_1.createCloseAccountInstruction)(wsolAta, user, user, [], spl_token_1.TOKEN_PROGRAM_ID));
|
|
1060
|
-
}
|
|
1061
870
|
const fillWsolAtaIxns = [];
|
|
1062
871
|
if (debtTokenMint.equals(utils_1.WRAPPED_SOL_MINT)) {
|
|
1063
|
-
const
|
|
872
|
+
const wsolAta = (0, utils_1.getAssociatedTokenAddress)(utils_1.WRAPPED_SOL_MINT, owner, false);
|
|
873
|
+
closeWsolAtaIxns.push((0, spl_token_1.createCloseAccountInstruction)(wsolAta, owner, owner, [], spl_token_1.TOKEN_PROGRAM_ID));
|
|
874
|
+
const halfSolBalance = (await kaminoMarket.getConnection().getBalance(owner)) / web3_js_1.LAMPORTS_PER_SOL / 2;
|
|
1064
875
|
const balanceToWrap = halfSolBalance < 0.1 ? halfSolBalance : 0.1;
|
|
1065
|
-
fillWsolAtaIxns.push(...(0, utils_1.getDepositWsolIxns)(
|
|
876
|
+
fillWsolAtaIxns.push(...(0, utils_1.getDepositWsolIxns)(owner, wsolAta, (0, classes_2.numberToLamportsDecimal)(balanceToWrap, debtReserve.stats.decimals).ceil()));
|
|
1066
877
|
}
|
|
1067
878
|
// 3. Flash borrow & repay amount to repay (debt)
|
|
1068
879
|
const { flashBorrowIxn, flashRepayIxn } = (0, instructions_1.getFlashLoanInstructions)({
|
|
1069
|
-
borrowIxnIndex: budgetIxns.length +
|
|
1070
|
-
walletPublicKey:
|
|
880
|
+
borrowIxnIndex: budgetIxns.length + atasAndCreateIxns.length + fillWsolAtaIxns.length,
|
|
881
|
+
walletPublicKey: owner,
|
|
1071
882
|
lendingMarketAuthority: kaminoMarket.getLendingMarketAuthority(),
|
|
1072
883
|
lendingMarketAddress: kaminoMarket.getAddress(),
|
|
1073
884
|
reserve: debtReserve,
|
|
1074
|
-
amountLamports: (0, classes_2.numberToLamportsDecimal)(
|
|
885
|
+
amountLamports: (0, classes_2.numberToLamportsDecimal)(decimal_js_1.default.abs(calcs.adjustBorrowPosition), debtReserve.stats.decimals),
|
|
1075
886
|
destinationAta: debtTokenAta,
|
|
1076
887
|
referrerAccount: kaminoMarket.programId,
|
|
1077
888
|
referrerTokenState: kaminoMarket.programId,
|
|
1078
889
|
programId: kaminoMarket.programId,
|
|
1079
890
|
});
|
|
1080
891
|
// 4. Actually do the repay of the flash borrowed amounts
|
|
1081
|
-
let obligationType;
|
|
1082
|
-
if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Multiply) {
|
|
1083
|
-
// multiply
|
|
1084
|
-
obligationType = new utils_1.MultiplyObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
1085
|
-
}
|
|
1086
|
-
else if (obligationTypeTagOverride === utils_1.ObligationTypeTag.Leverage) {
|
|
1087
|
-
// leverage
|
|
1088
|
-
obligationType = new utils_1.LeverageObligation(collTokenMint, debtTokenMint, kaminoMarket.programId);
|
|
1089
|
-
}
|
|
1090
|
-
else {
|
|
1091
|
-
throw Error('Obligation type tag not supported for leverage, please use 1 - multiply or 3 - leverage');
|
|
1092
|
-
}
|
|
1093
892
|
const scopeRefresh = scopeFeed ? { includeScopeRefresh: true, scopeFeed: scopeFeed } : undefined;
|
|
1094
|
-
const repayAction = await classes_1.KaminoAction.buildRepayTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(
|
|
893
|
+
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, currentSlot, undefined, 0, false, false, false, // 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)
|
|
1095
894
|
referrer, scopeRefresh);
|
|
1096
895
|
// 6. Withdraw collateral (a little bit more to be able to pay for the slippage on swap)
|
|
1097
|
-
const
|
|
1098
|
-
.mul(new decimal_js_1.default(1).plus(flashLoanFee))
|
|
1099
|
-
.mul(1 + slippagePct / 100);
|
|
1100
|
-
const withdrawAction = await classes_1.KaminoAction.buildWithdrawTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(withdrawAmountWithSlippageAndFlashLoanFee, collReserve.stats.decimals).ceil().toString(), collTokenMint, user, obligation ? obligation : obligationType, 0, false, false, false, // 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)
|
|
896
|
+
const withdrawAction = await classes_1.KaminoAction.buildWithdrawTxns(kaminoMarket, (0, classes_2.numberToLamportsDecimal)(calcs.withdrawAmountWithSlippageAndFlashLoanFee, collReserve.stats.decimals).ceil().toString(), collTokenMint, owner, obligation, 0, false, false, false, // 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)
|
|
1101
897
|
referrer, currentSlot, { includeScopeRefresh: true, scopeFeed: scopeFeed });
|
|
1102
|
-
const
|
|
1103
|
-
...budgetIxns,
|
|
1104
|
-
...createAtaIxs,
|
|
1105
|
-
...fillWsolAtaIxns,
|
|
1106
|
-
...[flashBorrowIxn],
|
|
1107
|
-
...repayAction.setupIxs,
|
|
1108
|
-
...repayAction.lendingIxs,
|
|
1109
|
-
...repayAction.cleanupIxs,
|
|
1110
|
-
...withdrawAction.setupIxs,
|
|
1111
|
-
...withdrawAction.lendingIxs,
|
|
1112
|
-
...withdrawAction.cleanupIxs,
|
|
1113
|
-
...[flashRepayIxn],
|
|
1114
|
-
...closeWsolAtaIxns,
|
|
1115
|
-
];
|
|
1116
|
-
const uniqueAccs = (0, utils_1.uniqueAccounts)(klendIxns);
|
|
1117
|
-
const totalKlendAccounts = uniqueAccs.length;
|
|
1118
|
-
// return early to avoid extra swapper calls
|
|
1119
|
-
if (getTotalKlendAccountsOnly) {
|
|
1120
|
-
return {
|
|
1121
|
-
ixns: [],
|
|
1122
|
-
lookupTablesAddresses: [],
|
|
1123
|
-
swapInputs: {
|
|
1124
|
-
inputAmountLamports: new decimal_js_1.default('0'),
|
|
1125
|
-
inputMint: web3_js_1.PublicKey.default,
|
|
1126
|
-
outputMint: web3_js_1.PublicKey.default,
|
|
1127
|
-
},
|
|
1128
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
1129
|
-
};
|
|
1130
|
-
}
|
|
1131
|
-
let withdrawSwapper;
|
|
1132
|
-
if (collIsKtoken) {
|
|
1133
|
-
if (kamino === undefined) {
|
|
1134
|
-
throw Error('Ktoken use as collateral for leverage without Kamino instance');
|
|
1135
|
-
}
|
|
1136
|
-
withdrawSwapper = await (0, utils_2.getKtokenToTokenSwapper)(kaminoMarket, kamino, user, swapper);
|
|
1137
|
-
}
|
|
1138
|
-
else {
|
|
1139
|
-
withdrawSwapper = swapper;
|
|
1140
|
-
}
|
|
1141
|
-
const swapInputs = {
|
|
1142
|
-
inputAmountLamports: (0, classes_2.numberToLamportsDecimal)(withdrawAmountWithSlippageAndFlashLoanFee, collReserve.stats.decimals).ceil(),
|
|
1143
|
-
inputMint: collTokenMint,
|
|
1144
|
-
outputMint: debtTokenMint,
|
|
1145
|
-
};
|
|
1146
|
-
// 5. Get swap ixns
|
|
1147
|
-
const [swapIxns, lookupTablesAddresses] = await withdrawSwapper(swapInputs.inputAmountLamports.toNumber(), swapInputs.inputMint, swapInputs.outputMint, slippagePct);
|
|
1148
|
-
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapIxns, []);
|
|
898
|
+
const swapInstructions = (0, utils_1.removeBudgetAndAtaIxns)(swapQuoteIxs.swapIxs, []);
|
|
1149
899
|
const ixns = [
|
|
1150
900
|
...budgetIxns,
|
|
1151
|
-
...
|
|
901
|
+
...atasAndCreateIxns.map((x) => x.createAtaIx),
|
|
1152
902
|
...fillWsolAtaIxns,
|
|
1153
903
|
...[flashBorrowIxn],
|
|
1154
904
|
...repayAction.setupIxs,
|
|
@@ -1161,24 +911,6 @@ const getDecreaseLeverageIxns = async (props) => {
|
|
|
1161
911
|
...[flashRepayIxn],
|
|
1162
912
|
...closeWsolAtaIxns,
|
|
1163
913
|
];
|
|
1164
|
-
ixns
|
|
1165
|
-
|
|
1166
|
-
});
|
|
1167
|
-
if (collIsKtoken) {
|
|
1168
|
-
if (strategy?.strategy.strategyLookupTable) {
|
|
1169
|
-
lookupTablesAddresses.push(strategy?.strategy.strategyLookupTable);
|
|
1170
|
-
}
|
|
1171
|
-
else {
|
|
1172
|
-
console.log('Strategy lookup table not found');
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
// Create and send transaction
|
|
1176
|
-
return {
|
|
1177
|
-
ixns,
|
|
1178
|
-
lookupTablesAddresses,
|
|
1179
|
-
swapInputs,
|
|
1180
|
-
totalKlendAccounts,
|
|
1181
|
-
};
|
|
1182
|
-
};
|
|
1183
|
-
exports.getDecreaseLeverageIxns = getDecreaseLeverageIxns;
|
|
914
|
+
return ixns;
|
|
915
|
+
}
|
|
1184
916
|
//# sourceMappingURL=operations.js.map
|