@kamino-finance/klend-sdk 4.0.1 → 4.1.0
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/README.md +2 -2
- package/dist/classes/action.d.ts +3 -1
- package/dist/classes/action.d.ts.map +1 -1
- package/dist/classes/action.js +62 -61
- package/dist/classes/action.js.map +1 -1
- package/dist/classes/market.d.ts +5 -5
- package/dist/classes/market.d.ts.map +1 -1
- package/dist/classes/market.js +14 -14
- package/dist/classes/market.js.map +1 -1
- package/dist/classes/obligation.d.ts +10 -1
- package/dist/classes/obligation.d.ts.map +1 -1
- package/dist/classes/obligation.js +48 -28
- package/dist/classes/obligation.js.map +1 -1
- package/dist/classes/reserve.d.ts +3 -1
- package/dist/classes/reserve.d.ts.map +1 -1
- package/dist/classes/reserve.js +39 -5
- package/dist/classes/reserve.js.map +1 -1
- package/dist/classes/shared.d.ts +8 -0
- package/dist/classes/shared.d.ts.map +1 -1
- package/dist/classes/shared.js +6 -1
- package/dist/classes/shared.js.map +1 -1
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +19 -5
- package/dist/classes/vault.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_calcs.d.ts +18 -1
- package/dist/lending_operations/repay_with_collateral_calcs.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_calcs.js +62 -0
- package/dist/lending_operations/repay_with_collateral_calcs.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.d.ts +27 -43
- package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.js +99 -152
- package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
- package/dist/leverage/operations.d.ts +14 -3
- package/dist/leverage/operations.d.ts.map +1 -1
- package/dist/leverage/operations.js +184 -128
- package/dist/leverage/operations.js.map +1 -1
- package/dist/utils/ata.d.ts +12 -3
- package/dist/utils/ata.d.ts.map +1 -1
- package/dist/utils/ata.js +26 -39
- package/dist/utils/ata.js.map +1 -1
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +0 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/instruction.d.ts +1 -0
- package/dist/utils/instruction.d.ts.map +1 -1
- package/dist/utils/instruction.js +18 -0
- package/dist/utils/instruction.js.map +1 -1
- package/package.json +3 -3
- package/src/classes/action.ts +92 -98
- package/src/classes/market.ts +19 -20
- package/src/classes/obligation.ts +80 -38
- package/src/classes/reserve.ts +56 -8
- package/src/classes/shared.ts +10 -0
- package/src/classes/vault.ts +23 -19
- package/src/lending_operations/repay_with_collateral_calcs.ts +98 -1
- package/src/lending_operations/repay_with_collateral_operations.ts +233 -253
- package/src/leverage/operations.ts +227 -140
- package/src/utils/ata.ts +33 -56
- package/src/utils/index.ts +0 -2
- package/src/utils/instruction.ts +22 -0
- package/dist/utils/layout.d.ts +0 -14
- package/dist/utils/layout.d.ts.map +0 -1
- package/dist/utils/layout.js +0 -123
- package/dist/utils/layout.js.map +0 -1
- package/dist/utils/syncNative.d.ts +0 -11
- package/dist/utils/syncNative.d.ts.map +0 -1
- package/dist/utils/syncNative.js +0 -45
- package/dist/utils/syncNative.js.map +0 -1
- package/src/global.d.ts +0 -1
- package/src/utils/layout.ts +0 -118
- package/src/utils/syncNative.ts +0 -22
|
@@ -1,224 +1,276 @@
|
|
|
1
1
|
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
2
|
-
import { KaminoAction, KaminoMarket, KaminoObligation,
|
|
3
|
-
import { SwapInputs, SwapIxnsProvider, getFlashLoanInstructions, toJson } from '../leverage';
|
|
2
|
+
import { KaminoAction, KaminoMarket, KaminoObligation, KaminoReserve } from '../classes';
|
|
4
3
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
getFlashLoanInstructions,
|
|
5
|
+
SwapInputs,
|
|
6
|
+
SwapQuote,
|
|
7
|
+
SwapQuoteIxs,
|
|
8
|
+
SwapQuoteIxsProvider,
|
|
9
|
+
SwapQuoteProvider,
|
|
10
|
+
} from '../leverage';
|
|
11
|
+
import {
|
|
12
|
+
createAtasIdempotent,
|
|
9
13
|
getComputeBudgetAndPriorityFeeIxns,
|
|
10
14
|
removeBudgetAndAtaIxns,
|
|
15
|
+
ScopeRefresh,
|
|
16
|
+
U64_MAX,
|
|
17
|
+
uniqueAccounts,
|
|
11
18
|
} from '../utils';
|
|
12
|
-
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
|
19
|
+
import { AddressLookupTableAccount, PublicKey, TransactionInstruction } from '@solana/web3.js';
|
|
13
20
|
import Decimal from 'decimal.js';
|
|
21
|
+
import { calcMaxWithdrawCollateral, calcRepayAmountWithSlippage } from './repay_with_collateral_calcs';
|
|
14
22
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}): {
|
|
21
|
-
repayAmount: Decimal;
|
|
22
|
-
collToSwapIn: Decimal;
|
|
23
|
-
swapDebtExpectedOut: Decimal;
|
|
24
|
-
} => {
|
|
25
|
-
// Initialize local variables from the props object
|
|
26
|
-
const { repayAmount, priceDebtToColl, slippagePct, flashLoanFeePct } = props;
|
|
27
|
-
|
|
28
|
-
const slippage = slippagePct.div('100');
|
|
29
|
-
const flashLoanFee = flashLoanFeePct.div('100');
|
|
30
|
-
|
|
31
|
-
const swapDebtExpectedOut = repayAmount.mul(new Decimal(1.0).add(flashLoanFee));
|
|
32
|
-
const collToSwapIn = swapDebtExpectedOut.mul(new Decimal(1.0).add(slippage)).mul(priceDebtToColl);
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
repayAmount,
|
|
36
|
-
collToSwapIn,
|
|
37
|
-
swapDebtExpectedOut,
|
|
38
|
-
};
|
|
23
|
+
export type RepayWithCollIxsResponse<QuoteResponse> = {
|
|
24
|
+
ixs: TransactionInstruction[];
|
|
25
|
+
lookupTables: AddressLookupTableAccount[];
|
|
26
|
+
swapInputs: SwapInputs;
|
|
27
|
+
initialInputs: InitialInputs<QuoteResponse>;
|
|
39
28
|
};
|
|
40
29
|
|
|
41
|
-
export type InitialInputs = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
export type InitialInputs<QuoteResponse> = {
|
|
31
|
+
debtRepayAmountLamports: Decimal;
|
|
32
|
+
flashRepayAmountLamports: Decimal;
|
|
33
|
+
swapQuote: SwapQuote<QuoteResponse>;
|
|
45
34
|
currentSlot: number;
|
|
35
|
+
klendAccounts: Array<PublicKey>;
|
|
46
36
|
};
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
repayAmount: Decimal;
|
|
50
|
-
priceDebtToColl: Decimal;
|
|
51
|
-
slippagePct: Decimal;
|
|
38
|
+
interface RepayWithCollSwapInputsProps<QuoteResponse> {
|
|
52
39
|
kaminoMarket: KaminoMarket;
|
|
53
40
|
debtTokenMint: PublicKey;
|
|
54
41
|
collTokenMint: PublicKey;
|
|
55
42
|
obligation: KaminoObligation;
|
|
43
|
+
referrer: PublicKey;
|
|
56
44
|
currentSlot: number;
|
|
57
|
-
|
|
45
|
+
repayAmount: Decimal;
|
|
46
|
+
isClosingPosition: boolean;
|
|
47
|
+
budgetAndPriorityFeeIxs?: TransactionInstruction[];
|
|
48
|
+
scopeRefresh?: ScopeRefresh;
|
|
49
|
+
quoter: SwapQuoteProvider<QuoteResponse>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
53
|
+
collTokenMint,
|
|
54
|
+
currentSlot,
|
|
55
|
+
debtTokenMint,
|
|
56
|
+
kaminoMarket,
|
|
57
|
+
obligation,
|
|
58
|
+
quoter,
|
|
59
|
+
referrer,
|
|
60
|
+
repayAmount,
|
|
61
|
+
isClosingPosition,
|
|
62
|
+
budgetAndPriorityFeeIxs,
|
|
63
|
+
scopeRefresh,
|
|
64
|
+
}: RepayWithCollSwapInputsProps<QuoteResponse>): Promise<{
|
|
58
65
|
swapInputs: SwapInputs;
|
|
59
|
-
initialInputs: InitialInputs
|
|
60
|
-
}
|
|
61
|
-
const
|
|
66
|
+
initialInputs: InitialInputs<QuoteResponse>;
|
|
67
|
+
}> {
|
|
68
|
+
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
69
|
+
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
70
|
+
if (!collReserve) {
|
|
71
|
+
throw new Error(`Collateral reserve with mint ${collReserve} not found in market ${kaminoMarket.getAddress()}`);
|
|
72
|
+
}
|
|
73
|
+
if (!debtReserve) {
|
|
74
|
+
throw new Error(`Debt reserve with mint ${debtReserve} not found in market ${kaminoMarket.getAddress()}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { repayAmountLamports, flashRepayAmountLamports } = calcRepayAmountWithSlippage(
|
|
78
|
+
kaminoMarket,
|
|
79
|
+
debtReserve,
|
|
80
|
+
currentSlot,
|
|
81
|
+
obligation,
|
|
62
82
|
repayAmount,
|
|
63
|
-
|
|
64
|
-
|
|
83
|
+
referrer
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const debtPosition = obligation.getBorrowByReserve(debtReserve.address);
|
|
87
|
+
const collPosition = obligation.getDepositByReserve(collReserve.address);
|
|
88
|
+
if (!debtPosition) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Debt position not found for ${debtReserve.stats.symbol} reserve ${debtReserve.address} in obligation ${obligation.obligationAddress}`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (!collPosition) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Collateral position not found for ${collReserve.stats.symbol} reserve ${collReserve.address} in obligation ${obligation.obligationAddress}`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const { withdrawableCollLamports } = calcMaxWithdrawCollateral(
|
|
65
99
|
kaminoMarket,
|
|
66
|
-
|
|
67
|
-
|
|
100
|
+
collReserve.address,
|
|
101
|
+
debtReserve.address,
|
|
68
102
|
obligation,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const collReserve = kaminoMarket.getReserveByMint(collTokenMint);
|
|
72
|
-
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
73
|
-
const flashLoanFeePct = debtReserve?.getFlashLoanFee().ceil() || new Decimal(0);
|
|
103
|
+
repayAmountLamports
|
|
104
|
+
);
|
|
74
105
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
currentSlot
|
|
81
|
-
)
|
|
82
|
-
.toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber()!, Decimal.ROUND_CEIL);
|
|
83
|
-
// add 0.1% to irSlippageBpsForDebt because we don't want to estimate slightly less than SC and end up not repaying enough
|
|
84
|
-
const repayAmountIrAdjusted = repayAmount
|
|
85
|
-
.mul(irSlippageBpsForDebt.mul(new Decimal('1.001')))
|
|
86
|
-
.toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber()!, Decimal.ROUND_CEIL);
|
|
106
|
+
const swapQuoteInputs: SwapInputs = {
|
|
107
|
+
inputAmountLamports: withdrawableCollLamports,
|
|
108
|
+
inputMint: collTokenMint,
|
|
109
|
+
outputMint: debtTokenMint,
|
|
110
|
+
};
|
|
87
111
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
// Build the repay & withdraw collateral tx to get the number of accounts
|
|
113
|
+
const klendIxs = await buildRepayWithCollateralIxs(
|
|
114
|
+
kaminoMarket,
|
|
115
|
+
debtReserve,
|
|
116
|
+
collReserve,
|
|
117
|
+
obligation,
|
|
118
|
+
referrer,
|
|
119
|
+
currentSlot,
|
|
120
|
+
budgetAndPriorityFeeIxs,
|
|
121
|
+
scopeRefresh,
|
|
122
|
+
{
|
|
123
|
+
preActionIxs: [],
|
|
124
|
+
swapIxs: [],
|
|
125
|
+
lookupTables: [],
|
|
126
|
+
},
|
|
127
|
+
isClosingPosition,
|
|
128
|
+
repayAmountLamports,
|
|
129
|
+
withdrawableCollLamports
|
|
130
|
+
);
|
|
131
|
+
const uniqueKlendAccounts = uniqueAccounts(klendIxs);
|
|
132
|
+
const swapQuote = await quoter(swapQuoteInputs, uniqueKlendAccounts);
|
|
133
|
+
|
|
134
|
+
const swapQuotePxDebtToColl = swapQuote.priceAInB;
|
|
135
|
+
const collSwapInLamports = flashRepayAmountLamports.div(debtReserve.getMintFactor()).div(swapQuotePxDebtToColl).mul(collReserve.getMintFactor()).ceil();
|
|
94
136
|
|
|
95
137
|
return {
|
|
96
138
|
swapInputs: {
|
|
97
|
-
inputAmountLamports:
|
|
98
|
-
.ceil()
|
|
99
|
-
.toNumber(),
|
|
139
|
+
inputAmountLamports: collSwapInLamports,
|
|
100
140
|
inputMint: collTokenMint,
|
|
101
141
|
outputMint: debtTokenMint,
|
|
102
142
|
},
|
|
103
143
|
initialInputs: {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
144
|
+
debtRepayAmountLamports: repayAmountLamports,
|
|
145
|
+
flashRepayAmountLamports,
|
|
146
|
+
swapQuote,
|
|
107
147
|
currentSlot,
|
|
148
|
+
klendAccounts: uniqueKlendAccounts,
|
|
108
149
|
},
|
|
109
150
|
};
|
|
110
|
-
}
|
|
151
|
+
}
|
|
111
152
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
initialInputs: InitialInputs;
|
|
134
|
-
}> => {
|
|
135
|
-
const {
|
|
136
|
-
kaminoMarket,
|
|
137
|
-
budgetAndPriorityFeeIxns,
|
|
138
|
-
amount,
|
|
139
|
-
debtTokenMint,
|
|
153
|
+
interface RepayWithCollIxsProps<QuoteResponse> extends RepayWithCollSwapInputsProps<QuoteResponse> {
|
|
154
|
+
swapper: SwapQuoteIxsProvider<QuoteResponse>;
|
|
155
|
+
logger?: (msg: string, ...extra: any[]) => void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export async function getRepayWithCollIxs<QuoteResponse>({
|
|
159
|
+
repayAmount,
|
|
160
|
+
isClosingPosition,
|
|
161
|
+
budgetAndPriorityFeeIxs,
|
|
162
|
+
collTokenMint,
|
|
163
|
+
currentSlot,
|
|
164
|
+
debtTokenMint,
|
|
165
|
+
kaminoMarket,
|
|
166
|
+
obligation,
|
|
167
|
+
quoter,
|
|
168
|
+
swapper,
|
|
169
|
+
referrer,
|
|
170
|
+
scopeRefresh,
|
|
171
|
+
logger = console.log,
|
|
172
|
+
}: RepayWithCollIxsProps<QuoteResponse>): Promise<RepayWithCollIxsResponse<QuoteResponse>> {
|
|
173
|
+
const { swapInputs, initialInputs } = await getRepayWithCollSwapInputs({
|
|
140
174
|
collTokenMint,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
isClosingPosition,
|
|
175
|
+
currentSlot,
|
|
176
|
+
debtTokenMint,
|
|
177
|
+
kaminoMarket,
|
|
145
178
|
obligation,
|
|
179
|
+
quoter,
|
|
146
180
|
referrer,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
181
|
+
repayAmount,
|
|
182
|
+
isClosingPosition,
|
|
183
|
+
budgetAndPriorityFeeIxs,
|
|
150
184
|
scopeRefresh,
|
|
151
|
-
}
|
|
185
|
+
});
|
|
186
|
+
const { debtRepayAmountLamports, flashRepayAmountLamports, swapQuote } = initialInputs;
|
|
187
|
+
const { inputAmountLamports: collSwapInLamports } = swapInputs;
|
|
152
188
|
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
156
|
-
// const solTokenReserve = kaminoMarket.getReserveByMint(WRAPPED_SOL_MINT);
|
|
157
|
-
const flashLoanFeePct = debtReserve?.getFlashLoanFee() || new Decimal(0);
|
|
189
|
+
const collReserve = kaminoMarket.getReserveByMint(collTokenMint)!;
|
|
190
|
+
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint)!;
|
|
158
191
|
|
|
159
|
-
|
|
160
|
-
.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
.toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber()!, Decimal.ROUND_CEIL);
|
|
167
|
-
// add 0.1% to irSlippageBpsForDebt because we don't want to estimate slightly less than SC and end up not reapying enough
|
|
168
|
-
const repayAmount = amount
|
|
169
|
-
.mul(irSlippageBpsForDebt.mul(new Decimal('1.001')))
|
|
170
|
-
.toDecimalPlaces(debtReserve?.state.liquidity.mintDecimals.toNumber()!, Decimal.ROUND_CEIL);
|
|
192
|
+
logger(
|
|
193
|
+
`Expected to swap in: ${collSwapInLamports.div(collReserve.getMintFactor())} ${
|
|
194
|
+
collReserve.symbol
|
|
195
|
+
}, for: ${flashRepayAmountLamports.div(debtReserve.getMintFactor())} ${debtReserve.symbol}, quoter px: ${
|
|
196
|
+
swapQuote.priceAInB
|
|
197
|
+
} ${debtReserve.symbol}/${collReserve.symbol}`
|
|
198
|
+
);
|
|
171
199
|
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
200
|
+
const swapResponse = await swapper(swapInputs, initialInputs.klendAccounts, swapQuote);
|
|
201
|
+
const ixs = await buildRepayWithCollateralIxs(
|
|
202
|
+
kaminoMarket,
|
|
203
|
+
debtReserve,
|
|
204
|
+
collReserve,
|
|
205
|
+
obligation,
|
|
206
|
+
referrer,
|
|
207
|
+
currentSlot,
|
|
208
|
+
budgetAndPriorityFeeIxs,
|
|
209
|
+
scopeRefresh,
|
|
210
|
+
swapResponse,
|
|
211
|
+
isClosingPosition,
|
|
212
|
+
debtRepayAmountLamports,
|
|
213
|
+
swapInputs.inputAmountLamports
|
|
214
|
+
);
|
|
178
215
|
|
|
179
|
-
|
|
216
|
+
return {
|
|
217
|
+
ixs,
|
|
218
|
+
lookupTables: swapResponse.lookupTables,
|
|
219
|
+
swapInputs,
|
|
220
|
+
initialInputs,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function buildRepayWithCollateralIxs(
|
|
225
|
+
market: KaminoMarket,
|
|
226
|
+
debtReserve: KaminoReserve,
|
|
227
|
+
collReserve: KaminoReserve,
|
|
228
|
+
obligation: KaminoObligation,
|
|
229
|
+
referrer: PublicKey,
|
|
230
|
+
currentSlot: number,
|
|
231
|
+
budgetAndPriorityFeeIxs: TransactionInstruction[] | undefined,
|
|
232
|
+
scopeRefresh: ScopeRefresh | undefined,
|
|
233
|
+
swapQuoteIxs: SwapQuoteIxs,
|
|
234
|
+
isClosingPosition: boolean,
|
|
235
|
+
debtRepayAmountLamports: Decimal,
|
|
236
|
+
collWithdrawLamports: Decimal
|
|
237
|
+
): Promise<TransactionInstruction[]> {
|
|
238
|
+
// 1. Create atas & budget txns
|
|
239
|
+
const budgetIxns = budgetAndPriorityFeeIxs || getComputeBudgetAndPriorityFeeIxns(1_400_000);
|
|
180
240
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
collReserve
|
|
185
|
-
debtReserve?.getLiquidityTokenProgram()!,
|
|
186
|
-
TOKEN_PROGRAM_ID,
|
|
241
|
+
const atas = [
|
|
242
|
+
{ mint: collReserve.getLiquidityMint(), tokenProgram: collReserve.getLiquidityTokenProgram() },
|
|
243
|
+
{ mint: debtReserve.getLiquidityMint(), tokenProgram: debtReserve.getLiquidityTokenProgram() },
|
|
244
|
+
{ mint: collReserve.getCTokenMint(), tokenProgram: TOKEN_PROGRAM_ID },
|
|
187
245
|
];
|
|
188
246
|
|
|
189
|
-
const
|
|
190
|
-
const {
|
|
191
|
-
atas: [, debtTokenAta],
|
|
192
|
-
createAtasIxns,
|
|
193
|
-
closeAtasIxns,
|
|
194
|
-
} = await getAtasWithCreateIxnsIfMissing(connection, owner, mintsToCreateAtas, mintsToCreateAtasTokenPrograms);
|
|
247
|
+
const atasAndIxs = createAtasIdempotent(obligation.state.owner, atas);
|
|
248
|
+
const [, { ata: debtTokenAta }] = atasAndIxs;
|
|
195
249
|
|
|
196
|
-
//
|
|
250
|
+
// 2. Flash borrow & repay the debt to repay amount needed
|
|
197
251
|
const { flashBorrowIxn, flashRepayIxn } = getFlashLoanInstructions({
|
|
198
|
-
borrowIxnIndex: budgetIxns.length +
|
|
199
|
-
walletPublicKey: owner,
|
|
200
|
-
lendingMarketAuthority:
|
|
201
|
-
lendingMarketAddress:
|
|
202
|
-
reserve: debtReserve
|
|
203
|
-
amountLamports:
|
|
252
|
+
borrowIxnIndex: budgetIxns.length + atasAndIxs.length,
|
|
253
|
+
walletPublicKey: obligation.state.owner,
|
|
254
|
+
lendingMarketAuthority: market.getLendingMarketAuthority(),
|
|
255
|
+
lendingMarketAddress: market.getAddress(),
|
|
256
|
+
reserve: debtReserve,
|
|
257
|
+
amountLamports: debtRepayAmountLamports,
|
|
204
258
|
destinationAta: debtTokenAta,
|
|
205
|
-
referrerAccount:
|
|
206
|
-
referrerTokenState:
|
|
207
|
-
programId:
|
|
259
|
+
referrerAccount: market.programId,
|
|
260
|
+
referrerTokenState: market.programId,
|
|
261
|
+
programId: market.programId,
|
|
208
262
|
});
|
|
209
263
|
|
|
210
|
-
const requestElevationGroup = obligation.state.elevationGroup !== 0
|
|
264
|
+
const requestElevationGroup = !isClosingPosition && obligation.state.elevationGroup !== 0;
|
|
211
265
|
|
|
212
|
-
//
|
|
266
|
+
// 3. Repay using the flash borrowed funds & withdraw collateral to swap and pay the flash loan
|
|
213
267
|
const repayAndWithdrawAction = await KaminoAction.buildRepayAndWithdrawTxns(
|
|
214
|
-
|
|
215
|
-
isClosingPosition ? U64_MAX :
|
|
216
|
-
|
|
217
|
-
isClosingPosition
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
new PublicKey(collTokenMint),
|
|
221
|
-
owner,
|
|
268
|
+
market,
|
|
269
|
+
isClosingPosition ? U64_MAX : debtRepayAmountLamports.toString(),
|
|
270
|
+
debtReserve.getLiquidityMint(),
|
|
271
|
+
isClosingPosition ? U64_MAX : collWithdrawLamports.toString(),
|
|
272
|
+
collReserve.getLiquidityMint(),
|
|
273
|
+
obligation.state.owner,
|
|
222
274
|
currentSlot,
|
|
223
275
|
obligation,
|
|
224
276
|
0,
|
|
@@ -230,89 +282,17 @@ export const getRepayWithCollIxns = async (props: {
|
|
|
230
282
|
scopeRefresh
|
|
231
283
|
);
|
|
232
284
|
|
|
233
|
-
|
|
285
|
+
// 4. Swap collateral to debt to repay flash loan
|
|
286
|
+
const { preActionIxs, swapIxs } = swapQuoteIxs;
|
|
287
|
+
const swapInstructions = removeBudgetAndAtaIxns(swapIxs, []);
|
|
288
|
+
|
|
289
|
+
return [
|
|
234
290
|
...budgetIxns,
|
|
235
|
-
...
|
|
236
|
-
|
|
237
|
-
...
|
|
238
|
-
...
|
|
239
|
-
...
|
|
240
|
-
|
|
241
|
-
...repayAndWithdrawAction.cleanupIxs,
|
|
242
|
-
...[flashRepayIxn],
|
|
243
|
-
...closeAtasIxns,
|
|
291
|
+
...atasAndIxs.map((x) => x.createAtaIx),
|
|
292
|
+
flashBorrowIxn,
|
|
293
|
+
...preActionIxs,
|
|
294
|
+
...KaminoAction.actionToIxs(repayAndWithdrawAction),
|
|
295
|
+
...swapInstructions,
|
|
296
|
+
flashRepayIxn,
|
|
244
297
|
];
|
|
245
|
-
|
|
246
|
-
const uniqueAccounts = new PublicKeySet<PublicKey>([]);
|
|
247
|
-
ixns.forEach((ixn) => {
|
|
248
|
-
ixn.keys.forEach((key) => {
|
|
249
|
-
uniqueAccounts.add(key.pubkey);
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
const totalKlendAccounts = uniqueAccounts.toArray().length;
|
|
253
|
-
|
|
254
|
-
// return early to avoid extra swapper calls
|
|
255
|
-
if (getTotalKlendAccountsOnly) {
|
|
256
|
-
return {
|
|
257
|
-
ixns: [],
|
|
258
|
-
lookupTablesAddresses: [],
|
|
259
|
-
swapInputs: { inputAmountLamports: 0, inputMint: PublicKey.default, outputMint: PublicKey.default },
|
|
260
|
-
totalKlendAccounts: totalKlendAccounts,
|
|
261
|
-
initialInputs: {
|
|
262
|
-
repayAmount,
|
|
263
|
-
priceDebtToColl,
|
|
264
|
-
slippagePct,
|
|
265
|
-
currentSlot,
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
console.log(
|
|
271
|
-
'Expected to swap in',
|
|
272
|
-
calcs.collToSwapIn.toString(),
|
|
273
|
-
'coll for',
|
|
274
|
-
calcs.swapDebtExpectedOut.toString(),
|
|
275
|
-
'debt'
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
const swapInputs: SwapInputs = {
|
|
279
|
-
inputAmountLamports: numberToLamportsDecimal(calcs.collToSwapIn, collReserve!.stats.decimals).ceil().toNumber(),
|
|
280
|
-
inputMint: collTokenMint,
|
|
281
|
-
outputMint: debtTokenMint,
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
// 3. Swap collateral to debt to repay flash loan
|
|
285
|
-
const [swapIxns, lookupTablesAddresses] = await swapper(
|
|
286
|
-
swapInputs.inputAmountLamports,
|
|
287
|
-
swapInputs.inputMint,
|
|
288
|
-
swapInputs.outputMint,
|
|
289
|
-
slippagePct.toNumber()
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
const swapInstructions = removeBudgetAndAtaIxns(swapIxns, []);
|
|
293
|
-
|
|
294
|
-
return {
|
|
295
|
-
ixns: [
|
|
296
|
-
...budgetIxns,
|
|
297
|
-
...createAtasIxns,
|
|
298
|
-
...[flashBorrowIxn],
|
|
299
|
-
...repayAndWithdrawAction.setupIxs,
|
|
300
|
-
...[repayAndWithdrawAction.lendingIxs[0]],
|
|
301
|
-
...repayAndWithdrawAction.inBetweenIxs,
|
|
302
|
-
...[repayAndWithdrawAction.lendingIxs[1]],
|
|
303
|
-
...repayAndWithdrawAction.cleanupIxs,
|
|
304
|
-
...swapInstructions,
|
|
305
|
-
...[flashRepayIxn],
|
|
306
|
-
...closeAtasIxns,
|
|
307
|
-
],
|
|
308
|
-
lookupTablesAddresses,
|
|
309
|
-
swapInputs,
|
|
310
|
-
totalKlendAccounts,
|
|
311
|
-
initialInputs: {
|
|
312
|
-
repayAmount,
|
|
313
|
-
priceDebtToColl,
|
|
314
|
-
slippagePct,
|
|
315
|
-
currentSlot,
|
|
316
|
-
},
|
|
317
|
-
};
|
|
318
|
-
};
|
|
298
|
+
}
|