@kamino-finance/klend-sdk 5.2.13 → 5.2.14
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 +2 -0
- package/dist/classes/obligation.d.ts.map +1 -1
- package/dist/classes/obligation.js +12 -6
- package/dist/classes/obligation.js.map +1 -1
- package/dist/classes/types.d.ts +1 -1
- package/dist/classes/types.d.ts.map +1 -1
- package/dist/classes/vault.d.ts +1 -1
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +16 -3
- package/dist/classes/vault.js.map +1 -1
- package/dist/client_kamino_manager.d.ts.map +1 -1
- package/dist/client_kamino_manager.js +38 -4
- package/dist/client_kamino_manager.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_calcs.d.ts +4 -2
- package/dist/lending_operations/repay_with_collateral_calcs.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_calcs.js +45 -52
- package/dist/lending_operations/repay_with_collateral_calcs.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.d.ts +7 -0
- package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.js +13 -3
- package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/obligation.ts +15 -6
- package/src/classes/types.ts +16 -17
- package/src/classes/vault.ts +18 -4
- package/src/client_kamino_manager.ts +55 -4
- package/src/lending_operations/repay_with_collateral_calcs.ts +55 -61
- package/src/lending_operations/repay_with_collateral_operations.ts +24 -4
- package/src/leverage/operations.ts +1 -1
|
@@ -76,79 +76,73 @@ export const calcFlashRepayAmount = (props: {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export function calcMaxWithdrawCollateral(
|
|
79
|
-
|
|
79
|
+
market: KaminoMarket,
|
|
80
|
+
obligation: KaminoObligation,
|
|
80
81
|
collReserveAddr: PublicKey,
|
|
81
82
|
debtReserveAddr: PublicKey,
|
|
82
|
-
obligation: KaminoObligation,
|
|
83
83
|
repayAmountLamports: Decimal
|
|
84
84
|
): {
|
|
85
|
-
|
|
85
|
+
repayAmountLamports: Decimal;
|
|
86
86
|
withdrawableCollLamports: Decimal;
|
|
87
|
+
canWithdrawAllColl: boolean;
|
|
88
|
+
repayingAllDebt: boolean;
|
|
87
89
|
} {
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (debtPosition.reserveAddress.equals(debtReserveAddr)) {
|
|
103
|
-
remainingDebtAmountLamports = remainingDebtAmountLamports.sub(repayAmountLamports);
|
|
104
|
-
}
|
|
105
|
-
const remainingDebtBfWeightedValue = remainingDebtAmountLamports
|
|
106
|
-
.ceil()
|
|
107
|
-
.div(debtReserve.getMintFactor())
|
|
108
|
-
.mul(debtBorrowFactor)
|
|
109
|
-
.mul(debtOraclePx);
|
|
110
|
-
totalRemainingDebtValue = totalRemainingDebtValue.add(remainingDebtBfWeightedValue);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let canWithdrawRemainingColl = false;
|
|
114
|
-
if (totalRemainingDebtValue.lte(new Decimal(0)) && borrows.length === 1) {
|
|
115
|
-
canWithdrawRemainingColl = true;
|
|
90
|
+
const deposit = obligation.getDepositByReserve(collReserveAddr)!;
|
|
91
|
+
const borrow = obligation.getBorrowByReserve(debtReserveAddr)!;
|
|
92
|
+
const depositReserve = market.getReserveByAddress(deposit.reserveAddress)!;
|
|
93
|
+
const debtReserve = market.getReserveByAddress(borrow.reserveAddress)!;
|
|
94
|
+
const depositTotalLamports = deposit.amount.floor();
|
|
95
|
+
|
|
96
|
+
const remainingBorrowLamports = borrow.amount.sub(repayAmountLamports).ceil();
|
|
97
|
+
const remainingBorrowAmount = remainingBorrowLamports.div(debtReserve.getMintFactor());
|
|
98
|
+
let remainingBorrowsValue = remainingBorrowAmount.mul(debtReserve.getOracleMarketPrice());
|
|
99
|
+
if (obligation.getBorrows().length > 1) {
|
|
100
|
+
remainingBorrowsValue = obligation
|
|
101
|
+
.getBorrows()
|
|
102
|
+
.filter((p) => !p.reserveAddress.equals(borrow.reserveAddress))
|
|
103
|
+
.reduce((acc, b) => acc.add(b.marketValueRefreshed), new Decimal('0'));
|
|
116
104
|
}
|
|
117
105
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
.floor()
|
|
128
|
-
.div(otherCollReserve.getMintFactor())
|
|
129
|
-
.mul(otherCollOraclePx)
|
|
130
|
-
.mul(otherCollMaxLtv);
|
|
131
|
-
totalOtherCollateralValue = totalOtherCollateralValue.add(otherCollValue);
|
|
106
|
+
let remainingDepositsValueWithLtv = new Decimal('0');
|
|
107
|
+
if (obligation.getDeposits().length > 1) {
|
|
108
|
+
remainingDepositsValueWithLtv = obligation
|
|
109
|
+
.getDeposits()
|
|
110
|
+
.filter((p) => !p.reserveAddress.equals(deposit.reserveAddress))
|
|
111
|
+
.reduce((acc, d) => {
|
|
112
|
+
const { maxLtv } = obligation.getLtvForReserve(market, market.getReserveByAddress(d.reserveAddress)!);
|
|
113
|
+
return acc.add(d.marketValueRefreshed.mul(maxLtv));
|
|
114
|
+
}, new Decimal('0'));
|
|
132
115
|
}
|
|
133
116
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const maxCollWithdrawAmount = numerator.div(denominator);
|
|
143
|
-
const maxCollateralWithdrawalAmountLamports = maxCollWithdrawAmount.mul(collReserve.getMintFactor()).floor();
|
|
144
|
-
|
|
145
|
-
let withdrawableCollLamports: Decimal;
|
|
146
|
-
if (canWithdrawRemainingColl) {
|
|
147
|
-
withdrawableCollLamports = Decimal.min(maxCollateralWithdrawalAmountLamports, collPosition.amount).floor();
|
|
117
|
+
// can withdraw all coll
|
|
118
|
+
if (remainingDepositsValueWithLtv.gte(remainingBorrowsValue)) {
|
|
119
|
+
return {
|
|
120
|
+
repayAmountLamports: repayAmountLamports,
|
|
121
|
+
withdrawableCollLamports: depositTotalLamports,
|
|
122
|
+
canWithdrawAllColl: true,
|
|
123
|
+
repayingAllDebt: repayAmountLamports.gte(borrow.amount),
|
|
124
|
+
};
|
|
148
125
|
} else {
|
|
149
|
-
|
|
126
|
+
const { maxLtv: collMaxLtv } = obligation.getLtvForReserve(
|
|
127
|
+
market,
|
|
128
|
+
market.getReserveByAddress(depositReserve.address)!
|
|
129
|
+
);
|
|
130
|
+
const numerator = deposit.marketValueRefreshed
|
|
131
|
+
.mul(collMaxLtv)
|
|
132
|
+
.add(remainingDepositsValueWithLtv)
|
|
133
|
+
.sub(remainingBorrowsValue);
|
|
134
|
+
|
|
135
|
+
const denominator = depositReserve.getOracleMarketPrice().mul(collMaxLtv);
|
|
136
|
+
const maxCollWithdrawAmount = numerator.div(denominator);
|
|
137
|
+
const withdrawableCollLamports = maxCollWithdrawAmount.mul(depositReserve.getMintFactor()).floor();
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
repayAmountLamports: repayAmountLamports,
|
|
141
|
+
withdrawableCollLamports,
|
|
142
|
+
canWithdrawAllColl: false,
|
|
143
|
+
repayingAllDebt: repayAmountLamports.gte(borrow.amount),
|
|
144
|
+
};
|
|
150
145
|
}
|
|
151
|
-
return { canWithdrawRemainingColl, withdrawableCollLamports };
|
|
152
146
|
}
|
|
153
147
|
|
|
154
148
|
export function estimateDebtRepaymentWithColl(props: {
|
|
@@ -29,6 +29,13 @@ export type RepayWithCollIxsResponse<QuoteResponse> = {
|
|
|
29
29
|
export type InitialInputs<QuoteResponse> = {
|
|
30
30
|
debtRepayAmountLamports: Decimal;
|
|
31
31
|
flashRepayAmountLamports: Decimal;
|
|
32
|
+
/**
|
|
33
|
+
* The amount of collateral available to withdraw, if this is less than the swap input amount, then the swap may fail due to slippage, or tokens may be debited from the user's ATA, so the caller needs to check this
|
|
34
|
+
*/
|
|
35
|
+
maxCollateralWithdrawLamports: Decimal;
|
|
36
|
+
/**
|
|
37
|
+
* The quote from the provided quoter
|
|
38
|
+
*/
|
|
32
39
|
swapQuote: SwapQuote<QuoteResponse>;
|
|
33
40
|
currentSlot: number;
|
|
34
41
|
klendAccounts: Array<PublicKey>;
|
|
@@ -93,9 +100,9 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
93
100
|
}
|
|
94
101
|
const { withdrawableCollLamports } = calcMaxWithdrawCollateral(
|
|
95
102
|
kaminoMarket,
|
|
103
|
+
obligation,
|
|
96
104
|
collReserve.address,
|
|
97
105
|
debtReserve.address,
|
|
98
|
-
obligation,
|
|
99
106
|
repayAmountLamports
|
|
100
107
|
);
|
|
101
108
|
|
|
@@ -156,6 +163,7 @@ export async function getRepayWithCollSwapInputs<QuoteResponse>({
|
|
|
156
163
|
initialInputs: {
|
|
157
164
|
debtRepayAmountLamports: repayAmountLamports,
|
|
158
165
|
flashRepayAmountLamports,
|
|
166
|
+
maxCollateralWithdrawLamports: withdrawableCollLamports,
|
|
159
167
|
swapQuote,
|
|
160
168
|
currentSlot,
|
|
161
169
|
klendAccounts: uniqueKlendAccounts,
|
|
@@ -196,18 +204,30 @@ export async function getRepayWithCollIxs<QuoteResponse>({
|
|
|
196
204
|
budgetAndPriorityFeeIxs,
|
|
197
205
|
scopeRefresh,
|
|
198
206
|
});
|
|
199
|
-
const { debtRepayAmountLamports, flashRepayAmountLamports, swapQuote } = initialInputs;
|
|
207
|
+
const { debtRepayAmountLamports, flashRepayAmountLamports, maxCollateralWithdrawLamports, swapQuote } = initialInputs;
|
|
200
208
|
const { inputAmountLamports: collSwapInLamports } = swapInputs;
|
|
201
209
|
|
|
202
210
|
const collReserve = kaminoMarket.getReserveByMint(collTokenMint)!;
|
|
203
211
|
const debtReserve = kaminoMarket.getReserveByMint(debtTokenMint)!;
|
|
204
212
|
|
|
213
|
+
// the client should use these values to prevent this input, but the tx may succeed, so we don't want to fail
|
|
214
|
+
// there is also a chance that the tx will consume debt token from the user's ata which they would not expect
|
|
215
|
+
if (collSwapInLamports.greaterThan(maxCollateralWithdrawLamports)) {
|
|
216
|
+
logger(
|
|
217
|
+
`Collateral swap in amount ${collSwapInLamports} exceeds max withdrawable collateral ${maxCollateralWithdrawLamports}, tx may fail with slippage`
|
|
218
|
+
);
|
|
219
|
+
swapInputs.inputAmountLamports = maxCollateralWithdrawLamports;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const actualSwapInLamports = Decimal.min(collSwapInLamports, maxCollateralWithdrawLamports);
|
|
205
223
|
logger(
|
|
206
|
-
`Expected to swap in: ${
|
|
224
|
+
`Expected to swap in: ${actualSwapInLamports.div(collReserve.getMintFactor())} ${
|
|
207
225
|
collReserve.symbol
|
|
208
226
|
}, for: ${flashRepayAmountLamports.div(debtReserve.getMintFactor())} ${debtReserve.symbol}, quoter px: ${
|
|
209
227
|
swapQuote.priceAInB
|
|
210
|
-
} ${debtReserve.symbol}/${collReserve.symbol}
|
|
228
|
+
} ${debtReserve.symbol}/${collReserve.symbol}, required px: ${flashRepayAmountLamports
|
|
229
|
+
.div(debtReserve.getMintFactor())
|
|
230
|
+
.div(actualSwapInLamports.div(collReserve.getMintFactor()))} ${debtReserve.symbol}/${collReserve.symbol}`
|
|
211
231
|
);
|
|
212
232
|
|
|
213
233
|
const swapResponse = await swapper(swapInputs, initialInputs.klendAccounts, swapQuote);
|
|
@@ -1045,7 +1045,7 @@ export async function getAdjustLeverageSwapInputs<QuoteResponse>({
|
|
|
1045
1045
|
|
|
1046
1046
|
const swapInputAmount = toLamports(
|
|
1047
1047
|
!collIsKtoken ? calcs.borrowAmount : calcs.amountToFlashBorrowDebt,
|
|
1048
|
-
debtReserve.stats.decimals
|
|
1048
|
+
debtReserve.stats.decimals
|
|
1049
1049
|
).ceil();
|
|
1050
1050
|
|
|
1051
1051
|
const swapInputsForQuote: SwapInputs = {
|