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