@kamino-finance/klend-sdk 7.1.9 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,10 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ReserveAllocationConfig = exports.KaminoVaultConfig = exports.KaminoVault = exports.KaminoVaultClient = exports.INITIAL_DEPOSIT_LAMPORTS = exports.METADATA_PROGRAM_ID = exports.METADATA_SEED = exports.kaminoVaultStagingId = exports.kaminoVaultId = void 0;
6
+ exports.VaultHoldings = exports.ReserveAllocationConfig = exports.KaminoVaultConfig = exports.KaminoVault = exports.KaminoVaultClient = exports.INITIAL_DEPOSIT_LAMPORTS = exports.METADATA_PROGRAM_ID = exports.METADATA_SEED = exports.kaminoVaultStagingId = exports.kaminoVaultId = void 0;
7
7
  exports.getCTokenVaultPda = getCTokenVaultPda;
8
8
  exports.getEventAuthorityPda = getEventAuthorityPda;
9
- exports.printHoldings = printHoldings;
10
9
  const bn_js_1 = __importDefault(require("bn.js"));
11
10
  const kit_1 = require("@solana/kit");
12
11
  const lib_1 = require("../lib");
@@ -67,6 +66,9 @@ class KaminoVaultClient {
67
66
  getProgramID() {
68
67
  return this._kaminoVaultProgramId;
69
68
  }
69
+ getRpc() {
70
+ return this._rpc;
71
+ }
70
72
  hasFarm() {
71
73
  return;
72
74
  }
@@ -82,7 +84,7 @@ class KaminoVaultClient {
82
84
  console.log(`Vault ${vaultPubkey.toString()} not found`);
83
85
  return;
84
86
  }
85
- const kaminoVault = new KaminoVault(vaultPubkey, vault, this._kaminoVaultProgramId);
87
+ const kaminoVault = KaminoVault.loadWithClientAndState(this, vaultPubkey, vault);
86
88
  const vaultName = this.decodeVaultName(vault.name);
87
89
  const slot = await this.getConnection().getSlot({ commitment: 'confirmed' }).send();
88
90
  const tokensPerShare = await this.getTokensPerShareSingleVault(kaminoVault, slot);
@@ -90,7 +92,7 @@ class KaminoVaultClient {
90
92
  const sharesIssued = new decimal_js_1.default(vault.sharesIssued.toString()).div(new decimal_js_1.default(vault.sharesMintDecimals.toString()));
91
93
  console.log('Name: ', vaultName);
92
94
  console.log('Shares issued: ', sharesIssued);
93
- printHoldings(holdings);
95
+ holdings.print();
94
96
  console.log('Tokens per share: ', tokensPerShare);
95
97
  }
96
98
  /**
@@ -224,7 +226,7 @@ class KaminoVaultClient {
224
226
  * @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
225
227
  */
226
228
  async updateReserveAllocationIxs(vault, reserveAllocationConfig, vaultAdminAuthority) {
227
- const vaultState = await vault.getState(this.getConnection());
229
+ const vaultState = await vault.getState();
228
230
  const reserveState = reserveAllocationConfig.getReserveState();
229
231
  const cTokenVault = await getCTokenVaultPda(vault.address, reserveAllocationConfig.getReserveAddress(), this._kaminoVaultProgramId);
230
232
  const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
@@ -267,7 +269,7 @@ class KaminoVaultClient {
267
269
  * @returns - a list of instructions to update the unallocated weight and cap
268
270
  */
269
271
  async updateVaultUnallocatedWeightAndCapIxs(vault, vaultAdminAuthority, unallocatedWeight, unallocatedCap) {
270
- const vaultState = await vault.getState(this.getConnection());
272
+ const vaultState = await vault.getState();
271
273
  const unallocatedWeightToUse = unallocatedWeight ? unallocatedWeight : vaultState.unallocatedWeight;
272
274
  const unallocatedCapToUse = unallocatedCap ? unallocatedCap : vaultState.unallocatedTokensCap;
273
275
  const ixs = [];
@@ -289,7 +291,7 @@ class KaminoVaultClient {
289
291
  * @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
290
292
  */
291
293
  async withdrawEverythingAndBlockInvestReserve(vault, reserve, vaultAdminAuthority) {
292
- const vaultState = await vault.getState(this.getConnection());
294
+ const vaultState = await vault.getState();
293
295
  const reserveIsPartOfAllocation = vaultState.vaultAllocationStrategy.some((allocation) => allocation.reserve === reserve);
294
296
  const withdrawAndBlockReserveIxs = {
295
297
  updateReserveAllocationIxs: [],
@@ -323,7 +325,7 @@ class KaminoVaultClient {
323
325
  * @returns - a struct with an instruction to update the reserve allocations (set weight and ctoken allocation to 0) and an a list of instructions to disinvest the funds in the reserves
324
326
  */
325
327
  async withdrawEverythingFromAllReservesAndBlockInvest(vault, vaultReservesMap, payer) {
326
- const vaultState = await vault.getState(this.getConnection());
328
+ const vaultState = await vault.getState();
327
329
  const reserves = this.getVaultReserves(vaultState);
328
330
  const withdrawAndBlockReserveIxs = {
329
331
  updateReserveAllocationIxs: [],
@@ -355,7 +357,7 @@ class KaminoVaultClient {
355
357
  * @returns - a struct with an instruction to update the reserve allocations to 0 weight and a list of instructions to disinvest the funds in the reserves
356
358
  */
357
359
  async disinvestAllReservesIxs(vault, vaultReservesMap, payer) {
358
- const vaultState = await vault.getState(this.getConnection());
360
+ const vaultState = await vault.getState();
359
361
  const reserves = this.getVaultReserves(vaultState);
360
362
  const disinvestAllReservesIxs = {
361
363
  updateReserveAllocationIxs: [],
@@ -391,7 +393,7 @@ class KaminoVaultClient {
391
393
  * @returns - an instruction to remove the reserve from the vault allocation strategy or undefined if the reserve is not part of the allocation strategy
392
394
  */
393
395
  async removeReserveFromAllocationIx(vault, reserve, vaultAdminAuthority) {
394
- const vaultState = await vault.getState(this.getConnection());
396
+ const vaultState = await vault.getState();
395
397
  const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
396
398
  const reserveIsPartOfAllocation = vaultState.vaultAllocationStrategy.some((allocation) => allocation.reserve === reserve);
397
399
  if (!reserveIsPartOfAllocation) {
@@ -413,7 +415,7 @@ class KaminoVaultClient {
413
415
  * @returns a struct that contains the instruction to update the field and an optional list of instructions to update the lookup table
414
416
  */
415
417
  async updateVaultConfigIxs(vault, mode, value, vaultAdminAuthority) {
416
- const vaultState = await vault.getState(this.getConnection());
418
+ const vaultState = await vault.getState();
417
419
  const admin = parseVaultAdmin(vaultState, vaultAdminAuthority);
418
420
  const updateVaultConfigAccs = {
419
421
  vaultAdminAuthority: admin,
@@ -479,7 +481,7 @@ class KaminoVaultClient {
479
481
  *
480
482
  */
481
483
  async setVaultFarmIxs(vault, farm, errorOnOverride = true, vaultAdminAuthority) {
482
- const vaultHasFarm = await vault.hasFarm(this.getConnection());
484
+ const vaultHasFarm = await vault.hasFarm();
483
485
  if (vaultHasFarm && errorOnOverride) {
484
486
  throw new Error('Vault already has a farm, if you want to override it set errorOnOverride to false');
485
487
  }
@@ -528,7 +530,7 @@ class KaminoVaultClient {
528
530
  * @returns - an instruction to accept the ownership of the vault and a list of instructions to update the lookup table
529
531
  */
530
532
  async acceptVaultOwnershipIxs(vault, pendingAdmin) {
531
- const vaultState = await vault.getState(this.getConnection());
533
+ const vaultState = await vault.getState();
532
534
  const signer = parseVaultPendingAdmin(vaultState, pendingAdmin);
533
535
  const acceptOwneshipAccounts = {
534
536
  pendingAdmin: signer,
@@ -559,7 +561,7 @@ class KaminoVaultClient {
559
561
  * @returns - an instruction to give up the specified pending fees
560
562
  */
561
563
  async giveUpPendingFeesIx(vault, maxAmountToGiveUp, vaultAdminAuthority) {
562
- const vaultState = await vault.getState(this.getConnection());
564
+ const vaultState = await vault.getState();
563
565
  const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
564
566
  const giveUpPendingFeesAccounts = {
565
567
  vaultAdminAuthority: vaultAdmin,
@@ -582,7 +584,7 @@ class KaminoVaultClient {
582
584
  * @returns - list of instructions to withdraw all pending fees, including the ATA creation instructions if needed
583
585
  */
584
586
  async withdrawPendingFeesIxs(vault, slot, vaultReservesMap, vaultAdminAuthority) {
585
- const vaultState = await vault.getState(this.getConnection());
587
+ const vaultState = await vault.getState();
586
588
  const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
587
589
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
588
590
  const [{ ata: adminTokenAta, createAtaIx }] = await (0, utils_2.createAtasIdempotent)(vaultAdmin, [
@@ -640,7 +642,7 @@ class KaminoVaultClient {
640
642
  * @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
641
643
  */
642
644
  async depositIxs(user, vault, tokenAmount, vaultReservesMap, farmState) {
643
- const vaultState = await vault.getState(this.getConnection());
645
+ const vaultState = await vault.getState();
644
646
  const tokenProgramID = vaultState.tokenProgram;
645
647
  const userTokenAta = await (0, lib_1.getAssociatedTokenAddress)(vaultState.tokenMint, user.address, tokenProgramID);
646
648
  const createAtasIxs = [];
@@ -691,7 +693,7 @@ class KaminoVaultClient {
691
693
  stakeInFarmIfNeededIxs: [],
692
694
  };
693
695
  // if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
694
- if (!(await vault.hasFarm(this.getConnection()))) {
696
+ if (!(await vault.hasFarm())) {
695
697
  return depositIxs;
696
698
  }
697
699
  // if there is a farm, stake the shares
@@ -708,13 +710,13 @@ class KaminoVaultClient {
708
710
  * @returns - a list of instructions for the user to stake shares into the vault's farm, including the creation of prerequisite accounts if needed
709
711
  */
710
712
  async stakeSharesIxs(user, vault, sharesAmount, farmState) {
711
- const vaultState = await vault.getState(this.getConnection());
713
+ const vaultState = await vault.getState();
712
714
  let sharesToStakeLamports = new decimal_js_1.default(utils_2.U64_MAX);
713
715
  if (sharesAmount) {
714
716
  sharesToStakeLamports = (0, utils_1.numberToLamportsDecimal)(sharesAmount, vaultState.sharesMintDecimals.toNumber());
715
717
  }
716
718
  // if tokens to be staked are 0 or vault has no farm there is no stake needed
717
- if (sharesToStakeLamports.lte(0) || !(await vault.hasFarm(this.getConnection()))) {
719
+ if (sharesToStakeLamports.lte(0) || !(await vault.hasFarm())) {
718
720
  return [];
719
721
  }
720
722
  // returns the ix to create the farm state account if needed and the ix to stake the shares
@@ -731,9 +733,8 @@ class KaminoVaultClient {
731
733
  * @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
732
734
  */
733
735
  async withdrawIxs(user, vault, shareAmountToWithdraw, slot, vaultReservesMap, farmState) {
734
- const vaultState = await vault.getState(this.getConnection());
735
- const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
736
- const hasFarm = await vault.hasFarm(this.getConnection());
736
+ const vaultState = await vault.getState();
737
+ const hasFarm = await vault.hasFarm();
737
738
  const withdrawIxs = {
738
739
  unstakeFromFarmIfNeededIxs: [],
739
740
  withdrawIxs: [],
@@ -781,11 +782,11 @@ class KaminoVaultClient {
781
782
  // if the vault has allocations withdraw otherwise wtihdraw from available ix
782
783
  const vaultAllocation = vaultState.vaultAllocationStrategy.find((allocation) => allocation.reserve !== lib_1.DEFAULT_PUBLIC_KEY);
783
784
  if (vaultAllocation) {
784
- const withdrawFromVaultIxs = await this.withdrawWithReserveIxs(user, kaminoVault, sharesToWithdraw, totalUserShares, slot, vaultReservesMap);
785
+ const withdrawFromVaultIxs = await this.withdrawWithReserveIxs(user, vault, sharesToWithdraw, totalUserShares, slot, vaultReservesMap);
785
786
  withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
786
787
  }
787
788
  else {
788
- const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, kaminoVault, sharesToWithdraw);
789
+ const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, vault, sharesToWithdraw);
789
790
  withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
790
791
  }
791
792
  // if the vault is for SOL return the ix to unwrap the SOL
@@ -799,7 +800,7 @@ class KaminoVaultClient {
799
800
  withdrawIxs.postWithdrawIxs.push(unwrapIx);
800
801
  }
801
802
  // if we burn all of user's shares close its shares ATA
802
- const burnAllUserShares = sharesToWithdraw.gt(userSharesAtaBalance);
803
+ const burnAllUserShares = sharesToWithdraw.gt(totalUserShares);
803
804
  if (burnAllUserShares) {
804
805
  const closeAtaIx = (0, token_2022_1.getCloseAccountInstruction)({
805
806
  account: userSharesAta,
@@ -811,8 +812,7 @@ class KaminoVaultClient {
811
812
  return withdrawIxs;
812
813
  }
813
814
  async withdrawFromAvailableIxs(user, vault, shareAmount) {
814
- const vaultState = await vault.getState(this.getConnection());
815
- const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
815
+ const vaultState = await vault.getState();
816
816
  const userSharesAta = await (0, lib_1.getAssociatedTokenAddress)(vaultState.sharesMint, user.address);
817
817
  const [{ ata: userTokenAta, createAtaIx }] = await (0, utils_2.createAtasIdempotent)(user, [
818
818
  {
@@ -821,11 +821,11 @@ class KaminoVaultClient {
821
821
  },
822
822
  ]);
823
823
  const shareLamportsToWithdraw = (0, kliquidity_sdk_1.collToLamportsDecimal)(shareAmount, vaultState.sharesMintDecimals.toNumber());
824
- const withdrawFromAvailableIxn = await this.withdrawFromAvailableIx(user, kaminoVault, vaultState, userSharesAta, userTokenAta, shareLamportsToWithdraw);
824
+ const withdrawFromAvailableIxn = await this.withdrawFromAvailableIx(user, vault, vaultState, userSharesAta, userTokenAta, shareLamportsToWithdraw);
825
825
  return [createAtaIx, withdrawFromAvailableIxn];
826
826
  }
827
827
  async withdrawWithReserveIxs(user, vault, shareAmount, allUserShares, slot, vaultReservesMap) {
828
- const vaultState = await vault.getState(this.getConnection());
828
+ const vaultState = await vault.getState();
829
829
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
830
830
  const userSharesAta = await (0, lib_1.getAssociatedTokenAddress)(vaultState.sharesMint, user.address);
831
831
  const [{ ata: userTokenAta, createAtaIx }] = await (0, utils_2.createAtasIdempotent)(user, [
@@ -915,7 +915,7 @@ class KaminoVaultClient {
915
915
  * @returns - an array of invest instructions for each invest action required for the vault reserves
916
916
  */
917
917
  async investAllReservesIxs(payer, vault, skipComputationChecks = false) {
918
- const vaultState = await vault.reloadState(this.getConnection());
918
+ const vaultState = await vault.reloadState();
919
919
  const minInvestAmount = vaultState.minInvestAmount;
920
920
  const allReserves = this.getVaultReserves(vaultState);
921
921
  if (allReserves.length === 0) {
@@ -999,7 +999,7 @@ class KaminoVaultClient {
999
999
  * @returns - an array of invest instructions for each invest action required for the vault reserves
1000
1000
  */
1001
1001
  async investSingleReserveIxs(payer, vault, reserve, vaultReservesMap, createAtaIfNeeded = true) {
1002
- const vaultState = await vault.getState(this.getConnection());
1002
+ const vaultState = await vault.getState();
1003
1003
  const cTokenVault = await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId);
1004
1004
  const [lendingMarketAuth] = await (0, utils_2.lendingMarketAuthPda)(reserve.state.lendingMarket, this._kaminoLendProgramId);
1005
1005
  const ixs = [];
@@ -1144,7 +1144,7 @@ class KaminoVaultClient {
1144
1144
  * @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
1145
1145
  */
1146
1146
  async syncVaultLookupTableIxs(authority, vault, vaultReservesMap) {
1147
- const vaultState = await vault.getState(this.getConnection());
1147
+ const vaultState = await vault.getState();
1148
1148
  const allAccountsToBeInserted = [
1149
1149
  vault.address,
1150
1150
  vaultState.vaultAdminAuthority,
@@ -1260,7 +1260,7 @@ class KaminoVaultClient {
1260
1260
  * @returns - user share balance in tokens (not lamports)
1261
1261
  */
1262
1262
  async getUserSharesBalanceSingleVault(user, vault) {
1263
- const vaultState = await vault.getState(this.getConnection());
1263
+ const vaultState = await vault.getState();
1264
1264
  const userShares = {
1265
1265
  unstakedShares: new decimal_js_1.default(0),
1266
1266
  stakedShares: new decimal_js_1.default(0),
@@ -1280,7 +1280,7 @@ class KaminoVaultClient {
1280
1280
  }
1281
1281
  return acc;
1282
1282
  }, new decimal_js_1.default(0));
1283
- if (await vault.hasFarm(this.getConnection())) {
1283
+ if (await vault.hasFarm()) {
1284
1284
  const userSharesInFarm = await (0, farm_utils_1.getUserSharesInTokensStakedInFarm)(this.getConnection(), user, vaultState.vaultFarm, vaultState.sharesMintDecimals.toNumber());
1285
1285
  userShares.stakedShares = userSharesInFarm;
1286
1286
  }
@@ -1317,7 +1317,7 @@ class KaminoVaultClient {
1317
1317
  return mint === state.sharesMint;
1318
1318
  });
1319
1319
  userSharesTokenAccountsPerVault.set(vault.address, userSharesTokenAccounts);
1320
- if (await vault.hasFarm(this.getConnection())) {
1320
+ if (await vault.hasFarm()) {
1321
1321
  const userFarmState = allUserFarmStatesMap.get(state.vaultFarm);
1322
1322
  if (userFarmState) {
1323
1323
  console.log('there is a farm state for vault', vault.address);
@@ -1386,7 +1386,7 @@ class KaminoVaultClient {
1386
1386
  */
1387
1387
  async getTokensPerShareSingleVault(vaultOrState, slot, vaultReservesMap, currentSlot) {
1388
1388
  // Determine if we have a KaminoVault or VaultState
1389
- const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState(this.getConnection()) : vaultOrState;
1389
+ const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
1390
1390
  if (vaultState.sharesIssued.isZero()) {
1391
1391
  return new decimal_js_1.default(0);
1392
1392
  }
@@ -1465,7 +1465,7 @@ class KaminoVaultClient {
1465
1465
  if (!kaminoVaultAccount) {
1466
1466
  throw Error(`kaminoVault with pubkey ${kaminoVault.address} could not be decoded`);
1467
1467
  }
1468
- return new KaminoVault(kaminoVault.address, kaminoVaultAccount, this._kaminoVaultProgramId);
1468
+ return KaminoVault.loadWithClientAndState(this, kaminoVault.address, kaminoVaultAccount);
1469
1469
  });
1470
1470
  }
1471
1471
  /**
@@ -1480,7 +1480,7 @@ class KaminoVaultClient {
1480
1480
  const vaultStates = await (0, kliquidity_sdk_1.batchFetch)(vaults, (chunk) => this.getVaultsStates(chunk));
1481
1481
  return vaults.map((vault, index) => {
1482
1482
  const state = vaultStates[index];
1483
- return state ? new KaminoVault(vault, state, this._kaminoVaultProgramId) : null;
1483
+ return state ? KaminoVault.loadWithClientAndState(this, vault, state) : null;
1484
1484
  });
1485
1485
  }
1486
1486
  async getVaultsStates(vaults) {
@@ -1557,7 +1557,7 @@ class KaminoVaultClient {
1557
1557
  * @returns an HashMap of reserves (key) with the amount available to withdraw for each (value)
1558
1558
  */
1559
1559
  async getReserveAllocationAvailableLiquidityToWithdraw(vault, slot, vaultReservesMap) {
1560
- const vaultState = await vault.getState(this.getConnection());
1560
+ const vaultState = await vault.getState();
1561
1561
  const reserveAllocationAvailableLiquidityToWithdraw = new Map();
1562
1562
  vaultState.vaultAllocationStrategy.forEach((allocationStrategy) => {
1563
1563
  if (allocationStrategy.reserve === lib_1.DEFAULT_PUBLIC_KEY) {
@@ -1739,13 +1739,13 @@ class KaminoVaultClient {
1739
1739
  * @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
1740
1740
  */
1741
1741
  async getVaultHoldings(vault, slot, vaultReserves, currentSlot) {
1742
- const vaultHoldings = {
1742
+ const vaultHoldings = new VaultHoldings({
1743
1743
  available: new decimal_js_1.default(vault.tokenAvailable.toString()),
1744
1744
  invested: new decimal_js_1.default(0),
1745
1745
  investedInReserves: new Map(),
1746
1746
  totalAUMIncludingFees: new decimal_js_1.default(0),
1747
1747
  pendingFees: new decimal_js_1.default(0),
1748
- };
1748
+ });
1749
1749
  const currentSlotToUse = currentSlot ?? (await this.getConnection().getSlot({ commitment: 'confirmed' }).send());
1750
1750
  const vaultReservesState = vaultReserves ? vaultReserves : await this.loadVaultReserves(vault);
1751
1751
  const decimals = new decimal_js_1.default(vault.tokenMintDecimals.toString());
@@ -1794,13 +1794,13 @@ class KaminoVaultClient {
1794
1794
  const totalAvailableDecimal = (0, lib_1.lamportsToDecimal)(vaultHoldings.available, decimals);
1795
1795
  const totalInvestedDecimal = (0, lib_1.lamportsToDecimal)(vaultHoldings.invested, decimals);
1796
1796
  const pendingFees = (0, lib_1.lamportsToDecimal)(totalPendingFees, decimals);
1797
- return {
1797
+ return new VaultHoldings({
1798
1798
  available: totalAvailableDecimal,
1799
1799
  invested: totalInvestedDecimal,
1800
1800
  investedInReserves: vaultHoldings.investedInReserves,
1801
1801
  totalAUMIncludingFees: totalAvailableDecimal.add(totalInvestedDecimal),
1802
1802
  pendingFees: pendingFees,
1803
- };
1803
+ });
1804
1804
  }
1805
1805
  /**
1806
1806
  * 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
@@ -1838,19 +1838,21 @@ class KaminoVaultClient {
1838
1838
  * @returns an VaultOverview object with details about the tokens available and invested in the vault, denominated in tokens and USD, along sie APYs
1839
1839
  */
1840
1840
  async getVaultOverview(vault, vaultTokenPrice, slot, vaultReservesMap, kaminoMarkets, currentSlot, tokensPrices) {
1841
- const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
1842
- const vaultHoldingsWithUSDValuePromise = this.getVaultHoldingsWithPrice(vault, vaultTokenPrice, slot, vaultReservesState, currentSlot);
1841
+ const vaultState = await vault.getState();
1842
+ const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
1843
+ const vaultHoldingsWithUSDValuePromise = this.getVaultHoldingsWithPrice(vaultState, vaultTokenPrice, slot, vaultReservesState, currentSlot);
1843
1844
  const slotForOverview = slot ? slot : await this.getConnection().getSlot().send();
1844
1845
  const farmsClient = new farms_sdk_1.Farms(this.getConnection());
1845
- const vaultTheoreticalAPYPromise = this.getVaultTheoreticalAPY(vault, slotForOverview, vaultReservesState);
1846
- const vaultActualAPYPromise = this.getVaultActualAPY(vault, slotForOverview, vaultReservesState);
1847
- const totalInvestedAndBorrowedPromise = this.getTotalBorrowedAndInvested(vault, slotForOverview, vaultReservesState);
1848
- const vaultCollateralsPromise = this.getVaultCollaterals(vault, slotForOverview, vaultReservesState, kaminoMarkets);
1849
- const reservesOverviewPromise = this.getVaultReservesDetails(vault, slotForOverview, vaultReservesState);
1846
+ const vaultTheoreticalAPYPromise = this.getVaultTheoreticalAPY(vaultState, slotForOverview, vaultReservesState);
1847
+ const vaultActualAPYPromise = this.getVaultActualAPY(vaultState, slotForOverview, vaultReservesState);
1848
+ const totalInvestedAndBorrowedPromise = this.getTotalBorrowedAndInvested(vaultState, slotForOverview, vaultReservesState);
1849
+ const vaultCollateralsPromise = this.getVaultCollaterals(vaultState, slotForOverview, vaultReservesState, kaminoMarkets);
1850
+ const reservesOverviewPromise = this.getVaultReservesDetails(vaultState, slotForOverview, vaultReservesState);
1850
1851
  const vaultFarmIncentivesPromise = this.getVaultRewardsAPY(vault, vaultTokenPrice, farmsClient, slotForOverview, tokensPrices);
1851
1852
  const vaultReservesFarmIncentivesPromise = this.getVaultReservesFarmsIncentives(vault, vaultTokenPrice, farmsClient, slotForOverview, vaultReservesState, tokensPrices);
1853
+ const vaultDelegatedFarmIncentivesPromise = this.getVaultDelegatedFarmRewardsAPY(vault, vaultTokenPrice, farmsClient, slotForOverview, tokensPrices);
1852
1854
  // all the async part of the functions above just read the vaultReservesState which is read beforehand, so excepting vaultCollateralsPromise they should do no additional network calls
1853
- const [vaultHoldingsWithUSDValue, vaultTheoreticalAPYs, vaultActualAPYs, totalInvestedAndBorrowed, vaultCollaterals, reservesOverview, vaultFarmIncentives, vaultReservesFarmIncentives,] = await Promise.all([
1855
+ const [vaultHoldingsWithUSDValue, vaultTheoreticalAPYs, vaultActualAPYs, totalInvestedAndBorrowed, vaultCollaterals, reservesOverview, vaultFarmIncentives, vaultReservesFarmIncentives, vaultDelegatedFarmIncentives,] = await Promise.all([
1854
1856
  vaultHoldingsWithUSDValuePromise,
1855
1857
  vaultTheoreticalAPYPromise,
1856
1858
  vaultActualAPYPromise,
@@ -1859,6 +1861,7 @@ class KaminoVaultClient {
1859
1861
  reservesOverviewPromise,
1860
1862
  vaultFarmIncentivesPromise,
1861
1863
  vaultReservesFarmIncentivesPromise,
1864
+ vaultDelegatedFarmIncentivesPromise,
1862
1865
  ]);
1863
1866
  return {
1864
1867
  holdingsUSD: vaultHoldingsWithUSDValue,
@@ -1868,6 +1871,7 @@ class KaminoVaultClient {
1868
1871
  theoreticalSupplyAPY: vaultTheoreticalAPYs,
1869
1872
  vaultFarmIncentives: vaultFarmIncentives,
1870
1873
  reservesFarmsIncentives: vaultReservesFarmIncentives,
1874
+ delegatedFarmIncentives: vaultDelegatedFarmIncentives,
1871
1875
  totalBorrowed: totalInvestedAndBorrowed.totalBorrowed,
1872
1876
  totalBorrowedUSD: totalInvestedAndBorrowed.totalBorrowed.mul(vaultTokenPrice),
1873
1877
  utilizationRatio: totalInvestedAndBorrowed.utilizationRatio,
@@ -2098,10 +2102,40 @@ class KaminoVaultClient {
2098
2102
  */
2099
2103
  computeUserFarmStateDelegateePDAForUserInVault(farmsProgramId, vault, reserve, user) {
2100
2104
  return (0, kit_1.getProgramDerivedAddress)({
2101
- seeds: [addressEncoder.encode(vault), addressEncoder.encode(reserve), addressEncoder.encode(user)],
2105
+ seeds: [addressEncoder.encode(reserve), addressEncoder.encode(vault), addressEncoder.encode(user)],
2102
2106
  programAddress: farmsProgramId,
2103
2107
  });
2104
2108
  }
2109
+ /**
2110
+ * Compute the delegatee PDA for the user farm state for a vault delegate farm
2111
+ * @param farmProgramID - the program ID of the farm program
2112
+ * @param vault - the address of the vault
2113
+ * @param farm - the address of the delegated farm
2114
+ * @param user - the address of the user
2115
+ * @returns the PDA of the delegatee user farm state for the delegated farm
2116
+ */
2117
+ async computeUserFarmStateDelegateePDAForUserInDelegatedVaultFarm(farmProgramID, vault, farm, user) {
2118
+ return (0, kit_1.getProgramDerivedAddress)({
2119
+ seeds: [addressEncoder.encode(vault), addressEncoder.encode(farm), addressEncoder.encode(user)],
2120
+ programAddress: farmProgramID,
2121
+ });
2122
+ }
2123
+ /**
2124
+ * Compute the user state PDA for a user in a delegated vault farm
2125
+ * @param farmProgramID - the program ID of the farm program
2126
+ * @param vault - the address of the vault
2127
+ * @param farm - the address of the delegated farm
2128
+ * @param user - the address of the user
2129
+ * @returns the PDA of the user state for the delegated farm
2130
+ */
2131
+ async computeUserStatePDAForUserInDelegatedVaultFarm(farmProgramID, vault, farm, user) {
2132
+ const delegateePDA = await this.computeDelegateeForUserInDelegatedFarm(farmProgramID, vault, farm, user);
2133
+ return (0, dist_1.getUserStatePDA)(farmProgramID, farm, delegateePDA);
2134
+ }
2135
+ async computeDelegateeForUserInDelegatedFarm(farmProgramID, vault, farm, user) {
2136
+ const delegateePDA = await this.computeUserFarmStateDelegateePDAForUserInDelegatedVaultFarm(farmProgramID, vault, farm, user);
2137
+ return delegateePDA[0];
2138
+ }
2105
2139
  /**
2106
2140
  * Read the APY of the farm built on top of the vault (farm in vaultState.vaultFarm)
2107
2141
  * @param vault - the vault to read the farm APY for
@@ -2112,7 +2146,7 @@ class KaminoVaultClient {
2112
2146
  */
2113
2147
  async getVaultRewardsAPY(vaultOrState, vaultTokenPrice, farmsClient, slot, tokensPrices) {
2114
2148
  // Determine if we have a KaminoVault or VaultState
2115
- const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState(this.getConnection()) : vaultOrState;
2149
+ const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
2116
2150
  if (vaultState.vaultFarm === lib_1.DEFAULT_PUBLIC_KEY) {
2117
2151
  return {
2118
2152
  incentivesStats: [],
@@ -2125,6 +2159,30 @@ class KaminoVaultClient {
2125
2159
  const kFarmsClient = farmsClient ? farmsClient : new farms_sdk_1.Farms(this.getConnection());
2126
2160
  return (0, apy_1.getFarmIncentives)(kFarmsClient, vaultState.vaultFarm, sharePrice, stakedTokenMintDecimals, tokensPrices);
2127
2161
  }
2162
+ /**
2163
+ * Read the APY of the delegated farm providing incentives for vault depositors
2164
+ * @param vault - the vault to read the farm APY for
2165
+ * @param vaultTokenPrice - the price of the vault token in USD (e.g. 1.0 for USDC)
2166
+ * @param [farmsClient] - the farms client to use. Optional. If not provided, the function will create a new one
2167
+ * @param [slot] - the slot to read the farm APY for. Optional. If not provided, the function will read the current slot
2168
+ * @param [tokensPrices] - the prices of the tokens in USD. Optional. If not provided, the function will fetch the prices
2169
+ * @returns the APY of the delegated farm providing incentives for vault depositors
2170
+ */
2171
+ async getVaultDelegatedFarmRewardsAPY(vault, vaultTokenPrice, farmsClient, slot, tokensPrices) {
2172
+ const delegatedFarm = await this.getDelegatedFarmForVault(vault.address);
2173
+ if (!delegatedFarm) {
2174
+ return {
2175
+ incentivesStats: [],
2176
+ totalIncentivesApy: 0,
2177
+ };
2178
+ }
2179
+ const vaultState = await vault.getState();
2180
+ const tokensPerShare = await this.getTokensPerShareSingleVault(vaultState, slot);
2181
+ const sharePrice = tokensPerShare.mul(vaultTokenPrice);
2182
+ const stakedTokenMintDecimals = vaultState.sharesMintDecimals.toNumber();
2183
+ const kFarmsClient = farmsClient ? farmsClient : new farms_sdk_1.Farms(this.getConnection());
2184
+ return (0, apy_1.getFarmIncentives)(kFarmsClient, delegatedFarm, sharePrice, stakedTokenMintDecimals, tokensPrices);
2185
+ }
2128
2186
  /**
2129
2187
  * Get all the token mints of the vault, vault farm rewards and the allocation rewards
2130
2188
  * @param vaults - the vaults to get the token mints for
@@ -2138,9 +2196,9 @@ class KaminoVaultClient {
2138
2196
  const farmsToFetch = new Set();
2139
2197
  const reservesToFetch = new Set();
2140
2198
  for (const vault of vaults) {
2141
- const vaultState = await vault.getState(this.getConnection());
2199
+ const vaultState = await vault.getState();
2142
2200
  vaultsTokenMints.add(vaultState.tokenMint);
2143
- const hasFarm = await vault.hasFarm(this.getConnection());
2201
+ const hasFarm = await vault.hasFarm();
2144
2202
  if (hasFarm) {
2145
2203
  const farmAddress = vaultState.vaultFarm;
2146
2204
  if (!kFarmsMap.has(farmAddress)) {
@@ -2216,9 +2274,9 @@ class KaminoVaultClient {
2216
2274
  return vaultsTokenMints;
2217
2275
  }
2218
2276
  async getVaultReservesFarmsIncentives(vaultOrState, vaultTokenPrice, farmsClient, slot, vaultReservesMap, tokensPrices) {
2219
- const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState(this.getConnection()) : vaultOrState;
2277
+ const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
2220
2278
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
2221
- const currentSlot = slot ? slot : await this.getConnection().getSlot({ commitment: 'confirmed' }).send();
2279
+ const currentSlot = slot ?? (await this.getConnection().getSlot({ commitment: 'confirmed' }).send());
2222
2280
  const holdings = await this.getVaultHoldings(vaultState, currentSlot, vaultReservesState);
2223
2281
  const vaultReservesAddresses = vaultState.vaultAllocationStrategy.map((allocationStrategy) => allocationStrategy.reserve);
2224
2282
  const vaultReservesFarmsIncentives = new Map();
@@ -2237,7 +2295,7 @@ class KaminoVaultClient {
2237
2295
  });
2238
2296
  continue;
2239
2297
  }
2240
- const reserveFarmIncentives = await (0, farmUtils_1.getReserveFarmRewardsAPY)(this._rpc, this.recentSlotDurationMs, reserveAddress, vaultTokenPrice, this._kaminoLendProgramId, kFarmsClient, currentSlot, reserveState.state, undefined, tokensPrices);
2298
+ const reserveFarmIncentives = await (0, farmUtils_1.getReserveFarmRewardsAPY)(this._rpc, this.recentSlotDurationMs, reserveAddress, vaultTokenPrice, this._kaminoLendProgramId, kFarmsClient, currentSlot, reserveState.state, tokensPrices);
2241
2299
  vaultReservesFarmsIncentives.set(reserveAddress, reserveFarmIncentives.collateralFarmIncentives);
2242
2300
  const investedInReserve = holdings.investedInReserves.get(reserveAddress);
2243
2301
  const weightedReserveAPY = new decimal_js_1.default(reserveFarmIncentives.collateralFarmIncentives.totalIncentivesApy)
@@ -2250,6 +2308,227 @@ class KaminoVaultClient {
2250
2308
  totalIncentivesAPY: totalIncentivesApy,
2251
2309
  };
2252
2310
  }
2311
+ /// reads the pending rewards for a user in the vault farm
2312
+ /// @param user - the user address
2313
+ /// @param vault - the vault
2314
+ /// @returns a map of the pending rewards token mint and amount in lamports
2315
+ async getUserPendingRewardsInVaultFarm(user, vault) {
2316
+ const vaultState = await vault.getState();
2317
+ const hasFarm = await vault.hasFarm();
2318
+ if (!hasFarm) {
2319
+ return new Map();
2320
+ }
2321
+ const farmClient = new farms_sdk_1.Farms(this.getConnection());
2322
+ const userState = await (0, dist_1.getUserStatePDA)(farmClient.getProgramID(), vaultState.vaultFarm, user);
2323
+ return (0, farm_utils_1.getUserPendingRewardsInFarm)(this.getConnection(), userState, vaultState.vaultFarm);
2324
+ }
2325
+ /// reads the pending rewards for a user in a delegated vault farm
2326
+ /// @param user - the user address
2327
+ /// @param vaultAddress - the address of the vault
2328
+ /// @returns a map of the pending rewards token mint and amount in lamports
2329
+ async getUserPendingRewardsInVaultDelegatedFarm(user, vaultAddress) {
2330
+ const delegatedFarm = await this.getDelegatedFarmForVault(vaultAddress);
2331
+ if (!delegatedFarm) {
2332
+ return new Map();
2333
+ }
2334
+ const farmClient = new farms_sdk_1.Farms(this.getConnection());
2335
+ const userState = await this.computeUserStatePDAForUserInDelegatedVaultFarm(farmClient.getProgramID(), vaultAddress, delegatedFarm, user);
2336
+ return (0, farm_utils_1.getUserPendingRewardsInFarm)(this.getConnection(), userState, delegatedFarm);
2337
+ }
2338
+ /// gets the delegated farm for a vault
2339
+ async getDelegatedFarmForVault(vault) {
2340
+ const response = await fetch(`${utils_2.CDN_ENDPOINT}/resources.json`);
2341
+ if (!response.ok) {
2342
+ console.log(`Failed to fetch CDN for user pending rewards in vault delegated farm: ${response.statusText}`);
2343
+ return undefined;
2344
+ }
2345
+ const data = (await response.json());
2346
+ const delegatedVaultFarms = data['mainnet-beta']?.delegatedVaultFarms;
2347
+ if (!delegatedVaultFarms) {
2348
+ return undefined;
2349
+ }
2350
+ const delegatedFarmWithVault = delegatedVaultFarms.find((vaultWithFarm) => vaultWithFarm.vault === vault);
2351
+ if (!delegatedFarmWithVault) {
2352
+ return undefined;
2353
+ }
2354
+ return (0, kit_1.address)(delegatedFarmWithVault.farm);
2355
+ }
2356
+ /// reads the pending rewards for a user in the reserves farms of a vault
2357
+ /// @param user - the user address
2358
+ /// @param vault - the vault
2359
+ /// @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
2360
+ /// @returns a map of the pending rewards token mint and amount in lamports
2361
+ async getUserPendingRewardsInVaultReservesFarms(user, vault, vaultReservesMap) {
2362
+ const vaultState = await vault.getState();
2363
+ const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
2364
+ const vaultReserves = vaultState.vaultAllocationStrategy
2365
+ .map((allocationStrategy) => allocationStrategy.reserve)
2366
+ .filter((reserve) => reserve !== lib_1.DEFAULT_PUBLIC_KEY);
2367
+ const pendingRewardsPerToken = new Map();
2368
+ const farmClient = new farms_sdk_1.Farms(this.getConnection());
2369
+ for (const reserveAddress of vaultReserves) {
2370
+ const reserveState = vaultReservesState.get(reserveAddress);
2371
+ if (!reserveState) {
2372
+ console.log(`Reserve to read farm incentives for not found: ${reserveAddress}`);
2373
+ continue;
2374
+ }
2375
+ if (reserveState.state.farmCollateral === lib_1.DEFAULT_PUBLIC_KEY) {
2376
+ continue;
2377
+ }
2378
+ const delegatee = await this.computeUserFarmStateDelegateePDAForUserInVault(farmClient.getProgramID(), vault.address, reserveAddress, user);
2379
+ const userState = await (0, dist_1.getUserStatePDA)(farmClient.getProgramID(), reserveState.state.farmCollateral, delegatee[0]);
2380
+ const pendingRewards = await (0, farm_utils_1.getUserPendingRewardsInFarm)(this.getConnection(), userState, reserveState.state.farmCollateral);
2381
+ pendingRewards.forEach((reward, token) => {
2382
+ const existingReward = pendingRewardsPerToken.get(token);
2383
+ if (existingReward) {
2384
+ pendingRewardsPerToken.set(token, existingReward.add(reward));
2385
+ }
2386
+ else {
2387
+ pendingRewardsPerToken.set(token, reward);
2388
+ }
2389
+ });
2390
+ }
2391
+ return pendingRewardsPerToken;
2392
+ }
2393
+ /// reads the pending rewards for a user in the vault farm, the reserves farms of the vault and the delegated vault farm
2394
+ /// @param user - the user address
2395
+ /// @param vault - the vault
2396
+ /// @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
2397
+ /// @returns a struct containing the pending rewards in the vault farm, the reserves farms of the vault and the delegated vault farm, and the total pending rewards in lamports
2398
+ async getAllPendingRewardsForUserInVault(user, vault, vaultReservesMap) {
2399
+ const pendingRewardsInVaultFarm = await this.getUserPendingRewardsInVaultFarm(user, vault);
2400
+ const pendingRewardsInVaultReservesFarms = await this.getUserPendingRewardsInVaultReservesFarms(user, vault, vaultReservesMap);
2401
+ const pendingRewardsInVaultDelegatedFarm = await this.getUserPendingRewardsInVaultDelegatedFarm(user, vault.address);
2402
+ const totalPendingRewards = new Map();
2403
+ pendingRewardsInVaultFarm.forEach((reward, token) => {
2404
+ const existingReward = totalPendingRewards.get(token);
2405
+ if (existingReward) {
2406
+ totalPendingRewards.set(token, existingReward.add(reward));
2407
+ }
2408
+ else {
2409
+ totalPendingRewards.set(token, reward);
2410
+ }
2411
+ });
2412
+ pendingRewardsInVaultReservesFarms.forEach((reward, token) => {
2413
+ const existingReward = totalPendingRewards.get(token);
2414
+ if (existingReward) {
2415
+ totalPendingRewards.set(token, existingReward.add(reward));
2416
+ }
2417
+ else {
2418
+ totalPendingRewards.set(token, reward);
2419
+ }
2420
+ });
2421
+ pendingRewardsInVaultDelegatedFarm.forEach((reward, token) => {
2422
+ const existingReward = totalPendingRewards.get(token);
2423
+ if (existingReward) {
2424
+ totalPendingRewards.set(token, existingReward.add(reward));
2425
+ }
2426
+ else {
2427
+ totalPendingRewards.set(token, reward);
2428
+ }
2429
+ });
2430
+ return {
2431
+ pendingRewardsInVaultFarm,
2432
+ pendingRewardsInVaultReservesFarms,
2433
+ pendingRewardsInVaultDelegatedFarm,
2434
+ totalPendingRewards,
2435
+ };
2436
+ }
2437
+ /**
2438
+ * This function will return the instructions to claim the rewards for the farm of a vault, the delegated farm of the vault and the reserves farms of the vault
2439
+ * @param user - the user to claim the rewards
2440
+ * @param vault - the vault
2441
+ * @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
2442
+ * @returns the instructions to claim the rewards for the farm of the vault, the delegated farm of the vault and the reserves farms of the vault
2443
+ */
2444
+ async getClaimAllRewardsForVaultIxs(user, vault, vaultReservesMap) {
2445
+ const [vaultFarmIxs, delegatedFarmIxs, reservesFarmsIxs] = await Promise.all([
2446
+ this.getClaimVaultFarmRewardsIxs(user, vault),
2447
+ this.getClaimVaultDelegatedFarmRewardsIxs(user, vault),
2448
+ this.getClaimVaultReservesFarmsRewardsIxs(user, vault, vaultReservesMap),
2449
+ ]);
2450
+ return [...new Set([...vaultFarmIxs, ...delegatedFarmIxs, ...reservesFarmsIxs])];
2451
+ }
2452
+ /**
2453
+ * This function will return the instructions to claim the rewards for the farm of a vault
2454
+ * @param user - the user to claim the rewards
2455
+ * @param vault - the vault
2456
+ * @returns the instructions to claim the rewards for the farm of the vault
2457
+ */
2458
+ async getClaimVaultFarmRewardsIxs(user, vault) {
2459
+ const vaultState = await vault.getState();
2460
+ const hasFarm = await vault.hasFarm();
2461
+ if (!hasFarm) {
2462
+ return [];
2463
+ }
2464
+ const farmClient = new farms_sdk_1.Farms(this.getConnection());
2465
+ const pendingRewardsInVaultFarm = await this.getUserPendingRewardsInVaultFarm(user.address, vault);
2466
+ // if there are no pending rewards of their total is 0 no ix is needed
2467
+ const totalPendingRewards = Array.from(pendingRewardsInVaultFarm.values()).reduce((acc, reward) => acc.add(reward), new decimal_js_1.default(0));
2468
+ if (totalPendingRewards.eq(0)) {
2469
+ return [];
2470
+ }
2471
+ return farmClient.claimForUserForFarmAllRewardsIx(user, vaultState.vaultFarm, false);
2472
+ }
2473
+ /**
2474
+ * This function will return the instructions to claim the rewards for the delegated farm of a vault
2475
+ * @param user - the user to claim the rewards
2476
+ * @param vault - the vault
2477
+ * @returns the instructions to claim the rewards for the delegated farm of the vault
2478
+ */
2479
+ async getClaimVaultDelegatedFarmRewardsIxs(user, vault) {
2480
+ const delegatedFarm = await this.getDelegatedFarmForVault(vault.address);
2481
+ if (!delegatedFarm) {
2482
+ return [];
2483
+ }
2484
+ const farmClient = new farms_sdk_1.Farms(this.getConnection());
2485
+ const delegatee = await this.computeDelegateeForUserInDelegatedFarm(farmClient.getProgramID(), vault.address, delegatedFarm, user.address);
2486
+ const userState = await (0, dist_1.getUserStatePDA)(farmClient.getProgramID(), delegatedFarm, delegatee);
2487
+ // check if the user state exists
2488
+ const userStateExists = await (0, kit_1.fetchEncodedAccount)(this.getConnection(), userState);
2489
+ if (!userStateExists.exists) {
2490
+ return [];
2491
+ }
2492
+ return farmClient.claimForUserForFarmAllRewardsIx(user, delegatedFarm, true, [delegatee]);
2493
+ }
2494
+ /**
2495
+ * This function will return the instructions to claim the rewards for the reserves farms of a vault
2496
+ * @param user - the user to claim the rewards
2497
+ * @param vault - the vault
2498
+ * @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
2499
+ * @returns the instructions to claim the rewards for the reserves farms of the vault
2500
+ */
2501
+ async getClaimVaultReservesFarmsRewardsIxs(user, vault, vaultReservesMap) {
2502
+ const vaultState = await vault.getState();
2503
+ const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
2504
+ const vaultReserves = vaultState.vaultAllocationStrategy
2505
+ .map((allocationStrategy) => allocationStrategy.reserve)
2506
+ .filter((reserve) => reserve !== lib_1.DEFAULT_PUBLIC_KEY);
2507
+ const ixs = [];
2508
+ const farmClient = new farms_sdk_1.Farms(this.getConnection());
2509
+ for (const reserveAddress of vaultReserves) {
2510
+ const reserveState = vaultReservesState.get(reserveAddress);
2511
+ if (!reserveState) {
2512
+ console.log(`Reserve to read farm incentives for not found: ${reserveAddress}`);
2513
+ continue;
2514
+ }
2515
+ if (reserveState.state.farmCollateral === lib_1.DEFAULT_PUBLIC_KEY) {
2516
+ continue;
2517
+ }
2518
+ const delegatee = await this.computeUserFarmStateDelegateePDAForUserInVault(farmClient.getProgramID(), vault.address, reserveAddress, user.address);
2519
+ const userState = await (0, dist_1.getUserStatePDA)(farmClient.getProgramID(), reserveState.state.farmCollateral, delegatee[0]);
2520
+ const pendingRewards = await (0, farm_utils_1.getUserPendingRewardsInFarm)(this.getConnection(), userState, reserveState.state.farmCollateral);
2521
+ const totalPendingRewards = Array.from(pendingRewards.values()).reduce((acc, reward) => acc.add(reward), new decimal_js_1.default(0));
2522
+ if (totalPendingRewards.eq(0)) {
2523
+ continue;
2524
+ }
2525
+ const ix = await farmClient.claimForUserForFarmAllRewardsIx(user, reserveState.state.farmCollateral, true, [
2526
+ delegatee[0],
2527
+ ]);
2528
+ ixs.push(...ix);
2529
+ }
2530
+ return ixs;
2531
+ }
2253
2532
  appendRemainingAccountsForVaultReserves(ix, vaultReserves, vaultReservesState) {
2254
2533
  let vaultReservesAccountMetas = [];
2255
2534
  let vaultReservesLendingMarkets = [];
@@ -2274,14 +2553,24 @@ class KaminoVault {
2274
2553
  address;
2275
2554
  state;
2276
2555
  programId;
2277
- constructor(vaultAddress, state, programId = exports.kaminoVaultId) {
2556
+ client;
2557
+ vaultReservesStateCache;
2558
+ constructor(rpc, vaultAddress, state, programId = exports.kaminoVaultId, recentSlotDurationMs = lib_1.DEFAULT_RECENT_SLOT_DURATION_MS) {
2278
2559
  this.address = vaultAddress;
2279
2560
  this.state = state;
2280
2561
  this.programId = programId;
2562
+ this.client = new KaminoVaultClient(rpc, recentSlotDurationMs);
2563
+ }
2564
+ static loadWithClientAndState(client, vaultAddress, state) {
2565
+ const vault = new KaminoVault(client.getConnection(), vaultAddress);
2566
+ vault.state = state;
2567
+ vault.programId = client.getProgramID();
2568
+ vault.client = client;
2569
+ return vault;
2281
2570
  }
2282
- async getState(rpc) {
2571
+ async getState() {
2283
2572
  if (!this.state) {
2284
- const res = await accounts_1.VaultState.fetch(rpc, this.address, this.programId);
2573
+ const res = await accounts_1.VaultState.fetch(this.client.getConnection(), this.address, this.programId);
2285
2574
  if (!res) {
2286
2575
  throw new Error('Invalid vault');
2287
2576
  }
@@ -2292,17 +2581,110 @@ class KaminoVault {
2292
2581
  return this.state;
2293
2582
  }
2294
2583
  }
2295
- async reloadState(rpc) {
2296
- this.state = await accounts_1.VaultState.fetch(rpc, this.address, this.programId);
2584
+ async reloadVaultReserves() {
2585
+ this.vaultReservesStateCache = await this.client.loadVaultReserves(this.state);
2586
+ }
2587
+ async reloadState() {
2588
+ this.state = await accounts_1.VaultState.fetch(this.client.getConnection(), this.address, this.programId);
2297
2589
  if (!this.state) {
2298
2590
  throw new Error('Could not fetch vault');
2299
2591
  }
2300
2592
  return this.state;
2301
2593
  }
2302
- async hasFarm(rpc) {
2303
- const state = await this.getState(rpc);
2594
+ async hasFarm() {
2595
+ const state = await this.getState();
2304
2596
  return state.vaultFarm !== lib_1.DEFAULT_PUBLIC_KEY;
2305
2597
  }
2598
+ /**
2599
+ * 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
2600
+ * @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
2601
+ */
2602
+ async getVaultHoldings() {
2603
+ if (!this.state || !this.vaultReservesStateCache) {
2604
+ await this.reloadState();
2605
+ await this.reloadVaultReserves();
2606
+ }
2607
+ return await this.client.getVaultHoldings(this.state, undefined, this.vaultReservesStateCache, undefined);
2608
+ }
2609
+ /**
2610
+ * This will return the a map between reserve pubkey and the allocation overview for the reserve
2611
+ * @returns a map between reserve pubkey and the allocation overview for the reserve
2612
+ */
2613
+ async getVaultAllocations() {
2614
+ if (!this.state) {
2615
+ await this.reloadState();
2616
+ }
2617
+ return this.client.getVaultAllocations(this.state);
2618
+ }
2619
+ /**
2620
+ * This will return the APY of the vault based on the current invested amounts and the theoretical APY if all the available tokens were invested
2621
+ * @returns a struct containing actualAPY and theoreticalAPY for the vault
2622
+ */
2623
+ async getAPYs(slot) {
2624
+ if (!this.state || !this.vaultReservesStateCache) {
2625
+ await this.reloadState();
2626
+ await this.reloadVaultReserves();
2627
+ }
2628
+ const latestSlot = slot ?? (await this.client.getConnection().getSlot({ commitment: 'confirmed' }).send());
2629
+ const actualApy = await this.client.getVaultActualAPY(this.state, latestSlot, this.vaultReservesStateCache);
2630
+ const theoreticalApy = await this.client.getVaultTheoreticalAPY(this.state, latestSlot, this.vaultReservesStateCache);
2631
+ return {
2632
+ actualAPY: actualApy,
2633
+ theoreticalAPY: theoreticalApy,
2634
+ };
2635
+ }
2636
+ /**
2637
+ * This method returns the exchange rate of the vault (tokens per share)
2638
+ * @returns - Decimal representing the exchange rate (tokens per share)
2639
+ */
2640
+ async getExchangeRate(slot) {
2641
+ if (!this.state || !this.vaultReservesStateCache) {
2642
+ await this.reloadState();
2643
+ await this.reloadVaultReserves();
2644
+ }
2645
+ const latestSlot = slot ?? (await this.client.getConnection().getSlot({ commitment: 'confirmed' }).send());
2646
+ const tokensPerShare = await this.client.getTokensPerShareSingleVault(this.state, latestSlot);
2647
+ return tokensPerShare;
2648
+ }
2649
+ /**
2650
+ * This method returns the user shares balance for a given vault
2651
+ * @param user - user to calculate the shares balance for
2652
+ * @param vault - vault to calculate shares balance for
2653
+ * @returns - a struct of user share balance (staked in vault farm if the vault has a farm and unstaked) in decimal (not lamports)
2654
+ */
2655
+ async getUserShares(user) {
2656
+ return this.client.getUserSharesBalanceSingleVault(user, this);
2657
+ }
2658
+ /**
2659
+ * 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
2660
+ * @param user - user to deposit
2661
+ * @param tokenAmount - token amount to be deposited, in decimals (will be converted in lamports)
2662
+ * @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
2663
+ * @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
2664
+ * @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
2665
+ */
2666
+ async depositIxs(user, tokenAmount, vaultReservesMap, farmState) {
2667
+ if (vaultReservesMap) {
2668
+ this.vaultReservesStateCache = vaultReservesMap;
2669
+ }
2670
+ return this.client.depositIxs(user, this, tokenAmount, this.vaultReservesStateCache, farmState);
2671
+ }
2672
+ /**
2673
+ * 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
2674
+ * @param user - user to withdraw
2675
+ * @param shareAmount - share amount to withdraw (in tokens, not lamports), in order to withdraw everything, any value > user share amount
2676
+ * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
2677
+ * @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
2678
+ * @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
2679
+ * @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
2680
+ */
2681
+ async withdrawIxs(user, shareAmount, slot, vaultReservesMap, farmState) {
2682
+ if (vaultReservesMap) {
2683
+ this.vaultReservesStateCache = vaultReservesMap;
2684
+ }
2685
+ const currentSlot = slot ?? (await this.client.getConnection().getSlot({ commitment: 'confirmed' }).send());
2686
+ return this.client.withdrawIxs(user, this, shareAmount, currentSlot, this.vaultReservesStateCache, farmState);
2687
+ }
2306
2688
  }
2307
2689
  exports.KaminoVault = KaminoVault;
2308
2690
  /**
@@ -2385,12 +2767,36 @@ function parseVaultAdmin(vault, signer) {
2385
2767
  function parseVaultPendingAdmin(vault, signer) {
2386
2768
  return signer ?? (0, signer_1.noopSigner)(vault.pendingAdmin);
2387
2769
  }
2388
- function printHoldings(holdings) {
2389
- console.log('Holdings:');
2390
- console.log(' Available:', holdings.available.toString());
2391
- console.log(' Invested:', holdings.invested.toString());
2392
- console.log(' Total AUM including fees:', holdings.totalAUMIncludingFees.toString());
2393
- console.log(' Pending fees:', holdings.pendingFees.toString());
2394
- console.log(' Invested in reserves:', (0, utils_1.pubkeyHashMapToJson)(holdings.investedInReserves));
2770
+ class VaultHoldings {
2771
+ available;
2772
+ invested;
2773
+ investedInReserves;
2774
+ pendingFees;
2775
+ totalAUMIncludingFees;
2776
+ constructor(params) {
2777
+ this.available = params.available;
2778
+ this.invested = params.invested;
2779
+ this.investedInReserves = params.investedInReserves;
2780
+ this.pendingFees = params.pendingFees;
2781
+ this.totalAUMIncludingFees = params.totalAUMIncludingFees;
2782
+ }
2783
+ asJSON() {
2784
+ return {
2785
+ available: this.available.toString(),
2786
+ invested: this.invested.toString(),
2787
+ totalAUMIncludingFees: this.totalAUMIncludingFees.toString(),
2788
+ pendingFees: this.pendingFees.toString(),
2789
+ investedInReserves: (0, utils_1.pubkeyHashMapToJson)(this.investedInReserves),
2790
+ };
2791
+ }
2792
+ print() {
2793
+ console.log('Holdings:');
2794
+ console.log(' Available:', this.available.toString());
2795
+ console.log(' Invested:', this.invested.toString());
2796
+ console.log(' Total AUM including fees:', this.totalAUMIncludingFees.toString());
2797
+ console.log(' Pending fees:', this.pendingFees.toString());
2798
+ console.log(' Invested in reserves:', (0, utils_1.pubkeyHashMapToJson)(this.investedInReserves));
2799
+ }
2395
2800
  }
2801
+ exports.VaultHoldings = VaultHoldings;
2396
2802
  //# sourceMappingURL=vault.js.map