@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.
- package/dist/classes/manager.d.ts +5 -2
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +14 -7
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/market.d.ts +2 -1
- package/dist/classes/market.d.ts.map +1 -1
- package/dist/classes/market.js +20 -7
- package/dist/classes/market.js.map +1 -1
- package/dist/classes/vault.d.ts +14 -9
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +49 -53
- package/dist/classes/vault.js.map +1 -1
- package/dist/client_kamino_manager.d.ts.map +1 -1
- package/dist/client_kamino_manager.js +4 -3
- package/dist/client_kamino_manager.js.map +1 -1
- package/dist/utils/rpc.d.ts +1 -0
- package/dist/utils/rpc.d.ts.map +1 -1
- package/dist/utils/rpc.js +8 -0
- package/dist/utils/rpc.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/manager.ts +15 -7
- package/src/classes/market.ts +21 -8
- package/src/classes/vault.ts +51 -65
- package/src/client_kamino_manager.ts +4 -3
- package/src/utils/rpc.ts +8 -0
package/dist/utils/rpc.d.ts.map
CHANGED
|
@@ -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 {
|
package/dist/utils/rpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/utils/rpc.ts"],"names":[],"mappings":";;;;;AAyBA,gDA+CC;
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/utils/rpc.ts"],"names":[],"mappings":";;;;;AAyBA,gDA+CC;AAED,0CAMC;AAhFD,6CAQyB;AACzB,mCAAgC;AAChC,kDAA0B;AAC1B,kDAAsD;AACtD,+BAAoC;AAEpC,CAAC,KAAK,IAAI,EAAE;IACV,MAAM,IAAA,gBAAI,GAAE,CAAC;AACf,CAAC,CAAC,EAAE,CAAC;AAEL;;;;;;GAMG;AACI,KAAK,UAAU,kBAAkB,CACtC,UAAsB,EACtB,SAAoB,EACpB,kBAA0D;IAE1D,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;IAC1C,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,2BAA2B,CAAC,kBAAkB,CAAC,CAAC;IAC/E,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,qBAAqB,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IACvE,oHAAoH;IACpH,uDAAuD;IACvD,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAC/B,UAAU,CAAC,WAAW,EACtB;QACE,MAAM,EAAE,oBAAoB;QAC5B,OAAO,EAAE,KAAK;QACd,MAAM,EAAE;YACN,YAAY;YACZ;gBACE,QAAQ,EAAE,aAAa;gBACvB,UAAU;gBACV,GAAG,qBAAqB;aACzB;SACF;QACD,EAAE,EAAE,IAAA,SAAM,GAAE;KACb,EACD;QACE,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;YAClC,iBAAiB,EAAE,eAAe;YAClC,eAAe,EAAE,UAAU;SAC5B;KACF,CACF,CAAC;IAEF,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC;IAChC,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,4BAAkB,CAAC,SAAS,CAAC,KAAK,EAAE,4CAA4C,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC9G,CAAC;IAED,MAAM,GAAG,GAAG,SAAsB,CAAC;IACnC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QAC/C,OAAO,EAAE,MAAM,sBAAsB,CAAC,OAAO,CAAC,OAAO,CAAC;QACtD,MAAM,EAAE,IAAI,mBAAS,CAAC,OAAO,CAAC,MAAM,CAAC;KACtC,CAAC,CAAC,CAAC;IACJ,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO,CAA+B,CAAC;AACzC,CAAC;AAEM,KAAK,UAAU,eAAe,CAAC,UAAsB,EAAE,OAAkB;IAC9E,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,MAAM,KAAK,CAAC,wBAAwB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,WAAkC;IACtE,MAAM,IAAI,GAAG,IAAA,sBAAU,EAAC,eAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO;QACL,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,IAAI,EAAE,eAAM,CAAC,IAAI,CAAC,IAAI,CAAC;KACxB,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAClC,kBAAyE;IAEzE,IAAI,UAAkC,CAAC;IACvC,IAAI,MAA+C,CAAC;IACpD,IAAI,OAAO,kBAAkB,KAAK,QAAQ,EAAE,CAAC;QAC3C,UAAU,GAAG,kBAAkB,CAAC;IAClC,CAAC;SAAM,IAAI,kBAAkB,EAAE,CAAC;QAC9B,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,eAAe,EAAE,GAAG,kBAAkB,CAAC;QACnF,UAAU,GAAG,mBAAmB,CAAC;QACjC,MAAM,GAAG,eAAe,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC"}
|
package/package.json
CHANGED
package/src/classes/manager.ts
CHANGED
|
@@ -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
|
-
|
|
463
|
-
|
|
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) {
|
package/src/classes/market.ts
CHANGED
|
@@ -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
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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) {
|
package/src/classes/vault.ts
CHANGED
|
@@ -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
|
|
55
|
-
import { withdraw } from '../idl_codegen_kamino_vault/instructions
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
787
|
-
new Decimal(10).pow(vaultState.sharesMintDecimals.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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
|
|
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
|
-
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
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
|
-
|
|
938
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 {
|