@kamino-finance/klend-sdk 7.4.0-beta.3 → 7.4.0-beta.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/market.d.ts +102 -7
- package/dist/classes/market.d.ts.map +1 -1
- package/dist/classes/market.js +153 -8
- package/dist/classes/market.js.map +1 -1
- package/dist/classes/reserve.d.ts +9 -1
- package/dist/classes/reserve.d.ts.map +1 -1
- package/dist/classes/reserve.js +20 -0
- package/dist/classes/reserve.js.map +1 -1
- package/dist/utils/ReserveKind.d.ts +57 -0
- package/dist/utils/ReserveKind.d.ts.map +1 -0
- package/dist/utils/ReserveKind.js +76 -0
- package/dist/utils/ReserveKind.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/market.ts +183 -8
- package/src/classes/reserve.ts +24 -0
- package/src/utils/ReserveKind.ts +94 -0
- package/src/utils/index.ts +1 -0
package/src/classes/market.ts
CHANGED
|
@@ -40,8 +40,10 @@ import {
|
|
|
40
40
|
MultiplyObligation,
|
|
41
41
|
MultiplyObligationFixedRate,
|
|
42
42
|
ObligationType,
|
|
43
|
+
FloatRateReserveKind,
|
|
43
44
|
PythPrices,
|
|
44
45
|
referrerTokenStatePda,
|
|
46
|
+
ReserveKind,
|
|
45
47
|
setOrAppend,
|
|
46
48
|
userMetadataPda,
|
|
47
49
|
VanillaObligation,
|
|
@@ -571,6 +573,12 @@ export class KaminoMarket {
|
|
|
571
573
|
return checkDefined(this.getReserveByAddress(address), `${description} reserve ${address} not found`);
|
|
572
574
|
}
|
|
573
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Returns all reserves for the given mint address (both float rate and fixed rate).
|
|
578
|
+
*
|
|
579
|
+
* @param mint The liquidity mint address
|
|
580
|
+
* @returns Array of all reserves for this mint
|
|
581
|
+
*/
|
|
574
582
|
getReservesByMint(address: Address): KaminoReserve[] {
|
|
575
583
|
const reserves: KaminoReserve[] = [];
|
|
576
584
|
for (const reserve of this.reserves.values()) {
|
|
@@ -581,14 +589,97 @@ export class KaminoMarket {
|
|
|
581
589
|
return reserves;
|
|
582
590
|
}
|
|
583
591
|
|
|
584
|
-
/**
|
|
585
|
-
* Returns this market's reserve of the given mint address, or throws an error (including the given description) if
|
|
586
|
-
* such reserve does not exist.
|
|
587
|
-
*/
|
|
588
592
|
getExistingReservesByMint(address: Address, description: string = 'Requested'): KaminoReserve[] {
|
|
589
593
|
return checkArrayNotEmpty(this.getReservesByMint(address), `${description} reserve with mint ${address} not found`);
|
|
590
594
|
}
|
|
591
595
|
|
|
596
|
+
/**
|
|
597
|
+
* Returns this market's reserve matching the given mint address and reserve kind.
|
|
598
|
+
* Since a market can have multiple reserves for the same mint (with different terms),
|
|
599
|
+
* the reserve kind specifies which reserve to select.
|
|
600
|
+
*
|
|
601
|
+
* Example for fixed-term reserves:
|
|
602
|
+
* const fixedReserveKind = new FixedReserveKind(new BN(30 * 24 * 60 * 60), 500); // 30 days, 5% borrow rate
|
|
603
|
+
* const fixedReserve = market.getReserveByMintAndKind(tokenMint, fixedReserveKind)!;
|
|
604
|
+
|
|
605
|
+
* @param mint The liquidity mint address
|
|
606
|
+
* @param reserveKind The reserve kind to match (e.g., FloatRateReserveKind or FixedRateReserveKind)
|
|
607
|
+
*/
|
|
608
|
+
getReserveByMintAndKind(mint: Address, reserveKind: ReserveKind): KaminoReserve | undefined {
|
|
609
|
+
for (const reserve of this.reserves.values()) {
|
|
610
|
+
if (reserve.getLiquidityMint() === mint && reserveKind.matches(reserve)) {
|
|
611
|
+
return reserve;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return undefined;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Returns this market's reserve matching the given mint address and reserve kind,
|
|
619
|
+
* or throws an error if not found.
|
|
620
|
+
*
|
|
621
|
+
* @param mint The liquidity mint address
|
|
622
|
+
* @param reserveKind The reserve kind to match
|
|
623
|
+
* @param description Optional description for the error message
|
|
624
|
+
*/
|
|
625
|
+
getExistingReserveByMintAndKind(
|
|
626
|
+
mint: Address,
|
|
627
|
+
reserveKind: ReserveKind,
|
|
628
|
+
description: string = 'Requested'
|
|
629
|
+
): KaminoReserve {
|
|
630
|
+
return checkDefined(
|
|
631
|
+
this.getReserveByMintAndKind(mint, reserveKind),
|
|
632
|
+
`${description} reserve with mint ${mint} and kind ${reserveKind.toString()} not found`
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Returns this market's float rate reserve for the given mint address.
|
|
638
|
+
* Float rate reserves are reserves without a fixed term (debtTermSeconds = 0).
|
|
639
|
+
*
|
|
640
|
+
* @param mint The liquidity mint address
|
|
641
|
+
* @returns The float rate reserve, or undefined if not found
|
|
642
|
+
*/
|
|
643
|
+
getFloatRateReserveByMint(mint: Address): KaminoReserve | undefined {
|
|
644
|
+
return this.getReserveByMintAndKind(mint, new FloatRateReserveKind());
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Returns this market's float rate reserve for the given mint address,
|
|
649
|
+
* or throws an error if not found.
|
|
650
|
+
*
|
|
651
|
+
* @param mint The liquidity mint address
|
|
652
|
+
* @param description Optional description for the error message
|
|
653
|
+
* @returns The float rate reserve
|
|
654
|
+
*/
|
|
655
|
+
getExistingFloatRateReserveByMint(mint: Address, description: string = 'Requested'): KaminoReserve {
|
|
656
|
+
return checkDefined(this.getFloatRateReserveByMint(mint), `${description} float rate reserve with mint ${mint} not found`);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Returns all fixed rate reserves for the given mint address.
|
|
661
|
+
* Fixed rate reserves have a non-zero debt term (debtTermSeconds > 0).
|
|
662
|
+
*
|
|
663
|
+
* @param mint The liquidity mint address
|
|
664
|
+
* @returns Array of all fixed rate reserves for this mint
|
|
665
|
+
*/
|
|
666
|
+
getFixedRateReservesByMint(mint: Address): KaminoReserve[] {
|
|
667
|
+
const fixedRateReserves: KaminoReserve[] = [];
|
|
668
|
+
const floatRateReserveKind = new FloatRateReserveKind();
|
|
669
|
+
for (const reserve of this.reserves.values()) {
|
|
670
|
+
if (reserve.getLiquidityMint() === mint && !floatRateReserveKind.matches(reserve)) {
|
|
671
|
+
fixedRateReserves.push(reserve);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return fixedRateReserves;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Returns all reserves for the given symbol (both float rate and fixed rate).
|
|
679
|
+
*
|
|
680
|
+
* @param symbol The reserve symbol
|
|
681
|
+
* @returns Array of all reserves for this symbol
|
|
682
|
+
*/
|
|
592
683
|
getReservesBySymbol(symbol: string): KaminoReserve[] {
|
|
593
684
|
const reserves: KaminoReserve[] = [];
|
|
594
685
|
for (const reserve of this.reserves.values()) {
|
|
@@ -599,10 +690,6 @@ export class KaminoMarket {
|
|
|
599
690
|
return reserves;
|
|
600
691
|
}
|
|
601
692
|
|
|
602
|
-
/**
|
|
603
|
-
* Returns this market's reserve of the given symbol, or throws an error (including the given description) if
|
|
604
|
-
* such reserve does not exist.
|
|
605
|
-
*/
|
|
606
693
|
getExistingReservesBySymbol(symbol: string, description: string = 'Requested'): KaminoReserve[] {
|
|
607
694
|
return checkArrayNotEmpty(
|
|
608
695
|
this.getReservesBySymbol(symbol),
|
|
@@ -610,6 +697,94 @@ export class KaminoMarket {
|
|
|
610
697
|
);
|
|
611
698
|
}
|
|
612
699
|
|
|
700
|
+
/**
|
|
701
|
+
* Returns this market's reserve matching the given symbol and reserve kind.
|
|
702
|
+
* Since a market can have multiple reserves for the same symbol (with different terms),
|
|
703
|
+
* the reserve kind specifies which reserve to select.
|
|
704
|
+
*
|
|
705
|
+
* @param symbol The reserve symbol
|
|
706
|
+
* @param reserveKind The reserve kind to match (e.g., FloatRateReserveKind or FixedRateReserveKind)
|
|
707
|
+
*/
|
|
708
|
+
getReserveBySymbolAndKind(symbol: string, reserveKind: ReserveKind): KaminoReserve | undefined {
|
|
709
|
+
for (const reserve of this.reserves.values()) {
|
|
710
|
+
if (reserve.symbol === symbol && reserveKind.matches(reserve)) {
|
|
711
|
+
return reserve;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return undefined;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Returns this market's reserve matching the given symbol and reserve kind,
|
|
719
|
+
* or throws an error if not found.
|
|
720
|
+
*
|
|
721
|
+
* @param symbol The reserve symbol
|
|
722
|
+
* @param reserveKind The reserve kind to match
|
|
723
|
+
* @param description Optional description for the error message
|
|
724
|
+
*/
|
|
725
|
+
getExistingReserveBySymbolAndKind(
|
|
726
|
+
symbol: string,
|
|
727
|
+
reserveKind: ReserveKind,
|
|
728
|
+
description: string = 'Requested'
|
|
729
|
+
): KaminoReserve {
|
|
730
|
+
return checkDefined(
|
|
731
|
+
this.getReserveBySymbolAndKind(symbol, reserveKind),
|
|
732
|
+
`${description} reserve with symbol ${symbol} and kind ${reserveKind.toString()} not found`
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Returns this market's float rate reserve for the given symbol.
|
|
738
|
+
* Float rate reserves are reserves without a fixed term (debtTermSeconds = 0).
|
|
739
|
+
*
|
|
740
|
+
* @param symbol The reserve symbol
|
|
741
|
+
* @returns The float rate reserve, or undefined if not found
|
|
742
|
+
*/
|
|
743
|
+
getFloatRateReserveBySymbol(symbol: string): KaminoReserve | undefined {
|
|
744
|
+
return this.getReserveBySymbolAndKind(symbol, new FloatRateReserveKind());
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Returns this market's float rate reserve for the given symbol,
|
|
749
|
+
* or throws an error if not found.
|
|
750
|
+
*
|
|
751
|
+
* @param symbol The reserve symbol
|
|
752
|
+
* @param description Optional description for the error message
|
|
753
|
+
* @returns The float rate reserve
|
|
754
|
+
*/
|
|
755
|
+
getExistingFloatRateReserveBySymbol(symbol: string, description: string = 'Requested'): KaminoReserve {
|
|
756
|
+
return checkDefined(
|
|
757
|
+
this.getFloatRateReserveBySymbol(symbol),
|
|
758
|
+
`${description} float rate reserve with symbol ${symbol} not found`
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Returns all fixed rate reserves for the given symbol.
|
|
764
|
+
* Fixed rate reserves have a non-zero debt term (debtTermSeconds > 0).
|
|
765
|
+
*
|
|
766
|
+
* @param symbol The reserve symbol
|
|
767
|
+
* @returns Array of all fixed rate reserves for this symbol
|
|
768
|
+
*/
|
|
769
|
+
getFixedRateReservesBySymbol(symbol: string): KaminoReserve[] {
|
|
770
|
+
const fixedRateReserves: KaminoReserve[] = [];
|
|
771
|
+
const floatRateReserveKind = new FloatRateReserveKind();
|
|
772
|
+
for (const reserve of this.reserves.values()) {
|
|
773
|
+
if (reserve.symbol === symbol && !floatRateReserveKind.matches(reserve)) {
|
|
774
|
+
fixedRateReserves.push(reserve);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
return fixedRateReserves;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
getReserveMintBySymbol(symbol: string) {
|
|
781
|
+
const reserves = this.getReservesBySymbol(symbol);
|
|
782
|
+
if (reserves.length === 0) {
|
|
783
|
+
throw new Error(`No reserves found for symbol ${symbol}`);
|
|
784
|
+
}
|
|
785
|
+
return reserves[0].getLiquidityMint();
|
|
786
|
+
}
|
|
787
|
+
|
|
613
788
|
async getReserveFarmInfo(
|
|
614
789
|
reserveAddress: Address,
|
|
615
790
|
getRewardPrice: (mint: Address) => Promise<number>
|
package/src/classes/reserve.ts
CHANGED
|
@@ -19,6 +19,7 @@ import Decimal from 'decimal.js';
|
|
|
19
19
|
import {
|
|
20
20
|
AllOracleAccounts,
|
|
21
21
|
DEFAULT_PUBLIC_KEY,
|
|
22
|
+
FixedRateReserveKind,
|
|
22
23
|
getTokenOracleData,
|
|
23
24
|
globalConfigPda,
|
|
24
25
|
INITIAL_COLLATERAL_RATE,
|
|
@@ -26,7 +27,9 @@ import {
|
|
|
26
27
|
MarketWithAddress,
|
|
27
28
|
MIN_INITIAL_DEPOSIT,
|
|
28
29
|
ONE_HUNDRED_PCT_IN_BPS,
|
|
30
|
+
FloatRateReserveKind,
|
|
29
31
|
reservePdas,
|
|
32
|
+
ReserveKind,
|
|
30
33
|
SLOTS_PER_DAY,
|
|
31
34
|
SLOTS_PER_SECOND,
|
|
32
35
|
SLOTS_PER_YEAR,
|
|
@@ -76,6 +79,7 @@ export class KaminoReserve {
|
|
|
76
79
|
private readonly recentSlotDurationMs: number;
|
|
77
80
|
|
|
78
81
|
private metadata?: ScopeEntryMetadata[];
|
|
82
|
+
private reserveKind: ReserveKind;
|
|
79
83
|
|
|
80
84
|
constructor(
|
|
81
85
|
state: Reserve,
|
|
@@ -91,6 +95,7 @@ export class KaminoReserve {
|
|
|
91
95
|
this.rpc = connection;
|
|
92
96
|
this.symbol = parseTokenSymbol(state.config.tokenInfo.name);
|
|
93
97
|
this.recentSlotDurationMs = recentSlotDurationMs;
|
|
98
|
+
this.reserveKind = KaminoReserve.createReserveKind(state);
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
static initialize(
|
|
@@ -130,6 +135,16 @@ export class KaminoReserve {
|
|
|
130
135
|
return new KaminoReserve(reserve, address, tokenOracleData, rpc, recentSlotDurationMs);
|
|
131
136
|
}
|
|
132
137
|
|
|
138
|
+
static createReserveKind(state: Reserve): ReserveKind {
|
|
139
|
+
const debtTermSeconds = state.config.debtTermSeconds;
|
|
140
|
+
if (debtTermSeconds.eqn(0)) {
|
|
141
|
+
return new FloatRateReserveKind();
|
|
142
|
+
} else {
|
|
143
|
+
const borrowRateBps = state.config.borrowRateCurve.points[0]?.borrowRateBps || 0;
|
|
144
|
+
return new FixedRateReserveKind(debtTermSeconds, borrowRateBps);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
133
148
|
/// GETTERS
|
|
134
149
|
|
|
135
150
|
/**
|
|
@@ -733,6 +748,15 @@ export class KaminoReserve {
|
|
|
733
748
|
return this.state.collateral.mintPubkey;
|
|
734
749
|
}
|
|
735
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Returns the reserve kind (FloatRateReserveKind or FixedRateReserveKind) for this reserve.
|
|
753
|
+
*
|
|
754
|
+
* @returns The reserve kind instance
|
|
755
|
+
*/
|
|
756
|
+
getKind(): ReserveKind {
|
|
757
|
+
return this.reserveKind;
|
|
758
|
+
}
|
|
759
|
+
|
|
736
760
|
calculateFees(
|
|
737
761
|
amountLamports: Decimal,
|
|
738
762
|
borrowFeeRate: Decimal,
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import BN from 'bn.js';
|
|
2
|
+
import { KaminoReserve } from '../classes/reserve';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base class for reserve kind identification.
|
|
6
|
+
* Since a market can have multiple reserves for the same mint (with different terms),
|
|
7
|
+
* this kind specifies which reserve to select.
|
|
8
|
+
*/
|
|
9
|
+
export abstract class ReserveKind {
|
|
10
|
+
/**
|
|
11
|
+
* Checks if a reserve matches this reserve kind's criteria
|
|
12
|
+
*/
|
|
13
|
+
abstract matches(reserve: KaminoReserve): boolean;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Returns a human-readable string representation
|
|
17
|
+
*/
|
|
18
|
+
abstract toString(): string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Type check: returns true if this is an open-term reserve
|
|
22
|
+
*/
|
|
23
|
+
abstract isFloatRate(): boolean;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Type check: returns true if this is a fixed-term reserve
|
|
27
|
+
*/
|
|
28
|
+
abstract isFixedRate(): boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Represents an open-term reserve with no fixed maturity.
|
|
33
|
+
*/
|
|
34
|
+
export class FloatRateReserveKind extends ReserveKind {
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a reserve matches this open-term reserve kind (debtTermSeconds == 0)
|
|
37
|
+
*/
|
|
38
|
+
matches(reserve: KaminoReserve): boolean {
|
|
39
|
+
return reserve.state.config.debtTermSeconds.eq(new BN(0));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toString(): string {
|
|
43
|
+
return 'FloatRate';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
isFloatRate(): boolean {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
isFixedRate(): boolean {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Represents a fixed-term reserve with specific loan parameters.
|
|
57
|
+
*/
|
|
58
|
+
export class FixedRateReserveKind extends ReserveKind {
|
|
59
|
+
/**
|
|
60
|
+
* @param debtTermSeconds The debt term in seconds (e.g., new BN(30 * 24 * 60 * 60) for 30 days)
|
|
61
|
+
* @param borrowRateBps The maximum borrow rate in basis points (e.g., 500 for 5%)
|
|
62
|
+
*/
|
|
63
|
+
constructor(public readonly debtTermSeconds: BN, public readonly borrowRateBps: number) {
|
|
64
|
+
super();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks if a reserve matches this fixed-term reserve kind
|
|
69
|
+
*/
|
|
70
|
+
matches(reserve: KaminoReserve): boolean {
|
|
71
|
+
// Check debt term matches
|
|
72
|
+
if (!reserve.state.config.debtTermSeconds.eq(this.debtTermSeconds)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// For fixed-term reserves, all points on the borrow rate curve should have the same rate
|
|
77
|
+
const curvePoints = reserve.state.config.borrowRateCurve.points;
|
|
78
|
+
|
|
79
|
+
// Check if all points have the expected borrow rate
|
|
80
|
+
return curvePoints.every((point) => point.borrowRateBps === this.borrowRateBps);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
toString(): string {
|
|
84
|
+
return `FixedRate(term=${this.debtTermSeconds.toString()}s, rate=${this.borrowRateBps}bps)`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
isFloatRate(): boolean {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
isFixedRate(): boolean {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/utils/index.ts
CHANGED