@kamino-finance/klend-sdk 5.10.0 → 5.10.2

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.
Files changed (37) hide show
  1. package/dist/classes/farm_utils.d.ts +22 -0
  2. package/dist/classes/farm_utils.d.ts.map +1 -0
  3. package/dist/classes/farm_utils.js +93 -0
  4. package/dist/classes/farm_utils.js.map +1 -0
  5. package/dist/classes/lut_utils.d.ts +29 -0
  6. package/dist/classes/lut_utils.d.ts.map +1 -0
  7. package/dist/classes/lut_utils.js +62 -0
  8. package/dist/classes/lut_utils.js.map +1 -0
  9. package/dist/classes/manager.d.ts +51 -28
  10. package/dist/classes/manager.d.ts.map +1 -1
  11. package/dist/classes/manager.js +53 -27
  12. package/dist/classes/manager.js.map +1 -1
  13. package/dist/classes/types.d.ts +15 -0
  14. package/dist/classes/types.d.ts.map +1 -1
  15. package/dist/classes/utils.d.ts +6 -0
  16. package/dist/classes/utils.d.ts.map +1 -1
  17. package/dist/classes/utils.js +10 -0
  18. package/dist/classes/utils.js.map +1 -1
  19. package/dist/classes/vault.d.ts +84 -56
  20. package/dist/classes/vault.d.ts.map +1 -1
  21. package/dist/classes/vault.js +229 -134
  22. package/dist/classes/vault.js.map +1 -1
  23. package/dist/client_kamino_manager.d.ts.map +1 -1
  24. package/dist/client_kamino_manager.js +10 -26
  25. package/dist/client_kamino_manager.js.map +1 -1
  26. package/dist/utils/ata.d.ts.map +1 -1
  27. package/dist/utils/ata.js +1 -0
  28. package/dist/utils/ata.js.map +1 -1
  29. package/package.json +6 -6
  30. package/src/classes/farm_utils.ts +155 -0
  31. package/src/classes/lut_utils.ts +63 -0
  32. package/src/classes/manager.ts +75 -31
  33. package/src/classes/types.ts +18 -0
  34. package/src/classes/utils.ts +10 -0
  35. package/src/classes/vault.ts +315 -158
  36. package/src/client_kamino_manager.ts +19 -33
  37. package/src/utils/ata.ts +1 -0
@@ -21,6 +21,7 @@ import {
21
21
  lamportsToDecimal,
22
22
  PubkeyHashMap,
23
23
  Reserve,
24
+ UserState,
24
25
  WRAPPED_SOL_MINT,
25
26
  } from '../lib';
