@kamino-finance/klend-sdk 5.1.2 → 5.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../src/utils/rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,SAAS,EAEV,MAAM,iBAAiB,CAAC;AAUzB;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,kBAAkB,CAAC,EAAE,wBAAwB,GAAG,UAAU,GACzD,OAAO,CAAC,0BAA0B,CAAC,CA2CrC;AAiCD,MAAM,MAAM,MAAM,GAAG,SAAS,QAAQ,CAAC;IACrC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/B,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,EAAE,CAAC"}
1
+ {"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../src/utils/rpc.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,SAAS,EAEV,MAAM,iBAAiB,CAAC;AAUzB;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,kBAAkB,CAAC,EAAE,wBAAwB,GAAG,UAAU,GACzD,OAAO,CAAC,0BAA0B,CAAC,CA2CrC;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAMpG;AAiCD,MAAM,MAAM,MAAM,GAAG,SAAS,QAAQ,CAAC;IACrC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/B,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,EAAE,CAAC"}
package/dist/utils/rpc.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getProgramAccounts = getProgramAccounts;
7
+ exports.getAccountOwner = getAccountOwner;
7
8
  const web3_js_1 = require("@solana/web3.js");
8
9
  const buffer_1 = require("buffer");
9
10
  const axios_1 = __importDefault(require("axios"));
@@ -57,6 +58,13 @@ async function getProgramAccounts(connection, programId, configOrCommitment) {
57
58
  const x = await Promise.all(deser);
58
59
  return x;
59
60
  }
