@kamino-finance/klend-sdk 7.1.10 → 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.
- package/dist/classes/farm_utils.d.ts +8 -0
- package/dist/classes/farm_utils.d.ts.map +1 -1
- package/dist/classes/farm_utils.js +39 -0
- package/dist/classes/farm_utils.js.map +1 -1
- package/dist/classes/manager.d.ts +52 -5
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +68 -9
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/reserve.d.ts +1 -1
- package/dist/classes/reserve.js +1 -1
- package/dist/classes/vault.d.ts +156 -10
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +477 -71
- package/dist/classes/vault.js.map +1 -1
- package/dist/manager/client_kamino_manager.js +69 -43
- package/dist/manager/client_kamino_manager.js.map +1 -1
- package/dist/utils/farmUtils.d.ts +1 -1
- package/dist/utils/farmUtils.d.ts.map +1 -1
- package/dist/utils/farmUtils.js +1 -1
- package/dist/utils/farmUtils.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/farm_utils.ts +48 -0
- package/src/classes/manager.ts +100 -14
- package/src/classes/reserve.ts +1 -1
- package/src/classes/vault.ts +677 -74
- package/src/manager/client_kamino_manager.ts +103 -44
- package/src/utils/farmUtils.ts +0 -1
package/dist/classes/vault.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
735
|
-
const
|
|
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,
|
|
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,
|
|
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
|
|
@@ -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(
|
|
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,
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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 ?
|
|
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(
|
|
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
|
|
1842
|
-
const
|
|
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(
|
|
1846
|
-
const vaultActualAPYPromise = this.getVaultActualAPY(
|
|
1847
|
-
const totalInvestedAndBorrowedPromise = this.getTotalBorrowedAndInvested(
|
|
1848
|
-
const vaultCollateralsPromise = this.getVaultCollaterals(
|
|
1849
|
-
const reservesOverviewPromise = this.getVaultReservesDetails(
|
|
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(
|
|
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(
|
|
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(
|
|
2199
|
+
const vaultState = await vault.getState();
|
|
2142
2200
|
vaultsTokenMints.add(vaultState.tokenMint);
|
|
2143
|
-
const hasFarm = await vault.hasFarm(
|
|
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(
|
|
2277
|
+
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
|
|
2220
2278
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
2221
|
-
const currentSlot = slot
|
|
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,
|
|
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
|
-
|
|
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(
|
|
2571
|
+
async getState() {
|
|
2283
2572
|
if (!this.state) {
|
|
2284
|
-
const res = await accounts_1.VaultState.fetch(
|
|
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
|
|
2296
|
-
this.
|
|
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(
|
|
2303
|
-
const state = await this.getState(
|
|
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
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
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
|