26
27
  import {
@@ -58,18 +59,30 @@ import { withdraw } from '../idl_codegen_kamino_vault/instructions';
58
59
  import { PROGRAM_ID } from '../idl_codegen/programId';
59
60
  import { DEFAULT_RECENT_SLOT_DURATION_MS, ReserveWithAddress } from './reserve';
60
61
  import { Fraction } from './fraction';
61
- import { createAtasIdempotent, lendingMarketAuthPda, PublicKeySet, SECONDS_PER_YEAR } from '../utils';
62
+ import { createAtasIdempotent, lendingMarketAuthPda, PublicKeySet, SECONDS_PER_YEAR, U64_MAX } from '../utils';
62
63
  import bs58 from 'bs58';
63
64
  import { getAccountOwner, getProgramAccounts } from '../utils/rpc';
64
65
  import {
65
66
  AcceptVaultOwnershipIxs,
67
+ DepositIxs,
66
68
  InitVaultIxs,
67
69
  SyncVaultLUTIxs,
68
70
  UpdateReserveAllocationIxs,
69
71
  UpdateVaultConfigIxs,
72
+ UserSharesForVault,
73
+ WithdrawIxs,
70
74
  } from './types';
71
75
  import { collToLamportsDecimal } from '@kamino-finance/kliquidity-sdk';
72
76
  import { FullBPSDecimal } from '@kamino-finance/kliquidity-sdk/dist/utils/CreationParameters';
77
+ import { FarmState } from '@kamino-finance/farms-sdk/dist';
78
+ import { getAccountsInLUT, initLookupTableIx } from './lut_utils';
79
+ import {
80
+ getFarmStakeIxs,
81
+ getFarmUnstakeAndWithdrawIxs,
82
+ getFarmUserStatePDA,
83
+ getSharesInFarmUserPosition,
84
+ getUserSharesInFarm,
85
+ } from './farm_utils';
73
86
 
74
87
  export const kaminoVaultId = new PublicKey('kvauTFR8qm1dhniz6pYuBZkuene3Hfrs1VQhVRgCNrr');
75
88
  export const kaminoVaultStagingId = new PublicKey('STkvh7ostar39Fwr4uZKASs1RNNuYMFMTsE77FiRsL2');
@@ -108,10 +121,13 @@ export class KaminoVaultClient {
108
121
  return this._kaminoVaultProgramId;
109
122
  }
110
123
 
124
+ hasFarm() {
125
+ return;
126
+ }
127
+
111
128
  /**
112
129
  * This method will create a vault with a given config. The config can be changed later on, but it is recommended to set it up correctly from the start
113
130
  * @param vaultConfig - the config object used to create a vault
114
- * @returns vault - keypair, should be used to sign the transaction which creates the vault account
115
131
  * @returns vault: the keypair of the vault, used to sign the initialization transaction; initVaultIxs: a struct with ixs to initialize the vault and its lookup table + populateLUTIxs, a list to populate the lookup table which has to be executed in a separate transaction
116
132
  */
117
133
  async createVaultIxs(vaultConfig: KaminoVaultConfig): Promise<{ vault: Keypair; initVaultIxs: InitVaultIxs }> {
@@ -121,7 +137,7 @@ export class KaminoVaultClient {
121
137
  const createVaultIx = SystemProgram.createAccount({
122
138
  fromPubkey: vaultConfig.admin,
123
139
  newAccountPubkey: vaultState.publicKey,
124
- lamports: await this._connection.getMinimumBalanceForRentExemption(size),
140
+ lamports: await this.getConnection().getMinimumBalanceForRentExemption(size),
125
141
  space: size,
126
142
  programId: this._kaminoVaultProgramId,
127
143
  });
@@ -156,8 +172,8 @@ export class KaminoVaultClient {
156
172
  const initVaultIx = initVault(initVaultAccounts, this._kaminoVaultProgramId);
157
173
 
158
174
  // create and set up the vault lookup table
159
- const slot = await this._connection.getSlot();
160
- const [createLUTIx, lut] = this.getInitLookupTableIx(vaultConfig.admin, slot);
175
+ const slot = await this.getConnection().getSlot();
176
+ const [createLUTIx, lut] = initLookupTableIx(vaultConfig.admin, slot);
161
177
 
162
178
  const accountsToBeInserted = [
163
179
  vaultConfig.admin,
@@ -218,7 +234,7 @@ export class KaminoVaultClient {
218
234
  * This method updates the vault reserve allocation cofnig for an exiting vault reserve, or adds a new reserve to the vault if it does not exist.
219
235
  * @param vault - vault to be updated
220
236
  * @param reserveAllocationConfig - new reserve allocation config
221
- * @returns - a list of instructions
237
+ * @returns - a struct with an instruction to update the reserve allocation and an optional list of instructions to update the lookup table for the allocation changes
222
238
  */
223
239
  async updateReserveAllocationIxs(
224
240
  vault: KaminoVault,
@@ -347,7 +363,7 @@ export class KaminoVaultClient {
347
363
 
348
364
  const updateLUTIxs = [];
349
365
 
350
- if (mode.kind === new VaultConfigField.PendingVaultAdmin().kind || mode.kind === new VaultConfigField.Farm().kind) {
366
+ if (mode.kind === new VaultConfigField.PendingVaultAdmin().kind) {
351
367
  const newPubkey = new PublicKey(value);
352
368
  const insertIntoLutIxs = await this.insertIntoLookupTableIxs(
353
369
  vaultState.adminAuthority,
@@ -355,6 +371,27 @@ export class KaminoVaultClient {
355
371
  [newPubkey]
356
372
  );
357
373
  updateLUTIxs.push(...insertIntoLutIxs);
374
+ } else if (mode.kind === new VaultConfigField.Farm().kind) {
375
+ const keysToAddToLUT = [new PublicKey(value)];
376
+ // if the farm already exist we want to read its state to add it to the LUT
377
+ try {
378
+ const farmState = await FarmState.fetch(this.getConnection(), keysToAddToLUT[0]);
379
+ keysToAddToLUT.push(
380
+ farmState!.farmVault,
381
+ farmState!.farmVaultsAuthority,
382
+ farmState!.token.mint,
383
+ farmState!.scopePrices,
384
+ farmState!.globalConfig
385
+ );
386
+ const insertIntoLutIxs = await this.insertIntoLookupTableIxs(
387
+ vaultState.adminAuthority,
388
+ vaultState.vaultLookupTable,
389
+ keysToAddToLUT
390
+ );
391
+ updateLUTIxs.push(...insertIntoLutIxs);
392
+ } catch (error) {
393
+ console.log(`Error fetching farm ${keysToAddToLUT[0].toString()} state`, error);
394
+ }
358
395
  }
359
396
 
360
397
  const updateVaultConfigIxs: UpdateVaultConfigIxs = {
@@ -365,14 +402,31 @@ export class KaminoVaultClient {
365
402
  return updateVaultConfigIxs;
366
403
  }
367
404
 
405
+ /** Sets the farm where the shares can be staked. This is store in vault state and a vault can only have one farm, so the new farm will ovveride the old farm
406
+ * @param vault - vault to set the farm for
407
+ * @param farm - the farm where the vault shares can be staked
408
+ * @param [errorOnOverride] - if true, the function will throw an error if the vault already has a farm. If false, it will override the farm
409
+ */
410
+ async setVaultFarm(
411
+ vault: KaminoVault,
412
+ farm: PublicKey,
413
+ errorOnOverride: boolean = true
414
+ ): Promise<UpdateVaultConfigIxs> {
415
+ const vaultHasFarm = await vault.hasFarm(this.getConnection());
416
+ if (vaultHasFarm && errorOnOverride) {
417
+ throw new Error('Vault already has a farm, if you want to override it set errorOnOverride to false');
418
+ }
419
+ return this.updateVaultConfigIxs(vault, new VaultConfigField.Farm(), farm.toBase58());
420
+ }
421
+
368
422
  /**
369
423
  * This method updates the vault config for a vault that
370
424
  * @param vault - address of vault to be updated
371
425
  * @param mode - the field to be updated
372
426
  * @param value - the new value for the field to be updated (number or pubkey)
373
- * @returns - a list of instructions
427
+ * @returns - an instruction to update the vault config
374
428
  */
375
- updateUninitialisedVaultConfigIx(
429
+ private updateUninitialisedVaultConfigIx(
376
430
  admin: PublicKey,
377
431
  vault: PublicKey,
378
432
  mode: VaultConfigFieldKind,
@@ -415,7 +469,7 @@ export class KaminoVaultClient {
415
469
  /**
416
470
  * This function creates the instruction for the `pendingAdmin` of the vault to accept to become the owner of the vault (step 2/2 of the ownership transfer)
417
471
  * @param vault - vault to change the ownership for
418
- * @returns - an instruction to be used to be executed
472
+ * @returns - an instruction to accept the ownership of the vault and a list of instructions to update the lookup table
419
473
  */
420
474
  async acceptVaultOwnershipIxs(vault: KaminoVault): Promise<AcceptVaultOwnershipIxs> {
421
475
  const vaultState: VaultState = await vault.getState(this.getConnection());
@@ -428,12 +482,12 @@ export class KaminoVaultClient {
428
482
  const acceptVaultOwnershipIx = updateAdmin(acceptOwneshipAccounts, this._kaminoVaultProgramId);
429
483
 
430
484
  // read the current LUT and create a new one for the new admin and backfill it
431
- const accountsInExistentLUT = (await this.getAccountsInLUT(vaultState.vaultLookupTable)).filter(
485
+ const accountsInExistentLUT = (await getAccountsInLUT(this.getConnection(), vaultState.vaultLookupTable)).filter(
432
486
  (account) => !account.equals(vaultState.adminAuthority)
433
487
  );
434
488
 
435
489
  const LUTIxs = [];
436
- const [initNewLUTIx, newLUT] = this.getInitLookupTableIx(vaultState.pendingAdmin, await this._connection.getSlot());
490
+ const [initNewLUTIx, newLUT] = initLookupTableIx(vaultState.pendingAdmin, await this.getConnection().getSlot());
437
491
  LUTIxs.push(initNewLUTIx);
438
492
 
439
493
  const insertIntoLUTIxs = await this.insertIntoLookupTableIxs(
@@ -464,7 +518,7 @@ export class KaminoVaultClient {
464
518
  * This function creates the instruction for the admin to give up a part of the pending fees (which will be accounted as part of the vault)
465
519
  * @param vault - vault to give up pending fees for
466
520
  * @param maxAmountToGiveUp - the maximum amount of fees to give up, in tokens
467
- * @returns - an instruction to be used to be executed
521
+ * @returns - an instruction to give up the specified pending fees
468
522
  */
469
523
  async giveUpPendingFeesIx(vault: KaminoVault, maxAmountToGiveUp: Decimal): Promise<TransactionInstruction> {
470
524
  const vaultState: VaultState = await vault.getState(this.getConnection());
@@ -490,7 +544,8 @@ export class KaminoVaultClient {
490
544
  * This method withdraws all the pending fees from the vault to the owner's token ATA
491
545
  * @param vault - vault for which the admin withdraws the pending fees
492
546
  * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
493
- * @returns - list of instructions to withdraw all pending fees
547
+ * @param [vaultReservesMap] - 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
548
+ * @returns - list of instructions to withdraw all pending fees, including the ATA creation instructions if needed
494
549
  */
495
550
  async withdrawPendingFeesIxs(
496
551
  vault: KaminoVault,
@@ -534,7 +589,11 @@ export class KaminoVaultClient {
534
589
  });
535
590
  }
536
591
 
537
- const reserveStates = await Reserve.fetchMultiple(this._connection, reservesToWithdraw, this._kaminoLendProgramId);
592
+ const reserveStates = await Reserve.fetchMultiple(
593
+ this.getConnection(),
594
+ reservesToWithdraw,
595
+ this._kaminoLendProgramId
596
+ );
538
597
  const withdrawIxns: TransactionInstruction[] = await Promise.all(
539
598
  reservesToWithdraw.map(async (reserve, index) => {
540
599
  if (reserveStates[index] === null) {
@@ -571,18 +630,20 @@ export class KaminoVaultClient {
571
630
  /**
572
631
  * This function creates instructions to deposit into a vault. It will also create ATA creation instructions for the vault shares that the user receives in return
573
632
  * @param user - user to deposit
574
- * @param vault - vault to deposit into
633
+ * @param vault - vault to deposit into (if the state is not provided, it will be fetched)
575
634
  * @param tokenAmount - token amount to be deposited, in decimals (will be converted in lamports)
576
- * @param vaultReservesMap - 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
577
- * @returns - an array of instructions to be used to be executed
635
+ * @param [vaultReservesMap] - optional parameter; 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
636
+ * @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
637
+ * @returns - an instance of DepositIxs which contains the instructions to deposit in vault and the instructions to stake the shares in the farm if the vault has a farm
578
638
  */
579
639
  async depositIxs(
580
640
  user: PublicKey,
581
641
  vault: KaminoVault,
582
642
  tokenAmount: Decimal,
583
- vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
584
- ): Promise<TransactionInstruction[]> {
585
- const vaultState = await vault.getState(this._connection);
643
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>,
644
+ farmState?: FarmState
645
+ ): Promise<DepositIxs> {
646
+ const vaultState = await vault.getState(this.getConnection());
586
647
 
587
648
  const tokenProgramID = vaultState.tokenProgram;
588
649
  const userTokenAta = getAssociatedTokenAddress(vaultState.tokenMint, user, true, tokenProgramID);
@@ -654,37 +715,112 @@ export class KaminoVaultClient {
654
715
  depositIx.keys = depositIx.keys.concat(vaultReservesAccountMetas);
655
716
  depositIx.keys = depositIx.keys.concat(vaultReservesLendingMarkets);
656
717
 
657
- return [...createAtasIxns, depositIx, ...closeAtasIxns];
718
+ const depositIxs: DepositIxs = {
719
+ depositIxs: [...createAtasIxns, depositIx, ...closeAtasIxns],
720
+ stakeInFarmIfNeededIxs: [],
721
+ };
722
+
723
+ // if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
724
+ if (!(await vault.hasFarm(this.getConnection()))) {
725
+ return depositIxs;
726
+ }
727
+
728
+ // if there is a farm, stake the shares
729
+ const stakeSharesIxs = await this.stakeSharesIxs(user, vault, undefined, farmState);
730
+ depositIxs.stakeInFarmIfNeededIxs = stakeSharesIxs;
731
+ return depositIxs;
732
+ }
733
+
734
+ /**
735
+ * This function creates instructions to stake the shares in the vault farm if the vault has a farm
736
+ * @param user - user to stake
737
+ * @param vault - vault to deposit into its farm (if the state is not provided, it will be fetched)
738
+ * @param [sharesAmount] - token amount to be deposited, in decimals (will be converted in lamports). Optional. If not provided, the user's share balance will be used
739
+ * @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
740
+ * @returns - a list of instructions for the user to stake shares into the vault's farm, including the creation of prerequisite accounts if needed
741
+ */
742
+ async stakeSharesIxs(
743
+ user: PublicKey,
744
+ vault: KaminoVault,
745
+ sharesAmount?: Decimal,
746
+ farmState?: FarmState
747
+ ): Promise<TransactionInstruction[]> {
748
+ const vaultState = await vault.getState(this.getConnection());
749
+
750
+ let sharesToStakeLamports = new Decimal(U64_MAX);
751
+ if (sharesAmount) {
752
+ sharesToStakeLamports = numberToLamportsDecimal(sharesAmount, vaultState.sharesMintDecimals.toNumber());
753
+ }
754
+
755
+ // if tokens to be staked are 0 or vault has no farm there is no stake needed
756
+ if (sharesToStakeLamports.lte(0) || !vault.hasFarm(this.getConnection())) {
757
+ return [];
758
+ }
759
+
760
+ // returns the ix to create the farm state account if needed and the ix to stake the shares
761
+ return getFarmStakeIxs(this.getConnection(), user, sharesToStakeLamports, vaultState.vaultFarm, farmState);
658
762
  }
659
763
 
660
764
  /**
661
- * This function will return the missing ATA creation instructions, as well as one or multiple withdraw instructions, based on how many reserves it's needed to withdraw from. This might have to be split in multiple transactions
765
+ * This function will return a struct with the instructions to unstake from the farm if necessary and the instructions for the missing ATA creation instructions, as well as one or multiple withdraw instructions, based on how many reserves it's needed to withdraw from. This might have to be split in multiple transactions
662
766
  * @param user - user to withdraw
663
767
  * @param vault - vault to withdraw from
664
768
  * @param shareAmount - share amount to withdraw, in order to withdraw everything, any value > user share amount
665
769
  * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
666
- * @returns an array of instructions to be executed
770
+ * @param [vaultReservesMap] - 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
771
+ * @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
772
+ * @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
667
773
  */
668
774
  async withdrawIxs(
669
775
  user: PublicKey,
670
776
  vault: KaminoVault,
671
777
  shareAmount: Decimal,
672
778
  slot: number,
673
- vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
674
- ): Promise<TransactionInstruction[]> {
675
- const vaultState = await vault.getState(this._connection);
779
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>,
780
+ farmState?: FarmState
781
+ ): Promise<WithdrawIxs> {
782
+ const vaultState = await vault.getState(this.getConnection());
676
783
  const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
677
784
 
785
+ const withdrawIxs: WithdrawIxs = {
786
+ unstakeFromFarmIfNeededIxs: [],
787
+ withdrawIxs: [],
788
+ };
789
+
790
+ const shareLamportsToWithdraw = collToLamportsDecimal(shareAmount, vaultState.sharesMintDecimals.toNumber());
791
+ const hasFarm = await vault.hasFarm(this.getConnection());
792
+ if (hasFarm) {
793
+ const unstakeAndWithdrawFromFarmIxs = await getFarmUnstakeAndWithdrawIxs(
794
+ this.getConnection(),
795
+ user,
796
+ shareLamportsToWithdraw,
797
+ vaultState.vaultFarm,
798
+ farmState
799
+ );
800
+ withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.unstakeIx);
801
+ withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.withdrawIx);
802
+ }
803
+
678
804
  // if the vault has allocations withdraw otherwise wtihdraw from available ix
679
805
  const vaultAllocation = vaultState.vaultAllocationStrategy.find((allocation) =>
680
806
  allocation.reserve.equals(PublicKey.default)
681
807
  );
682
808
 
683
809
  if (vaultAllocation) {
684
- return this.wihdrdrawWithReserveIxns(user, kaminoVault, shareAmount, slot, vaultReservesMap);
810
+ const withdrawFromVaultIxs = await this.wihdrdrawWithReserveIxns(
811
+ user,
812
+ kaminoVault,
813
+ shareAmount,
814
+ slot,
815
+ vaultReservesMap
816
+ );
817
+ withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
685
818
  } else {
686
- return this.withdrawFromAvailableIxns(user, kaminoVault, shareAmount);
819
+ const withdrawFromVaultIxs = await this.withdrawFromAvailableIxns(user, kaminoVault, shareAmount);
820
+ withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
687
821
  }
822
+
823
+ return withdrawIxs;
688
824
  }
689
825
 
690
826
  private async withdrawFromAvailableIxns(
@@ -692,7 +828,7 @@ export class KaminoVaultClient {
692
828
  vault: KaminoVault,
693
829
  shareAmount: Decimal
694
830
  ): Promise<TransactionInstruction[]> {
695
- const vaultState = await vault.getState(this._connection);
831
+ const vaultState = await vault.getState(this.getConnection());
696
832
  const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
697
833
 
698
834
  const userSharesAta = getAssociatedTokenAddress(vaultState.sharesMint, user);
@@ -723,7 +859,7 @@ export class KaminoVaultClient {
723
859
  slot: number,
724
860
  vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
725
861
  ): Promise<TransactionInstruction[]> {
726
- const vaultState = await vault.getState(this._connection);
862
+ const vaultState = await vault.getState(this.getConnection());
727
863
 
728
864
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
729
865
 
@@ -785,7 +921,6 @@ export class KaminoVaultClient {
785
921
  const withdrawIxns: TransactionInstruction[] = [];
786
922
  withdrawIxns.push(createAtaIx);
787
923
 
788
- // let sharesLeftToWithdraw = shareAmount;
789
924
  for (let reserveIndex = 0; reserveIndex < reserveWithSharesAmountToWithdraw.length; reserveIndex++) {
790
925
  const reserveWithTokens = reserveWithSharesAmountToWithdraw[reserveIndex];
791
926
  const reserveState = vaultReservesState.get(reserveWithTokens.reserve);
@@ -818,6 +953,7 @@ export class KaminoVaultClient {
818
953
  return withdrawIxns;
819
954
  }
820
955
 
956
+ // todo: make sure we also check the ata of the investor for the vault token exists
821
957
  /**
822
958
  * This will trigger invest by balancing, based on weights, the reserve allocations of the vault. It can either withdraw or deposit into reserves to balance them. This is a function that should be cranked
823
959
  * @param payer wallet that pays the tx
@@ -826,11 +962,11 @@ export class KaminoVaultClient {
826
962
  */
827
963
  async investAllReservesIxs(payer: PublicKey, vault: KaminoVault): Promise<TransactionInstruction[]> {
828
964
  //TODO: Order invest ixns by - invest that removes first, then invest that adds
829
- const vaultState = await vault.getState(this._connection);
965
+ const vaultState = await vault.getState(this.getConnection());
830
966
  const vaultReserves = this.getVaultReserves(vaultState);
831
967
  const investIxnsPromises: Promise<TransactionInstruction[]>[] = [];
832
968
  for (const reserve of vaultReserves) {
833
- const reserveState = await Reserve.fetch(this._connection, reserve, this._kaminoLendProgramId);
969
+ const reserveState = await Reserve.fetch(this.getConnection(), reserve, this._kaminoLendProgramId);
834
970
  if (reserveState === null) {
835
971
  throw new Error(`Reserve ${reserve.toBase58()} not found`);
836
972
  }
@@ -843,11 +979,13 @@ export class KaminoVaultClient {
843
979
  return investIxns;
844
980
  }
845
981
 
982
+ // todo: make sure we also check the ata of the investor for the vault token exists
846
983
  /**
847
984
  * This will trigger invest by balancing, based on weights, the reserve allocation of the vault. It can either withdraw or deposit into the given reserve to balance it
848
985
  * @param payer wallet pubkey
849
986
  * @param vault - vault to invest from
850
987
  * @param reserve - reserve to invest into or disinvest from
988
+ * @param [vaultReservesMap] - 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
851
989
  * @returns - an array of invest instructions for each invest action required for the vault reserves
852
990
  */
853
991
  async investSingleReserveIxs(
@@ -856,11 +994,11 @@ export class KaminoVaultClient {
856
994
  reserve: ReserveWithAddress,
857
995
  vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
858
996
  ): Promise<TransactionInstruction[]> {
859
- const vaultState = await vault.getState(this._connection);
997
+ const vaultState = await vault.getState(this.getConnection());
860
998
  const cTokenVault = getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId);
861
999
  const lendingMarketAuth = lendingMarketAuthPda(reserve.state.lendingMarket, this._kaminoLendProgramId)[0];
862
1000
 
863
- const tokenProgram = await getAccountOwner(this._connection, vaultState.tokenMint);
1001
+ const tokenProgram = await getAccountOwner(this.getConnection(), vaultState.tokenMint);
864
1002
  const [{ ata: payerTokenAta, createAtaIx }] = createAtasIdempotent(payer, [
865
1003
  { mint: vaultState.tokenMint, tokenProgram },
866
1004
  ]);
@@ -910,6 +1048,7 @@ export class KaminoVaultClient {
910
1048
  return [createAtaIx, investIx];
911
1049
  }
912
1050
 
1051
+ /** Convert a string to a u8 representation to be stored on chain */
913
1052
  encodeVaultName(token: string): Uint8Array {
914
1053
  const maxArray = new Uint8Array(40);
915
1054
  const s: Uint8Array = new TextEncoder().encode(token);
@@ -917,6 +1056,7 @@ export class KaminoVaultClient {
917
1056
  return maxArray;
918
1057
  }
919
1058
 
1059
+ /**Convert an u8 array to a string */
920
1060
  decodeVaultName(token: number[]): string {
921
1061
  const maxArray = new Uint8Array(token);
922
1062
  let s: string = new TextDecoder().decode(maxArray);
@@ -1084,13 +1224,14 @@ export class KaminoVaultClient {
1084
1224
  * Sync a vault for lookup table; create and set the LUT for the vault if needed and fill it with all the needed accounts
1085
1225
  * @param vault the vault to sync and set the LUT for if needed
1086
1226
  * @param vaultReserves optional; the state of the reserves in the vault allocation
1227
+ * @param [vaultReservesMap] - optional parameter; 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
1087
1228
  * @returns a struct that contains a list of ix to create the LUT and assign it to the vault if needed + a list of ixs to insert all the accounts in the LUT
1088
1229
  */
1089
- async syncVaultLookupTable(
1230
+ async syncVaultLookupTableIxs(
1090
1231
  vault: KaminoVault,
1091
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
1232
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
1092
1233
  ): Promise<SyncVaultLUTIxs> {
1093
- const vaultState = await vault.getState(this._connection);
1234
+ const vaultState = await vault.getState(this.getConnection());
1094
1235
  const allAccountsToBeInserted = [
1095
1236
  vault.address,
1096
1237
  vaultState.adminAuthority,
@@ -1107,8 +1248,8 @@ export class KaminoVaultClient {
1107
1248
  allAccountsToBeInserted.push(allocation.ctokenVault);
1108
1249
  });
1109
1250
 
1110
- if (vaultReserves) {
1111
- vaultReserves.forEach((reserve) => {
1251
+ if (vaultReservesMap) {
1252
+ vaultReservesMap.forEach((reserve) => {
1112
1253
  allAccountsToBeInserted.push(reserve.state.lendingMarket);
1113
1254
  allAccountsToBeInserted.push(reserve.state.farmCollateral);
1114
1255
  allAccountsToBeInserted.push(reserve.state.farmDebt);
@@ -1137,8 +1278,8 @@ export class KaminoVaultClient {
1137
1278
  const setupLUTIfNeededIxs: TransactionInstruction[] = [];
1138
1279
  let lut = vaultState.vaultLookupTable;
1139
1280
  if (lut.equals(PublicKey.default)) {
1140
- const recentSlot = await this._connection.getSlot();
1141
- const [ixn, address] = this.getInitLookupTableIx(vaultState.adminAuthority, recentSlot);
1281
+ const recentSlot = await this.getConnection().getSlot();
1282
+ const [ixn, address] = initLookupTableIx(vaultState.adminAuthority, recentSlot);
1142
1283
  setupLUTIfNeededIxs.push(ixn);
1143
1284
  lut = address;
1144
1285
 
@@ -1171,17 +1312,7 @@ export class KaminoVaultClient {
1171
1312
  };
1172
1313
  }
1173
1314
 
1174
- getInitLookupTableIx(payer: PublicKey, slot: number): [TransactionInstruction, PublicKey] {
1175
- const [ixn, address] = AddressLookupTableProgram.createLookupTable({
1176
- authority: payer,
1177
- payer,
1178
- recentSlot: slot,
1179
- });
1180
-
1181
- return [ixn, address];
1182
- }
1183
-
1184
- getReserveAccountsToInsertInLut(reserveState: Reserve): PublicKey[] {
1315
+ private getReserveAccountsToInsertInLut(reserveState: Reserve): PublicKey[] {
1185
1316
  return [
1186
1317
  reserveState.lendingMarket,
1187
1318
  reserveState.farmCollateral,
@@ -1194,6 +1325,14 @@ export class KaminoVaultClient {
1194
1325
  ];
1195
1326
  }
1196
1327
 
1328
+ /**
1329
+ * This method inserts the missing keys from the provided keys into an existent lookup table
1330
+ * @param payer - payer wallet pubkey
1331
+ * @param lookupTable - lookup table to insert the keys into
1332
+ * @param keys - keys to insert into the lookup table
1333
+ * @param [accountsInLUT] - the existent accounts in the lookup table. Optional. If provided, the function will not fetch the accounts in the lookup table
1334
+ * @returns - an array of instructions to insert the missing keys into the lookup table
1335
+ */
1197
1336
  async insertIntoLookupTableIxs(
1198
1337
  payer: PublicKey,
1199
1338
  lookupTable: PublicKey,
@@ -1202,7 +1341,7 @@ export class KaminoVaultClient {
1202
1341
  ): Promise<TransactionInstruction[]> {
1203
1342
  let lutContents = accountsInLUT;
1204
1343
  if (!accountsInLUT) {
1205
- lutContents = await this.getAccountsInLUT(lookupTable);
1344
+ lutContents = await getAccountsInLUT(this.getConnection(), lookupTable);
1206
1345
  } else {
1207
1346
  lutContents = accountsInLUT;
1208
1347
  }
@@ -1228,98 +1367,104 @@ export class KaminoVaultClient {
1228
1367
  return ixns;
1229
1368
  }
1230
1369
 
1231
- /**
1232
- *
1233
- * @param connection
1234
- * @param lookupTable
1235
- * @returns
1236
- */
1237
- async getAccountsInLUT(lookupTable: PublicKey): Promise<PublicKey[]> {
1238
- const lutState = await this._connection.getAddressLookupTable(lookupTable);
1239
- if (!lutState || !lutState.value) {
1240
- throw new Error(`Lookup table ${lookupTable} not found`);
1241
- }
1242
-
1243
- return lutState.value.state.addresses;
1244
- }
1245
-
1246
- deactivateLookupTableIx(payer: PublicKey, lookupTable: PublicKey): TransactionInstruction {
1247
- const ixn = AddressLookupTableProgram.deactivateLookupTable({
1248
- authority: payer,
1249
- lookupTable: lookupTable,
1250
- });
1251
-
1252
- return ixn;
1253
- }
1254
-
1255
- /// this require the LUT to be deactivated at least 500 blocks before
1256
- closeLookupTableIx(payer: PublicKey, lookupTable: PublicKey): TransactionInstruction {
1257
- const ixn = AddressLookupTableProgram.closeLookupTable({
1258
- authority: payer,
1259
- recipient: payer,
1260
- lookupTable: lookupTable,
1261
- });
1262
-
1263
- return ixn;
1264
- }
1265
-
1266
1370
  /**
1267
1371
  * This method returns the user shares balance for a given vault
1268
1372
  * @param user - user to calculate the shares balance for
1269
1373
  * @param vault - vault to calculate shares balance for
1270
- * @returns - user share balance in decimal (not lamports)
1374
+ * @returns - user share balance in tokens (not lamports)
1271
1375
  */
1272
- async getUserSharesBalanceSingleVault(user: PublicKey, vault: KaminoVault): Promise<Decimal> {
1273
- const vaultState = await vault.getState(this._connection);
1376
+ async getUserSharesBalanceSingleVault(user: PublicKey, vault: KaminoVault): Promise<UserSharesForVault> {
1377
+ const vaultState = await vault.getState(this.getConnection());
1378
+
1379
+ const userShares: UserSharesForVault = { unstakedShares: new Decimal(0), stakedShares: new Decimal(0) };
1274
1380
  const userSharesAta = getAssociatedTokenAddress(vaultState.sharesMint, user);
1275
- const userSharesAccountInfo = await this._connection.getAccountInfo(userSharesAta);
1276
- if (!userSharesAccountInfo) {
1277
- return new Decimal(0);
1381
+ const userSharesAccountInfo = await this.getConnection().getAccountInfo(userSharesAta);
1382
+ if (userSharesAccountInfo) {
1383
+ const userSharesAccount = unpackAccount(userSharesAta, userSharesAccountInfo);
1384
+
1385
+ userShares.unstakedShares = new Decimal(userSharesAccount.amount.toString()).div(
1386
+ new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
1387
+ );
1278
1388
  }
1279
- const userSharesAccount = unpackAccount(userSharesAta, userSharesAccountInfo);
1280
1389
 
1281
- return new Decimal(userSharesAccount.amount.toString()).div(
1282
- new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
1283
- );
1390
+ if (await vault.hasFarm(this.getConnection())) {
1391
+ const userSharesInFarm = await getUserSharesInFarm(
1392
+ this.getConnection(),
1393
+ user,
1394
+ vaultState.vaultFarm,
1395
+ vaultState.sharesMintDecimals.toNumber()
1396
+ );
1397
+
1398
+ userShares.stakedShares = userSharesInFarm;
1399
+ }
1400
+
1401
+ return userShares;
1284
1402
  }
1285
1403
 
1286
1404
  /**
1287
1405
  * This method returns the user shares balance for all existing vaults
1288
1406
  * @param user - user to calculate the shares balance for
1289
- * @param vaultsOverride - the kamino vaults if already fetched, in order to reduce rpc calls
1290
- * @returns - hash map with keyh as vault address and value as user share balance in decimal (not lamports)
1407
+ * @param [vaultsOverride] - the kamino vaults if already fetched, in order to reduce rpc calls.Optional
1408
+ * @returns - hash map with keys as vault address and value as user share balance in decimal (not lamports)
1291
1409
  */
1292
1410
  async getUserSharesBalanceAllVaults(
1293
1411
  user: PublicKey,
1294
1412
  vaultsOverride?: Array<KaminoVault>
1295
- ): Promise<PubkeyHashMap<PublicKey, Decimal>> {
1413
+ ): Promise<PubkeyHashMap<PublicKey, UserSharesForVault>> {
1296
1414
  const vaults = vaultsOverride ? vaultsOverride : await this.getAllVaults();
1297
1415
  // stores vault address for each userSharesAta
1298
- const vaultUserShareBalance = new PubkeyHashMap<PublicKey, Decimal>();
1416
+ const vaultUserShareBalance = new PubkeyHashMap<PublicKey, UserSharesForVault>();
1417
+
1418
+ const vaultToUserFarmStateAddress = new PubkeyHashMap<PublicKey, PublicKey>();
1299
1419
  const userSharesAtaArray: PublicKey[] = [];
1300
- vaults.forEach((vault) => {
1420
+ vaults.forEach(async (vault) => {
1301
1421
  const state = vault.state;
1302
1422
  if (!state) {
1303
1423
  throw new Error(`Vault ${vault.address.toBase58()} not fetched`);
1304
1424
  }
1305
1425
  const userSharesAta = getAssociatedTokenAddress(state.sharesMint, user);
1306
1426
  userSharesAtaArray.push(userSharesAta);
1427
+
1428
+ if (await vault.hasFarm(this.getConnection())) {
1429
+ const farmUserState = await getFarmUserStatePDA(this.getConnection(), user, state.vaultFarm);
1430
+ vaultToUserFarmStateAddress.set(vault.address, farmUserState);
1431
+ }
1307
1432
  });
1308
- const userSharesAtaAccounts = await this._connection.getMultipleAccountsInfo(userSharesAtaArray);
1433
+
1434
+ const [userSharesAtaAccounts, userFarmStates] = await Promise.all([
1435
+ this.getConnection().getMultipleAccountsInfo(userSharesAtaArray),
1436
+ UserState.fetchMultiple(this.getConnection(), Array.from(vaultToUserFarmStateAddress.values())),
1437
+ ]);
1309
1438
 
1310
1439
  userSharesAtaAccounts.forEach((userShareAtaAccount, index) => {
1440
+ const userSharesForVault = { unstakedShares: new Decimal(0), stakedShares: new Decimal(0) };
1311
1441
  if (!userShareAtaAccount) {
1312
- vaultUserShareBalance.set(vaults[index].address, new Decimal(0));
1442
+ vaultUserShareBalance.set(vaults[index].address, userSharesForVault);
1313
1443
  } else {
1314
- vaultUserShareBalance.set(
1315
- vaults[index].address,
1316
- getTokenBalanceFromAccountInfoLamports(userShareAtaAccount).div(
1317
- new Decimal(10).pow(vaults[index].state!.sharesMintDecimals.toString())
1318
- )
1444
+ userSharesForVault.unstakedShares = getTokenBalanceFromAccountInfoLamports(userShareAtaAccount).div(
1445
+ new Decimal(10).pow(vaults[index].state!.sharesMintDecimals.toString())
1319
1446
  );
1447
+ vaultUserShareBalance.set(vaults[index].address, userSharesForVault);
1320
1448
  }
1321
1449
  });
1322
1450
 
1451
+ userFarmStates.forEach((userFarmState, _) => {
1452
+ if (!userFarmState) {
1453
+ return;
1454
+ }
1455
+ const farmState = userFarmState.farmState;
1456
+ // find the vault which has the farm
1457
+ const vault = vaults.find((vault) => vault.state!.vaultFarm.equals(farmState));
1458
+ if (!vault) {
1459
+ throw new Error(`Vault with farm ${farmState.toBase58()} not found`);
1460
+ }
1461
+
1462
+ const shares = getSharesInFarmUserPosition(userFarmState, vault.state!.sharesMintDecimals.toNumber());
1463
+ const userSharesBalance = vaultUserShareBalance.get(vault.address);
1464
+ userSharesBalance!.stakedShares = shares;
1465
+ vaultUserShareBalance.set(vault.address, userSharesBalance!);
1466
+ });
1467
+
1323
1468
  return vaultUserShareBalance;
1324
1469
  }
1325
1470
 
@@ -1339,7 +1484,7 @@ export class KaminoVaultClient {
1339
1484
  * This method calculates the token per shar 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
1340
1485
  * @param vault - vault to calculate tokensPerShare for
1341
1486
  * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
1342
- * @param vaultReservesMap - 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
1487
+ * @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
1343
1488
  * @returns - token per share value
1344
1489
  */
1345
1490
  async getTokensPerShareSingleVault(
@@ -1347,7 +1492,7 @@ export class KaminoVaultClient {
1347
1492
  slot: number,
1348
1493
  vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
1349
1494
  ): Promise<Decimal> {
1350
- const vaultState = await vault.getState(this._connection);
1495
+ const vaultState = await vault.getState(this.getConnection());
1351
1496
  if (vaultState.sharesIssued.isZero()) {
1352
1497
  return new Decimal(0);
1353
1498
  }
@@ -1361,7 +1506,7 @@ export class KaminoVaultClient {
1361
1506
 
1362
1507
  const holdings = await this.getVaultHoldings(
1363
1508
  vaultState,
1364
- await this._connection.getSlot('confirmed'),
1509
+ await this.getConnection().getSlot('confirmed'),
1365
1510
  vaultReservesState
1366
1511
  );
1367
1512
 
@@ -1370,8 +1515,8 @@ export class KaminoVaultClient {
1370
1515
 
1371
1516
  /**
1372
1517
  * 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
1373
- * @param vaultsOverride - a list of vaults to get the tokens per share for; if provided with state it will not fetch the state again
1374
- * @param vaultReservesMap - optional parameter; a hashmap from pubkey to reserve state. If provided the function will be significantly faster as it will not have to fetch the reserves
1518
+ * @param [vaultsOverride] - a list of vaults to get the tokens per share for; if provided with state it will not fetch the state again. Optional
1519
+ * @param [vaultReservesMap] - optional parameter; 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
1375
1520
  * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
1376
1521
  * @returns - token per share value
1377
1522
  */
@@ -1408,11 +1553,11 @@ export class KaminoVaultClient {
1408
1553
  ];
1409
1554
 
1410
1555
  const kaminoVaults: GetProgramAccountsResponse = await getProgramAccounts(
1411
- this._connection,
1556
+ this.getConnection(),
1412
1557
  this._kaminoVaultProgramId,
1413
1558
  VaultState.layout.span + 8,
1414
1559
  {
1415
- commitment: this._connection.commitment ?? 'processed',
1560
+ commitment: this.getConnection().commitment ?? 'processed',
1416
1561
  filters,
1417
1562
  }
1418
1563
  );
@@ -1496,21 +1641,22 @@ export class KaminoVaultClient {
1496
1641
  * This will return an unsorted hash map of all reserves that the given vault has allocations for, toghether with the amount that can be withdrawn from each of the reserves
1497
1642
  * @param vault - the kamino vault to get available liquidity to withdraw for
1498
1643
  * @param slot - current slot
1644
+ *@param [vaultReservesMap] - a hashmap from each reserve pubkey to the reserve state
1499
1645
  * @returns an HashMap of reserves (key) with the amount available to withdraw for each (value)
1500
1646
  */
1501
1647
  private async getReserveAllocationAvailableLiquidityToWithdraw(
1502
1648
  vault: KaminoVault,
1503
1649
  slot: number,
1504
- reserves: PubkeyHashMap<PublicKey, KaminoReserve>
1650
+ vaultReservesMap: PubkeyHashMap<PublicKey, KaminoReserve>
1505
1651
  ): Promise<PubkeyHashMap<PublicKey, Decimal>> {
1506
- const vaultState = await vault.getState(this._connection);
1652
+ const vaultState = await vault.getState(this.getConnection());
1507
1653
 
1508
1654
  const reserveAllocationAvailableLiquidityToWithdraw = new PubkeyHashMap<PublicKey, Decimal>();
1509
1655
  vaultState.vaultAllocationStrategy.forEach((allocationStrategy) => {
1510
1656
  if (allocationStrategy.reserve.equals(PublicKey.default)) {
1511
1657
  return;
1512
1658
  }
1513
- const reserve = reserves.get(allocationStrategy.reserve);
1659
+ const reserve = vaultReservesMap.get(allocationStrategy.reserve);
1514
1660
  if (reserve === undefined) {
1515
1661
  throw new Error(`Reserve ${allocationStrategy.reserve.toBase58()} not found`);
1516
1662
  }
@@ -1564,7 +1710,7 @@ export class KaminoVaultClient {
1564
1710
  */
1565
1711
  async loadVaultReserves(vaultState: VaultState): Promise<PubkeyHashMap<PublicKey, KaminoReserve>> {
1566
1712
  const vaultReservesAddresses = this.getVaultReserves(vaultState);
1567
- const reserveAccounts = await this._connection.getMultipleAccountsInfo(vaultReservesAddresses, 'processed');
1713
+ const reserveAccounts = await this.getConnection().getMultipleAccountsInfo(vaultReservesAddresses, 'processed');
1568
1714
 
1569
1715
  const deserializedReserves = reserveAccounts.map((reserve, i) => {
1570
1716
  if (reserve === null) {
@@ -1578,7 +1724,7 @@ export class KaminoVaultClient {
1578
1724
  return reserveAccount;
1579
1725
  });
1580
1726
 
1581
- const reservesAndOracles = await getTokenOracleData(this._connection, deserializedReserves);
1727
+ const reservesAndOracles = await getTokenOracleData(this.getConnection(), deserializedReserves);
1582
1728
 
1583
1729
  const kaminoReserves = new PubkeyHashMap<PublicKey, KaminoReserve>();
1584
1730
 
@@ -1591,7 +1737,7 @@ export class KaminoVaultClient {
1591
1737
  vaultReservesAddresses[index],
1592
1738
  reserve,
1593
1739
  oracle,
1594
- this._connection,
1740
+ this.getConnection(),
1595
1741
  this.recentSlotDurationMs
1596
1742
  );
1597
1743
  kaminoReserves.set(kaminoReserve.address, kaminoReserve);
@@ -1601,18 +1747,20 @@ export class KaminoVaultClient {
1601
1747
  }
1602
1748
 
1603
1749
  /**
1604
- * This will retrieve all the tokens that can be use as collateral by the users who borrow the token in the vault alongside details about the min and max loan to value ratio
1750
+ * This will retrieve all the tokens that can be used as collateral by the users who borrow the token in the vault alongside details about the min and max loan to value ratio
1605
1751
  * @param vaultState - the vault state to load reserves for
1606
- *
1752
+ * @param slot - current slot
1753
+ * @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
1754
+ * @param [kaminoMarkets] - a list of all the kamino markets. Optional. If provided the function will be significantly faster as it will not have to fetch the markets
1607
1755
  * @returns a hashmap from each reserve pubkey to the market overview of the collaterals that can be used and the min and max loan to value ratio in that market
1608
1756
  */
1609
1757
  async getVaultCollaterals(
1610
1758
  vaultState: VaultState,
1611
1759
  slot: number,
1612
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>,
1760
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>,
1613
1761
  kaminoMarkets?: KaminoMarket[]
1614
1762
  ): Promise<PubkeyHashMap<PublicKey, MarketOverview>> {
1615
- const vaultReservesStateMap = vaultReserves ? vaultReserves : await this.loadVaultReserves(vaultState);
1763
+ const vaultReservesStateMap = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
1616
1764
  const vaultReservesState = Array.from(vaultReservesStateMap.values());
1617
1765
 
1618
1766
  const vaultCollateralsPerReserve: PubkeyHashMap<PublicKey, MarketOverview> = new PubkeyHashMap();
@@ -1627,7 +1775,7 @@ export class KaminoVaultClient {
1627
1775
  }
1628
1776
 
1629
1777
  if (!lendingMarket) {
1630
- const fetchedLendingMarket = await KaminoMarket.load(this._connection, reserve.state.lendingMarket, slot);
1778
+ const fetchedLendingMarket = await KaminoMarket.load(this.getConnection(), reserve.state.lendingMarket, slot);
1631
1779
  if (!fetchedLendingMarket) {
1632
1780
  throw Error(`Could not fetch lending market ${reserve.state.lendingMarket.toBase58()}`);
1633
1781
  }
@@ -1674,8 +1822,8 @@ export class KaminoVaultClient {
1674
1822
  * 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
1675
1823
  * @param vault - the kamino vault to get available liquidity to withdraw for
1676
1824
  * @param slot - current slot
1677
- * @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
1678
- * @returns an VaultHoldings object
1825
+ * @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
1826
+ * @returns an VaultHoldings object representing the amount available (uninvested) in vault, total amount invested in reseves and a breakdown of the amount invested in each reserve
1679
1827
  */
1680
1828
  async getVaultHoldings(
1681
1829
  vault: VaultState,
@@ -1728,17 +1876,17 @@ export class KaminoVaultClient {
1728
1876
  * 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
1729
1877
  * @param vault - the kamino vault to get available liquidity to withdraw for
1730
1878
  * @param slot - current slot
1731
- * @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
1732
1879
  * @param price - the price of the token in the vault (e.g. USDC)
1880
+ * @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
1733
1881
  * @returns an VaultHoldingsWithUSDValue object with details about the tokens available and invested in the vault, denominated in tokens and USD
1734
1882
  */
1735
1883
  async getVaultHoldingsWithPrice(
1736
1884
  vault: VaultState,
1737
1885
  slot: number,
1738
1886
  price: Decimal,
1739
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
1887
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
1740
1888
  ): Promise<VaultHoldingsWithUSDValue> {
1741
- const holdings = await this.getVaultHoldings(vault, slot, vaultReserves);
1889
+ const holdings = await this.getVaultHoldings(vault, slot, vaultReservesMap);
1742
1890
 
1743
1891
  const investedInReservesUSD = new PubkeyHashMap<PublicKey, Decimal>();
1744
1892
  holdings.investedInReserves.forEach((amount, reserve) => {
@@ -1758,18 +1906,18 @@ export class KaminoVaultClient {
1758
1906
  * @param vault - the kamino vault to get available liquidity to withdraw for
1759
1907
  * @param slot - current slot
1760
1908
  * @param price - the price of the token in the vault (e.g. USDC)
1761
- * @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
1762
- * @param kaminoMarkets - optional parameter; a list of all kamino markets. If provided the function will be significantly faster as it will not have to fetch the markets
1763
- * @returns an VaultHoldingsWithUSDValue object with details about the tokens available and invested in the vault, denominated in tokens and USD
1909
+ * @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
1910
+ * @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
1911
+ * @returns an VaultOverview object with details about the tokens available and invested in the vault, denominated in tokens and USD
1764
1912
  */
1765
1913
  async getVaultOverview(
1766
1914
  vault: VaultState,
1767
1915
  slot: number,
1768
1916
  price: Decimal,
1769
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>,
1917
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>,
1770
1918
  kaminoMarkets?: KaminoMarket[]
1771
1919
  ): Promise<VaultOverview> {
1772
- const vaultReservesState = vaultReserves ? vaultReserves : await this.loadVaultReserves(vault);
1920
+ const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
1773
1921
 
1774
1922
  const vaultHoldingsWithUSDValuePromise = await this.getVaultHoldingsWithPrice(
1775
1923
  vault,
@@ -1812,15 +1960,15 @@ export class KaminoVaultClient {
1812
1960
  * This will return an aggregation of the current state of the vault with all the invested amounts and the utilization ratio of the vault
1813
1961
  * @param vault - the kamino vault to get available liquidity to withdraw for
1814
1962
  * @param slot - current slot
1815
- * @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
1963
+ * @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
1816
1964
  * @returns an VaultReserveTotalBorrowedAndInvested object with the total invested amount, total borrowed amount and the utilization ratio of the vault
1817
1965
  */
1818
1966
  async getTotalBorrowedAndInvested(
1819
1967
  vault: VaultState,
1820
1968
  slot: number,
1821
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
1969
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
1822
1970
  ): Promise<VaultReserveTotalBorrowedAndInvested> {
1823
- const vaultReservesState = vaultReserves ? vaultReserves : await this.loadVaultReserves(vault);
1971
+ const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
1824
1972
 
1825
1973
  const totalAvailable = lamportsToDecimal(
1826
1974
  new Decimal(vault.tokenAvailable.toString()),
@@ -1868,7 +2016,7 @@ export class KaminoVaultClient {
1868
2016
  * This will return an overview of each reserve that is part of the vault allocation
1869
2017
  * @param vault - the kamino vault to get available liquidity to withdraw for
1870
2018
  * @param slot - current slot
1871
- * @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
2019
+ * @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
1872
2020
  * @returns a hashmap from vault reserve pubkey to ReserveOverview object
1873
2021
  */
1874
2022
  async getVaultReservesDetails(
@@ -1908,15 +2056,15 @@ export class KaminoVaultClient {
1908
2056
  * This will return the APY of the vault under the assumption that all the available tokens in the vault are all the time invested in the reserves as ratio; for percentage it needs multiplication by 100
1909
2057
  * @param vault - the kamino vault to get APY for
1910
2058
  * @param slot - current slot
1911
- * @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
2059
+ * @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
1912
2060
  * @returns APY for the vault
1913
2061
  */
1914
2062
  async getVaultTheoreticalAPY(
1915
2063
  vault: VaultState,
1916
2064
  slot: number,
1917
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
2065
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>
1918
2066
  ): Promise<Decimal> {
1919
- const vaultReservesState = vaultReserves ? vaultReserves : await this.loadVaultReserves(vault);
2067
+ const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
1920
2068
 
1921
2069
  let totalWeights = new Decimal(0);
1922
2070
  let totalAPY = new Decimal(0);
@@ -1945,9 +2093,9 @@ export class KaminoVaultClient {
1945
2093
  /**
1946
2094
  * Retrive the total amount of interest earned by the vault since its inception, including what was charged as fees
1947
2095
  * @param vaultState the kamino vault state to get total net yield for
1948
- * @returns a decimal representing the net number of tokens earned by the vault since its inception
2096
+ * @returns a Decimal representing the net number of tokens earned by the vault since its inception
1949
2097
  */
1950
- async getVaultCumulativeInterest(vaultState: VaultState) {
2098
+ async getVaultCumulativeInterest(vaultState: VaultState): Promise<Decimal> {
1951
2099
  const netYieldLamports = new Fraction(vaultState.cumulativeEarnedInterestSf).toDecimal();
1952
2100
  return lamportsToDecimal(netYieldLamports, vaultState.tokenMintDecimals.toString());
1953
2101
  }
@@ -1955,20 +2103,22 @@ export class KaminoVaultClient {
1955
2103
  /**
1956
2104
  * Simulate the current holdings of the vault and the earned interest
1957
2105
  * @param vaultState the kamino vault state to get simulated holdings and earnings for
1958
- * @param vaultReserves optional; the state of the reserves in the vault allocation
2106
+ * @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
2107
+ * @param [currentSlot] - the current slot. Optional. If not provided it will fetch the current slot
1959
2108
  * @returns a struct of simulated vault holdings and earned interest
1960
2109
  */
1961
2110
  async calculateSimulatedHoldingsWithInterest(
1962
2111
  vaultState: VaultState,
1963
- vaultReserves?: PubkeyHashMap<PublicKey, KaminoReserve>
2112
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>,
2113
+ currentSlot?: number
1964
2114
  ): Promise<SimulatedVaultHoldingsWithEarnedInterest> {
1965
2115
  const latestUpdateTs = vaultState.lastFeeChargeTimestamp.toNumber();
1966
2116
  const lastUpdateSlot = latestUpdateTs / this.recentSlotDurationMs;
1967
2117
 
1968
- const currentSlot = await this._connection.getSlot('confirmed');
2118
+ const slot = currentSlot ? currentSlot : await this.getConnection().getSlot('confirmed');
1969
2119
 
1970
- const lastUpdateHoldingsPromise = this.getVaultHoldings(vaultState, lastUpdateSlot, vaultReserves);
1971
- const currentHoldingsPromise = this.getVaultHoldings(vaultState, currentSlot, vaultReserves);
2120
+ const lastUpdateHoldingsPromise = this.getVaultHoldings(vaultState, lastUpdateSlot, vaultReservesMap);
2121
+ const currentHoldingsPromise = this.getVaultHoldings(vaultState, slot, vaultReservesMap);
1972
2122
  const [lastUpdateHoldings, currentHoldings] = await Promise.all([
1973
2123
  lastUpdateHoldingsPromise,
1974
2124
  currentHoldingsPromise,
@@ -1985,14 +2135,16 @@ export class KaminoVaultClient {
1985
2135
  /**
1986
2136
  * Simulate the current holdings and compute the fees that would be charged
1987
2137
  * @param vaultState the kamino vault state to get simulated fees for
1988
- * @param simulatedCurrentHoldingsWithInterest optional; the simulated holdings and interest earned by the vault
1989
- * @returns a struct of simulated management and interest fees
2138
+ * @param [simulatedCurrentHoldingsWithInterest] the simulated holdings and interest earned by the vault. Optional
2139
+ * @param [currentTimestamp] the current timestamp. Optional. If not provided it will fetch the current unix timestamp
2140
+ * @returns a VaultFees struct of simulated management and interest fees
1990
2141
  */
1991
2142
  async calculateSimulatedFees(
1992
2143
  vaultState: VaultState,
1993
- simulatedCurrentHoldingsWithInterest?: SimulatedVaultHoldingsWithEarnedInterest
2144
+ simulatedCurrentHoldingsWithInterest?: SimulatedVaultHoldingsWithEarnedInterest,
2145
+ currentTimestamp?: number
1994
2146
  ): Promise<VaultFees> {
1995
- const timestampNow = new Date().getTime();
2147
+ const timestampNow = currentTimestamp ? currentTimestamp : Date.now();
1996
2148
  const timestampLastUpdate = vaultState.lastFeeChargeTimestamp.toNumber();
1997
2149
  const timeElapsed = timestampNow - timestampLastUpdate;
1998
2150
 
@@ -2048,6 +2200,11 @@ export class KaminoVault {
2048
2200
  }
2049
2201
  return this.state;
2050
2202
  }
2203
+
2204
+ async hasFarm(connection: Connection): Promise<boolean> {
2205
+ const state = await this.getState(connection);
2206
+ return !state.vaultFarm.equals(PublicKey.default);
2207
+ }
2051
2208
  }
2052
2209
 
2053
2210
  /**