61
+ async function getAccountOwner(connection, address) {
62
+ const acc = await connection.getAccountInfo(address);
63
+ if (acc == null) {
64
+ throw Error(`Could not fetch mint ${address.toString()}`);
65
+ }
66
+ return acc.owner;
67
+ }
60
68
  async function deserializeAccountInfo(accountInfo) {
61
69
  const data = (0, zstd_wasm_1.decompress)(buffer_1.Buffer.from(accountInfo.data[0], 'base64'));
62
70
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/utils/rpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/utils/rpc.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamino-finance/klend-sdk",
3
- "version": "5.1.2",
3
+ "version": "5.1.4",
4
4
  "description": "Typescript SDK for interacting with the Kamino Lending (klend) protocol",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  AccountInfo,
3
3
  Connection,
4
+ GetProgramAccountsResponse,
4
5
  Keypair,
5
6
  ParsedAccountData,
6
7
  PublicKey,
@@ -430,17 +431,20 @@ export class KaminoManager {
430
431
 
431
432
  /**
432
433
  * Get all vaults
434
+ * @param useOptimisedRPCCall - if set to true, it will use the optimized getProgramAccounts RPC call, which is more efficient but doesn't work in web environments
433
435
  * @returns an array of all vaults
434
436
  */
435
- async getAllVaults(): Promise<KaminoVault[]> {
436
- return this._vaultClient.getAllVaults();
437
+ async getAllVaults(useOptimisedRPCCall: boolean = true): Promise<KaminoVault[]> {
438
+ return this._vaultClient.getAllVaults(useOptimisedRPCCall);
437
439
  }
438
440
 
439
441
  /**
440
442
  * Get all vaults for owner
443
+ * @param owner the pubkey of the vaults owner
444
+ * @param useOptimisedRPCCall - if set to true, it will use the optimized getProgramAccounts RPC call, which is more efficient but doesn't work in web environments
441
445
  * @returns an array of all vaults owned by a given pubkey
442
446
  */
443
- async getAllVaultsForOwner(owner: PublicKey): Promise<KaminoVault[]> {
447
+ async getAllVaultsForOwner(owner: PublicKey, useOptimisedRPCCall: boolean = true): Promise<KaminoVault[]> {
444
448
  const filters = [
445
449
  {
446
450
  dataSize: VaultState.layout.span + 8,
@@ -459,12 +463,16 @@ export class KaminoManager {
459
463
  },
460
464
  ];
461
465
 
462
- const [kaminoVaults] = await Promise.all([
463
- getProgramAccounts(this._connection, this._kaminoVaultProgramId, {
466
+ let kaminoVaults: GetProgramAccountsResponse = [];
467
+
468
+ if (useOptimisedRPCCall) {
469
+ kaminoVaults = await getProgramAccounts(this._connection, this._kaminoVaultProgramId, {
464
470
  commitment: this._connection.commitment ?? 'processed',
465
471
  filters,
466
- }),
467
- ]);
472
+ });
473
+ } else {
474
+ kaminoVaults = await this._connection.getProgramAccounts(this._kaminoVaultProgramId, { filters });
475
+ }
468
476
 
469
477
  return kaminoVaults.map((kaminoVault) => {
470
478
  if (kaminoVault.account === null) {
@@ -1,4 +1,4 @@
1
- import { AccountInfo, Connection, PublicKey } from '@solana/web3.js';
1
+ import { AccountInfo, Connection, GetProgramAccountsResponse, PublicKey } from '@solana/web3.js';
2
2
  import { KaminoObligation } from './obligation';
3
3
  import { KaminoReserve } from './reserve';
4
4
  import { LendingMarket, Obligation, UserMetadata, ReferrerTokenState, Reserve } from '../idl_codegen/accounts';
@@ -531,8 +531,9 @@ export class KaminoMarket {
531
531
  * This function will likely require an RPC capable of returning more than the default 100k rows in a single scan
532
532
  *
533
533
  * @param tag
534
+ * @param useOptimisedRPCCall - use the optimised RPC call (compressed) to get all obligations
534
535
  */
535
- async getAllObligationsForMarket(tag?: number): Promise<KaminoObligation[]> {
536
+ async getAllObligationsForMarket(tag?: number, useOptimisedRPCCall: boolean = true): Promise<KaminoObligation[]> {
536
537
  const filters = [
537
538
  {
538
539
  dataSize: Obligation.layout.span + 8,
@@ -557,14 +558,26 @@ export class KaminoMarket {
557
558
  const collateralExchangeRates = new PubkeyHashMap<PublicKey, Decimal>();
558
559
  const cumulativeBorrowRates = new PubkeyHashMap<PublicKey, Decimal>();
559
560
 
560
- const [slot, obligations] = await Promise.all([
561
- this.connection.getSlot(),
562
- getProgramAccounts(this.connection, this.programId, {
563
- commitment: this.connection.commitment ?? 'processed',
561
+ let obligations: GetProgramAccountsResponse = [];
562
+ let slot = 0;
563
+ const slotPromise = this.connection.getSlot();
564
+
565
+ if (useOptimisedRPCCall) {
566
+ [slot, obligations] = await Promise.all([
567
+ slotPromise,
568
+ getProgramAccounts(this.connection, this.programId, {
569
+ commitment: this.connection.commitment ?? 'processed',
570
+ filters,
571
+ dataSlice: { offset: 0, length: ObligationZP.layout.span + 8 }, // truncate the padding
572
+ }),
573
+ ]);
574
+ } else {
575
+ const obligationsPromise = this.connection.getProgramAccounts(this.programId, {
564
576
  filters,
565
577
  dataSlice: { offset: 0, length: ObligationZP.layout.span + 8 }, // truncate the padding
566
- }),
567
- ]);
578
+ });
579
+ [slot, obligations] = await Promise.all([slotPromise, obligationsPromise]);
580
+ }
568
581
 
569
582
  return obligations.map((obligation) => {
570
583
  if (obligation.account === null) {
@@ -2,11 +2,12 @@ import { BN } from '@coral-xyz/anchor';
2
2
  import {
3
3
  AccountMeta,
4
4
  Connection,
5
+ GetProgramAccountsResponse,
5
6
  Keypair,
6
7
  PublicKey,
8
+ SystemProgram,
7
9
  SYSVAR_INSTRUCTIONS_PUBKEY,
8
10
  SYSVAR_RENT_PUBKEY,
9
- SystemProgram,
10
11
  TransactionInstruction,
11
12
  } from '@solana/web3.js';
12
13
  import { TOKEN_PROGRAM_ID, unpackAccount } from '@solana/spl-token';
@@ -23,8 +24,6 @@ import {
23
24
  WRAPPED_SOL_MINT,
24
25
  } from '../lib';
25
26
  import {
26
- // closeVault,
27
- // CloseVaultAccounts,
28
27
  DepositAccounts,
29
28
  DepositArgs,
30
29
  giveUpPendingFees,
@@ -51,12 +50,12 @@ import { VaultConfigFieldKind } from '../idl_codegen_kamino_vault/types';
51
50
  import { VaultState } from '../idl_codegen_kamino_vault/accounts';
52
51
  import Decimal from 'decimal.js';
53
52
  import { numberToLamportsDecimal, parseTokenSymbol } from './utils';
54
- import { deposit } from '../idl_codegen_kamino_vault/instructions/deposit';
55
- import { withdraw } from '../idl_codegen_kamino_vault/instructions/withdraw';
53
+ import { deposit } from '../idl_codegen_kamino_vault/instructions';
54
+ import { withdraw } from '../idl_codegen_kamino_vault/instructions';
56
55
  import { PROGRAM_ID } from '../idl_codegen/programId';
57
56
  import { DEFAULT_RECENT_SLOT_DURATION_MS, ReserveWithAddress } from './reserve';
58
57
  import { Fraction } from './fraction';
59
- import { lendingMarketAuthPda } from '../utils/seeds';
58
+ import { lendingMarketAuthPda } from '../utils';
60
59
  import bs58 from 'bs58';
61
60
  import { getProgramAccounts } from '../utils/rpc';
62
61
 
@@ -390,7 +389,7 @@ export class KaminoVaultClient {
390
389
  * @param user - user to deposit
391
390
  * @param vault - vault to deposit into
392
391
  * @param tokenAmount - token amount to be deposited, in decimals (will be converted in lamports)
393
- * @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
392
+ * @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
394
393
  * @returns - an array of instructions to be used to be executed
395
394
  */
396
395
  async depositIxs(
@@ -574,7 +573,8 @@ export class KaminoVaultClient {
574
573
 
575
574
  /**
576
575
  * 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
577
- * @param kaminoVault - vault to invest from
576
+ * @param payer wallet that pays the tx
577
+ * @param vault - vault to invest from
578
578
  * @returns - an array of invest instructions for each invest action required for the vault reserves
579
579
  */
580
580
  async investAllReservesIxs(payer: PublicKey, vault: KaminoVault): Promise<TransactionInstruction[]> {
@@ -596,7 +596,8 @@ export class KaminoVaultClient {
596
596
 
597
597
  /**
598
598
  * 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
599
- * @param kaminoVault - vault to invest from
599
+ * @param payer wallet pubkey
600
+ * @param vault - vault to invest from
600
601
  * @param reserve - reserve to invest into or disinvest from
601
602
  * @returns - an array of invest instructions for each invest action required for the vault reserves
602
603
  */
@@ -783,8 +784,8 @@ export class KaminoVaultClient {
783
784
  }
784
785
  const userSharesAccount = unpackAccount(userSharesAta, userSharesAccountInfo);
785
786
 
786
- return new Decimal(new Decimal(userSharesAccount.amount.toString()).toNumber()).div(
787
- new Decimal(10).pow(vaultState.sharesMintDecimals.toNumber())
787
+ return new Decimal(userSharesAccount.amount.toString()).div(
788
+ new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
788
789
  );
789
790
  }
790
791
 
@@ -819,7 +820,7 @@ export class KaminoVaultClient {
819
820
  vaultUserShareBalance.set(
820
821
  vaults[index].address,
821
822
  new Decimal(userShareAtaAccount.lamports).div(
822
- new Decimal(10).pow(vaults[index].state!.sharesMintDecimals.toNumber())
823
+ new Decimal(10).pow(vaults[index].state!.sharesMintDecimals.toString())
823
824
  )
824
825
  );
825
826
  }
@@ -832,7 +833,7 @@ export class KaminoVaultClient {
832
833
  * 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
833
834
  * @param vault - vault to calculate tokensPerShare for
834
835
  * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
835
- * @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
836
+ * @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
836
837
  * @returns - token per share value
837
838
  */
838
839
  async getTokensPerShareSingleVault(
@@ -843,7 +844,7 @@ export class KaminoVaultClient {
843
844
  const vaultState = await vault.getState(this._connection);
844
845
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
845
846
 
846
- const totalVaultLiquidityAmount = new Decimal(vaultState.tokenAvailable.toString());
847
+ let totalVaultLiquidityAmount = new Decimal(vaultState.tokenAvailable.toString());
847
848
  vaultState.vaultAllocationStrategy.forEach((allocationStrategy) => {
848
849
  if (!allocationStrategy.reserve.equals(PublicKey.default)) {
849
850
  const reserve = vaultReservesState.get(allocationStrategy.reserve);
@@ -858,70 +859,51 @@ export class KaminoVaultClient {
858
859
  .floor()
859
860
  .toNumber()
860
861
  );
861
- const reserveAllocationLiquidityAmount = new Decimal(allocationStrategy.cTokenAllocation.toString()).div(
862
- reserveCollExchangeRate
863
- );
864
- totalVaultLiquidityAmount.add(reserveAllocationLiquidityAmount);
862
+ if (reserveCollExchangeRate.gt(0)) {
863
+ const reserveAllocationLiquidityAmount = new Decimal(allocationStrategy.cTokenAllocation.toString()).div(
864
+ reserveCollExchangeRate
865
+ );
866
+ totalVaultLiquidityAmount = totalVaultLiquidityAmount.add(reserveAllocationLiquidityAmount);
867
+ }
865
868
  }
866
869
  });
870
+ if (totalVaultLiquidityAmount.isZero()) {
871
+ return new Decimal(0);
872
+ }
867
873
 
868
874
  return new Decimal(vaultState.sharesIssued.toString()).div(totalVaultLiquidityAmount);
869
875
  }
870
876
 
871
877
  /**
872
878
  * 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
873
- * @param vault - vault to calculate tokensPerShare for
879
+ * @param vaultsOverride - a list of vaults to get the tokens per share for; if provided with state it will not fetch the state again
880
+ * @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
874
881
  * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
882
+ * @param useOptimisedRPCCall - if set to true, it will use the optimized getProgramAccounts RPC call, which is more efficient but doesn't work in web environments
875
883
  * @returns - token per share value
876
884
  */
877
885
  async getTokensPerShareAllVaults(
878
886
  slot: number,
879
- vaultsOverride?: Array<KaminoVault>
887
+ vaultsOverride?: Array<KaminoVault>,
888
+ vaultReservesMap?: PubkeyHashMap<PublicKey, KaminoReserve>,
889
+ useOptimisedRPCCall: boolean = true
880
890
  ): Promise<PubkeyHashMap<PublicKey, Decimal>> {
881
- const vaults = vaultsOverride ? vaultsOverride : await this.getAllVaults();
891
+ const vaults = vaultsOverride ? vaultsOverride : await this.getAllVaults(useOptimisedRPCCall);
882
892
  const vaultTokensPerShare = new PubkeyHashMap<PublicKey, Decimal>();
883
- vaults.forEach(async (vault) => {
884
- const vaultState = vault.state;
885
- if (!vaultState) {
886
- throw new Error(`Vault ${vault.address.toBase58()} not fetched`);
887
- }
888
- const reserves = await this.loadVaultReserves(vaultState);
889
-
890
- const totalVaultLiquidityAmount = new Decimal(vaultState.tokenAvailable.toString());
891
- vaultState.vaultAllocationStrategy.forEach((allocationStrategy) => {
892
- if (!allocationStrategy.reserve.equals(PublicKey.default)) {
893
- const reserve = reserves.get(allocationStrategy.reserve);
894
- if (reserve === undefined) {
895
- throw new Error(`Reserve ${allocationStrategy.reserve.toBase58()} not found`);
896
- }
897
- const reserveCollExchangeRate = reserve.getEstimatedCollateralExchangeRate(
898
- slot,
899
- new Fraction(reserve.state.liquidity.absoluteReferralRateSf)
900
- .toDecimal()
901
- .div(reserve.state.config.protocolTakeRatePct / 100)
902
- .floor()
903
- .toNumber()
904
- );
905
- const reserveAllocationLiquidityAmount = new Decimal(allocationStrategy.cTokenAllocation.toString()).div(
906
- reserveCollExchangeRate
907
- );
908
- totalVaultLiquidityAmount.add(reserveAllocationLiquidityAmount);
909
- }
910
- });
911
- vaultTokensPerShare.set(
912
- vault.address,
913
- new Decimal(vaultState.sharesIssued.toString()).div(totalVaultLiquidityAmount)
914
- );
915
- });
893
+ for (const vault of vaults) {
894
+ const tokensPerShare = await this.getTokensPerShareSingleVault(vault, slot, vaultReservesMap);
895
+ vaultTokensPerShare.set(vault.address, tokensPerShare);
896
+ }
916
897
 
917
898
  return vaultTokensPerShare;
918
899
  }
919
900
 
920
901
  /**
921
902
  * Get all vaults
903
+ * @param useOptimisedRPCCall - if set to true, it will use the optimized getProgramAccounts RPC call, which is more efficient but doesn't work in web environments
922
904
  * @returns an array of all vaults
923
905
  */
924
- async getAllVaults(): Promise<KaminoVault[]> {
906
+ async getAllVaults(useOptimisedRPCCall: boolean = true): Promise<KaminoVault[]> {
925
907
  const filters = [
926
908
  {
927
909
  dataSize: VaultState.layout.span + 8,
@@ -934,12 +916,16 @@ export class KaminoVaultClient {
934
916
  },
935
917
  ];
936
918
 
937
- const [kaminoVaults] = await Promise.all([
938
- getProgramAccounts(this._connection, this._kaminoVaultProgramId, {
919
+ let kaminoVaults: GetProgramAccountsResponse = [];
920
+
921
+ if (useOptimisedRPCCall) {
922
+ kaminoVaults = await getProgramAccounts(this._connection, this._kaminoVaultProgramId, {
939
923
  commitment: this._connection.commitment ?? 'processed',
940
924
  filters,
941
- }),
942
- ]);
925
+ });
926
+ } else {
927
+ kaminoVaults = await this._connection.getProgramAccounts(this._kaminoVaultProgramId, { filters });
928
+ }
943
929
 
944
930
  return kaminoVaults.map((kaminoVault) => {
945
931
  if (kaminoVault.account === null) {
@@ -997,7 +983,7 @@ export class KaminoVaultClient {
997
983
 
998
984
  /**
999
985
  * This will get the list of all reserve pubkeys that the vault has allocations for
1000
- * @param vaultState - the vault state to load reserves for
986
+ * @param vault - the vault state to load reserves for
1001
987
  * @returns a hashmap from each reserve pubkey to the reserve state
1002
988
  */
1003
989
  getAllVaultReserves(vault: VaultState): PublicKey[] {
@@ -1006,7 +992,7 @@ export class KaminoVaultClient {
1006
992
 
1007
993
  /**
1008
994
  * This will get the list of all reserve pubkeys that the vault has allocations for ex
1009
- * @param vaultState - the vault state to load reserves for
995
+ * @param vault - the vault state to load reserves for
1010
996
  * @returns a hashmap from each reserve pubkey to the reserve state
1011
997
  */
1012
998
  getVaultReserves(vault: VaultState): PublicKey[] {
@@ -1120,14 +1106,12 @@ export class KaminoVaultClient {
1120
1106
  holdings.investedInReserves.forEach((amount, reserve) => {
1121
1107
  investedInReservesUSD.set(reserve, amount.mul(price));
1122
1108
  });
1123
- const holdingsWithUSDValue: VaultHoldingsWithUSDValue = {
1109
+ return {
1124
1110
  holdings: holdings,
1125
1111
  availableUSD: holdings.available.mul(price),
1126
1112
  investedUSD: holdings.invested.mul(price),
1127
1113
  investedInReservesUSD: investedInReservesUSD,
1128
1114
  };
1129
-
1130
- return holdingsWithUSDValue;
1131
1115
  }
1132
1116
 
1133
1117
  /**
@@ -1200,7 +1184,9 @@ export class KaminoVaultClient {
1200
1184
  totalAPY = totalAPY.add(weightedAPY);
1201
1185
  totalWeights = totalWeights.add(weight);
1202
1186
  });
1203
-
1187
+ if (totalWeights.isZero()) {
1188
+ return new Decimal(0);
1189
+ }
1204
1190
  return totalAPY.div(totalWeights);
1205
1191
  }
1206
1192
  } // KaminoVaultClient
@@ -45,13 +45,13 @@ import Decimal from 'decimal.js';
45
45
  import { BN } from '@coral-xyz/anchor';
46
46
  import { PythConfiguration, SwitchboardConfiguration } from './idl_codegen_kamino_vault/types';
47
47
  import * as fs from 'fs';
48
- import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
49
48
  import { MarketWithAddress } from './utils/managerTypes';
50
49
  import {
51
50
  ManagementFeeBps,
52
51
  PendingVaultAdmin,
53
52
  PerformanceFeeBps,
54
53
  } from './idl_codegen_kamino_vault/types/VaultConfigField';
54
+ import { getAccountOwner } from './utils/rpc';
55
55
 
56
56
  dotenv.config({
57
57
  path: `.env${process.env.ENV ? '.' + process.env.ENV : ''}`,
@@ -237,10 +237,11 @@ async function main() {
237
237
  const multisigPk = multisig ? new PublicKey(multisig) : PublicKey.default;
238
238
  const kaminoManager = new KaminoManager(env.connection, env.kLendProgramId, env.kVaultProgramId);
239
239
 
240
+ const tokenProgramID = await getAccountOwner(env.connection, tokenMint);
240
241
  const kaminoVaultConfig = new KaminoVaultConfig({
241
242
  admin: mode === 'multisig' ? multisigPk : env.payer.publicKey,
242
243
  tokenMint: tokenMint,
243
- tokenMintProgramId: TOKEN_PROGRAM_ID,
244
+ tokenMintProgramId: tokenProgramID,
244
245
  performanceFeeRate: new Decimal(0.0),
245
246
  managementFeeRate: new Decimal(0.0),
246
247
  });
@@ -500,7 +501,7 @@ async function main() {
500
501
  const env = initializeClient(false, false);
501
502
  const kaminoManager = new KaminoManager(env.connection, env.kLendProgramId, env.kVaultProgramId);
502
503
 
503
- const allVaults = await kaminoManager.getAllVaults();
504
+ const allVaults = await kaminoManager.getAllVaults(true);
504
505
  console.log('all vaults', allVaults);
505
506
  });
506
507
 
package/src/utils/rpc.ts CHANGED
@@ -72,6 +72,14 @@ export async function getProgramAccounts(
72
72
  return x as GetProgramAccountsResponse;
73
73
  }
74
74
 
75
+ export async function getAccountOwner(connection: Connection, address: PublicKey): Promise<PublicKey> {
76
+ const acc = await connection.getAccountInfo(address);
77
+ if (acc == null) {
78
+ throw Error(`Could not fetch mint ${address.toString()}`);
79
+ }
80
+ return acc.owner;
81
+ }
82
+
75
83
  async function deserializeAccountInfo(accountInfo: AccountInfo<string[]>): Promise<AccountInfo<Buffer>> {
76
84
  const data = decompress(Buffer.from(accountInfo.data[0], 'base64'));
77
85
  return {