@kamino-finance/klend-sdk 5.10.6 → 5.10.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/action.d.ts +7 -3
- package/dist/classes/action.d.ts.map +1 -1
- package/dist/classes/action.js +28 -13
- package/dist/classes/action.js.map +1 -1
- package/dist/classes/manager.d.ts +20 -18
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +27 -20
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/market.d.ts +11 -0
- package/dist/classes/market.d.ts.map +1 -1
- package/dist/classes/market.js +26 -0
- package/dist/classes/market.js.map +1 -1
- package/dist/classes/obligation.d.ts +14 -0
- package/dist/classes/obligation.d.ts.map +1 -1
- package/dist/classes/obligation.js +25 -0
- package/dist/classes/obligation.js.map +1 -1
- package/dist/classes/types_utils.d.ts +11 -0
- package/dist/classes/types_utils.d.ts.map +1 -0
- package/dist/classes/types_utils.js +21 -0
- package/dist/classes/types_utils.js.map +1 -0
- package/dist/classes/utils.d.ts +7 -0
- package/dist/classes/utils.d.ts.map +1 -1
- package/dist/classes/utils.js +21 -0
- package/dist/classes/utils.js.map +1 -1
- package/dist/classes/vault.d.ts +23 -14
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +65 -33
- package/dist/classes/vault.js.map +1 -1
- package/dist/client_kamino_manager.d.ts.map +1 -1
- package/dist/client_kamino_manager.js +25 -2
- package/dist/client_kamino_manager.js.map +1 -1
- package/dist/lending_operations/index.d.ts +1 -0
- package/dist/lending_operations/index.d.ts.map +1 -1
- package/dist/lending_operations/index.js +1 -0
- package/dist/lending_operations/index.js.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.d.ts +5 -5
- package/dist/lending_operations/repay_with_collateral_operations.d.ts.map +1 -1
- package/dist/lending_operations/repay_with_collateral_operations.js +3 -2
- package/dist/lending_operations/repay_with_collateral_operations.js.map +1 -1
- package/dist/lending_operations/swap_collateral_operations.d.ts +102 -0
- package/dist/lending_operations/swap_collateral_operations.d.ts.map +1 -0
- package/dist/lending_operations/swap_collateral_operations.js +306 -0
- package/dist/lending_operations/swap_collateral_operations.js.map +1 -0
- package/dist/leverage/operations.d.ts +2 -2
- package/dist/leverage/operations.d.ts.map +1 -1
- package/dist/leverage/operations.js +4 -0
- package/dist/leverage/operations.js.map +1 -1
- package/dist/leverage/types.d.ts +5 -5
- package/dist/leverage/types.d.ts.map +1 -1
- package/dist/leverage/utils.d.ts +5 -5
- package/dist/leverage/utils.d.ts.map +1 -1
- package/dist/leverage/utils.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/pubkey.d.ts +3 -0
- package/dist/utils/pubkey.d.ts.map +1 -1
- package/dist/utils/pubkey.js +16 -2
- package/dist/utils/pubkey.js.map +1 -1
- package/dist/utils/seeds.d.ts +1 -1
- package/dist/utils/seeds.js +1 -1
- package/package.json +4 -4
- package/src/classes/action.ts +37 -19
- package/src/classes/manager.ts +40 -23
- package/src/classes/market.ts +35 -1
- package/src/classes/obligation.ts +75 -0
- package/src/classes/types_utils.ts +19 -0
- package/src/classes/utils.ts +22 -1
- package/src/classes/vault.ts +93 -41
- package/src/client_kamino_manager.ts +43 -4
- package/src/lending_operations/index.ts +1 -0
- package/src/lending_operations/repay_with_collateral_operations.ts +10 -9
- package/src/lending_operations/swap_collateral_operations.ts +586 -0
- package/src/leverage/operations.ts +14 -10
- package/src/leverage/types.ts +6 -6
- package/src/leverage/utils.ts +8 -8
- package/src/utils/constants.ts +2 -0
- package/src/utils/pubkey.ts +19 -2
- package/src/utils/seeds.ts +1 -1
package/src/classes/action.ts
CHANGED
|
@@ -411,7 +411,7 @@ export class KaminoAction {
|
|
|
411
411
|
obligation: KaminoObligation | ObligationType,
|
|
412
412
|
extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
|
|
413
413
|
includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
|
|
414
|
-
requestElevationGroup: boolean = false,
|
|
414
|
+
requestElevationGroup: boolean = false, // to be requested *before* the deposit
|
|
415
415
|
includeUserMetadata: boolean = true, // if true it includes user metadata
|
|
416
416
|
referrer: PublicKey = PublicKey.default,
|
|
417
417
|
currentSlot: number = 0,
|
|
@@ -855,11 +855,17 @@ export class KaminoAction {
|
|
|
855
855
|
obligation: KaminoObligation | ObligationType,
|
|
856
856
|
extraComputeBudget: number = 1_000_000, // if > 0 then adds the ixn
|
|
857
857
|
includeAtaIxns: boolean = true, // if true it includes create and close wsol and token atas,
|
|
858
|
-
requestElevationGroup: boolean = false,
|
|
858
|
+
requestElevationGroup: boolean = false, // to be requested *after* the withdraw
|
|
859
859
|
includeUserMetadata: boolean = true, // if true it includes user metadata
|
|
860
860
|
referrer: PublicKey = PublicKey.default,
|
|
861
861
|
currentSlot: number = 0,
|
|
862
|
-
scopeRefresh: ScopeRefresh
|
|
862
|
+
scopeRefresh: ScopeRefresh | undefined = undefined,
|
|
863
|
+
overrideElevationGroupRequest?: number,
|
|
864
|
+
// Optional customizations which may be needed if the obligation was mutated by some previous ixn.
|
|
865
|
+
obligationCustomizations?: {
|
|
866
|
+
// Any newly-added deposit reserves.
|
|
867
|
+
addedDepositReserves?: PublicKey[];
|
|
868
|
+
}
|
|
863
869
|
) {
|
|
864
870
|
const axn = await KaminoAction.initialize(
|
|
865
871
|
'withdraw',
|
|
@@ -877,6 +883,8 @@ export class KaminoAction {
|
|
|
877
883
|
axn.addComputeBudgetIxn(extraComputeBudget);
|
|
878
884
|
}
|
|
879
885
|
|
|
886
|
+
axn.depositReserves.push(...(obligationCustomizations?.addedDepositReserves || []));
|
|
887
|
+
|
|
880
888
|
const allReserves = new PublicKeySet<PublicKey>([
|
|
881
889
|
...axn.depositReserves,
|
|
882
890
|
...axn.borrowReserves,
|
|
@@ -884,7 +892,7 @@ export class KaminoAction {
|
|
|
884
892
|
]).toArray();
|
|
885
893
|
const tokenIds = axn.getTokenIdsForScopeRefresh(kaminoMarket, allReserves);
|
|
886
894
|
|
|
887
|
-
if (tokenIds.length > 0 && scopeRefresh.includeScopeRefresh) {
|
|
895
|
+
if (tokenIds.length > 0 && scopeRefresh && scopeRefresh.includeScopeRefresh) {
|
|
888
896
|
await axn.addScopeRefreshIxs(tokenIds, scopeRefresh.scopeFeed);
|
|
889
897
|
}
|
|
890
898
|
|
|
@@ -893,7 +901,9 @@ export class KaminoAction {
|
|
|
893
901
|
includeAtaIxns,
|
|
894
902
|
requestElevationGroup,
|
|
895
903
|
includeUserMetadata,
|
|
896
|
-
addInitObligationForFarm
|
|
904
|
+
addInitObligationForFarm,
|
|
905
|
+
false,
|
|
906
|
+
overrideElevationGroupRequest
|
|
897
907
|
);
|
|
898
908
|
await axn.addWithdrawIx();
|
|
899
909
|
axn.addRefreshFarmsCleanupTxnIxsToCleanupIxs();
|
|
@@ -1827,6 +1837,16 @@ export class KaminoAction {
|
|
|
1827
1837
|
this.addRefreshReserveIxs(allReservesExcludingCurrent, addAsSupportIx);
|
|
1828
1838
|
this.addRefreshReserveIxs(currentReserveAddresses.toArray(), addAsSupportIx);
|
|
1829
1839
|
this.addRefreshObligationIx(addAsSupportIx);
|
|
1840
|
+
} else if (
|
|
1841
|
+
action === 'withdraw' &&
|
|
1842
|
+
overrideElevationGroupRequest !== undefined
|
|
1843
|
+
// Note: contrary to the 'deposit' case above, we allow requesting the same group as in the [stale, cached] obligation state, since our current use-case is "deposit X, withdraw Y"
|
|
1844
|
+
) {
|
|
1845
|
+
console.log('Withdraw: Requesting elevation group', overrideElevationGroupRequest);
|
|
1846
|
+
// Skip the withdrawn reserve if we are in the process of closing it:
|
|
1847
|
+
const skipReserveIfClosing = this.amount.eq(new BN(U64_MAX)) ? [this.reserve.address] : [];
|
|
1848
|
+
this.addRefreshObligationIx('cleanup', skipReserveIfClosing);
|
|
1849
|
+
this.addRequestElevationIx(overrideElevationGroupRequest, 'cleanup', skipReserveIfClosing);
|
|
1830
1850
|
}
|
|
1831
1851
|
}
|
|
1832
1852
|
|
|
@@ -1996,7 +2016,7 @@ export class KaminoAction {
|
|
|
1996
2016
|
});
|
|
1997
2017
|
}
|
|
1998
2018
|
|
|
1999
|
-
private addRefreshObligationIx(addAsSupportIx: AuxiliaryIx = 'setup',
|
|
2019
|
+
private addRefreshObligationIx(addAsSupportIx: AuxiliaryIx = 'setup', skipReserves: PublicKey[] = []) {
|
|
2000
2020
|
const marketAddress = this.kaminoMarket.getAddress();
|
|
2001
2021
|
const obligationPda = this.getObligationPda();
|
|
2002
2022
|
const refreshObligationIx = refreshObligation(
|
|
@@ -2007,15 +2027,16 @@ export class KaminoAction {
|
|
|
2007
2027
|
this.kaminoMarket.programId
|
|
2008
2028
|
);
|
|
2009
2029
|
|
|
2010
|
-
const
|
|
2030
|
+
const skipReservesSet = new PublicKeySet(skipReserves);
|
|
2011
2031
|
|
|
2032
|
+
const depositReservesList = this.getAdditionalDepositReservesList().filter(
|
|
2033
|
+
(reserve) => !skipReservesSet.contains(reserve)
|
|
2034
|
+
);
|
|
2012
2035
|
const depositReserveAccountMetas = depositReservesList.map((reserve) => {
|
|
2013
2036
|
return { pubkey: reserve, isSigner: false, isWritable: true };
|
|
2014
2037
|
});
|
|
2015
2038
|
|
|
2016
|
-
const
|
|
2017
|
-
const borrowReservesList = this.borrowReserves.filter((reserve) => !skipBorrowsSet.contains(reserve));
|
|
2018
|
-
|
|
2039
|
+
const borrowReservesList = this.borrowReserves.filter((reserve) => !skipReservesSet.contains(reserve));
|
|
2019
2040
|
const borrowReserveAccountMetas = borrowReservesList.map((reserve) => {
|
|
2020
2041
|
return { pubkey: reserve, isSigner: false, isWritable: true };
|
|
2021
2042
|
});
|
|
@@ -2048,11 +2069,7 @@ export class KaminoAction {
|
|
|
2048
2069
|
}
|
|
2049
2070
|
}
|
|
2050
2071
|
|
|
2051
|
-
private addRequestElevationIx(
|
|
2052
|
-
elevationGroup: number,
|
|
2053
|
-
addAsSupportIx: AuxiliaryIx,
|
|
2054
|
-
skipBorrowReserves: PublicKey[] = []
|
|
2055
|
-
) {
|
|
2072
|
+
private addRequestElevationIx(elevationGroup: number, addAsSupportIx: AuxiliaryIx, skipReserves: PublicKey[] = []) {
|
|
2056
2073
|
const obligationPda = this.getObligationPda();
|
|
2057
2074
|
const args: RequestElevationGroupArgs = {
|
|
2058
2075
|
elevationGroup,
|
|
@@ -2065,15 +2082,16 @@ export class KaminoAction {
|
|
|
2065
2082
|
|
|
2066
2083
|
const requestElevationGroupIx = requestElevationGroup(args, accounts, this.kaminoMarket.programId);
|
|
2067
2084
|
|
|
2068
|
-
const
|
|
2085
|
+
const skipReservesSet = new PublicKeySet<PublicKey>(skipReserves);
|
|
2069
2086
|
|
|
2087
|
+
const depositReservesList = this.getAdditionalDepositReservesList().filter(
|
|
2088
|
+
(reserve) => !skipReservesSet.contains(reserve)
|
|
2089
|
+
);
|
|
2070
2090
|
const depositReserveAccountMetas = depositReservesList.map((reserve) => {
|
|
2071
2091
|
return { pubkey: reserve, isSigner: false, isWritable: true };
|
|
2072
2092
|
});
|
|
2073
2093
|
|
|
2074
|
-
const
|
|
2075
|
-
const borrowReservesList = this.borrowReserves.filter((reserve) => !skipBorrowReservesSet.contains(reserve));
|
|
2076
|
-
|
|
2094
|
+
const borrowReservesList = this.borrowReserves.filter((reserve) => !skipReservesSet.contains(reserve));
|
|
2077
2095
|
const borrowReserveAccountMetas = borrowReservesList.map((reserve) => {
|
|
2078
2096
|
return { pubkey: reserve, isSigner: false, isWritable: true };
|
|
2079
2097
|
});
|
package/src/classes/manager.ts
CHANGED
|
@@ -66,7 +66,7 @@ import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
|
66
66
|
import { Data } from '@kamino-finance/kliquidity-sdk';
|
|
67
67
|
import bs58 from 'bs58';
|
|
68
68
|
import { getProgramAccounts } from '../utils/rpc';
|
|
69
|
-
import { VaultConfigFieldKind } from '../idl_codegen_kamino_vault/types';
|
|
69
|
+
import { VaultConfigField, VaultConfigFieldKind } from '../idl_codegen_kamino_vault/types';
|
|
70
70
|
import {
|
|
71
71
|
AcceptVaultOwnershipIxs,
|
|
72
72
|
DepositIxs,
|
|
@@ -369,9 +369,14 @@ export class KaminoManager {
|
|
|
369
369
|
*/
|
|
370
370
|
async updateVaultConfigIxs(
|
|
371
371
|
vault: KaminoVault,
|
|
372
|
-
mode: VaultConfigFieldKind,
|
|
372
|
+
mode: VaultConfigFieldKind | string,
|
|
373
373
|
value: string
|
|
374
374
|
): Promise<UpdateVaultConfigIxs> {
|
|
375
|
+
if (typeof mode === 'string') {
|
|
376
|
+
const field = VaultConfigField.fromDecoded({ [mode]: '' });
|
|
377
|
+
return this._vaultClient.updateVaultConfigIxs(vault, field, value);
|
|
378
|
+
}
|
|
379
|
+
|
|
375
380
|
return this._vaultClient.updateVaultConfigIxs(vault, mode, value);
|
|
376
381
|
}
|
|
377
382
|
|
|
@@ -465,21 +470,26 @@ export class KaminoManager {
|
|
|
465
470
|
/**
|
|
466
471
|
* This method calculates the token per share value. This will always change based on interest earned from the vault, but calculating it requires a bunch of rpc requests. Caching this for a short duration would be optimal
|
|
467
472
|
* @param vault - vault to calculate tokensPerShare for
|
|
468
|
-
* @param slot -
|
|
473
|
+
* @param [slot] - the slot at which we retrieve the tokens per share. Optional. If not provided, the function will fetch the current slot
|
|
474
|
+
* @param [vaultReservesMap] - hashmap from each reserve pubkey to the reserve state. Optional. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
469
475
|
* @returns - token per share value
|
|
470
476
|
*/
|
|
471
|
-
async getTokensPerShareSingleVault(
|
|
472
|
-
|
|
477
|
+
async getTokensPerShareSingleVault(
|
|
478
|
+
vault: KaminoVault,
|
|
479
|
+
slot?: number,
|
|
480
|
+
vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
|
|
481
|
+
): Promise<Decimal> {
|
|
482
|
+
return this._vaultClient.getTokensPerShareSingleVault(vault, slot, vaultReservesMap);
|
|
473
483
|
}
|
|
474
484
|
|
|
475
485
|
/**
|
|
476
486
|
* This method calculates the price of one vault share(kToken)
|
|
477
487
|
* @param vault - vault to calculate sharePrice for
|
|
478
|
-
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
479
488
|
* @param tokenPrice - the price of the vault token (e.g. SOL) in USD
|
|
489
|
+
* @param [slot] - the slot at which we retrieve the tokens per share. Optional. If not provided, the function will fetch the current slot
|
|
480
490
|
* @returns - share value in USD
|
|
481
491
|
*/
|
|
482
|
-
async getSharePriceInUSD(vault: KaminoVault,
|
|
492
|
+
async getSharePriceInUSD(vault: KaminoVault, tokenPrice: Decimal, slot?: number): Promise<Decimal> {
|
|
483
493
|
const tokensPerShare = await this.getTokensPerShareSingleVault(vault, slot);
|
|
484
494
|
return tokensPerShare.mul(tokenPrice);
|
|
485
495
|
}
|
|
@@ -638,13 +648,13 @@ export class KaminoManager {
|
|
|
638
648
|
/**
|
|
639
649
|
* This will return an VaultHoldings object which contains the amount available (uninvested) in vault, total amount invested in reseves and a breakdown of the amount invested in each reserve
|
|
640
650
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
641
|
-
* @param slot - current slot
|
|
642
|
-
* @param vaultReserves -
|
|
651
|
+
* @param [slot] - the slot for which to calculate the holdings. Optional. If not provided the function will fetch the current slot
|
|
652
|
+
* @param [vaultReserves] - a hashmap from each reserve pubkey to the reserve state. Optional. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
643
653
|
* @returns an VaultHoldings object
|
|
644
654
|
*/
|
|
645
655
|
async getVaultHoldings(
|
|
646
656
|
vault: VaultState,
|
|
647
|
-
slot
|
|
657
|
+
slot?: number,
|
|
648
658
|
vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
|
|
649
659
|
): Promise<VaultHoldings> {
|
|
650
660
|
return this._vaultClient.getVaultHoldings(vault, slot, vaultReserves);
|
|
@@ -653,37 +663,37 @@ export class KaminoManager {
|
|
|
653
663
|
/**
|
|
654
664
|
* This will return an VaultHoldingsWithUSDValue object which contains an holdings field representing the amount available (uninvested) in vault, total amount invested in reseves and a breakdown of the amount invested in each reserve and additional fields for the total USD value of the available and invested amounts
|
|
655
665
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
656
|
-
* @param slot - current slot
|
|
657
|
-
* @param vaultReserves - optional parameter; a hashmap from each reserve pubkey to the reserve state. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
658
666
|
* @param price - the price of the token in the vault (e.g. USDC)
|
|
667
|
+
* @param [slot] - the slot for which to calculate the holdings. Optional. If not provided the function will fetch the current slot
|
|
668
|
+
* @param [vaultReservesMap] - hashmap from each reserve pubkey to the reserve state. Optional. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
659
669
|
* @returns an VaultHoldingsWithUSDValue object with details about the tokens available and invested in the vault, denominated in tokens and USD
|
|
660
670
|
*/
|
|
661
671
|
async getVaultHoldingsWithPrice(
|
|
662
672
|
vault: VaultState,
|
|
663
|
-
slot: number,
|
|
664
673
|
price: Decimal,
|
|
674
|
+
slot?: number,
|
|
665
675
|
vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
|
|
666
676
|
): Promise<VaultHoldingsWithUSDValue> {
|
|
667
|
-
return this._vaultClient.getVaultHoldingsWithPrice(vault,
|
|
677
|
+
return this._vaultClient.getVaultHoldingsWithPrice(vault, price, slot, vaultReserves);
|
|
668
678
|
}
|
|
669
679
|
|
|
670
680
|
/**
|
|
671
681
|
* This will return an VaultOverview object that encapsulates all the information about the vault, including the holdings, reserves details, theoretical APY, utilization ratio and total borrowed amount
|
|
672
682
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
673
|
-
* @param slot - current slot
|
|
674
683
|
* @param price - the price of the token in the vault (e.g. USDC)
|
|
675
|
-
* @param
|
|
676
|
-
* @param
|
|
677
|
-
* @
|
|
684
|
+
* @param [slot] - the slot for which to retrieve the vault overview for. Optional. If not provided the function will fetch the current slot
|
|
685
|
+
* @param [vaultReservesMap] - hashmap from each reserve pubkey to the reserve state. Optional. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
686
|
+
* @param [kaminoMarkets] - a list of all kamino markets. Optional. If provided the function will be significantly faster as it will not have to fetch the markets
|
|
687
|
+
* @returns an VaultOverview object with details about the tokens available and invested in the vault, denominated in tokens and USD
|
|
678
688
|
*/
|
|
679
689
|
async getVaultOverview(
|
|
680
690
|
vault: VaultState,
|
|
681
|
-
slot: number,
|
|
682
691
|
price: Decimal,
|
|
692
|
+
slot?: number,
|
|
683
693
|
vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>,
|
|
684
694
|
kaminoMarkets?: KaminoMarket[]
|
|
685
695
|
): Promise<VaultOverview> {
|
|
686
|
-
return this._vaultClient.getVaultOverview(vault,
|
|
696
|
+
return this._vaultClient.getVaultOverview(vault, price, slot, vaultReserves, kaminoMarkets);
|
|
687
697
|
}
|
|
688
698
|
|
|
689
699
|
/**
|
|
@@ -743,16 +753,23 @@ export class KaminoManager {
|
|
|
743
753
|
/**
|
|
744
754
|
* Simulate the current holdings of the vault and the earned interest
|
|
745
755
|
* @param vaultState the kamino vault state to get simulated holdings and earnings for
|
|
746
|
-
* @param
|
|
756
|
+
* @param [vaultReservesMap] - hashmap from each reserve pubkey to the reserve state. Optional. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
747
757
|
* @param [currentSlot] - the current slot. Optional. If not provided it will fetch the current slot
|
|
758
|
+
* @param [previousTotalAUM] - the previous AUM of the vault to compute the earned interest relative to this value. Optional. If not provided the function will estimate the total AUM at the slot of the last state update on chain
|
|
748
759
|
* @returns a struct of simulated vault holdings and earned interest
|
|
749
760
|
*/
|
|
750
761
|
async calculateSimulatedHoldingsWithInterest(
|
|
751
762
|
vaultState: VaultState,
|
|
752
763
|
vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>,
|
|
753
|
-
currentSlot?: number
|
|
764
|
+
currentSlot?: number,
|
|
765
|
+
previousTotalAUM?: Decimal
|
|
754
766
|
): Promise<SimulatedVaultHoldingsWithEarnedInterest> {
|
|
755
|
-
return this._vaultClient.calculateSimulatedHoldingsWithInterest(
|
|
767
|
+
return this._vaultClient.calculateSimulatedHoldingsWithInterest(
|
|
768
|
+
vaultState,
|
|
769
|
+
vaultReserves,
|
|
770
|
+
currentSlot,
|
|
771
|
+
previousTotalAUM
|
|
772
|
+
);
|
|
756
773
|
}
|
|
757
774
|
|
|
758
775
|
/**
|
package/src/classes/market.ts
CHANGED
|
@@ -169,6 +169,26 @@ export class KaminoMarket {
|
|
|
169
169
|
return this.state.elevationGroups[elevationGroup - 1];
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Returns this market's elevation group of the given ID, or `null` for the default group `0`, or throws an error
|
|
174
|
+
* (including the given description) if the requested group does not exist.
|
|
175
|
+
*/
|
|
176
|
+
getExistingElevationGroup(
|
|
177
|
+
elevationGroupId: number,
|
|
178
|
+
description: string = 'Requested'
|
|
179
|
+
): ElevationGroupDescription | null {
|
|
180
|
+
if (elevationGroupId === 0) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const elevationGroup = this.getMarketElevationGroupDescriptions().find(
|
|
184
|
+
(candidate) => candidate.elevationGroup === elevationGroupId
|
|
185
|
+
);
|
|
186
|
+
if (elevationGroup === undefined) {
|
|
187
|
+
throw new Error(`${description} elevation group ${elevationGroupId} not found in market ${this.getAddress()}`);
|
|
188
|
+
}
|
|
189
|
+
return elevationGroup;
|
|
190
|
+
}
|
|
191
|
+
|
|
172
192
|
getMinNetValueObligation(): Decimal {
|
|
173
193
|
return new Fraction(this.state.minNetValueInObligationSf).toDecimal();
|
|
174
194
|
}
|
|
@@ -399,7 +419,7 @@ export class KaminoMarket {
|
|
|
399
419
|
return this.reserves.get(address);
|
|
400
420
|
}
|
|
401
421
|
|
|
402
|
-
getReserveByMint(address: PublicKey) {
|
|
422
|
+
getReserveByMint(address: PublicKey): KaminoReserve | undefined {
|
|
403
423
|
for (const reserve of this.reserves.values()) {
|
|
404
424
|
if (reserve.getLiquidityMint().equals(address)) {
|
|
405
425
|
return reserve;
|
|
@@ -408,6 +428,18 @@ export class KaminoMarket {
|
|
|
408
428
|
return undefined;
|
|
409
429
|
}
|
|
410
430
|
|
|
431
|
+
/**
|
|
432
|
+
* Returns this market's reserve of the given mint address, or throws an error (including the given description) if
|
|
433
|
+
* such reserve does not exist.
|
|
434
|
+
*/
|
|
435
|
+
getExistingReserveByMint(address: PublicKey, description: string = 'Requested'): KaminoReserve {
|
|
436
|
+
const reserve = this.getReserveByMint(address);
|
|
437
|
+
if (!reserve) {
|
|
438
|
+
throw new Error(`${description} reserve with mint ${address} not found in market ${this.getAddress()}`);
|
|
439
|
+
}
|
|
440
|
+
return reserve;
|
|
441
|
+
}
|
|
442
|
+
|
|
411
443
|
getReserveBySymbol(symbol: string) {
|
|
412
444
|
for (const reserve of this.reserves.values()) {
|
|
413
445
|
if (reserve.symbol === symbol) {
|
|
@@ -1297,6 +1329,7 @@ export class KaminoMarket {
|
|
|
1297
1329
|
debtReserve: elevationGroup.debtReserve,
|
|
1298
1330
|
debtLiquidityMint: PublicKey.default,
|
|
1299
1331
|
elevationGroup: elevationGroup.id,
|
|
1332
|
+
maxReservesAsCollateral: elevationGroup.maxReservesAsCollateral,
|
|
1300
1333
|
});
|
|
1301
1334
|
}
|
|
1302
1335
|
|
|
@@ -1392,6 +1425,7 @@ export type ElevationGroupDescription = {
|
|
|
1392
1425
|
debtReserve: PublicKey;
|
|
1393
1426
|
debtLiquidityMint: PublicKey;
|
|
1394
1427
|
elevationGroup: number;
|
|
1428
|
+
maxReservesAsCollateral: number;
|
|
1395
1429
|
};
|
|
1396
1430
|
|
|
1397
1431
|
export type KlendPrices = {
|
|
@@ -262,6 +262,11 @@ export class KaminoObligation {
|
|
|
262
262
|
return undefined;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
getBorrowAmountByReserve(reserve: KaminoReserve): Decimal {
|
|
266
|
+
const amountLamports = this.getBorrowByMint(reserve.getLiquidityMint())?.amount ?? new Decimal(0);
|
|
267
|
+
return amountLamports.div(reserve.getMintFactor());
|
|
268
|
+
}
|
|
269
|
+
|
|
265
270
|
getDepositByMint(mint: PublicKey): Position | undefined {
|
|
266
271
|
for (const value of this.deposits.values()) {
|
|
267
272
|
if (value.mintAddress.equals(mint)) {
|
|
@@ -271,6 +276,11 @@ export class KaminoObligation {
|
|
|
271
276
|
return undefined;
|
|
272
277
|
}
|
|
273
278
|
|
|
279
|
+
getDepositAmountByReserve(reserve: KaminoReserve): Decimal {
|
|
280
|
+
const amountLamports = this.getDepositByMint(reserve.getLiquidityMint())?.amount ?? new Decimal(0);
|
|
281
|
+
return amountLamports.div(reserve.getMintFactor());
|
|
282
|
+
}
|
|
283
|
+
|
|
274
284
|
/**
|
|
275
285
|
*
|
|
276
286
|
* @returns Market value of the borrow in the specified obligation liquidity/borrow asset (USD) (no borrow factor weighting)
|
|
@@ -652,6 +662,71 @@ export class KaminoObligation {
|
|
|
652
662
|
};
|
|
653
663
|
}
|
|
654
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Calculates the stats of the obligation after a hypothetical collateral swap.
|
|
667
|
+
*/
|
|
668
|
+
getPostSwapCollObligationStats(params: {
|
|
669
|
+
withdrawAmountLamports: Decimal;
|
|
670
|
+
withdrawReserveAddress: PublicKey;
|
|
671
|
+
depositAmountLamports: Decimal;
|
|
672
|
+
depositReserveAddress: PublicKey;
|
|
673
|
+
newElevationGroup: number;
|
|
674
|
+
market: KaminoMarket;
|
|
675
|
+
slot: number;
|
|
676
|
+
}): ObligationStats {
|
|
677
|
+
const {
|
|
678
|
+
withdrawAmountLamports,
|
|
679
|
+
withdrawReserveAddress,
|
|
680
|
+
depositAmountLamports,
|
|
681
|
+
depositReserveAddress,
|
|
682
|
+
newElevationGroup,
|
|
683
|
+
market,
|
|
684
|
+
slot,
|
|
685
|
+
} = params;
|
|
686
|
+
|
|
687
|
+
const additionalReserves = [withdrawReserveAddress, depositReserveAddress].filter(
|
|
688
|
+
(reserveAddress) => !market.isReserveInObligation(this, reserveAddress)
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
const { collateralExchangeRates } = KaminoObligation.getRatesForObligation(
|
|
692
|
+
market,
|
|
693
|
+
this.state,
|
|
694
|
+
slot,
|
|
695
|
+
additionalReserves
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
let newObligationDeposits = this.state.deposits;
|
|
699
|
+
newObligationDeposits = this.simulateDepositChange(
|
|
700
|
+
newObligationDeposits,
|
|
701
|
+
withdrawAmountLamports.neg().toNumber(),
|
|
702
|
+
withdrawReserveAddress,
|
|
703
|
+
collateralExchangeRates
|
|
704
|
+
);
|
|
705
|
+
newObligationDeposits = this.simulateDepositChange(
|
|
706
|
+
newObligationDeposits,
|
|
707
|
+
depositAmountLamports.toNumber(),
|
|
708
|
+
depositReserveAddress,
|
|
709
|
+
collateralExchangeRates
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
const { refreshedStats } = this.calculatePositions(
|
|
713
|
+
market,
|
|
714
|
+
newObligationDeposits,
|
|
715
|
+
this.state.borrows,
|
|
716
|
+
newElevationGroup,
|
|
717
|
+
collateralExchangeRates,
|
|
718
|
+
null
|
|
719
|
+
);
|
|
720
|
+
|
|
721
|
+
const newStats = refreshedStats;
|
|
722
|
+
newStats.netAccountValue = newStats.userTotalDeposit.minus(newStats.userTotalBorrow);
|
|
723
|
+
newStats.loanToValue = valueOrZero(
|
|
724
|
+
newStats.userTotalBorrowBorrowFactorAdjusted.dividedBy(newStats.userTotalCollateralDeposit)
|
|
725
|
+
);
|
|
726
|
+
newStats.leverage = valueOrZero(newStats.userTotalDeposit.dividedBy(newStats.netAccountValue));
|
|
727
|
+
return newStats;
|
|
728
|
+
}
|
|
729
|
+
|
|
655
730
|
estimateObligationInterestRate = (
|
|
656
731
|
market: KaminoMarket,
|
|
657
732
|
reserve: KaminoReserve,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { pubkeyHashMapToJson } from './utils';
|
|
2
|
+
import { VaultHoldings } from './vault';
|
|
3
|
+
|
|
4
|
+
export function holdingsToJson(holdings: VaultHoldings) {
|
|
5
|
+
return {
|
|
6
|
+
available: holdings.available.toString(),
|
|
7
|
+
invested: holdings.invested.toString(),
|
|
8
|
+
total: holdings.total.toString(),
|
|
9
|
+
investedInReserves: pubkeyHashMapToJson(holdings.investedInReserves),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function printHoldings(holdings: VaultHoldings) {
|
|
14
|
+
console.log('Holdings:');
|
|
15
|
+
console.log(' Available:', holdings.available.toString());
|
|
16
|
+
console.log(' Invested:', holdings.invested.toString());
|
|
17
|
+
console.log(' Total:', holdings.total.toString());
|
|
18
|
+
console.log(' Invested in reserves:', pubkeyHashMapToJson(holdings.investedInReserves));
|
|
19
|
+
}
|
package/src/classes/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SLOTS_PER_SECOND, SLOTS_PER_YEAR } from '../utils';
|
|
1
|
+
import { PubkeyHashMap, SLOTS_PER_SECOND, SLOTS_PER_YEAR } from '../utils';
|
|
2
2
|
import Decimal from 'decimal.js';
|
|
3
3
|
import { AccountInfo, PublicKey } from '@solana/web3.js';
|
|
4
4
|
import { SOL_MINTS } from '../lib';
|
|
@@ -250,3 +250,24 @@ export function truncateDecimals(num: Decimal.Value, maxDecimals: number): Decim
|
|
|
250
250
|
const factor = new Decimal(10).pow(maxDecimals);
|
|
251
251
|
return new Decimal(num).times(factor).floor().dividedBy(factor);
|
|
252
252
|
}
|
|
253
|
+
|
|
254
|
+
/**Convert an u8 array to a string */
|
|
255
|
+
export function decodeVaultName(token: number[]): string {
|
|
256
|
+
const maxArray = new Uint8Array(token);
|
|
257
|
+
let s: string = new TextDecoder().decode(maxArray);
|
|
258
|
+
// Remove trailing zeros and spaces
|
|
259
|
+
s = s.replace(/[\0 ]+$/, '');
|
|
260
|
+
return s;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function pubkeyHashMapToJson(map: PubkeyHashMap<PublicKey, any>): { [key: string]: string } {
|
|
264
|
+
const obj: { [key: string]: any } = {};
|
|
265
|
+
map.forEach((value, key) => {
|
|
266
|
+
obj[key.toBase58()] = value.toString();
|
|
267
|
+
});
|
|
268
|
+
return obj;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function printPubkeyHashMap<V>(map: PubkeyHashMap<PublicKey, V>) {
|
|
272
|
+
console.log(pubkeyHashMapToJson(map));
|
|
273
|
+
}
|