@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
package/src/classes/action.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
NATIVE_MINT,
|
|
16
16
|
TOKEN_PROGRAM_ID,
|
|
17
17
|
createCloseAccountInstruction,
|
|
18
|
+
createSyncNativeInstruction,
|
|
18
19
|
} from '@solana/spl-token';
|
|
19
20
|
import BN from 'bn.js';
|
|
20
21
|
import Decimal from 'decimal.js';
|
|
@@ -47,7 +48,6 @@ import {
|
|
|
47
48
|
buildComputeBudgetIx,
|
|
48
49
|
createAssociatedTokenAccountIdempotentInstruction,
|
|
49
50
|
ObligationType,
|
|
50
|
-
syncNative,
|
|
51
51
|
U64_MAX,
|
|
52
52
|
referrerTokenStatePda,
|
|
53
53
|
userMetadataPda,
|
|
@@ -1043,14 +1043,14 @@ export class KaminoAction {
|
|
|
1043
1043
|
kaminoMarket: KaminoMarket,
|
|
1044
1044
|
currentSlot: number = 0
|
|
1045
1045
|
) {
|
|
1046
|
-
const { axn,
|
|
1046
|
+
const { axn, createAtaIxs } = await KaminoAction.initializeWithdrawReferrerFees(
|
|
1047
1047
|
tokenMint,
|
|
1048
1048
|
owner,
|
|
1049
1049
|
kaminoMarket,
|
|
1050
1050
|
currentSlot
|
|
1051
1051
|
);
|
|
1052
1052
|
|
|
1053
|
-
axn.preTxnIxs.push(...
|
|
1053
|
+
axn.preTxnIxs.push(...createAtaIxs);
|
|
1054
1054
|
axn.preTxnIxsLabels.push(`createAtasIxs[${axn.userTokenAccountAddress.toString()}]`);
|
|
1055
1055
|
|
|
1056
1056
|
axn.addRefreshReserveIxs([axn.reserve.address]);
|
|
@@ -2445,70 +2445,57 @@ export class KaminoAction {
|
|
|
2445
2445
|
}
|
|
2446
2446
|
|
|
2447
2447
|
if ((action === 'withdraw' || action === 'borrow' || action === 'redeem') && !this.mint.equals(WRAPPED_SOL_MINT)) {
|
|
2448
|
-
const
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
this.reserve.getLiquidityTokenProgram(),
|
|
2456
|
-
this.userTokenAccountAddress
|
|
2457
|
-
);
|
|
2448
|
+
const [, createUserTokenAccountIx] = createAssociatedTokenAccountIdempotentInstruction(
|
|
2449
|
+
this.owner,
|
|
2450
|
+
this.reserve.getLiquidityMint(),
|
|
2451
|
+
this.owner,
|
|
2452
|
+
this.reserve.getLiquidityTokenProgram(),
|
|
2453
|
+
this.userTokenAccountAddress
|
|
2454
|
+
);
|
|
2458
2455
|
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
}
|
|
2456
|
+
if (this.positions === POSITION_LIMIT) {
|
|
2457
|
+
this.preTxnIxs.push(createUserTokenAccountIx);
|
|
2458
|
+
this.preTxnIxsLabels.push(`CreateLiquidityUserAta[${this.owner}]`);
|
|
2459
|
+
} else {
|
|
2460
|
+
this.setupIxs.unshift(createUserTokenAccountIx);
|
|
2461
|
+
this.setupIxsLabels.unshift(`CreateLiquidityUserAta[${this.owner}]`);
|
|
2466
2462
|
}
|
|
2467
2463
|
}
|
|
2468
2464
|
|
|
2469
2465
|
if (action === 'liquidate') {
|
|
2470
|
-
const userTokenAccountInfo = await this.kaminoMarket.getConnection().getAccountInfo(this.userTokenAccountAddress);
|
|
2471
|
-
|
|
2472
2466
|
if (!this.outflowReserve) {
|
|
2473
2467
|
throw new Error(`Outflow reserve state not found ${this.mint}`);
|
|
2474
2468
|
}
|
|
2475
2469
|
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
this.setupIxsLabels.unshift(`CreateUserAta[${this.userTokenAccountAddress.toBase58()}]`);
|
|
2490
|
-
}
|
|
2470
|
+
const [, createUserTokenAccountIx] = createAssociatedTokenAccountIdempotentInstruction(
|
|
2471
|
+
this.owner,
|
|
2472
|
+
this.outflowReserve.getLiquidityMint(),
|
|
2473
|
+
this.owner,
|
|
2474
|
+
this.outflowReserve.getLiquidityTokenProgram(),
|
|
2475
|
+
this.userTokenAccountAddress
|
|
2476
|
+
);
|
|
2477
|
+
if (this.positions === POSITION_LIMIT && this.mint.equals(WRAPPED_SOL_MINT)) {
|
|
2478
|
+
this.preTxnIxs.push(createUserTokenAccountIx);
|
|
2479
|
+
this.preTxnIxsLabels.push(`CreateUserAta[${this.userTokenAccountAddress.toBase58()}]`);
|
|
2480
|
+
} else {
|
|
2481
|
+
this.setupIxs.unshift(createUserTokenAccountIx);
|
|
2482
|
+
this.setupIxsLabels.unshift(`CreateUserAta[${this.userTokenAccountAddress.toBase58()}]`);
|
|
2491
2483
|
}
|
|
2492
2484
|
|
|
2493
|
-
const
|
|
2494
|
-
.
|
|
2495
|
-
.
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
this.owner,
|
|
2501
|
-
TOKEN_PROGRAM_ID,
|
|
2502
|
-
this.userCollateralAccountAddress
|
|
2503
|
-
);
|
|
2485
|
+
const [, createUserCollateralAccountIx] = createAssociatedTokenAccountIdempotentInstruction(
|
|
2486
|
+
this.owner,
|
|
2487
|
+
this.outflowReserve.getCTokenMint(),
|
|
2488
|
+
this.owner,
|
|
2489
|
+
TOKEN_PROGRAM_ID,
|
|
2490
|
+
this.userCollateralAccountAddress
|
|
2491
|
+
);
|
|
2504
2492
|
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
}
|
|
2493
|
+
if (this.positions === POSITION_LIMIT && this.mint.equals(WRAPPED_SOL_MINT)) {
|
|
2494
|
+
this.preTxnIxs.push(createUserCollateralAccountIx);
|
|
2495
|
+
this.preTxnIxsLabels.push(`CreateCollateralUserAta[${this.userCollateralAccountAddress.toString()}]`);
|
|
2496
|
+
} else {
|
|
2497
|
+
this.setupIxs.unshift(createUserCollateralAccountIx);
|
|
2498
|
+
this.setupIxsLabels.unshift(`CreateCollateralUserAta[${this.userCollateralAccountAddress.toString()}]`);
|
|
2512
2499
|
}
|
|
2513
2500
|
|
|
2514
2501
|
if (!this.additionalTokenAccountAddress) {
|
|
@@ -2547,43 +2534,32 @@ export class KaminoAction {
|
|
|
2547
2534
|
}
|
|
2548
2535
|
|
|
2549
2536
|
if (action === 'withdraw' || action === 'mint' || action === 'deposit' || action === 'repayAndWithdraw') {
|
|
2550
|
-
const
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
this.userTokenAccountAddress
|
|
2560
|
-
);
|
|
2561
|
-
this.preTxnIxs.push(createUserTokenAccountIx);
|
|
2562
|
-
this.preTxnIxsLabels.push(`CreateUserAta[${this.userTokenAccountAddress.toBase58()}]`);
|
|
2563
|
-
}
|
|
2537
|
+
const [, createUserTokenAccountIx] = createAssociatedTokenAccountIdempotentInstruction(
|
|
2538
|
+
this.owner,
|
|
2539
|
+
this.reserve.getLiquidityMint(),
|
|
2540
|
+
this.owner,
|
|
2541
|
+
this.reserve.getLiquidityTokenProgram(),
|
|
2542
|
+
this.userTokenAccountAddress
|
|
2543
|
+
);
|
|
2544
|
+
this.preTxnIxs.push(createUserTokenAccountIx);
|
|
2545
|
+
this.preTxnIxsLabels.push(`CreateUserAta[${this.userTokenAccountAddress.toBase58()}]`);
|
|
2564
2546
|
}
|
|
2565
2547
|
if (action === 'mint') {
|
|
2566
|
-
const
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
collateralMintPubkey,
|
|
2575
|
-
this.owner,
|
|
2576
|
-
TOKEN_PROGRAM_ID,
|
|
2577
|
-
this.userCollateralAccountAddress
|
|
2578
|
-
);
|
|
2548
|
+
const collateralMintPubkey = this.reserve.getCTokenMint();
|
|
2549
|
+
const [, createUserCollateralAccountIx] = createAssociatedTokenAccountIdempotentInstruction(
|
|
2550
|
+
this.owner,
|
|
2551
|
+
collateralMintPubkey,
|
|
2552
|
+
this.owner,
|
|
2553
|
+
TOKEN_PROGRAM_ID,
|
|
2554
|
+
this.userCollateralAccountAddress
|
|
2555
|
+
);
|
|
2579
2556
|
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
}
|
|
2557
|
+
if (this.positions === POSITION_LIMIT && this.mint.equals(WRAPPED_SOL_MINT)) {
|
|
2558
|
+
this.preTxnIxs.push(createUserCollateralAccountIx);
|
|
2559
|
+
this.preTxnIxsLabels.push(`CreateCollateralUserAta[${this.userCollateralAccountAddress.toString()}]`);
|
|
2560
|
+
} else {
|
|
2561
|
+
this.setupIxs.unshift(createUserCollateralAccountIx);
|
|
2562
|
+
this.setupIxsLabels.unshift(`CreateCollateralUserAta[${this.userCollateralAccountAddress.toString()}]`);
|
|
2587
2563
|
}
|
|
2588
2564
|
}
|
|
2589
2565
|
}
|
|
@@ -2661,7 +2637,7 @@ export class KaminoAction {
|
|
|
2661
2637
|
TOKEN_PROGRAM_ID
|
|
2662
2638
|
);
|
|
2663
2639
|
|
|
2664
|
-
const syncIx =
|
|
2640
|
+
const syncIx = createSyncNativeInstruction(userTokenAccountAddress);
|
|
2665
2641
|
if (userWSOLAccountInfo) {
|
|
2666
2642
|
if (sendAction) {
|
|
2667
2643
|
preIxs.push(syncIx);
|
|
@@ -2801,12 +2777,12 @@ export class KaminoAction {
|
|
|
2801
2777
|
throw new Error(`Reserve ${mint} not found in market ${kaminoMarket.getAddress().toBase58()}`);
|
|
2802
2778
|
}
|
|
2803
2779
|
|
|
2804
|
-
const { atas,
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
);
|
|
2780
|
+
const { atas, createAtaIxs } = await getAtasWithCreateIxnsIfMissing(kaminoMarket.getConnection(), owner, [
|
|
2781
|
+
{
|
|
2782
|
+
mint: reserve.getLiquidityMint(),
|
|
2783
|
+
tokenProgram: reserve.getLiquidityTokenProgram(),
|
|
2784
|
+
},
|
|
2785
|
+
]);
|
|
2810
2786
|
|
|
2811
2787
|
const userTokenAccountAddress = atas[0];
|
|
2812
2788
|
|
|
@@ -2830,7 +2806,7 @@ export class KaminoAction {
|
|
|
2830
2806
|
undefined,
|
|
2831
2807
|
undefined
|
|
2832
2808
|
),
|
|
2833
|
-
|
|
2809
|
+
createAtaIxs,
|
|
2834
2810
|
};
|
|
2835
2811
|
}
|
|
2836
2812
|
|
|
@@ -2867,7 +2843,7 @@ export class KaminoAction {
|
|
|
2867
2843
|
owner: PublicKey,
|
|
2868
2844
|
kaminoObligation: KaminoObligation | null,
|
|
2869
2845
|
referrer: PublicKey
|
|
2870
|
-
) {
|
|
2846
|
+
): Promise<PublicKey> {
|
|
2871
2847
|
let referrerKey = referrer;
|
|
2872
2848
|
if (!referrer || referrer.equals(PublicKey.default)) {
|
|
2873
2849
|
if (kaminoObligation === null) {
|
|
@@ -2881,4 +2857,22 @@ export class KaminoAction {
|
|
|
2881
2857
|
}
|
|
2882
2858
|
return referrerKey;
|
|
2883
2859
|
}
|
|
2860
|
+
|
|
2861
|
+
public static actionToIxs(action: KaminoAction): Array<TransactionInstruction> {
|
|
2862
|
+
const ixs: TransactionInstruction[] = [...action.setupIxs];
|
|
2863
|
+
ixs.push(...KaminoAction.actionToLendingIxs(action));
|
|
2864
|
+
ixs.push(...action.cleanupIxs);
|
|
2865
|
+
return ixs;
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
public static actionToLendingIxs(action: KaminoAction): Array<TransactionInstruction> {
|
|
2869
|
+
const ixs: TransactionInstruction[] = [];
|
|
2870
|
+
for (let i = 0; i < action.lendingIxs.length; i++) {
|
|
2871
|
+
ixs.push(action.lendingIxs[i]);
|
|
2872
|
+
if (i !== action.lendingIxs.length - 1) {
|
|
2873
|
+
ixs.push(...action.inBetweenIxs);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
return ixs;
|
|
2877
|
+
}
|
|
2884
2878
|
}
|
package/src/classes/market.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
cacheOrGetSwitchboardPrice,
|
|
21
21
|
PubkeyHashMap,
|
|
22
22
|
CandidatePrice,
|
|
23
|
+
PublicKeySet,
|
|
23
24
|
} from '../utils';
|
|
24
25
|
import base58 from 'bs58';
|
|
25
26
|
import { BN } from '@coral-xyz/anchor';
|
|
@@ -1208,10 +1209,10 @@ export class KaminoMarket {
|
|
|
1208
1209
|
continue;
|
|
1209
1210
|
}
|
|
1210
1211
|
elevationGroups.push({
|
|
1211
|
-
collateralReserves: [],
|
|
1212
|
-
collateralLiquidityMints: [],
|
|
1213
|
-
debtReserve: elevationGroup.debtReserve
|
|
1214
|
-
debtLiquidityMint:
|
|
1212
|
+
collateralReserves: new PublicKeySet<PublicKey>([]),
|
|
1213
|
+
collateralLiquidityMints: new PublicKeySet<PublicKey>([]),
|
|
1214
|
+
debtReserve: elevationGroup.debtReserve,
|
|
1215
|
+
debtLiquidityMint: PublicKey.default,
|
|
1215
1216
|
elevationGroup: elevationGroup.id,
|
|
1216
1217
|
});
|
|
1217
1218
|
}
|
|
@@ -1219,7 +1220,7 @@ export class KaminoMarket {
|
|
|
1219
1220
|
// Fill the remaining
|
|
1220
1221
|
for (const reserve of this.reserves.values()) {
|
|
1221
1222
|
const reserveLiquidityMint = reserve.getLiquidityMint();
|
|
1222
|
-
const reserveAddress = reserve.address
|
|
1223
|
+
const reserveAddress = reserve.address;
|
|
1223
1224
|
const reserveElevationGroups = reserve.state.config.elevationGroups;
|
|
1224
1225
|
for (const elevationGroupId of reserveElevationGroups) {
|
|
1225
1226
|
if (elevationGroupId === 0) {
|
|
@@ -1228,14 +1229,14 @@ export class KaminoMarket {
|
|
|
1228
1229
|
|
|
1229
1230
|
const elevationGroupDescription = elevationGroups[elevationGroupId - 1];
|
|
1230
1231
|
if (elevationGroupDescription) {
|
|
1231
|
-
if (reserveAddress
|
|
1232
|
-
elevationGroups[elevationGroupId - 1].debtLiquidityMint = reserveLiquidityMint
|
|
1232
|
+
if (reserveAddress.equals(elevationGroupDescription.debtReserve)) {
|
|
1233
|
+
elevationGroups[elevationGroupId - 1].debtLiquidityMint = reserveLiquidityMint;
|
|
1233
1234
|
} else {
|
|
1234
|
-
elevationGroups[elevationGroupId - 1].collateralReserves.
|
|
1235
|
-
elevationGroups[elevationGroupId - 1].collateralLiquidityMints.
|
|
1235
|
+
elevationGroups[elevationGroupId - 1].collateralReserves.add(reserveAddress);
|
|
1236
|
+
elevationGroups[elevationGroupId - 1].collateralLiquidityMints.add(reserveLiquidityMint);
|
|
1236
1237
|
}
|
|
1237
1238
|
} else {
|
|
1238
|
-
throw new Error(`Invalid elevation group id ${elevationGroupId} at reserve ${reserveAddress}`);
|
|
1239
|
+
throw new Error(`Invalid elevation group id ${elevationGroupId} at reserve ${reserveAddress.toString()}`);
|
|
1239
1240
|
}
|
|
1240
1241
|
}
|
|
1241
1242
|
}
|
|
@@ -1252,10 +1253,8 @@ export class KaminoMarket {
|
|
|
1252
1253
|
|
|
1253
1254
|
return allElevationGroups.filter((elevationGroupDescription) => {
|
|
1254
1255
|
return (
|
|
1255
|
-
collLiquidityMints.every((mint) =>
|
|
1256
|
-
|
|
1257
|
-
) &&
|
|
1258
|
-
(debtLiquidityMint == undefined || debtLiquidityMint.toString() === elevationGroupDescription.debtLiquidityMint)
|
|
1256
|
+
collLiquidityMints.every((mint) => elevationGroupDescription.collateralLiquidityMints.contains(mint)) &&
|
|
1257
|
+
(debtLiquidityMint == undefined || debtLiquidityMint.equals(elevationGroupDescription.debtLiquidityMint))
|
|
1259
1258
|
);
|
|
1260
1259
|
});
|
|
1261
1260
|
}
|
|
@@ -1269,8 +1268,8 @@ export class KaminoMarket {
|
|
|
1269
1268
|
|
|
1270
1269
|
return allElevationGroups.filter((elevationGroupDescription) => {
|
|
1271
1270
|
return (
|
|
1272
|
-
collReserves.every((mint) => elevationGroupDescription.collateralReserves.
|
|
1273
|
-
(debtReserve == undefined || debtReserve.
|
|
1271
|
+
collReserves.every((mint) => elevationGroupDescription.collateralReserves.contains(mint)) &&
|
|
1272
|
+
(debtReserve == undefined || debtReserve.equals(elevationGroupDescription.debtReserve))
|
|
1274
1273
|
);
|
|
1275
1274
|
});
|
|
1276
1275
|
}
|
|
@@ -1305,10 +1304,10 @@ export type BorrowCapsAndCounters = {
|
|
|
1305
1304
|
};
|
|
1306
1305
|
|
|
1307
1306
|
export type ElevationGroupDescription = {
|
|
1308
|
-
collateralReserves:
|
|
1309
|
-
collateralLiquidityMints:
|
|
1310
|
-
debtReserve:
|
|
1311
|
-
debtLiquidityMint:
|
|
1307
|
+
collateralReserves: PublicKeySet<PublicKey>;
|
|
1308
|
+
collateralLiquidityMints: PublicKeySet<PublicKey>;
|
|
1309
|
+
debtReserve: PublicKey;
|
|
1310
|
+
debtLiquidityMint: PublicKey;
|
|
1312
1311
|
elevationGroup: number;
|
|
1313
1312
|
};
|
|
1314
1313
|
|
|
@@ -305,6 +305,15 @@ export class KaminoObligation {
|
|
|
305
305
|
return this.refreshedStats.netAccountValue;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Get the loan to value and liquidation loan to value for a collateral token reserve as ratios, accounting for the obligation elevation group if it is active
|
|
310
|
+
* @param market
|
|
311
|
+
* @param reserve
|
|
312
|
+
*/
|
|
313
|
+
public getLtvForReserve(market: KaminoMarket, reserve: KaminoReserve): { maxLtv: Decimal; liquidationLtv: Decimal } {
|
|
314
|
+
return KaminoObligation.getLtvForReserve(market, reserve, this.state.elevationGroup);
|
|
315
|
+
}
|
|
316
|
+
|
|
308
317
|
/**
|
|
309
318
|
* @returns the potential elevation groups the obligation qualifies for
|
|
310
319
|
*/
|
|
@@ -372,19 +381,31 @@ export class KaminoObligation {
|
|
|
372
381
|
simulateBorrowChange(
|
|
373
382
|
obligationBorrows: ObligationLiquidity[],
|
|
374
383
|
changeInLamports: number,
|
|
375
|
-
changeReserve: PublicKey
|
|
384
|
+
changeReserve: PublicKey,
|
|
385
|
+
cumulativeBorrowRate: Decimal
|
|
376
386
|
): ObligationLiquidity[] {
|
|
377
387
|
const newBorrows: ObligationLiquidity[] = [];
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
+
const borrowIndex = obligationBorrows.findIndex((borrow) => borrow.borrowReserve.equals(changeReserve));
|
|
389
|
+
|
|
390
|
+
if (borrowIndex !== -1) {
|
|
391
|
+
const borrow: ObligationLiquidityFields = { ...obligationBorrows[borrowIndex] };
|
|
392
|
+
const newBorrowedAmount: Decimal = new Fraction(borrow.borrowedAmountSf).toDecimal().add(changeInLamports);
|
|
393
|
+
const newBorrowedAmountSf = Fraction.fromDecimal(positiveOrZero(newBorrowedAmount)).getValue();
|
|
394
|
+
borrow.borrowedAmountSf = newBorrowedAmountSf;
|
|
395
|
+
newBorrows.push(new ObligationLiquidity(borrow));
|
|
396
|
+
} else {
|
|
397
|
+
const firstBorrowIndexAvailable = obligationBorrows.findIndex((borrow) =>
|
|
398
|
+
borrow.borrowReserve.equals(PublicKey.default)
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const borrow: ObligationLiquidityFields = { ...obligationBorrows[firstBorrowIndexAvailable] };
|
|
402
|
+
borrow.borrowedAmountSf = Fraction.fromDecimal(new Decimal(changeInLamports)).getValue();
|
|
403
|
+
borrow.borrowReserve = changeReserve;
|
|
404
|
+
borrow.cumulativeBorrowRateBsf = {
|
|
405
|
+
padding: [],
|
|
406
|
+
value: [Fraction.fromDecimal(cumulativeBorrowRate).getValue(), new BN(0), new BN(0), new BN(0)],
|
|
407
|
+
};
|
|
408
|
+
newBorrows.push(new ObligationLiquidity(borrow));
|
|
388
409
|
}
|
|
389
410
|
|
|
390
411
|
return newBorrows;
|
|
@@ -412,11 +433,7 @@ export class KaminoObligation {
|
|
|
412
433
|
const { amountCollateral, amountDebt, action, mintCollateral, mintDebt, market } = params;
|
|
413
434
|
let newStats = { ...this.refreshedStats };
|
|
414
435
|
|
|
415
|
-
const { collateralExchangeRates
|
|
416
|
-
market,
|
|
417
|
-
this.state,
|
|
418
|
-
params.slot
|
|
419
|
-
);
|
|
436
|
+
const { collateralExchangeRates } = KaminoObligation.getRatesForObligation(market, this.state, params.slot);
|
|
420
437
|
|
|
421
438
|
const elevationGroup = params.elevationGroupOverride ?? this.state.elevationGroup;
|
|
422
439
|
|
|
@@ -427,8 +444,11 @@ export class KaminoObligation {
|
|
|
427
444
|
// so we have to recalculate the entire position, not just an updated deposit or borrow
|
|
428
445
|
// as both LTVs and borrow factors can change, affecting all calcs
|
|
429
446
|
|
|
430
|
-
const
|
|
431
|
-
const
|
|
447
|
+
const collateralReservePk = mintCollateral ? market.getReserveByMint(mintCollateral)!.address : undefined;
|
|
448
|
+
const debtReservePk = mintDebt ? market.getReserveByMint(mintDebt)!.address : undefined;
|
|
449
|
+
const debtReserveCumulativeBorrowRate = mintDebt
|
|
450
|
+
? market.getReserveByMint(mintDebt)!.getCumulativeBorrowRate()
|
|
451
|
+
: undefined;
|
|
432
452
|
|
|
433
453
|
let newObligationDeposits = this.state.deposits;
|
|
434
454
|
let newObligationBorrows = this.state.borrows;
|
|
@@ -441,7 +461,7 @@ export class KaminoObligation {
|
|
|
441
461
|
newObligationDeposits = this.simulateDepositChange(
|
|
442
462
|
this.state.deposits,
|
|
443
463
|
amountCollateral.toNumber(),
|
|
444
|
-
|
|
464
|
+
collateralReservePk!,
|
|
445
465
|
collateralExchangeRates
|
|
446
466
|
);
|
|
447
467
|
break;
|
|
@@ -451,14 +471,25 @@ export class KaminoObligation {
|
|
|
451
471
|
throw Error('amountDebt & mintDebt are required for borrow action');
|
|
452
472
|
}
|
|
453
473
|
|
|
454
|
-
newObligationBorrows = this.simulateBorrowChange(
|
|
474
|
+
newObligationBorrows = this.simulateBorrowChange(
|
|
475
|
+
this.state.borrows,
|
|
476
|
+
amountDebt.toNumber(),
|
|
477
|
+
debtReservePk!,
|
|
478
|
+
debtReserveCumulativeBorrowRate!
|
|
479
|
+
);
|
|
455
480
|
break;
|
|
456
481
|
}
|
|
457
482
|
case 'repay': {
|
|
458
483
|
if (amountDebt === undefined || mintDebt === undefined) {
|
|
459
484
|
throw Error('amountDebt & mintDebt are required for repay action');
|
|
460
485
|
}
|
|
461
|
-
|
|
486
|
+
|
|
487
|
+
newObligationBorrows = this.simulateBorrowChange(
|
|
488
|
+
this.state.borrows,
|
|
489
|
+
amountDebt.neg().toNumber(),
|
|
490
|
+
debtReservePk!,
|
|
491
|
+
debtReserveCumulativeBorrowRate!
|
|
492
|
+
);
|
|
462
493
|
|
|
463
494
|
break;
|
|
464
495
|
}
|
|
@@ -470,7 +501,7 @@ export class KaminoObligation {
|
|
|
470
501
|
newObligationDeposits = this.simulateDepositChange(
|
|
471
502
|
this.state.deposits,
|
|
472
503
|
amountCollateral.neg().toNumber(),
|
|
473
|
-
|
|
504
|
+
collateralReservePk!,
|
|
474
505
|
collateralExchangeRates
|
|
475
506
|
);
|
|
476
507
|
break;
|
|
@@ -487,10 +518,16 @@ export class KaminoObligation {
|
|
|
487
518
|
newObligationDeposits = this.simulateDepositChange(
|
|
488
519
|
this.state.deposits,
|
|
489
520
|
amountCollateral.toNumber(),
|
|
490
|
-
|
|
521
|
+
collateralReservePk!,
|
|
491
522
|
collateralExchangeRates
|
|
492
523
|
);
|
|
493
|
-
|
|
524
|
+
|
|
525
|
+
newObligationBorrows = this.simulateBorrowChange(
|
|
526
|
+
this.state.borrows,
|
|
527
|
+
amountDebt.toNumber(),
|
|
528
|
+
debtReservePk!,
|
|
529
|
+
debtReserveCumulativeBorrowRate!
|
|
530
|
+
);
|
|
494
531
|
break;
|
|
495
532
|
}
|
|
496
533
|
case 'repayAndWithdraw': {
|
|
@@ -505,10 +542,15 @@ export class KaminoObligation {
|
|
|
505
542
|
newObligationDeposits = this.simulateDepositChange(
|
|
506
543
|
this.state.deposits,
|
|
507
544
|
amountCollateral.neg().toNumber(),
|
|
508
|
-
|
|
545
|
+
collateralReservePk!,
|
|
509
546
|
collateralExchangeRates
|
|
510
547
|
);
|
|
511
|
-
newObligationBorrows = this.simulateBorrowChange(
|
|
548
|
+
newObligationBorrows = this.simulateBorrowChange(
|
|
549
|
+
this.state.borrows,
|
|
550
|
+
amountDebt.neg().toNumber(),
|
|
551
|
+
debtReservePk!,
|
|
552
|
+
debtReserveCumulativeBorrowRate!
|
|
553
|
+
);
|
|
512
554
|
break;
|
|
513
555
|
}
|
|
514
556
|
default: {
|
|
@@ -522,7 +564,7 @@ export class KaminoObligation {
|
|
|
522
564
|
newObligationBorrows,
|
|
523
565
|
elevationGroup,
|
|
524
566
|
collateralExchangeRates,
|
|
525
|
-
|
|
567
|
+
null
|
|
526
568
|
);
|
|
527
569
|
|
|
528
570
|
newStats = refreshedStats;
|
|
@@ -568,7 +610,7 @@ export class KaminoObligation {
|
|
|
568
610
|
obligationBorrows: ObligationLiquidity[],
|
|
569
611
|
elevationGroup: number,
|
|
570
612
|
collateralExchangeRates: Map<PublicKey, Decimal>,
|
|
571
|
-
cumulativeBorrowRates: Map<PublicKey, Decimal>
|
|
613
|
+
cumulativeBorrowRates: Map<PublicKey, Decimal> | null
|
|
572
614
|
): {
|
|
573
615
|
borrows: Map<PublicKey, Position>;
|
|
574
616
|
deposits: Map<PublicKey, Position>;
|
|
@@ -774,12 +816,12 @@ export class KaminoObligation {
|
|
|
774
816
|
return borrowLimit.div(userTotalDeposit);
|
|
775
817
|
}
|
|
776
818
|
|
|
777
|
-
/*
|
|
778
|
-
How much of a given token can a user borrow extra given an elevation group,
|
|
819
|
+
/*
|
|
820
|
+
How much of a given token can a user borrow extra given an elevation group,
|
|
779
821
|
regardless of caps and liquidity or assuming infinite liquidity and infinite caps,
|
|
780
822
|
until it hits max LTV.
|
|
781
823
|
|
|
782
|
-
This is purely a function about the borrow power of an obligation,
|
|
824
|
+
This is purely a function about the borrow power of an obligation,
|
|
783
825
|
not a reserve-specific, caps-specific, liquidity-specific function.
|
|
784
826
|
|
|
785
827
|
* @param market - The KaminoMarket instance.
|
|
@@ -857,7 +899,7 @@ export class KaminoObligation {
|
|
|
857
899
|
return Decimal.max(new Decimal(0), maxBorrowAmount);
|
|
858
900
|
}
|
|
859
901
|
|
|
860
|
-
/*
|
|
902
|
+
/*
|
|
861
903
|
How much of a given token can a user borrow extra given an elevation group,
|
|
862
904
|
and a specific reserve, until it hits max LTV and given available liquidity and caps.
|
|
863
905
|
|
|
@@ -891,7 +933,7 @@ export class KaminoObligation {
|
|
|
891
933
|
}
|
|
892
934
|
}
|
|
893
935
|
|
|
894
|
-
/*
|
|
936
|
+
/*
|
|
895
937
|
Returns true if the loan is eligible for the elevation group, including for the default one.
|
|
896
938
|
* @param market - The KaminoMarket object representing the market.
|
|
897
939
|
* @param slot - The slot number of the loan.
|
|
@@ -904,8 +946,8 @@ export class KaminoObligation {
|
|
|
904
946
|
// - [x] due to collateral / debt reserves combination
|
|
905
947
|
// - [x] due to LTV, etc
|
|
906
948
|
|
|
907
|
-
const reserveDeposits:
|
|
908
|
-
const reserveBorrows:
|
|
949
|
+
const reserveDeposits: PublicKey[] = Array.from(this.deposits.keys());
|
|
950
|
+
const reserveBorrows: PublicKey[] = Array.from(this.borrows.keys());
|
|
909
951
|
|
|
910
952
|
if (reserveBorrows.length > 1) {
|
|
911
953
|
return false;
|
|
@@ -918,11 +960,11 @@ export class KaminoObligation {
|
|
|
918
960
|
|
|
919
961
|
// Has to be a subset
|
|
920
962
|
const allCollsIncluded = reserveDeposits.every((reserve) =>
|
|
921
|
-
elevationGroupDescription.collateralReserves.
|
|
963
|
+
elevationGroupDescription.collateralReserves.contains(reserve)
|
|
922
964
|
);
|
|
923
965
|
const allDebtsIncluded =
|
|
924
966
|
reserveBorrows.length === 0 ||
|
|
925
|
-
(reserveBorrows.length === 1 && elevationGroupDescription.debtReserve
|
|
967
|
+
(reserveBorrows.length === 1 && elevationGroupDescription.debtReserve.equals(reserveBorrows[0]));
|
|
926
968
|
|
|
927
969
|
if (!allCollsIncluded || !allDebtsIncluded) {
|
|
928
970
|
return false;
|
|
@@ -946,7 +988,7 @@ export class KaminoObligation {
|
|
|
946
988
|
return isEligibleBasedOnLtv;
|
|
947
989
|
}
|
|
948
990
|
|
|
949
|
-
/*
|
|
991
|
+
/*
|
|
950
992
|
Returns all elevation groups for a given obligation, except the default one
|
|
951
993
|
* @param market - The KaminoMarket instance.
|
|
952
994
|
* @returns An array of ElevationGroupDescription objects representing the elevation groups for the obligation.
|