@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/dist/classes/vault.js
CHANGED
|
@@ -24,6 +24,9 @@ const bs58_1 = __importDefault(require("bs58"));
|
|
|
24
24
|
const rpc_1 = require("../utils/rpc");
|
|
25
25
|
const kliquidity_sdk_1 = require("@kamino-finance/kliquidity-sdk");
|
|
26
26
|
const CreationParameters_1 = require("@kamino-finance/kliquidity-sdk/dist/utils/CreationParameters");
|
|
27
|
+
const dist_1 = require("@kamino-finance/farms-sdk/dist");
|
|
28
|
+
const lut_utils_1 = require("./lut_utils");
|
|
29
|
+
const farm_utils_1 = require("./farm_utils");
|
|
27
30
|
exports.kaminoVaultId = new web3_js_1.PublicKey('kvauTFR8qm1dhniz6pYuBZkuene3Hfrs1VQhVRgCNrr');
|
|
28
31
|
exports.kaminoVaultStagingId = new web3_js_1.PublicKey('STkvh7ostar39Fwr4uZKASs1RNNuYMFMTsE77FiRsL2');
|
|
29
32
|
const TOKEN_VAULT_SEED = 'token_vault';
|
|
@@ -50,10 +53,12 @@ class KaminoVaultClient {
|
|
|
50
53
|
getProgramID() {
|
|
51
54
|
return this._kaminoVaultProgramId;
|
|
52
55
|
}
|
|
56
|
+
hasFarm() {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
53
59
|
/**
|
|
54
60
|
* 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
|
|
55
61
|
* @param vaultConfig - the config object used to create a vault
|
|
56
|
-
* @returns vault - keypair, should be used to sign the transaction which creates the vault account
|
|
57
62
|
* @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
|
|
58
63
|
*/
|
|
59
64
|
async createVaultIxs(vaultConfig) {
|
|
@@ -62,7 +67,7 @@ class KaminoVaultClient {
|
|
|
62
67
|
const createVaultIx = web3_js_1.SystemProgram.createAccount({
|
|
63
68
|
fromPubkey: vaultConfig.admin,
|
|
64
69
|
newAccountPubkey: vaultState.publicKey,
|
|
65
|
-
lamports: await this.
|
|
70
|
+
lamports: await this.getConnection().getMinimumBalanceForRentExemption(size),
|
|
66
71
|
space: size,
|
|
67
72
|
programId: this._kaminoVaultProgramId,
|
|
68
73
|
});
|
|
@@ -83,8 +88,8 @@ class KaminoVaultClient {
|
|
|
83
88
|
};
|
|
84
89
|
const initVaultIx = (0, instructions_1.initVault)(initVaultAccounts, this._kaminoVaultProgramId);
|
|
85
90
|
// create and set up the vault lookup table
|
|
86
|
-
const slot = await this.
|
|
87
|
-
const [createLUTIx, lut] =
|
|
91
|
+
const slot = await this.getConnection().getSlot();
|
|
92
|
+
const [createLUTIx, lut] = (0, lut_utils_1.initLookupTableIx)(vaultConfig.admin, slot);
|
|
88
93
|
const accountsToBeInserted = [
|
|
89
94
|
vaultConfig.admin,
|
|
90
95
|
vaultState.publicKey,
|
|
@@ -119,7 +124,7 @@ class KaminoVaultClient {
|
|
|
119
124
|
* 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.
|
|
120
125
|
* @param vault - vault to be updated
|
|
121
126
|
* @param reserveAllocationConfig - new reserve allocation config
|
|
122
|
-
* @returns - a list of instructions
|
|
127
|
+
* @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
|
|
123
128
|
*/
|
|
124
129
|
async updateReserveAllocationIxs(vault, reserveAllocationConfig) {
|
|
125
130
|
const vaultState = await vault.getState(this.getConnection());
|
|
@@ -208,23 +213,48 @@ class KaminoVaultClient {
|
|
|
208
213
|
updateVaultConfigIx.keys = updateVaultConfigIx.keys.concat(vaultReservesAccountMetas);
|
|
209
214
|
updateVaultConfigIx.keys = updateVaultConfigIx.keys.concat(vaultReservesLendingMarkets);
|
|
210
215
|
const updateLUTIxs = [];
|
|
211
|
-
if (mode.kind === new types_1.VaultConfigField.PendingVaultAdmin().kind
|
|
216
|
+
if (mode.kind === new types_1.VaultConfigField.PendingVaultAdmin().kind) {
|
|
212
217
|
const newPubkey = new web3_js_1.PublicKey(value);
|
|
213
218
|
const insertIntoLutIxs = await this.insertIntoLookupTableIxs(vaultState.adminAuthority, vaultState.vaultLookupTable, [newPubkey]);
|
|
214
219
|
updateLUTIxs.push(...insertIntoLutIxs);
|
|
215
220
|
}
|
|
221
|
+
else if (mode.kind === new types_1.VaultConfigField.Farm().kind) {
|
|
222
|
+
const keysToAddToLUT = [new web3_js_1.PublicKey(value)];
|
|
223
|
+
// if the farm already exist we want to read its state to add it to the LUT
|
|
224
|
+
try {
|
|
225
|
+
const farmState = await dist_1.FarmState.fetch(this.getConnection(), keysToAddToLUT[0]);
|
|
226
|
+
keysToAddToLUT.push(farmState.farmVault, farmState.farmVaultsAuthority, farmState.token.mint, farmState.scopePrices, farmState.globalConfig);
|
|
227
|
+
const insertIntoLutIxs = await this.insertIntoLookupTableIxs(vaultState.adminAuthority, vaultState.vaultLookupTable, keysToAddToLUT);
|
|
228
|
+
updateLUTIxs.push(...insertIntoLutIxs);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
console.log(`Error fetching farm ${keysToAddToLUT[0].toString()} state`, error);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
216
234
|
const updateVaultConfigIxs = {
|
|
217
235
|
updateVaultConfigIx,
|
|
218
236
|
updateLUTIxs,
|
|
219
237
|
};
|
|
220
238
|
return updateVaultConfigIxs;
|
|
221
239
|
}
|
|
240
|
+
/** 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
|
|
241
|
+
* @param vault - vault to set the farm for
|
|
242
|
+
* @param farm - the farm where the vault shares can be staked
|
|
243
|
+
* @param [errorOnOverride] - if true, the function will throw an error if the vault already has a farm. If false, it will override the farm
|
|
244
|
+
*/
|
|
245
|
+
async setVaultFarm(vault, farm, errorOnOverride = true) {
|
|
246
|
+
const vaultHasFarm = await vault.hasFarm(this.getConnection());
|
|
247
|
+
if (vaultHasFarm && errorOnOverride) {
|
|
248
|
+
throw new Error('Vault already has a farm, if you want to override it set errorOnOverride to false');
|
|
249
|
+
}
|
|
250
|
+
return this.updateVaultConfigIxs(vault, new types_1.VaultConfigField.Farm(), farm.toBase58());
|
|
251
|
+
}
|
|
222
252
|
/**
|
|
223
253
|
* This method updates the vault config for a vault that
|
|
224
254
|
* @param vault - address of vault to be updated
|
|
225
255
|
* @param mode - the field to be updated
|
|
226
256
|
* @param value - the new value for the field to be updated (number or pubkey)
|
|
227
|
-
* @returns -
|
|
257
|
+
* @returns - an instruction to update the vault config
|
|
228
258
|
*/
|
|
229
259
|
updateUninitialisedVaultConfigIx(admin, vault, mode, value) {
|
|
230
260
|
const updateVaultConfigAccs = {
|
|
@@ -257,7 +287,7 @@ class KaminoVaultClient {
|
|
|
257
287
|
/**
|
|
258
288
|
* 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)
|
|
259
289
|
* @param vault - vault to change the ownership for
|
|
260
|
-
* @returns - an instruction to
|
|
290
|
+
* @returns - an instruction to accept the ownership of the vault and a list of instructions to update the lookup table
|
|
261
291
|
*/
|
|
262
292
|
async acceptVaultOwnershipIxs(vault) {
|
|
263
293
|
const vaultState = await vault.getState(this.getConnection());
|
|
@@ -267,9 +297,9 @@ class KaminoVaultClient {
|
|
|
267
297
|
};
|
|
268
298
|
const acceptVaultOwnershipIx = (0, instructions_1.updateAdmin)(acceptOwneshipAccounts, this._kaminoVaultProgramId);
|
|
269
299
|
// read the current LUT and create a new one for the new admin and backfill it
|
|
270
|
-
const accountsInExistentLUT = (await
|
|
300
|
+
const accountsInExistentLUT = (await (0, lut_utils_1.getAccountsInLUT)(this.getConnection(), vaultState.vaultLookupTable)).filter((account) => !account.equals(vaultState.adminAuthority));
|
|
271
301
|
const LUTIxs = [];
|
|
272
|
-
const [initNewLUTIx, newLUT] =
|
|
302
|
+
const [initNewLUTIx, newLUT] = (0, lut_utils_1.initLookupTableIx)(vaultState.pendingAdmin, await this.getConnection().getSlot());
|
|
273
303
|
LUTIxs.push(initNewLUTIx);
|
|
274
304
|
const insertIntoLUTIxs = await this.insertIntoLookupTableIxs(vaultState.pendingAdmin, newLUT, accountsInExistentLUT);
|
|
275
305
|
LUTIxs.push(...insertIntoLUTIxs);
|
|
@@ -286,7 +316,7 @@ class KaminoVaultClient {
|
|
|
286
316
|
* 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)
|
|
287
317
|
* @param vault - vault to give up pending fees for
|
|
288
318
|
* @param maxAmountToGiveUp - the maximum amount of fees to give up, in tokens
|
|
289
|
-
* @returns - an instruction to
|
|
319
|
+
* @returns - an instruction to give up the specified pending fees
|
|
290
320
|
*/
|
|
291
321
|
async giveUpPendingFeesIx(vault, maxAmountToGiveUp) {
|
|
292
322
|
const vaultState = await vault.getState(this.getConnection());
|
|
@@ -305,7 +335,8 @@ class KaminoVaultClient {
|
|
|
305
335
|
* This method withdraws all the pending fees from the vault to the owner's token ATA
|
|
306
336
|
* @param vault - vault for which the admin withdraws the pending fees
|
|
307
337
|
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
308
|
-
* @
|
|
338
|
+
* @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
|
|
339
|
+
* @returns - list of instructions to withdraw all pending fees, including the ATA creation instructions if needed
|
|
309
340
|
*/
|
|
310
341
|
async withdrawPendingFeesIxs(vault, slot, vaultReservesMap) {
|
|
311
342
|
const vaultState = await vault.getState(this.getConnection());
|
|
@@ -336,7 +367,7 @@ class KaminoVaultClient {
|
|
|
336
367
|
}
|
|
337
368
|
});
|
|
338
369
|
}
|
|
339
|
-
const reserveStates = await lib_1.Reserve.fetchMultiple(this.
|
|
370
|
+
const reserveStates = await lib_1.Reserve.fetchMultiple(this.getConnection(), reservesToWithdraw, this._kaminoLendProgramId);
|
|
340
371
|
const withdrawIxns = await Promise.all(reservesToWithdraw.map(async (reserve, index) => {
|
|
341
372
|
if (reserveStates[index] === null) {
|
|
342
373
|
throw new Error(`Reserve ${reserve.toBase58()} not found`);
|
|
@@ -358,13 +389,14 @@ class KaminoVaultClient {
|
|
|
358
389
|
/**
|
|
359
390
|
* 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
|
|
360
391
|
* @param user - user to deposit
|
|
361
|
-
* @param vault - vault to deposit into
|
|
392
|
+
* @param vault - vault to deposit into (if the state is not provided, it will be fetched)
|
|
362
393
|
* @param tokenAmount - token amount to be deposited, in decimals (will be converted in lamports)
|
|
363
|
-
* @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
|
|
364
|
-
* @
|
|
394
|
+
* @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
|
|
395
|
+
* @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
|
|
396
|
+
* @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
|
|
365
397
|
*/
|
|
366
|
-
async depositIxs(user, vault, tokenAmount, vaultReservesMap) {
|
|
367
|
-
const vaultState = await vault.getState(this.
|
|
398
|
+
async depositIxs(user, vault, tokenAmount, vaultReservesMap, farmState) {
|
|
399
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
368
400
|
const tokenProgramID = vaultState.tokenProgram;
|
|
369
401
|
const userTokenAta = (0, lib_1.getAssociatedTokenAddress)(vaultState.tokenMint, user, true, tokenProgramID);
|
|
370
402
|
const createAtasIxns = [];
|
|
@@ -423,30 +455,78 @@ class KaminoVaultClient {
|
|
|
423
455
|
});
|
|
424
456
|
depositIx.keys = depositIx.keys.concat(vaultReservesAccountMetas);
|
|
425
457
|
depositIx.keys = depositIx.keys.concat(vaultReservesLendingMarkets);
|
|
426
|
-
|
|
458
|
+
const depositIxs = {
|
|
459
|
+
depositIxs: [...createAtasIxns, depositIx, ...closeAtasIxns],
|
|
460
|
+
stakeInFarmIfNeededIxs: [],
|
|
461
|
+
};
|
|
462
|
+
// if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
|
|
463
|
+
if (!(await vault.hasFarm(this.getConnection()))) {
|
|
464
|
+
return depositIxs;
|
|
465
|
+
}
|
|
466
|
+
// if there is a farm, stake the shares
|
|
467
|
+
const stakeSharesIxs = await this.stakeSharesIxs(user, vault, undefined, farmState);
|
|
468
|
+
depositIxs.stakeInFarmIfNeededIxs = stakeSharesIxs;
|
|
469
|
+
return depositIxs;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* This function creates instructions to stake the shares in the vault farm if the vault has a farm
|
|
473
|
+
* @param user - user to stake
|
|
474
|
+
* @param vault - vault to deposit into its farm (if the state is not provided, it will be fetched)
|
|
475
|
+
* @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
|
|
476
|
+
* @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
|
|
477
|
+
* @returns - a list of instructions for the user to stake shares into the vault's farm, including the creation of prerequisite accounts if needed
|
|
478
|
+
*/
|
|
479
|
+
async stakeSharesIxs(user, vault, sharesAmount, farmState) {
|
|
480
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
481
|
+
let sharesToStakeLamports = new decimal_js_1.default(utils_2.U64_MAX);
|
|
482
|
+
if (sharesAmount) {
|
|
483
|
+
sharesToStakeLamports = (0, utils_1.numberToLamportsDecimal)(sharesAmount, vaultState.sharesMintDecimals.toNumber());
|
|
484
|
+
}
|
|
485
|
+
// if tokens to be staked are 0 or vault has no farm there is no stake needed
|
|
486
|
+
if (sharesToStakeLamports.lte(0) || !vault.hasFarm(this.getConnection())) {
|
|
487
|
+
return [];
|
|
488
|
+
}
|
|
489
|
+
// returns the ix to create the farm state account if needed and the ix to stake the shares
|
|
490
|
+
return (0, farm_utils_1.getFarmStakeIxs)(this.getConnection(), user, sharesToStakeLamports, vaultState.vaultFarm, farmState);
|
|
427
491
|
}
|
|
428
492
|
/**
|
|
429
|
-
* 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
|
|
493
|
+
* 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
|
|
430
494
|
* @param user - user to withdraw
|
|
431
495
|
* @param vault - vault to withdraw from
|
|
432
496
|
* @param shareAmount - share amount to withdraw, in order to withdraw everything, any value > user share amount
|
|
433
497
|
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
434
|
-
* @
|
|
498
|
+
* @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
|
|
499
|
+
* @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
|
|
500
|
+
* @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
|
|
435
501
|
*/
|
|
436
|
-
async withdrawIxs(user, vault, shareAmount, slot, vaultReservesMap) {
|
|
437
|
-
const vaultState = await vault.getState(this.
|
|
502
|
+
async withdrawIxs(user, vault, shareAmount, slot, vaultReservesMap, farmState) {
|
|
503
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
438
504
|
const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
|
|
505
|
+
const withdrawIxs = {
|
|
506
|
+
unstakeFromFarmIfNeededIxs: [],
|
|
507
|
+
withdrawIxs: [],
|
|
508
|
+
};
|
|
509
|
+
const shareLamportsToWithdraw = (0, kliquidity_sdk_1.collToLamportsDecimal)(shareAmount, vaultState.sharesMintDecimals.toNumber());
|
|
510
|
+
const hasFarm = await vault.hasFarm(this.getConnection());
|
|
511
|
+
if (hasFarm) {
|
|
512
|
+
const unstakeAndWithdrawFromFarmIxs = await (0, farm_utils_1.getFarmUnstakeAndWithdrawIxs)(this.getConnection(), user, shareLamportsToWithdraw, vaultState.vaultFarm, farmState);
|
|
513
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.unstakeIx);
|
|
514
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.withdrawIx);
|
|
515
|
+
}
|
|
439
516
|
// if the vault has allocations withdraw otherwise wtihdraw from available ix
|
|
440
517
|
const vaultAllocation = vaultState.vaultAllocationStrategy.find((allocation) => allocation.reserve.equals(web3_js_1.PublicKey.default));
|
|
441
518
|
if (vaultAllocation) {
|
|
442
|
-
|
|
519
|
+
const withdrawFromVaultIxs = await this.wihdrdrawWithReserveIxns(user, kaminoVault, shareAmount, slot, vaultReservesMap);
|
|
520
|
+
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
443
521
|
}
|
|
444
522
|
else {
|
|
445
|
-
|
|
523
|
+
const withdrawFromVaultIxs = await this.withdrawFromAvailableIxns(user, kaminoVault, shareAmount);
|
|
524
|
+
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
446
525
|
}
|
|
526
|
+
return withdrawIxs;
|
|
447
527
|
}
|
|
448
528
|
async withdrawFromAvailableIxns(user, vault, shareAmount) {
|
|
449
|
-
const vaultState = await vault.getState(this.
|
|
529
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
450
530
|
const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
|
|
451
531
|
const userSharesAta = (0, lib_1.getAssociatedTokenAddress)(vaultState.sharesMint, user);
|
|
452
532
|
const [{ ata: userTokenAta, createAtaIx }] = (0, utils_2.createAtasIdempotent)(user, [
|
|
@@ -460,7 +540,7 @@ class KaminoVaultClient {
|
|
|
460
540
|
return [createAtaIx, withdrawFromAvailableIxn];
|
|
461
541
|
}
|
|
462
542
|
async wihdrdrawWithReserveIxns(user, vault, shareAmount, slot, vaultReservesMap) {
|
|
463
|
-
const vaultState = await vault.getState(this.
|
|
543
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
464
544
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
465
545
|
const userSharesAta = (0, lib_1.getAssociatedTokenAddress)(vaultState.sharesMint, user);
|
|
466
546
|
const [{ ata: userTokenAta, createAtaIx }] = (0, utils_2.createAtasIdempotent)(user, [
|
|
@@ -508,7 +588,6 @@ class KaminoVaultClient {
|
|
|
508
588
|
}
|
|
509
589
|
const withdrawIxns = [];
|
|
510
590
|
withdrawIxns.push(createAtaIx);
|
|
511
|
-
// let sharesLeftToWithdraw = shareAmount;
|
|
512
591
|
for (let reserveIndex = 0; reserveIndex < reserveWithSharesAmountToWithdraw.length; reserveIndex++) {
|
|
513
592
|
const reserveWithTokens = reserveWithSharesAmountToWithdraw[reserveIndex];
|
|
514
593
|
const reserveState = vaultReservesState.get(reserveWithTokens.reserve);
|
|
@@ -527,6 +606,7 @@ class KaminoVaultClient {
|
|
|
527
606
|
}
|
|
528
607
|
return withdrawIxns;
|
|
529
608
|
}
|
|
609
|
+
// todo: make sure we also check the ata of the investor for the vault token exists
|
|
530
610
|
/**
|
|
531
611
|
* 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
|
|
532
612
|
* @param payer wallet that pays the tx
|
|
@@ -535,11 +615,11 @@ class KaminoVaultClient {
|
|
|
535
615
|
*/
|
|
536
616
|
async investAllReservesIxs(payer, vault) {
|
|
537
617
|
//TODO: Order invest ixns by - invest that removes first, then invest that adds
|
|
538
|
-
const vaultState = await vault.getState(this.
|
|
618
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
539
619
|
const vaultReserves = this.getVaultReserves(vaultState);
|
|
540
620
|
const investIxnsPromises = [];
|
|
541
621
|
for (const reserve of vaultReserves) {
|
|
542
|
-
const reserveState = await lib_1.Reserve.fetch(this.
|
|
622
|
+
const reserveState = await lib_1.Reserve.fetch(this.getConnection(), reserve, this._kaminoLendProgramId);
|
|
543
623
|
if (reserveState === null) {
|
|
544
624
|
throw new Error(`Reserve ${reserve.toBase58()} not found`);
|
|
545
625
|
}
|
|
@@ -549,18 +629,20 @@ class KaminoVaultClient {
|
|
|
549
629
|
const investIxns = await Promise.all(investIxnsPromises).then((ixns) => ixns.flat());
|
|
550
630
|
return investIxns;
|
|
551
631
|
}
|
|
632
|
+
// todo: make sure we also check the ata of the investor for the vault token exists
|
|
552
633
|
/**
|
|
553
634
|
* 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
|
|
554
635
|
* @param payer wallet pubkey
|
|
555
636
|
* @param vault - vault to invest from
|
|
556
637
|
* @param reserve - reserve to invest into or disinvest from
|
|
638
|
+
* @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
|
|
557
639
|
* @returns - an array of invest instructions for each invest action required for the vault reserves
|
|
558
640
|
*/
|
|
559
641
|
async investSingleReserveIxs(payer, vault, reserve, vaultReservesMap) {
|
|
560
|
-
const vaultState = await vault.getState(this.
|
|
642
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
561
643
|
const cTokenVault = getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId);
|
|
562
644
|
const lendingMarketAuth = (0, utils_2.lendingMarketAuthPda)(reserve.state.lendingMarket, this._kaminoLendProgramId)[0];
|
|
563
|
-
const tokenProgram = await (0, rpc_1.getAccountOwner)(this.
|
|
645
|
+
const tokenProgram = await (0, rpc_1.getAccountOwner)(this.getConnection(), vaultState.tokenMint);
|
|
564
646
|
const [{ ata: payerTokenAta, createAtaIx }] = (0, utils_2.createAtasIdempotent)(payer, [
|
|
565
647
|
{ mint: vaultState.tokenMint, tokenProgram },
|
|
566
648
|
]);
|
|
@@ -604,12 +686,14 @@ class KaminoVaultClient {
|
|
|
604
686
|
investIx.keys = investIx.keys.concat(vaultReservesLendingMarkets);
|
|
605
687
|
return [createAtaIx, investIx];
|
|
606
688
|
}
|
|
689
|
+
/** Convert a string to a u8 representation to be stored on chain */
|
|
607
690
|
encodeVaultName(token) {
|
|
608
691
|
const maxArray = new Uint8Array(40);
|
|
609
692
|
const s = new TextEncoder().encode(token);
|
|
610
693
|
maxArray.set(s);
|
|
611
694
|
return maxArray;
|
|
612
695
|
}
|
|
696
|
+
/**Convert an u8 array to a string */
|
|
613
697
|
decodeVaultName(token) {
|
|
614
698
|
const maxArray = new Uint8Array(token);
|
|
615
699
|
let s = new TextDecoder().decode(maxArray);
|
|
@@ -733,10 +817,11 @@ class KaminoVaultClient {
|
|
|
733
817
|
* Sync a vault for lookup table; create and set the LUT for the vault if needed and fill it with all the needed accounts
|
|
734
818
|
* @param vault the vault to sync and set the LUT for if needed
|
|
735
819
|
* @param vaultReserves optional; the state of the reserves in the vault allocation
|
|
820
|
+
* @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
|
|
736
821
|
* @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
|
|
737
822
|
*/
|
|
738
|
-
async
|
|
739
|
-
const vaultState = await vault.getState(this.
|
|
823
|
+
async syncVaultLookupTableIxs(vault, vaultReservesMap) {
|
|
824
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
740
825
|
const allAccountsToBeInserted = [
|
|
741
826
|
vault.address,
|
|
742
827
|
vaultState.adminAuthority,
|
|
@@ -751,8 +836,8 @@ class KaminoVaultClient {
|
|
|
751
836
|
allAccountsToBeInserted.push(allocation.reserve);
|
|
752
837
|
allAccountsToBeInserted.push(allocation.ctokenVault);
|
|
753
838
|
});
|
|
754
|
-
if (
|
|
755
|
-
|
|
839
|
+
if (vaultReservesMap) {
|
|
840
|
+
vaultReservesMap.forEach((reserve) => {
|
|
756
841
|
allAccountsToBeInserted.push(reserve.state.lendingMarket);
|
|
757
842
|
allAccountsToBeInserted.push(reserve.state.farmCollateral);
|
|
758
843
|
allAccountsToBeInserted.push(reserve.state.farmDebt);
|
|
@@ -780,8 +865,8 @@ class KaminoVaultClient {
|
|
|
780
865
|
const setupLUTIfNeededIxs = [];
|
|
781
866
|
let lut = vaultState.vaultLookupTable;
|
|
782
867
|
if (lut.equals(web3_js_1.PublicKey.default)) {
|
|
783
|
-
const recentSlot = await this.
|
|
784
|
-
const [ixn, address] =
|
|
868
|
+
const recentSlot = await this.getConnection().getSlot();
|
|
869
|
+
const [ixn, address] = (0, lut_utils_1.initLookupTableIx)(vaultState.adminAuthority, recentSlot);
|
|
785
870
|
setupLUTIfNeededIxs.push(ixn);
|
|
786
871
|
lut = address;
|
|
787
872
|
// set the new LUT for the vault
|
|
@@ -799,14 +884,6 @@ class KaminoVaultClient {
|
|
|
799
884
|
syncLUTIxs: ixns,
|
|
800
885
|
};
|
|
801
886
|
}
|
|
802
|
-
getInitLookupTableIx(payer, slot) {
|
|
803
|
-
const [ixn, address] = web3_js_1.AddressLookupTableProgram.createLookupTable({
|
|
804
|
-
authority: payer,
|
|
805
|
-
payer,
|
|
806
|
-
recentSlot: slot,
|
|
807
|
-
});
|
|
808
|
-
return [ixn, address];
|
|
809
|
-
}
|
|
810
887
|
getReserveAccountsToInsertInLut(reserveState) {
|
|
811
888
|
return [
|
|
812
889
|
reserveState.lendingMarket,
|
|
@@ -819,10 +896,18 @@ class KaminoVaultClient {
|
|
|
819
896
|
reserveState.collateral.supplyVault,
|
|
820
897
|
];
|
|
821
898
|
}
|
|
899
|
+
/**
|
|
900
|
+
* This method inserts the missing keys from the provided keys into an existent lookup table
|
|
901
|
+
* @param payer - payer wallet pubkey
|
|
902
|
+
* @param lookupTable - lookup table to insert the keys into
|
|
903
|
+
* @param keys - keys to insert into the lookup table
|
|
904
|
+
* @param [accountsInLUT] - the existent accounts in the lookup table. Optional. If provided, the function will not fetch the accounts in the lookup table
|
|
905
|
+
* @returns - an array of instructions to insert the missing keys into the lookup table
|
|
906
|
+
*/
|
|
822
907
|
async insertIntoLookupTableIxs(payer, lookupTable, keys, accountsInLUT) {
|
|
823
908
|
let lutContents = accountsInLUT;
|
|
824
909
|
if (!accountsInLUT) {
|
|
825
|
-
lutContents = await
|
|
910
|
+
lutContents = await (0, lut_utils_1.getAccountsInLUT)(this.getConnection(), lookupTable);
|
|
826
911
|
}
|
|
827
912
|
else {
|
|
828
913
|
lutContents = accountsInLUT;
|
|
@@ -844,79 +929,80 @@ class KaminoVaultClient {
|
|
|
844
929
|
}
|
|
845
930
|
return ixns;
|
|
846
931
|
}
|
|
847
|
-
/**
|
|
848
|
-
*
|
|
849
|
-
* @param connection
|
|
850
|
-
* @param lookupTable
|
|
851
|
-
* @returns
|
|
852
|
-
*/
|
|
853
|
-
async getAccountsInLUT(lookupTable) {
|
|
854
|
-
const lutState = await this._connection.getAddressLookupTable(lookupTable);
|
|
855
|
-
if (!lutState || !lutState.value) {
|
|
856
|
-
throw new Error(`Lookup table ${lookupTable} not found`);
|
|
857
|
-
}
|
|
858
|
-
return lutState.value.state.addresses;
|
|
859
|
-
}
|
|
860
|
-
deactivateLookupTableIx(payer, lookupTable) {
|
|
861
|
-
const ixn = web3_js_1.AddressLookupTableProgram.deactivateLookupTable({
|
|
862
|
-
authority: payer,
|
|
863
|
-
lookupTable: lookupTable,
|
|
864
|
-
});
|
|
865
|
-
return ixn;
|
|
866
|
-
}
|
|
867
|
-
/// this require the LUT to be deactivated at least 500 blocks before
|
|
868
|
-
closeLookupTableIx(payer, lookupTable) {
|
|
869
|
-
const ixn = web3_js_1.AddressLookupTableProgram.closeLookupTable({
|
|
870
|
-
authority: payer,
|
|
871
|
-
recipient: payer,
|
|
872
|
-
lookupTable: lookupTable,
|
|
873
|
-
});
|
|
874
|
-
return ixn;
|
|
875
|
-
}
|
|
876
932
|
/**
|
|
877
933
|
* This method returns the user shares balance for a given vault
|
|
878
934
|
* @param user - user to calculate the shares balance for
|
|
879
935
|
* @param vault - vault to calculate shares balance for
|
|
880
|
-
* @returns - user share balance in
|
|
936
|
+
* @returns - user share balance in tokens (not lamports)
|
|
881
937
|
*/
|
|
882
938
|
async getUserSharesBalanceSingleVault(user, vault) {
|
|
883
|
-
const vaultState = await vault.getState(this.
|
|
939
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
940
|
+
const userShares = { unstakedShares: new decimal_js_1.default(0), stakedShares: new decimal_js_1.default(0) };
|
|
884
941
|
const userSharesAta = (0, lib_1.getAssociatedTokenAddress)(vaultState.sharesMint, user);
|
|
885
|
-
const userSharesAccountInfo = await this.
|
|
886
|
-
if (
|
|
887
|
-
|
|
942
|
+
const userSharesAccountInfo = await this.getConnection().getAccountInfo(userSharesAta);
|
|
943
|
+
if (userSharesAccountInfo) {
|
|
944
|
+
const userSharesAccount = (0, spl_token_1.unpackAccount)(userSharesAta, userSharesAccountInfo);
|
|
945
|
+
userShares.unstakedShares = new decimal_js_1.default(userSharesAccount.amount.toString()).div(new decimal_js_1.default(10).pow(vaultState.sharesMintDecimals.toString()));
|
|
946
|
+
}
|
|
947
|
+
if (await vault.hasFarm(this.getConnection())) {
|
|
948
|
+
const userSharesInFarm = await (0, farm_utils_1.getUserSharesInFarm)(this.getConnection(), user, vaultState.vaultFarm, vaultState.sharesMintDecimals.toNumber());
|
|
949
|
+
userShares.stakedShares = userSharesInFarm;
|
|
888
950
|
}
|
|
889
|
-
|
|
890
|
-
return new decimal_js_1.default(userSharesAccount.amount.toString()).div(new decimal_js_1.default(10).pow(vaultState.sharesMintDecimals.toString()));
|
|
951
|
+
return userShares;
|
|
891
952
|
}
|
|
892
953
|
/**
|
|
893
954
|
* This method returns the user shares balance for all existing vaults
|
|
894
955
|
* @param user - user to calculate the shares balance for
|
|
895
|
-
* @param vaultsOverride - the kamino vaults if already fetched, in order to reduce rpc calls
|
|
896
|
-
* @returns - hash map with
|
|
956
|
+
* @param [vaultsOverride] - the kamino vaults if already fetched, in order to reduce rpc calls.Optional
|
|
957
|
+
* @returns - hash map with keys as vault address and value as user share balance in decimal (not lamports)
|
|
897
958
|
*/
|
|
898
959
|
async getUserSharesBalanceAllVaults(user, vaultsOverride) {
|
|
899
960
|
const vaults = vaultsOverride ? vaultsOverride : await this.getAllVaults();
|
|
900
961
|
// stores vault address for each userSharesAta
|
|
901
962
|
const vaultUserShareBalance = new lib_1.PubkeyHashMap();
|
|
963
|
+
const vaultToUserFarmStateAddress = new lib_1.PubkeyHashMap();
|
|
902
964
|
const userSharesAtaArray = [];
|
|
903
|
-
vaults.forEach((vault) => {
|
|
965
|
+
vaults.forEach(async (vault) => {
|
|
904
966
|
const state = vault.state;
|
|
905
967
|
if (!state) {
|
|
906
968
|
throw new Error(`Vault ${vault.address.toBase58()} not fetched`);
|
|
907
969
|
}
|
|
908
970
|
const userSharesAta = (0, lib_1.getAssociatedTokenAddress)(state.sharesMint, user);
|
|
909
971
|
userSharesAtaArray.push(userSharesAta);
|
|
972
|
+
if (await vault.hasFarm(this.getConnection())) {
|
|
973
|
+
const farmUserState = await (0, farm_utils_1.getFarmUserStatePDA)(this.getConnection(), user, state.vaultFarm);
|
|
974
|
+
vaultToUserFarmStateAddress.set(vault.address, farmUserState);
|
|
975
|
+
}
|
|
910
976
|
});
|
|
911
|
-
const userSharesAtaAccounts = await
|
|
977
|
+
const [userSharesAtaAccounts, userFarmStates] = await Promise.all([
|
|
978
|
+
this.getConnection().getMultipleAccountsInfo(userSharesAtaArray),
|
|
979
|
+
lib_1.UserState.fetchMultiple(this.getConnection(), Array.from(vaultToUserFarmStateAddress.values())),
|
|
980
|
+
]);
|
|
912
981
|
userSharesAtaAccounts.forEach((userShareAtaAccount, index) => {
|
|
982
|
+
const userSharesForVault = { unstakedShares: new decimal_js_1.default(0), stakedShares: new decimal_js_1.default(0) };
|
|
913
983
|
if (!userShareAtaAccount) {
|
|
914
|
-
vaultUserShareBalance.set(vaults[index].address,
|
|
984
|
+
vaultUserShareBalance.set(vaults[index].address, userSharesForVault);
|
|
915
985
|
}
|
|
916
986
|
else {
|
|
917
|
-
|
|
987
|
+
userSharesForVault.unstakedShares = (0, utils_1.getTokenBalanceFromAccountInfoLamports)(userShareAtaAccount).div(new decimal_js_1.default(10).pow(vaults[index].state.sharesMintDecimals.toString()));
|
|
988
|
+
vaultUserShareBalance.set(vaults[index].address, userSharesForVault);
|
|
918
989
|
}
|
|
919
990
|
});
|
|
991
|
+
userFarmStates.forEach((userFarmState, _) => {
|
|
992
|
+
if (!userFarmState) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
const farmState = userFarmState.farmState;
|
|
996
|
+
// find the vault which has the farm
|
|
997
|
+
const vault = vaults.find((vault) => vault.state.vaultFarm.equals(farmState));
|
|
998
|
+
if (!vault) {
|
|
999
|
+
throw new Error(`Vault with farm ${farmState.toBase58()} not found`);
|
|
1000
|
+
}
|
|
1001
|
+
const shares = (0, farm_utils_1.getSharesInFarmUserPosition)(userFarmState, vault.state.sharesMintDecimals.toNumber());
|
|
1002
|
+
const userSharesBalance = vaultUserShareBalance.get(vault.address);
|
|
1003
|
+
userSharesBalance.stakedShares = shares;
|
|
1004
|
+
vaultUserShareBalance.set(vault.address, userSharesBalance);
|
|
1005
|
+
});
|
|
920
1006
|
return vaultUserShareBalance;
|
|
921
1007
|
}
|
|
922
1008
|
/**
|
|
@@ -934,23 +1020,23 @@ class KaminoVaultClient {
|
|
|
934
1020
|
* 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
|
|
935
1021
|
* @param vault - vault to calculate tokensPerShare for
|
|
936
1022
|
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
937
|
-
* @param vaultReservesMap -
|
|
1023
|
+
* @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
|
|
938
1024
|
* @returns - token per share value
|
|
939
1025
|
*/
|
|
940
1026
|
async getTokensPerShareSingleVault(vault, slot, vaultReservesMap) {
|
|
941
|
-
const vaultState = await vault.getState(this.
|
|
1027
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
942
1028
|
if (vaultState.sharesIssued.isZero()) {
|
|
943
1029
|
return new decimal_js_1.default(0);
|
|
944
1030
|
}
|
|
945
1031
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
946
1032
|
const sharesDecimal = (0, lib_1.lamportsToDecimal)(vaultState.sharesIssued.toString(), vaultState.sharesMintDecimals.toString());
|
|
947
|
-
const holdings = await this.getVaultHoldings(vaultState, await this.
|
|
1033
|
+
const holdings = await this.getVaultHoldings(vaultState, await this.getConnection().getSlot('confirmed'), vaultReservesState);
|
|
948
1034
|
return holdings.total.div(sharesDecimal);
|
|
949
1035
|
}
|
|
950
1036
|
/**
|
|
951
1037
|
* 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
|
|
952
|
-
* @param vaultsOverride - a list of vaults to get the tokens per share for; if provided with state it will not fetch the state again
|
|
953
|
-
* @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
|
|
1038
|
+
* @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
|
|
1039
|
+
* @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
|
|
954
1040
|
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
955
1041
|
* @returns - token per share value
|
|
956
1042
|
*/
|
|
@@ -979,8 +1065,8 @@ class KaminoVaultClient {
|
|
|
979
1065
|
},
|
|
980
1066
|
},
|
|
981
1067
|
];
|
|
982
|
-
const kaminoVaults = await (0, rpc_1.getProgramAccounts)(this.
|
|
983
|
-
commitment: this.
|
|
1068
|
+
const kaminoVaults = await (0, rpc_1.getProgramAccounts)(this.getConnection(), this._kaminoVaultProgramId, accounts_1.VaultState.layout.span + 8, {
|
|
1069
|
+
commitment: this.getConnection().commitment ?? 'processed',
|
|
984
1070
|
filters,
|
|
985
1071
|
});
|
|
986
1072
|
return kaminoVaults.map((kaminoVault) => {
|
|
@@ -1037,16 +1123,17 @@ class KaminoVaultClient {
|
|
|
1037
1123
|
* 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
|
|
1038
1124
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
1039
1125
|
* @param slot - current slot
|
|
1126
|
+
*@param [vaultReservesMap] - a hashmap from each reserve pubkey to the reserve state
|
|
1040
1127
|
* @returns an HashMap of reserves (key) with the amount available to withdraw for each (value)
|
|
1041
1128
|
*/
|
|
1042
|
-
async getReserveAllocationAvailableLiquidityToWithdraw(vault, slot,
|
|
1043
|
-
const vaultState = await vault.getState(this.
|
|
1129
|
+
async getReserveAllocationAvailableLiquidityToWithdraw(vault, slot, vaultReservesMap) {
|
|
1130
|
+
const vaultState = await vault.getState(this.getConnection());
|
|
1044
1131
|
const reserveAllocationAvailableLiquidityToWithdraw = new lib_1.PubkeyHashMap();
|
|
1045
1132
|
vaultState.vaultAllocationStrategy.forEach((allocationStrategy) => {
|
|
1046
1133
|
if (allocationStrategy.reserve.equals(web3_js_1.PublicKey.default)) {
|
|
1047
1134
|
return;
|
|
1048
1135
|
}
|
|
1049
|
-
const reserve =
|
|
1136
|
+
const reserve = vaultReservesMap.get(allocationStrategy.reserve);
|
|
1050
1137
|
if (reserve === undefined) {
|
|
1051
1138
|
throw new Error(`Reserve ${allocationStrategy.reserve.toBase58()} not found`);
|
|
1052
1139
|
}
|
|
@@ -1091,7 +1178,7 @@ class KaminoVaultClient {
|
|
|
1091
1178
|
*/
|
|
1092
1179
|
async loadVaultReserves(vaultState) {
|
|
1093
1180
|
const vaultReservesAddresses = this.getVaultReserves(vaultState);
|
|
1094
|
-
const reserveAccounts = await this.
|
|
1181
|
+
const reserveAccounts = await this.getConnection().getMultipleAccountsInfo(vaultReservesAddresses, 'processed');
|
|
1095
1182
|
const deserializedReserves = reserveAccounts.map((reserve, i) => {
|
|
1096
1183
|
if (reserve === null) {
|
|
1097
1184
|
// maybe reuse old here
|
|
@@ -1103,25 +1190,27 @@ class KaminoVaultClient {
|
|
|
1103
1190
|
}
|
|
1104
1191
|
return reserveAccount;
|
|
1105
1192
|
});
|
|
1106
|
-
const reservesAndOracles = await (0, lib_1.getTokenOracleData)(this.
|
|
1193
|
+
const reservesAndOracles = await (0, lib_1.getTokenOracleData)(this.getConnection(), deserializedReserves);
|
|
1107
1194
|
const kaminoReserves = new lib_1.PubkeyHashMap();
|
|
1108
1195
|
reservesAndOracles.forEach(([reserve, oracle], index) => {
|
|
1109
1196
|
if (!oracle) {
|
|
1110
1197
|
throw Error(`Could not find oracle for ${(0, utils_1.parseTokenSymbol)(reserve.config.tokenInfo.name)} reserve`);
|
|
1111
1198
|
}
|
|
1112
|
-
const kaminoReserve = lib_1.KaminoReserve.initialize(reserveAccounts[index], vaultReservesAddresses[index], reserve, oracle, this.
|
|
1199
|
+
const kaminoReserve = lib_1.KaminoReserve.initialize(reserveAccounts[index], vaultReservesAddresses[index], reserve, oracle, this.getConnection(), this.recentSlotDurationMs);
|
|
1113
1200
|
kaminoReserves.set(kaminoReserve.address, kaminoReserve);
|
|
1114
1201
|
});
|
|
1115
1202
|
return kaminoReserves;
|
|
1116
1203
|
}
|
|
1117
1204
|
/**
|
|
1118
|
-
* This will retrieve all the tokens that can be
|
|
1205
|
+
* 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
|
|
1119
1206
|
* @param vaultState - the vault state to load reserves for
|
|
1120
|
-
*
|
|
1207
|
+
* @param slot - current slot
|
|
1208
|
+
* @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
|
|
1209
|
+
* @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
|
|
1121
1210
|
* @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
|
|
1122
1211
|
*/
|
|
1123
|
-
async getVaultCollaterals(vaultState, slot,
|
|
1124
|
-
const vaultReservesStateMap =
|
|
1212
|
+
async getVaultCollaterals(vaultState, slot, vaultReservesMap, kaminoMarkets) {
|
|
1213
|
+
const vaultReservesStateMap = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1125
1214
|
const vaultReservesState = Array.from(vaultReservesStateMap.values());
|
|
1126
1215
|
const vaultCollateralsPerReserve = new lib_1.PubkeyHashMap();
|
|
1127
1216
|
for (const reserve of vaultReservesState) {
|
|
@@ -1131,7 +1220,7 @@ class KaminoVaultClient {
|
|
|
1131
1220
|
lendingMarket = kaminoMarkets?.find((market) => reserve.state.lendingMarket.equals(new web3_js_1.PublicKey(market.address)));
|
|
1132
1221
|
}
|
|
1133
1222
|
if (!lendingMarket) {
|
|
1134
|
-
const fetchedLendingMarket = await lib_1.KaminoMarket.load(this.
|
|
1223
|
+
const fetchedLendingMarket = await lib_1.KaminoMarket.load(this.getConnection(), reserve.state.lendingMarket, slot);
|
|
1135
1224
|
if (!fetchedLendingMarket) {
|
|
1136
1225
|
throw Error(`Could not fetch lending market ${reserve.state.lendingMarket.toBase58()}`);
|
|
1137
1226
|
}
|
|
@@ -1171,8 +1260,8 @@ class KaminoVaultClient {
|
|
|
1171
1260
|
* 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
|
|
1172
1261
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
1173
1262
|
* @param slot - current slot
|
|
1174
|
-
* @param vaultReserves -
|
|
1175
|
-
* @returns an VaultHoldings object
|
|
1263
|
+
* @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
|
|
1264
|
+
* @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
|
|
1176
1265
|
*/
|
|
1177
1266
|
async getVaultHoldings(vault, slot, vaultReserves) {
|
|
1178
1267
|
const vaultHoldings = {
|
|
@@ -1209,12 +1298,12 @@ class KaminoVaultClient {
|
|
|
1209
1298
|
* 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
|
|
1210
1299
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
1211
1300
|
* @param slot - current slot
|
|
1212
|
-
* @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
|
|
1213
1301
|
* @param price - the price of the token in the vault (e.g. USDC)
|
|
1302
|
+
* @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
|
|
1214
1303
|
* @returns an VaultHoldingsWithUSDValue object with details about the tokens available and invested in the vault, denominated in tokens and USD
|
|
1215
1304
|
*/
|
|
1216
|
-
async getVaultHoldingsWithPrice(vault, slot, price,
|
|
1217
|
-
const holdings = await this.getVaultHoldings(vault, slot,
|
|
1305
|
+
async getVaultHoldingsWithPrice(vault, slot, price, vaultReservesMap) {
|
|
1306
|
+
const holdings = await this.getVaultHoldings(vault, slot, vaultReservesMap);
|
|
1218
1307
|
const investedInReservesUSD = new lib_1.PubkeyHashMap();
|
|
1219
1308
|
holdings.investedInReserves.forEach((amount, reserve) => {
|
|
1220
1309
|
investedInReservesUSD.set(reserve, amount.mul(price));
|
|
@@ -1232,12 +1321,12 @@ class KaminoVaultClient {
|
|
|
1232
1321
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
1233
1322
|
* @param slot - current slot
|
|
1234
1323
|
* @param price - the price of the token in the vault (e.g. USDC)
|
|
1235
|
-
* @param
|
|
1236
|
-
* @param kaminoMarkets -
|
|
1237
|
-
* @returns an
|
|
1324
|
+
* @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
|
|
1325
|
+
* @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
|
|
1326
|
+
* @returns an VaultOverview object with details about the tokens available and invested in the vault, denominated in tokens and USD
|
|
1238
1327
|
*/
|
|
1239
|
-
async getVaultOverview(vault, slot, price,
|
|
1240
|
-
const vaultReservesState =
|
|
1328
|
+
async getVaultOverview(vault, slot, price, vaultReservesMap, kaminoMarkets) {
|
|
1329
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
|
|
1241
1330
|
const vaultHoldingsWithUSDValuePromise = await this.getVaultHoldingsWithPrice(vault, slot, price, vaultReservesState);
|
|
1242
1331
|
const vaultTheoreticalAPYPromise = await this.getVaultTheoreticalAPY(vault, slot, vaultReservesState);
|
|
1243
1332
|
const totalInvestedAndBorrowedPromise = await this.getTotalBorrowedAndInvested(vault, slot, vaultReservesState);
|
|
@@ -1265,11 +1354,11 @@ class KaminoVaultClient {
|
|
|
1265
1354
|
* This will return an aggregation of the current state of the vault with all the invested amounts and the utilization ratio of the vault
|
|
1266
1355
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
1267
1356
|
* @param slot - current slot
|
|
1268
|
-
* @param
|
|
1357
|
+
* @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
|
|
1269
1358
|
* @returns an VaultReserveTotalBorrowedAndInvested object with the total invested amount, total borrowed amount and the utilization ratio of the vault
|
|
1270
1359
|
*/
|
|
1271
|
-
async getTotalBorrowedAndInvested(vault, slot,
|
|
1272
|
-
const vaultReservesState =
|
|
1360
|
+
async getTotalBorrowedAndInvested(vault, slot, vaultReservesMap) {
|
|
1361
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
|
|
1273
1362
|
const totalAvailable = (0, lib_1.lamportsToDecimal)(new decimal_js_1.default(vault.tokenAvailable.toString()), new decimal_js_1.default(vault.tokenMintDecimals.toString()));
|
|
1274
1363
|
let totalInvested = new decimal_js_1.default(0);
|
|
1275
1364
|
let totalBorrowed = new decimal_js_1.default(0);
|
|
@@ -1302,7 +1391,7 @@ class KaminoVaultClient {
|
|
|
1302
1391
|
* This will return an overview of each reserve that is part of the vault allocation
|
|
1303
1392
|
* @param vault - the kamino vault to get available liquidity to withdraw for
|
|
1304
1393
|
* @param slot - current slot
|
|
1305
|
-
* @param
|
|
1394
|
+
* @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
|
|
1306
1395
|
* @returns a hashmap from vault reserve pubkey to ReserveOverview object
|
|
1307
1396
|
*/
|
|
1308
1397
|
async getVaultReservesDetails(vault, slot, vaultReserves) {
|
|
@@ -1333,11 +1422,11 @@ class KaminoVaultClient {
|
|
|
1333
1422
|
* 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
|
|
1334
1423
|
* @param vault - the kamino vault to get APY for
|
|
1335
1424
|
* @param slot - current slot
|
|
1336
|
-
* @param
|
|
1425
|
+
* @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
|
|
1337
1426
|
* @returns APY for the vault
|
|
1338
1427
|
*/
|
|
1339
|
-
async getVaultTheoreticalAPY(vault, slot,
|
|
1340
|
-
const vaultReservesState =
|
|
1428
|
+
async getVaultTheoreticalAPY(vault, slot, vaultReservesMap) {
|
|
1429
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vault);
|
|
1341
1430
|
let totalWeights = new decimal_js_1.default(0);
|
|
1342
1431
|
let totalAPY = new decimal_js_1.default(0);
|
|
1343
1432
|
vault.vaultAllocationStrategy.forEach((allocationStrategy) => {
|
|
@@ -1362,7 +1451,7 @@ class KaminoVaultClient {
|
|
|
1362
1451
|
/**
|
|
1363
1452
|
* Retrive the total amount of interest earned by the vault since its inception, including what was charged as fees
|
|
1364
1453
|
* @param vaultState the kamino vault state to get total net yield for
|
|
1365
|
-
* @returns a
|
|
1454
|
+
* @returns a Decimal representing the net number of tokens earned by the vault since its inception
|
|
1366
1455
|
*/
|
|
1367
1456
|
async getVaultCumulativeInterest(vaultState) {
|
|
1368
1457
|
const netYieldLamports = new fraction_1.Fraction(vaultState.cumulativeEarnedInterestSf).toDecimal();
|
|
@@ -1371,15 +1460,15 @@ class KaminoVaultClient {
|
|
|
1371
1460
|
/**
|
|
1372
1461
|
* Simulate the current holdings of the vault and the earned interest
|
|
1373
1462
|
* @param vaultState the kamino vault state to get simulated holdings and earnings for
|
|
1374
|
-
* @param
|
|
1463
|
+
* @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
|
|
1375
1464
|
* @returns a struct of simulated vault holdings and earned interest
|
|
1376
1465
|
*/
|
|
1377
|
-
async calculateSimulatedHoldingsWithInterest(vaultState,
|
|
1466
|
+
async calculateSimulatedHoldingsWithInterest(vaultState, vaultReservesMap) {
|
|
1378
1467
|
const latestUpdateTs = vaultState.lastFeeChargeTimestamp.toNumber();
|
|
1379
1468
|
const lastUpdateSlot = latestUpdateTs / this.recentSlotDurationMs;
|
|
1380
|
-
const currentSlot = await this.
|
|
1381
|
-
const lastUpdateHoldingsPromise = this.getVaultHoldings(vaultState, lastUpdateSlot,
|
|
1382
|
-
const currentHoldingsPromise = this.getVaultHoldings(vaultState, currentSlot,
|
|
1469
|
+
const currentSlot = await this.getConnection().getSlot('confirmed');
|
|
1470
|
+
const lastUpdateHoldingsPromise = this.getVaultHoldings(vaultState, lastUpdateSlot, vaultReservesMap);
|
|
1471
|
+
const currentHoldingsPromise = this.getVaultHoldings(vaultState, currentSlot, vaultReservesMap);
|
|
1383
1472
|
const [lastUpdateHoldings, currentHoldings] = await Promise.all([
|
|
1384
1473
|
lastUpdateHoldingsPromise,
|
|
1385
1474
|
currentHoldingsPromise,
|
|
@@ -1393,8 +1482,8 @@ class KaminoVaultClient {
|
|
|
1393
1482
|
/**
|
|
1394
1483
|
* Simulate the current holdings and compute the fees that would be charged
|
|
1395
1484
|
* @param vaultState the kamino vault state to get simulated fees for
|
|
1396
|
-
* @param simulatedCurrentHoldingsWithInterest
|
|
1397
|
-
* @returns a struct of simulated management and interest fees
|
|
1485
|
+
* @param simulatedCurrentHoldingsWithInterest the simulated holdings and interest earned by the vault. Optional
|
|
1486
|
+
* @returns a VaultFees struct of simulated management and interest fees
|
|
1398
1487
|
*/
|
|
1399
1488
|
async calculateSimulatedFees(vaultState, simulatedCurrentHoldingsWithInterest) {
|
|
1400
1489
|
const timestampNow = new Date().getTime();
|
|
@@ -1445,6 +1534,10 @@ class KaminoVault {
|
|
|
1445
1534
|
}
|
|
1446
1535
|
return this.state;
|
|
1447
1536
|
}
|
|
1537
|
+
async hasFarm(connection) {
|
|
1538
|
+
const state = await this.getState(connection);
|
|
1539
|
+
return !state.vaultFarm.equals(web3_js_1.PublicKey.default);
|
|
1540
|
+
}
|
|
1448
1541
|
}
|
|
1449
1542
|
exports.KaminoVault = KaminoVault;
|
|
1450
1543
|
/**
|