@kamino-finance/klend-sdk 5.13.7 → 5.13.8
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 +1 -0
- package/dist/classes/obligation.d.ts.map +1 -1
- package/dist/classes/obligation.js +7 -0
- package/dist/classes/obligation.js.map +1 -1
- package/dist/classes/vault.d.ts +9 -1
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +37 -0
- package/dist/classes/vault.js.map +1 -1
- package/dist/classes/vault_types.d.ts +4 -0
- package/dist/classes/vault_types.d.ts.map +1 -1
- package/dist/client_kamino_manager.d.ts.map +1 -1
- package/dist/client_kamino_manager.js +8 -0
- package/dist/client_kamino_manager.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_calcs.d.ts +3 -4
- package/dist/lending_operations/repay_with_collateral_calcs.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_calcs.js +36 -34
- package/dist/lending_operations/repay_with_collateral_calcs.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.d.ts +3 -2
- package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.js +40 -30
- package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
- package/dist/utils/multisig.d.ts +11 -1
- package/dist/utils/multisig.d.ts.map +1 -1
- package/dist/utils/multisig.js +8 -5
- package/dist/utils/multisig.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/obligation.ts +10 -0
- package/src/classes/vault.ts +51 -0
- package/src/classes/vault_types.ts +5 -0
- package/src/client_kamino_manager.ts +9 -0
- package/src/lending_operations/repay_with_collateral_calcs.ts +56 -39
- package/src/lending_operations/repay_with_collateral_operations.ts +84 -33
- package/src/utils/multisig.ts +19 -5
|
@@ -83,14 +83,8 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
83
83
|
flashLoanInfo: FlashLoanInfo;
|
|
84
84
|
initialInputs: RepayWithCollInitialInputs<QuoteResponse>;
|
|
85
85
|
}> {
|
|
86
|
-
const collReserve = kaminoMarket.
|
|
87
|
-
const debtReserve = kaminoMarket.
|
|
88
|
-
if (!collReserve) {
|
|
89
|
-
throw new Error(`Collateral reserve with mint ${collTokenMint} not found in market ${kaminoMarket.getAddress()}`);
|
|
90
|
-
}
|
|
91
|
-
if (!debtReserve) {
|
|
92
|
-
throw new Error(`Debt reserve with mint ${debtTokenMint} not found in market ${kaminoMarket.getAddress()}`);
|
|
93
|
-
}
|
|
86
|
+
const collReserve = kaminoMarket.getExistingReserveByMint(collTokenMint);
|
|
87
|
+
const debtReserve = kaminoMarket.getExistingReserveByMint(debtTokenMint);
|
|
94
88
|
|
|
95
89
|
const {
|
|
96
90
|
repayAmountLamports,
|
|
@@ -110,7 +104,7 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
110
104
|
`Collateral position not found for ${collReserve.stats.symbol} reserve ${collReserve.address} in obligation ${obligation.obligationAddress}`
|
|
111
105
|
);
|
|
112
106
|
}
|
|
113
|
-
const {
|
|
107
|
+
const { maxWithdrawableCollLamports } = calcMaxWithdrawCollateral(
|
|
114
108
|
kaminoMarket,
|
|
115
109
|
obligation,
|
|
116
110
|
collReserve.address,
|
|
@@ -118,14 +112,8 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
118
112
|
repayAmountLamports
|
|
119
113
|
);
|
|
120
114
|
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
.mul(debtReserve.getOracleMarketPrice())
|
|
124
|
-
.div(collReserve.getOracleMarketPrice())
|
|
125
|
-
.mul('1.1')
|
|
126
|
-
.mul(collReserve.getMintFactor())
|
|
127
|
-
.ceil();
|
|
128
|
-
const inputAmountLamports = Decimal.min(withdrawableCollLamports, maxCollNeededFromOracle);
|
|
115
|
+
const maxCollNeededFromOracle = getMaxCollateralFromRepayAmount(finalRepayAmount, debtReserve, collReserve);
|
|
116
|
+
const inputAmountLamports = Decimal.min(maxWithdrawableCollLamports, maxCollNeededFromOracle);
|
|
129
117
|
|
|
130
118
|
// Build the repay & withdraw collateral tx to get the number of accounts
|
|
131
119
|
const klendIxs: LeverageIxsOutput = await buildRepayWithCollateralIxs(
|
|
@@ -153,7 +141,7 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
153
141
|
inputAmountLamports,
|
|
154
142
|
inputMint: collTokenMint,
|
|
155
143
|
outputMint: debtTokenMint,
|
|
156
|
-
amountDebtAtaBalance:
|
|
144
|
+
amountDebtAtaBalance: undefined, // only used for kTokens
|
|
157
145
|
};
|
|
158
146
|
|
|
159
147
|
const swapQuote = await quoter(swapQuoteInputs, uniqueKlendAccounts);
|
|
@@ -171,13 +159,13 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
171
159
|
minOutAmountLamports: flashRepayAmountLamports,
|
|
172
160
|
inputMint: collTokenMint,
|
|
173
161
|
outputMint: debtTokenMint,
|
|
174
|
-
amountDebtAtaBalance:
|
|
162
|
+
amountDebtAtaBalance: undefined, // only used for kTokens
|
|
175
163
|
},
|
|
176
164
|
flashLoanInfo: klendIxs.flashLoanInfo,
|
|
177
165
|
initialInputs: {
|
|
178
166
|
debtRepayAmountLamports: repayAmountLamports,
|
|
179
167
|
flashRepayAmountLamports,
|
|
180
|
-
maxCollateralWithdrawLamports:
|
|
168
|
+
maxCollateralWithdrawLamports: maxWithdrawableCollLamports,
|
|
181
169
|
swapQuote,
|
|
182
170
|
currentSlot,
|
|
183
171
|
klendAccounts: uniqueKlendAccounts,
|
|
@@ -223,17 +211,8 @@ export async function getRepayWithCollIxs<QuoteResponse>({
|
|
|
223
211
|
const { debtRepayAmountLamports, flashRepayAmountLamports, maxCollateralWithdrawLamports, swapQuote } = initialInputs;
|
|
224
212
|
const { inputAmountLamports: collSwapInLamports } = swapInputs;
|
|
225
213
|
|
|
226
|
-
const collReserve = kaminoMarket.
|
|
227
|
-
|
|
228
|
-
if (!collReserve) {
|
|
229
|
-
throw new Error(`Collateral reserve with mint ${collTokenMint} not found in market ${kaminoMarket.getAddress()}`);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint);
|
|
233
|
-
|
|
234
|
-
if (!debtReserve) {
|
|
235
|
-
throw new Error(`Debt reserve with mint ${debtTokenMint} not found in market ${kaminoMarket.getAddress()}`);
|
|
236
|
-
}
|
|
214
|
+
const collReserve = kaminoMarket.getExistingReserveByMint(collTokenMint);
|
|
215
|
+
const debtReserve = kaminoMarket.getExistingReserveByMint(debtTokenMint);
|
|
237
216
|
|
|
238
217
|
// the client should use these values to prevent this input, but the tx may succeed, so we don't want to fail
|
|
239
218
|
// there is also a chance that the tx will consume debt token from the user's ata which they would not expect
|
|
@@ -326,7 +305,13 @@ async function buildRepayWithCollateralIxs(
|
|
|
326
305
|
|
|
327
306
|
const requestElevationGroup = !isClosingPosition && obligation.state.elevationGroup !== 0;
|
|
328
307
|
|
|
329
|
-
const maxWithdrawLtvCheck = getMaxWithdrawLtvCheck(
|
|
308
|
+
const maxWithdrawLtvCheck = getMaxWithdrawLtvCheck(
|
|
309
|
+
obligation,
|
|
310
|
+
debtRepayAmountLamports,
|
|
311
|
+
debtReserve,
|
|
312
|
+
collWithdrawLamports,
|
|
313
|
+
collReserve
|
|
314
|
+
);
|
|
330
315
|
|
|
331
316
|
// 3. Repay using the flash borrowed funds & withdraw collateral to swap and pay the flash loan
|
|
332
317
|
let repayAndWithdrawAction;
|
|
@@ -393,8 +378,74 @@ async function buildRepayWithCollateralIxs(
|
|
|
393
378
|
return res;
|
|
394
379
|
}
|
|
395
380
|
|
|
396
|
-
export const getMaxWithdrawLtvCheck = (
|
|
381
|
+
export const getMaxWithdrawLtvCheck = (
|
|
382
|
+
obligation: KaminoObligation,
|
|
383
|
+
repayAmountLamports: Decimal,
|
|
384
|
+
debtReserve: KaminoReserve,
|
|
385
|
+
collWithdrawAmount: Decimal,
|
|
386
|
+
collReserve: KaminoReserve
|
|
387
|
+
) => {
|
|
388
|
+
const [finalLtv, finalMaxLtv] = calculatePostOperationLtv(
|
|
389
|
+
obligation,
|
|
390
|
+
repayAmountLamports,
|
|
391
|
+
debtReserve,
|
|
392
|
+
collWithdrawAmount,
|
|
393
|
+
collReserve
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
if (finalLtv.lte(finalMaxLtv)) {
|
|
397
|
+
return MaxWithdrawLtvCheck.MAX_LTV;
|
|
398
|
+
}
|
|
399
|
+
|
|
397
400
|
return obligation.refreshedStats.userTotalBorrowBorrowFactorAdjusted.gte(obligation.refreshedStats.borrowLimit)
|
|
398
401
|
? MaxWithdrawLtvCheck.LIQUIDATION_THRESHOLD
|
|
399
402
|
: MaxWithdrawLtvCheck.MAX_LTV;
|
|
400
403
|
};
|
|
404
|
+
|
|
405
|
+
function calculatePostOperationLtv(
|
|
406
|
+
obligation: KaminoObligation,
|
|
407
|
+
repayAmountLamports: Decimal,
|
|
408
|
+
debtReserve: KaminoReserve,
|
|
409
|
+
collWithdrawAmount: Decimal,
|
|
410
|
+
collReserve: KaminoReserve
|
|
411
|
+
): [Decimal, Decimal] {
|
|
412
|
+
const repayValue = repayAmountLamports
|
|
413
|
+
.div(debtReserve.getMintFactor())
|
|
414
|
+
.mul(debtReserve.getOracleMarketPrice())
|
|
415
|
+
.mul(debtReserve.getBorrowFactor());
|
|
416
|
+
const collWithdrawValue = collWithdrawAmount.div(collReserve.getMintFactor()).mul(collReserve.getOracleMarketPrice());
|
|
417
|
+
|
|
418
|
+
// Calculate new borrow value and deposit value
|
|
419
|
+
const newBorrowBfValue = Decimal.max(
|
|
420
|
+
new Decimal(0),
|
|
421
|
+
obligation.refreshedStats.userTotalBorrowBorrowFactorAdjusted.sub(repayValue)
|
|
422
|
+
);
|
|
423
|
+
const newDepositValue = Decimal.max(
|
|
424
|
+
new Decimal(0),
|
|
425
|
+
obligation.refreshedStats.userTotalDeposit.sub(collWithdrawValue)
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
const newMaxBorrowableValue = Decimal.max(
|
|
429
|
+
new Decimal(0),
|
|
430
|
+
obligation.refreshedStats.borrowLimit.sub(collWithdrawValue.mul(collReserve.stats.loanToValue))
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const newMaxLtv = newMaxBorrowableValue.div(newDepositValue);
|
|
434
|
+
|
|
435
|
+
// return final ltv and final max ltv
|
|
436
|
+
return [newBorrowBfValue.div(newDepositValue), newMaxLtv];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export function getMaxCollateralFromRepayAmount(
|
|
440
|
+
repayAmount: Decimal,
|
|
441
|
+
debtReserve: KaminoReserve,
|
|
442
|
+
collReserve: KaminoReserve
|
|
443
|
+
) {
|
|
444
|
+
// sanity check: we have extra collateral to swap, but we want to ensure we don't quote for way more than needed and get a bad px
|
|
445
|
+
return repayAmount
|
|
446
|
+
.mul(debtReserve.getOracleMarketPrice())
|
|
447
|
+
.div(collReserve.getOracleMarketPrice())
|
|
448
|
+
.mul('1.1')
|
|
449
|
+
.mul(collReserve.getMintFactor())
|
|
450
|
+
.ceil();
|
|
451
|
+
}
|
package/src/utils/multisig.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { PublicKey } from '@solana/web3.js';
|
|
2
2
|
|
|
3
|
-
const SQUADS_API_BASE_URL = 'https://4fnetmviidiqkjzenwxe66vgoa0soerr.lambda-url.us-east-1.on.aws
|
|
3
|
+
const SQUADS_API_BASE_URL = 'https://4fnetmviidiqkjzenwxe66vgoa0soerr.lambda-url.us-east-1.on.aws';
|
|
4
4
|
|
|
5
5
|
export async function walletIsSquadsMultisig(wallet: PublicKey) {
|
|
6
|
-
const response = await fetch(`${SQUADS_API_BASE_URL}/
|
|
6
|
+
const response = await fetch(`${SQUADS_API_BASE_URL}/isSquad/${wallet.toBase58()}`);
|
|
7
7
|
const data = await response.json();
|
|
8
8
|
const squadsResponse = data as SquadsMultisigResponse;
|
|
9
9
|
return squadsResponse.isSquad;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// todo: find a way to get the admins number and threshold
|
|
13
|
-
export async function getSquadsMultisigAdminsAndThreshold(
|
|
13
|
+
export async function getSquadsMultisigAdminsAndThreshold(wallet: PublicKey): Promise<{
|
|
14
14
|
adminsNumber: number;
|
|
15
15
|
threshold: number;
|
|
16
16
|
}> {
|
|
17
|
+
const response = await fetch(`${SQUADS_API_BASE_URL}/multisig/${wallet.toBase58()}`);
|
|
18
|
+
const data = await response.json();
|
|
19
|
+
const squadsResponse = data as SquadsMultisigAccountResponse;
|
|
17
20
|
return {
|
|
18
|
-
adminsNumber:
|
|
19
|
-
threshold:
|
|
21
|
+
adminsNumber: squadsResponse.keys.length,
|
|
22
|
+
threshold: squadsResponse.threshold,
|
|
20
23
|
};
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -31,3 +34,14 @@ export interface WalletType {
|
|
|
31
34
|
walletAdminsNumber: number;
|
|
32
35
|
walletThreshold: number;
|
|
33
36
|
}
|
|
37
|
+
|
|
38
|
+
export type SquadsMultisigAccountResponse = {
|
|
39
|
+
allow_external_execute: boolean;
|
|
40
|
+
authority_index: number;
|
|
41
|
+
bump: number;
|
|
42
|
+
create_key: string;
|
|
43
|
+
keys: number[][];
|
|
44
|
+
ms_change_index: number;
|
|
45
|
+
threshold: number;
|
|
46
|
+
transaction_index: number;
|
|
47
|
+
};
|