@kamino-finance/klend-sdk 7.1.10 → 7.2.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 +8 -0
- package/dist/classes/farm_utils.d.ts.map +1 -1
- package/dist/classes/farm_utils.js +39 -0
- package/dist/classes/farm_utils.js.map +1 -1
- package/dist/classes/manager.d.ts +52 -5
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +68 -9
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/reserve.d.ts +1 -1
- package/dist/classes/reserve.js +1 -1
- package/dist/classes/vault.d.ts +156 -10
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +480 -80
- package/dist/classes/vault.js.map +1 -1
- package/dist/manager/client_kamino_manager.js +103 -50
- package/dist/manager/client_kamino_manager.js.map +1 -1
- package/dist/utils/farmUtils.d.ts +1 -1
- package/dist/utils/farmUtils.d.ts.map +1 -1
- package/dist/utils/farmUtils.js +1 -1
- package/dist/utils/farmUtils.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/farm_utils.ts +48 -0
- package/src/classes/manager.ts +100 -14
- package/src/classes/reserve.ts +1 -1
- package/src/classes/vault.ts +680 -84
- package/src/manager/client_kamino_manager.ts +144 -62
- package/src/utils/farmUtils.ts +0 -1
package/src/classes/vault.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
Base58EncodedBytes,
|
|
8
8
|
fetchEncodedAccount,
|
|
9
9
|
generateKeyPairSigner,
|
|
10
|
-
GetAccountInfoApi,
|
|
11
10
|
getAddressEncoder,
|
|
12
11
|
getBase58Decoder,
|
|
13
12
|
GetProgramAccountsDatasizeFilter,
|
|
@@ -78,6 +77,7 @@ import { PROGRAM_ID } from '../@codegen/klend/programId';
|
|
|
78
77
|
import { ReserveWithAddress } from './reserve';
|
|
79
78
|
import { Fraction } from './fraction';
|
|
80
79
|
import {
|
|
80
|
+
CDN_ENDPOINT,
|
|
81
81
|
createAtasIdempotent,
|
|
82
82
|
createWsolAtaIfMissing,
|
|
83
83
|
getAllStandardTokenProgramTokenAccounts,
|
|
@@ -107,12 +107,13 @@ import {
|
|
|
107
107
|
} from './vault_types';
|
|
108
108
|
import { batchFetch, collToLamportsDecimal, ZERO } from '@kamino-finance/kliquidity-sdk';
|
|
109
109
|
import { FullBPSDecimal } from '@kamino-finance/kliquidity-sdk/dist/utils/CreationParameters';
|
|
110
|
-
import { FarmIncentives, FarmState } from '@kamino-finance/farms-sdk/dist';
|
|
110
|
+
import { FarmIncentives, FarmState, getUserStatePDA } from '@kamino-finance/farms-sdk/dist';
|
|
111
111
|
import { getAccountsInLut, initLookupTableIx, insertIntoLookupTableIxs } from '../utils/lookupTable';
|
|
112
112
|
import {
|
|
113
113
|
getFarmStakeIxs,
|
|
114
114
|
getFarmUnstakeAndWithdrawIxs,
|
|
115
115
|
getSharesInFarmUserPosition,
|
|
116
|
+
getUserPendingRewardsInFarm,
|
|
116
117
|
getUserSharesInTokensStakedInFarm,
|
|
117
118
|
} from './farm_utils';
|
|
118
119
|
import { getCreateAccountInstruction, SYSTEM_PROGRAM_ADDRESS } from '@solana-program/system';
|
|
@@ -173,6 +174,10 @@ export class KaminoVaultClient {
|
|
|
173
174
|
return this._kaminoVaultProgramId;
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
getRpc() {
|
|
178
|
+
return this._rpc;
|
|
179
|
+
}
|
|
180
|
+
|
|
176
181
|
hasFarm() {
|
|
177
182
|
return;
|
|
178
183
|
}
|
|
@@ -191,7 +196,7 @@ export class KaminoVaultClient {
|
|
|
191
196
|
return;
|
|
192
197
|
}
|
|
193
198
|
|
|
194
|
-
const kaminoVault =
|
|
199
|
+
const kaminoVault = KaminoVault.loadWithClientAndState(this, vaultPubkey, vault);
|
|
195
200
|
const vaultName = this.decodeVaultName(vault.name);
|
|
196
201
|
const slot = await this.getConnection().getSlot({ commitment: 'confirmed' }).send();
|
|
197
202
|
const tokensPerShare = await this.getTokensPerShareSingleVault(kaminoVault, slot);
|
|
@@ -203,7 +208,7 @@ export class KaminoVaultClient {
|
|
|
203
208
|
|
|
204
209
|
console.log('Name: ', vaultName);
|
|
205
210
|
console.log('Shares issued: ', sharesIssued);
|
|
206
|
-
|
|
211
|
+
holdings.print();
|
|
207
212
|
console.log('Tokens per share: ', tokensPerShare);
|
|
208
213
|
}
|
|
209
214
|
|
|
@@ -408,7 +413,7 @@ export class KaminoVaultClient {
|
|
|
408
413
|
reserveAllocationConfig: ReserveAllocationConfig,
|
|
409
414
|
vaultAdminAuthority?: TransactionSigner
|
|
410
415
|
): Promise<UpdateReserveAllocationIxs> {
|
|
411
|
-
const vaultState: VaultState = await vault.getState(
|
|
416
|
+
const vaultState: VaultState = await vault.getState();
|
|
412
417
|
const reserveState: Reserve = reserveAllocationConfig.getReserveState();
|
|
413
418
|
|
|
414
419
|
const cTokenVault = await getCTokenVaultPda(
|
|
@@ -480,7 +485,7 @@ export class KaminoVaultClient {
|
|
|
480
485
|
unallocatedWeight?: BN,
|
|
481
486
|
unallocatedCap?: BN
|
|
482
487
|
) {
|
|
483
|
-
const vaultState = await vault.getState(
|
|
488
|
+
const vaultState = await vault.getState();
|
|
484
489
|
|
|
485
490
|
const unallocatedWeightToUse = unallocatedWeight ? unallocatedWeight : vaultState.unallocatedWeight;
|
|
486
491
|
const unallocatedCapToUse = unallocatedCap ? unallocatedCap : vaultState.unallocatedTokensCap;
|
|
@@ -522,7 +527,7 @@ export class KaminoVaultClient {
|
|
|
522
527
|
reserve: Address,
|
|
523
528
|
vaultAdminAuthority?: TransactionSigner
|
|
524
529
|
): Promise<WithdrawAndBlockReserveIxs> {
|
|
525
|
-
const vaultState = await vault.getState(
|
|
530
|
+
const vaultState = await vault.getState();
|
|
526
531
|
|
|
527
532
|
const reserveIsPartOfAllocation = vaultState.vaultAllocationStrategy.some(
|
|
528
533
|
(allocation) => allocation.reserve === reserve
|
|
@@ -570,7 +575,7 @@ export class KaminoVaultClient {
|
|
|
570
575
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
571
576
|
payer?: TransactionSigner
|
|
572
577
|
): Promise<WithdrawAndBlockReserveIxs> {
|
|
573
|
-
const vaultState = await vault.getState(
|
|
578
|
+
const vaultState = await vault.getState();
|
|
574
579
|
|
|
575
580
|
const reserves = this.getVaultReserves(vaultState);
|
|
576
581
|
const withdrawAndBlockReserveIxs: WithdrawAndBlockReserveIxs = {
|
|
@@ -613,7 +618,7 @@ export class KaminoVaultClient {
|
|
|
613
618
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
614
619
|
payer?: TransactionSigner
|
|
615
620
|
): Promise<DisinvestAllReservesIxs> {
|
|
616
|
-
const vaultState = await vault.getState(
|
|
621
|
+
const vaultState = await vault.getState();
|
|
617
622
|
|
|
618
623
|
const reserves = this.getVaultReserves(vaultState);
|
|
619
624
|
const disinvestAllReservesIxs: DisinvestAllReservesIxs = {
|
|
@@ -666,7 +671,7 @@ export class KaminoVaultClient {
|
|
|
666
671
|
reserve: Address,
|
|
667
672
|
vaultAdminAuthority?: TransactionSigner
|
|
668
673
|
): Promise<Instruction | undefined> {
|
|
669
|
-
const vaultState = await vault.getState(
|
|
674
|
+
const vaultState = await vault.getState();
|
|
670
675
|
const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
|
|
671
676
|
|
|
672
677
|
const reserveIsPartOfAllocation = vaultState.vaultAllocationStrategy.some(
|
|
@@ -700,7 +705,7 @@ export class KaminoVaultClient {
|
|
|
700
705
|
value: string,
|
|
701
706
|
vaultAdminAuthority?: TransactionSigner
|
|
702
707
|
): Promise<UpdateVaultConfigIxs> {
|
|
703
|
-
const vaultState: VaultState = await vault.getState(
|
|
708
|
+
const vaultState: VaultState = await vault.getState();
|
|
704
709
|
const admin = parseVaultAdmin(vaultState, vaultAdminAuthority);
|
|
705
710
|
|
|
706
711
|
const updateVaultConfigAccs: UpdateVaultConfigAccounts = {
|
|
@@ -802,7 +807,7 @@ export class KaminoVaultClient {
|
|
|
802
807
|
errorOnOverride: boolean = true,
|
|
803
808
|
vaultAdminAuthority?: TransactionSigner
|
|
804
809
|
): Promise<UpdateVaultConfigIxs> {
|
|
805
|
-
const vaultHasFarm = await vault.hasFarm(
|
|
810
|
+
const vaultHasFarm = await vault.hasFarm();
|
|
806
811
|
if (vaultHasFarm && errorOnOverride) {
|
|
807
812
|
throw new Error('Vault already has a farm, if you want to override it set errorOnOverride to false');
|
|
808
813
|
}
|
|
@@ -868,7 +873,7 @@ export class KaminoVaultClient {
|
|
|
868
873
|
vault: KaminoVault,
|
|
869
874
|
pendingAdmin?: TransactionSigner
|
|
870
875
|
): Promise<AcceptVaultOwnershipIxs> {
|
|
871
|
-
const vaultState: VaultState = await vault.getState(
|
|
876
|
+
const vaultState: VaultState = await vault.getState();
|
|
872
877
|
const signer = parseVaultPendingAdmin(vaultState, pendingAdmin);
|
|
873
878
|
|
|
874
879
|
const acceptOwneshipAccounts: UpdateAdminAccounts = {
|
|
@@ -929,7 +934,7 @@ export class KaminoVaultClient {
|
|
|
929
934
|
maxAmountToGiveUp: Decimal,
|
|
930
935
|
vaultAdminAuthority?: TransactionSigner
|
|
931
936
|
): Promise<Instruction> {
|
|
932
|
-
const vaultState: VaultState = await vault.getState(
|
|
937
|
+
const vaultState: VaultState = await vault.getState();
|
|
933
938
|
const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
|
|
934
939
|
|
|
935
940
|
const giveUpPendingFeesAccounts: GiveUpPendingFeesAccounts = {
|
|
@@ -964,7 +969,7 @@ export class KaminoVaultClient {
|
|
|
964
969
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
965
970
|
vaultAdminAuthority?: TransactionSigner
|
|
966
971
|
): Promise<Instruction[]> {
|
|
967
|
-
const vaultState: VaultState = await vault.getState(
|
|
972
|
+
const vaultState: VaultState = await vault.getState();
|
|
968
973
|
const vaultAdmin = parseVaultAdmin(vaultState, vaultAdminAuthority);
|
|
969
974
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
970
975
|
const [{ ata: adminTokenAta, createAtaIx }] = await createAtasIdempotent(vaultAdmin, [
|
|
@@ -1057,7 +1062,7 @@ export class KaminoVaultClient {
|
|
|
1057
1062
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1058
1063
|
farmState?: FarmState
|
|
1059
1064
|
): Promise<DepositIxs> {
|
|
1060
|
-
const vaultState = await vault.getState(
|
|
1065
|
+
const vaultState = await vault.getState();
|
|
1061
1066
|
|
|
1062
1067
|
const tokenProgramID = vaultState.tokenProgram;
|
|
1063
1068
|
const userTokenAta = await getAssociatedTokenAddress(vaultState.tokenMint, user.address, tokenProgramID);
|
|
@@ -1125,7 +1130,7 @@ export class KaminoVaultClient {
|
|
|
1125
1130
|
};
|
|
1126
1131
|
|
|
1127
1132
|
// if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
|
|
1128
|
-
if (!(await vault.hasFarm(
|
|
1133
|
+
if (!(await vault.hasFarm())) {
|
|
1129
1134
|
return depositIxs;
|
|
1130
1135
|
}
|
|
1131
1136
|
|
|
@@ -1149,7 +1154,7 @@ export class KaminoVaultClient {
|
|
|
1149
1154
|
sharesAmount?: Decimal,
|
|
1150
1155
|
farmState?: FarmState
|
|
1151
1156
|
): Promise<Instruction[]> {
|
|
1152
|
-
const vaultState = await vault.getState(
|
|
1157
|
+
const vaultState = await vault.getState();
|
|
1153
1158
|
|
|
1154
1159
|
let sharesToStakeLamports = new Decimal(U64_MAX);
|
|
1155
1160
|
if (sharesAmount) {
|
|
@@ -1157,7 +1162,7 @@ export class KaminoVaultClient {
|
|
|
1157
1162
|
}
|
|
1158
1163
|
|
|
1159
1164
|
// if tokens to be staked are 0 or vault has no farm there is no stake needed
|
|
1160
|
-
if (sharesToStakeLamports.lte(0) || !(await vault.hasFarm(
|
|
1165
|
+
if (sharesToStakeLamports.lte(0) || !(await vault.hasFarm())) {
|
|
1161
1166
|
return [];
|
|
1162
1167
|
}
|
|
1163
1168
|
|
|
@@ -1183,9 +1188,8 @@ export class KaminoVaultClient {
|
|
|
1183
1188
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1184
1189
|
farmState?: FarmState
|
|
1185
1190
|
): Promise<WithdrawIxs> {
|
|
1186
|
-
const vaultState = await vault.getState(
|
|
1187
|
-
const
|
|
1188
|
-
const hasFarm = await vault.hasFarm(this.getConnection());
|
|
1191
|
+
const vaultState = await vault.getState();
|
|
1192
|
+
const hasFarm = await vault.hasFarm();
|
|
1189
1193
|
|
|
1190
1194
|
const withdrawIxs: WithdrawIxs = {
|
|
1191
1195
|
unstakeFromFarmIfNeededIxs: [],
|
|
@@ -1226,7 +1230,7 @@ export class KaminoVaultClient {
|
|
|
1226
1230
|
|
|
1227
1231
|
// if not enough shares in ATA unstake from farm
|
|
1228
1232
|
const sharesInAtaAreEnoughForWithdraw = sharesToWithdraw.lte(userSharesAtaBalance);
|
|
1229
|
-
if (hasFarm && !sharesInAtaAreEnoughForWithdraw) {
|
|
1233
|
+
if (hasFarm && !sharesInAtaAreEnoughForWithdraw && userSharesInFarm.gt(0)) {
|
|
1230
1234
|
// if we need to unstake we need to make sure share ata is created
|
|
1231
1235
|
const [{ createAtaIx }] = await createAtasIdempotent(user, [
|
|
1232
1236
|
{
|
|
@@ -1262,7 +1266,7 @@ export class KaminoVaultClient {
|
|
|
1262
1266
|
if (vaultAllocation) {
|
|
1263
1267
|
const withdrawFromVaultIxs = await this.withdrawWithReserveIxs(
|
|
1264
1268
|
user,
|
|
1265
|
-
|
|
1269
|
+
vault,
|
|
1266
1270
|
sharesToWithdraw,
|
|
1267
1271
|
totalUserShares,
|
|
1268
1272
|
slot,
|
|
@@ -1270,7 +1274,7 @@ export class KaminoVaultClient {
|
|
|
1270
1274
|
);
|
|
1271
1275
|
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1272
1276
|
} else {
|
|
1273
|
-
const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user,
|
|
1277
|
+
const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, vault, sharesToWithdraw);
|
|
1274
1278
|
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1275
1279
|
}
|
|
1276
1280
|
|
|
@@ -1310,8 +1314,7 @@ export class KaminoVaultClient {
|
|
|
1310
1314
|
vault: KaminoVault,
|
|
1311
1315
|
shareAmount: Decimal
|
|
1312
1316
|
): Promise<Instruction[]> {
|
|
1313
|
-
const vaultState = await vault.getState(
|
|
1314
|
-
const kaminoVault = new KaminoVault(vault.address, vaultState, vault.programId);
|
|
1317
|
+
const vaultState = await vault.getState();
|
|
1315
1318
|
|
|
1316
1319
|
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
1317
1320
|
const [{ ata: userTokenAta, createAtaIx }] = await createAtasIdempotent(user, [
|
|
@@ -1324,7 +1327,7 @@ export class KaminoVaultClient {
|
|
|
1324
1327
|
const shareLamportsToWithdraw = collToLamportsDecimal(shareAmount, vaultState.sharesMintDecimals.toNumber());
|
|
1325
1328
|
const withdrawFromAvailableIxn = await this.withdrawFromAvailableIx(
|
|
1326
1329
|
user,
|
|
1327
|
-
|
|
1330
|
+
vault,
|
|
1328
1331
|
vaultState,
|
|
1329
1332
|
userSharesAta,
|
|
1330
1333
|
userTokenAta,
|
|
@@ -1342,7 +1345,7 @@ export class KaminoVaultClient {
|
|
|
1342
1345
|
slot: Slot,
|
|
1343
1346
|
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
1344
1347
|
): Promise<Instruction[]> {
|
|
1345
|
-
const vaultState = await vault.getState(
|
|
1348
|
+
const vaultState = await vault.getState();
|
|
1346
1349
|
|
|
1347
1350
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1348
1351
|
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
@@ -1408,7 +1411,7 @@ export class KaminoVaultClient {
|
|
|
1408
1411
|
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: new Decimal(U64_MAX.toString()) });
|
|
1409
1412
|
} else {
|
|
1410
1413
|
// round up to the nearest integer the shares to withdraw
|
|
1411
|
-
const sharesToWithdrawFromReserve = tokensToWithdrawFromReserve.mul(sharesPerToken).
|
|
1414
|
+
const sharesToWithdrawFromReserve = tokensToWithdrawFromReserve.mul(sharesPerToken).floor();
|
|
1412
1415
|
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: sharesToWithdrawFromReserve });
|
|
1413
1416
|
}
|
|
1414
1417
|
|
|
@@ -1427,13 +1430,6 @@ export class KaminoVaultClient {
|
|
|
1427
1430
|
}
|
|
1428
1431
|
const marketAddress = reserveState.state.lendingMarket;
|
|
1429
1432
|
|
|
1430
|
-
const isLastWithdraw = reserveIndex === reserveWithSharesAmountToWithdraw.length - 1;
|
|
1431
|
-
// if it is not last withdraw it means that we can pass all shares as we are withdrawing everything from that reserve
|
|
1432
|
-
let sharesToWithdraw = shareAmount;
|
|
1433
|
-
if (isLastWithdraw) {
|
|
1434
|
-
sharesToWithdraw = reserveWithTokens.shares;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
1433
|
const withdrawFromReserveIx = await this.withdrawIx(
|
|
1438
1434
|
user,
|
|
1439
1435
|
vault,
|
|
@@ -1442,7 +1438,7 @@ export class KaminoVaultClient {
|
|
|
1442
1438
|
{ address: reserveWithTokens.reserve, state: reserveState.state },
|
|
1443
1439
|
userSharesAta,
|
|
1444
1440
|
userTokenAta,
|
|
1445
|
-
|
|
1441
|
+
reserveWithTokens.shares,
|
|
1446
1442
|
vaultReservesState
|
|
1447
1443
|
);
|
|
1448
1444
|
withdrawIxs.push(withdrawFromReserveIx);
|
|
@@ -1463,7 +1459,7 @@ export class KaminoVaultClient {
|
|
|
1463
1459
|
vault: KaminoVault,
|
|
1464
1460
|
skipComputationChecks: boolean = false
|
|
1465
1461
|
): Promise<Instruction[]> {
|
|
1466
|
-
const vaultState = await vault.reloadState(
|
|
1462
|
+
const vaultState = await vault.reloadState();
|
|
1467
1463
|
const minInvestAmount = vaultState.minInvestAmount;
|
|
1468
1464
|
const allReserves = this.getVaultReserves(vaultState);
|
|
1469
1465
|
if (allReserves.length === 0) {
|
|
@@ -1576,7 +1572,7 @@ export class KaminoVaultClient {
|
|
|
1576
1572
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1577
1573
|
createAtaIfNeeded: boolean = true
|
|
1578
1574
|
): Promise<Instruction[]> {
|
|
1579
|
-
const vaultState = await vault.getState(
|
|
1575
|
+
const vaultState = await vault.getState();
|
|
1580
1576
|
const cTokenVault = await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId);
|
|
1581
1577
|
const [lendingMarketAuth] = await lendingMarketAuthPda(reserve.state.lendingMarket, this._kaminoLendProgramId);
|
|
1582
1578
|
|
|
@@ -1784,7 +1780,7 @@ export class KaminoVaultClient {
|
|
|
1784
1780
|
vault: KaminoVault,
|
|
1785
1781
|
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
1786
1782
|
): Promise<SyncVaultLUTIxs> {
|
|
1787
|
-
const vaultState = await vault.getState(
|
|
1783
|
+
const vaultState = await vault.getState();
|
|
1788
1784
|
const allAccountsToBeInserted = [
|
|
1789
1785
|
vault.address,
|
|
1790
1786
|
vaultState.vaultAdminAuthority,
|
|
@@ -1940,7 +1936,7 @@ export class KaminoVaultClient {
|
|
|
1940
1936
|
* @returns - user share balance in tokens (not lamports)
|
|
1941
1937
|
*/
|
|
1942
1938
|
async getUserSharesBalanceSingleVault(user: Address, vault: KaminoVault): Promise<UserSharesForVault> {
|
|
1943
|
-
const vaultState = await vault.getState(
|
|
1939
|
+
const vaultState = await vault.getState();
|
|
1944
1940
|
|
|
1945
1941
|
const userShares: UserSharesForVault = {
|
|
1946
1942
|
unstakedShares: new Decimal(0),
|
|
@@ -1964,7 +1960,7 @@ export class KaminoVaultClient {
|
|
|
1964
1960
|
return acc;
|
|
1965
1961
|
}, new Decimal(0));
|
|
1966
1962
|
|
|
1967
|
-
if (await vault.hasFarm(
|
|
1963
|
+
if (await vault.hasFarm()) {
|
|
1968
1964
|
const userSharesInFarm = await getUserSharesInTokensStakedInFarm(
|
|
1969
1965
|
this.getConnection(),
|
|
1970
1966
|
user,
|
|
@@ -2019,7 +2015,7 @@ export class KaminoVaultClient {
|
|
|
2019
2015
|
});
|
|
2020
2016
|
userSharesTokenAccountsPerVault.set(vault.address, userSharesTokenAccounts);
|
|
2021
2017
|
|
|
2022
|
-
if (await vault.hasFarm(
|
|
2018
|
+
if (await vault.hasFarm()) {
|
|
2023
2019
|
const userFarmState = allUserFarmStatesMap.get(state.vaultFarm);
|
|
2024
2020
|
if (userFarmState) {
|
|
2025
2021
|
console.log('there is a farm state for vault', vault.address);
|
|
@@ -2096,7 +2092,7 @@ export class KaminoVaultClient {
|
|
|
2096
2092
|
currentSlot?: Slot
|
|
2097
2093
|
): Promise<Decimal> {
|
|
2098
2094
|
// Determine if we have a KaminoVault or VaultState
|
|
2099
|
-
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState(
|
|
2095
|
+
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
|
|
2100
2096
|
|
|
2101
2097
|
if (vaultState.sharesIssued.isZero()) {
|
|
2102
2098
|
return new Decimal(0);
|
|
@@ -2203,7 +2199,7 @@ export class KaminoVaultClient {
|
|
|
2203
2199
|
throw Error(`kaminoVault with pubkey ${kaminoVault.address} could not be decoded`);
|
|
2204
2200
|
}
|
|
2205
2201
|
|
|
2206
|
-
return
|
|
2202
|
+
return KaminoVault.loadWithClientAndState(this, kaminoVault.address, kaminoVaultAccount);
|
|
2207
2203
|
});
|
|
2208
2204
|
}
|
|
2209
2205
|
|
|
@@ -2219,7 +2215,7 @@ export class KaminoVaultClient {
|
|
|
2219
2215
|
const vaultStates = await batchFetch(vaults, (chunk) => this.getVaultsStates(chunk));
|
|
2220
2216
|
return vaults.map((vault, index) => {
|
|
2221
2217
|
const state = vaultStates[index];
|
|
2222
|
-
return state ?
|
|
2218
|
+
return state ? KaminoVault.loadWithClientAndState(this, vault, state) : null;
|
|
2223
2219
|
});
|
|
2224
2220
|
}
|
|
2225
2221
|
|
|
@@ -2325,7 +2321,7 @@ export class KaminoVaultClient {
|
|
|
2325
2321
|
slot: Slot,
|
|
2326
2322
|
vaultReservesMap: Map<Address, KaminoReserve>
|
|
2327
2323
|
): Promise<Map<Address, Decimal>> {
|
|
2328
|
-
const vaultState = await vault.getState(
|
|
2324
|
+
const vaultState = await vault.getState();
|
|
2329
2325
|
|
|
2330
2326
|
const reserveAllocationAvailableLiquidityToWithdraw = new Map<Address, Decimal>();
|
|
2331
2327
|
vaultState.vaultAllocationStrategy.forEach((allocationStrategy) => {
|
|
@@ -2572,13 +2568,13 @@ export class KaminoVaultClient {
|
|
|
2572
2568
|
vaultReserves?: Map<Address, KaminoReserve>,
|
|
2573
2569
|
currentSlot?: Slot
|
|
2574
2570
|
): Promise<VaultHoldings> {
|
|
2575
|
-
const vaultHoldings: VaultHoldings = {
|
|
2571
|
+
const vaultHoldings: VaultHoldings = new VaultHoldings({
|
|
2576
2572
|
available: new Decimal(vault.tokenAvailable.toString()),
|
|
2577
2573
|
invested: new Decimal(0),
|
|
2578
2574
|
investedInReserves: new Map<Address, Decimal>(),
|
|
2579
2575
|
totalAUMIncludingFees: new Decimal(0),
|
|
2580
2576
|
pendingFees: new Decimal(0),
|
|
2581
|
-
};
|
|
2577
|
+
});
|
|
2582
2578
|
|
|
2583
2579
|
const currentSlotToUse = currentSlot ?? (await this.getConnection().getSlot({ commitment: 'confirmed' }).send());
|
|
2584
2580
|
const vaultReservesState = vaultReserves ? vaultReserves : await this.loadVaultReserves(vault);
|
|
@@ -2643,13 +2639,13 @@ export class KaminoVaultClient {
|
|
|
2643
2639
|
const totalAvailableDecimal = lamportsToDecimal(vaultHoldings.available, decimals);
|
|
2644
2640
|
const totalInvestedDecimal = lamportsToDecimal(vaultHoldings.invested, decimals);
|
|
2645
2641
|
const pendingFees = lamportsToDecimal(totalPendingFees, decimals);
|
|
2646
|
-
return {
|
|
2642
|
+
return new VaultHoldings({
|
|
2647
2643
|
available: totalAvailableDecimal,
|
|
2648
2644
|
invested: totalInvestedDecimal,
|
|
2649
2645
|
investedInReserves: vaultHoldings.investedInReserves,
|
|
2650
2646
|
totalAUMIncludingFees: totalAvailableDecimal.add(totalInvestedDecimal),
|
|
2651
2647
|
pendingFees: pendingFees,
|
|
2652
|
-
};
|
|
2648
|
+
});
|
|
2653
2649
|
}
|
|
2654
2650
|
|
|
2655
2651
|
/**
|
|
@@ -2696,7 +2692,7 @@ export class KaminoVaultClient {
|
|
|
2696
2692
|
* @returns an VaultOverview object with details about the tokens available and invested in the vault, denominated in tokens and USD, along sie APYs
|
|
2697
2693
|
*/
|
|
2698
2694
|
async getVaultOverview(
|
|
2699
|
-
vault:
|
|
2695
|
+
vault: KaminoVault,
|
|
2700
2696
|
vaultTokenPrice: Decimal,
|
|
2701
2697
|
slot?: Slot,
|
|
2702
2698
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
@@ -2704,10 +2700,11 @@ export class KaminoVaultClient {
|
|
|
2704
2700
|
currentSlot?: Slot,
|
|
2705
2701
|
tokensPrices?: Map<Address, Decimal>
|
|
2706
2702
|
): Promise<VaultOverview> {
|
|
2707
|
-
const
|
|
2703
|
+
const vaultState = await vault.getState();
|
|
2704
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
2708
2705
|
|
|
2709
2706
|
const vaultHoldingsWithUSDValuePromise = this.getVaultHoldingsWithPrice(
|
|
2710
|
-
|
|
2707
|
+
vaultState,
|
|
2711
2708
|
vaultTokenPrice,
|
|
2712
2709
|
slot,
|
|
2713
2710
|
vaultReservesState,
|
|
@@ -2717,15 +2714,20 @@ export class KaminoVaultClient {
|
|
|
2717
2714
|
const slotForOverview = slot ? slot : await this.getConnection().getSlot().send();
|
|
2718
2715
|
const farmsClient = new Farms(this.getConnection());
|
|
2719
2716
|
|
|
2720
|
-
const vaultTheoreticalAPYPromise = this.getVaultTheoreticalAPY(
|
|
2721
|
-
const vaultActualAPYPromise = this.getVaultActualAPY(
|
|
2717
|
+
const vaultTheoreticalAPYPromise = this.getVaultTheoreticalAPY(vaultState, slotForOverview, vaultReservesState);
|
|
2718
|
+
const vaultActualAPYPromise = this.getVaultActualAPY(vaultState, slotForOverview, vaultReservesState);
|
|
2722
2719
|
const totalInvestedAndBorrowedPromise = this.getTotalBorrowedAndInvested(
|
|
2723
|
-
|
|
2720
|
+
vaultState,
|
|
2724
2721
|
slotForOverview,
|
|
2725
2722
|
vaultReservesState
|
|
2726
2723
|
);
|
|
2727
|
-
const vaultCollateralsPromise = this.getVaultCollaterals(
|
|
2728
|
-
|
|
2724
|
+
const vaultCollateralsPromise = this.getVaultCollaterals(
|
|
2725
|
+
vaultState,
|
|
2726
|
+
slotForOverview,
|
|
2727
|
+
vaultReservesState,
|
|
2728
|
+
kaminoMarkets
|
|
2729
|
+
);
|
|
2730
|
+
const reservesOverviewPromise = this.getVaultReservesDetails(vaultState, slotForOverview, vaultReservesState);
|
|
2729
2731
|
const vaultFarmIncentivesPromise = this.getVaultRewardsAPY(
|
|
2730
2732
|
vault,
|
|
2731
2733
|
vaultTokenPrice,
|
|
@@ -2741,6 +2743,13 @@ export class KaminoVaultClient {
|
|
|
2741
2743
|
vaultReservesState,
|
|
2742
2744
|
tokensPrices
|
|
2743
2745
|
);
|
|
2746
|
+
const vaultDelegatedFarmIncentivesPromise = this.getVaultDelegatedFarmRewardsAPY(
|
|
2747
|
+
vault,
|
|
2748
|
+
vaultTokenPrice,
|
|
2749
|
+
farmsClient,
|
|
2750
|
+
slotForOverview,
|
|
2751
|
+
tokensPrices
|
|
2752
|
+
);
|
|
2744
2753
|
|
|
2745
2754
|
// all the async part of the functions above just read the vaultReservesState which is read beforehand, so excepting vaultCollateralsPromise they should do no additional network calls
|
|
2746
2755
|
const [
|
|
@@ -2752,6 +2761,7 @@ export class KaminoVaultClient {
|
|
|
2752
2761
|
reservesOverview,
|
|
2753
2762
|
vaultFarmIncentives,
|
|
2754
2763
|
vaultReservesFarmIncentives,
|
|
2764
|
+
vaultDelegatedFarmIncentives,
|
|
2755
2765
|
] = await Promise.all([
|
|
2756
2766
|
vaultHoldingsWithUSDValuePromise,
|
|
2757
2767
|
vaultTheoreticalAPYPromise,
|
|
@@ -2761,6 +2771,7 @@ export class KaminoVaultClient {
|
|
|
2761
2771
|
reservesOverviewPromise,
|
|
2762
2772
|
vaultFarmIncentivesPromise,
|
|
2763
2773
|
vaultReservesFarmIncentivesPromise,
|
|
2774
|
+
vaultDelegatedFarmIncentivesPromise,
|
|
2764
2775
|
]);
|
|
2765
2776
|
|
|
2766
2777
|
return {
|
|
@@ -2771,6 +2782,7 @@ export class KaminoVaultClient {
|
|
|
2771
2782
|
theoreticalSupplyAPY: vaultTheoreticalAPYs,
|
|
2772
2783
|
vaultFarmIncentives: vaultFarmIncentives,
|
|
2773
2784
|
reservesFarmsIncentives: vaultReservesFarmIncentives,
|
|
2785
|
+
delegatedFarmIncentives: vaultDelegatedFarmIncentives,
|
|
2774
2786
|
totalBorrowed: totalInvestedAndBorrowed.totalBorrowed,
|
|
2775
2787
|
totalBorrowedUSD: totalInvestedAndBorrowed.totalBorrowed.mul(vaultTokenPrice),
|
|
2776
2788
|
utilizationRatio: totalInvestedAndBorrowed.utilizationRatio,
|
|
@@ -3080,11 +3092,64 @@ export class KaminoVaultClient {
|
|
|
3080
3092
|
user: Address
|
|
3081
3093
|
): Promise<ProgramDerivedAddress> {
|
|
3082
3094
|
return getProgramDerivedAddress({
|
|
3083
|
-
seeds: [addressEncoder.encode(
|
|
3095
|
+
seeds: [addressEncoder.encode(reserve), addressEncoder.encode(vault), addressEncoder.encode(user)],
|
|
3084
3096
|
programAddress: farmsProgramId,
|
|
3085
3097
|
});
|
|
3086
3098
|
}
|
|
3087
3099
|
|
|
3100
|
+
/**
|
|
3101
|
+
* Compute the delegatee PDA for the user farm state for a vault delegate farm
|
|
3102
|
+
* @param farmProgramID - the program ID of the farm program
|
|
3103
|
+
* @param vault - the address of the vault
|
|
3104
|
+
* @param farm - the address of the delegated farm
|
|
3105
|
+
* @param user - the address of the user
|
|
3106
|
+
* @returns the PDA of the delegatee user farm state for the delegated farm
|
|
3107
|
+
*/
|
|
3108
|
+
async computeUserFarmStateDelegateePDAForUserInDelegatedVaultFarm(
|
|
3109
|
+
farmProgramID: Address,
|
|
3110
|
+
vault: Address,
|
|
3111
|
+
farm: Address,
|
|
3112
|
+
user: Address
|
|
3113
|
+
): Promise<ProgramDerivedAddress> {
|
|
3114
|
+
return getProgramDerivedAddress({
|
|
3115
|
+
seeds: [addressEncoder.encode(vault), addressEncoder.encode(farm), addressEncoder.encode(user)],
|
|
3116
|
+
programAddress: farmProgramID,
|
|
3117
|
+
});
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3120
|
+
/**
|
|
3121
|
+
* Compute the user state PDA for a user in a delegated vault farm
|
|
3122
|
+
* @param farmProgramID - the program ID of the farm program
|
|
3123
|
+
* @param vault - the address of the vault
|
|
3124
|
+
* @param farm - the address of the delegated farm
|
|
3125
|
+
* @param user - the address of the user
|
|
3126
|
+
* @returns the PDA of the user state for the delegated farm
|
|
3127
|
+
*/
|
|
3128
|
+
async computeUserStatePDAForUserInDelegatedVaultFarm(
|
|
3129
|
+
farmProgramID: Address,
|
|
3130
|
+
vault: Address,
|
|
3131
|
+
farm: Address,
|
|
3132
|
+
user: Address
|
|
3133
|
+
): Promise<Address> {
|
|
3134
|
+
const delegateePDA = await this.computeDelegateeForUserInDelegatedFarm(farmProgramID, vault, farm, user);
|
|
3135
|
+
return getUserStatePDA(farmProgramID, farm, delegateePDA);
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
async computeDelegateeForUserInDelegatedFarm(
|
|
3139
|
+
farmProgramID: Address,
|
|
3140
|
+
vault: Address,
|
|
3141
|
+
farm: Address,
|
|
3142
|
+
user: Address
|
|
3143
|
+
): Promise<Address> {
|
|
3144
|
+
const delegateePDA = await this.computeUserFarmStateDelegateePDAForUserInDelegatedVaultFarm(
|
|
3145
|
+
farmProgramID,
|
|
3146
|
+
vault,
|
|
3147
|
+
farm,
|
|
3148
|
+
user
|
|
3149
|
+
);
|
|
3150
|
+
return delegateePDA[0];
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3088
3153
|
/**
|
|
3089
3154
|
* Read the APY of the farm built on top of the vault (farm in vaultState.vaultFarm)
|
|
3090
3155
|
* @param vault - the vault to read the farm APY for
|
|
@@ -3101,7 +3166,7 @@ export class KaminoVaultClient {
|
|
|
3101
3166
|
tokensPrices?: Map<Address, Decimal>
|
|
3102
3167
|
): Promise<FarmIncentives> {
|
|
3103
3168
|
// Determine if we have a KaminoVault or VaultState
|
|
3104
|
-
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState(
|
|
3169
|
+
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
|
|
3105
3170
|
if (vaultState.vaultFarm === DEFAULT_PUBLIC_KEY) {
|
|
3106
3171
|
return {
|
|
3107
3172
|
incentivesStats: [],
|
|
@@ -3117,6 +3182,39 @@ export class KaminoVaultClient {
|
|
|
3117
3182
|
return getFarmIncentives(kFarmsClient, vaultState.vaultFarm, sharePrice, stakedTokenMintDecimals, tokensPrices);
|
|
3118
3183
|
}
|
|
3119
3184
|
|
|
3185
|
+
/**
|
|
3186
|
+
* Read the APY of the delegated farm providing incentives for vault depositors
|
|
3187
|
+
* @param vault - the vault to read the farm APY for
|
|
3188
|
+
* @param vaultTokenPrice - the price of the vault token in USD (e.g. 1.0 for USDC)
|
|
3189
|
+
* @param [farmsClient] - the farms client to use. Optional. If not provided, the function will create a new one
|
|
3190
|
+
* @param [slot] - the slot to read the farm APY for. Optional. If not provided, the function will read the current slot
|
|
3191
|
+
* @param [tokensPrices] - the prices of the tokens in USD. Optional. If not provided, the function will fetch the prices
|
|
3192
|
+
* @returns the APY of the delegated farm providing incentives for vault depositors
|
|
3193
|
+
*/
|
|
3194
|
+
async getVaultDelegatedFarmRewardsAPY(
|
|
3195
|
+
vault: KaminoVault,
|
|
3196
|
+
vaultTokenPrice: Decimal,
|
|
3197
|
+
farmsClient?: Farms,
|
|
3198
|
+
slot?: Slot,
|
|
3199
|
+
tokensPrices?: Map<Address, Decimal>
|
|
3200
|
+
): Promise<FarmIncentives> {
|
|
3201
|
+
const delegatedFarm = await this.getDelegatedFarmForVault(vault.address);
|
|
3202
|
+
if (!delegatedFarm) {
|
|
3203
|
+
return {
|
|
3204
|
+
incentivesStats: [],
|
|
3205
|
+
totalIncentivesApy: 0,
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
const vaultState = await vault.getState();
|
|
3210
|
+
const tokensPerShare = await this.getTokensPerShareSingleVault(vaultState, slot);
|
|
3211
|
+
const sharePrice = tokensPerShare.mul(vaultTokenPrice);
|
|
3212
|
+
const stakedTokenMintDecimals = vaultState.sharesMintDecimals.toNumber();
|
|
3213
|
+
|
|
3214
|
+
const kFarmsClient = farmsClient ? farmsClient : new Farms(this.getConnection());
|
|
3215
|
+
return getFarmIncentives(kFarmsClient, delegatedFarm, sharePrice, stakedTokenMintDecimals, tokensPrices);
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3120
3218
|
/**
|
|
3121
3219
|
* Get all the token mints of the vault, vault farm rewards and the allocation rewards
|
|
3122
3220
|
* @param vaults - the vaults to get the token mints for
|
|
@@ -3137,9 +3235,9 @@ export class KaminoVaultClient {
|
|
|
3137
3235
|
const reservesToFetch = new Set<Address>();
|
|
3138
3236
|
|
|
3139
3237
|
for (const vault of vaults) {
|
|
3140
|
-
const vaultState = await vault.getState(
|
|
3238
|
+
const vaultState = await vault.getState();
|
|
3141
3239
|
vaultsTokenMints.add(vaultState.tokenMint);
|
|
3142
|
-
const hasFarm = await vault.hasFarm(
|
|
3240
|
+
const hasFarm = await vault.hasFarm();
|
|
3143
3241
|
if (hasFarm) {
|
|
3144
3242
|
const farmAddress = vaultState.vaultFarm;
|
|
3145
3243
|
if (!kFarmsMap.has(farmAddress)) {
|
|
@@ -3225,10 +3323,10 @@ export class KaminoVaultClient {
|
|
|
3225
3323
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
3226
3324
|
tokensPrices?: Map<Address, Decimal>
|
|
3227
3325
|
): Promise<VaultReservesFarmsIncentives> {
|
|
3228
|
-
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState(
|
|
3326
|
+
const vaultState = 'getState' in vaultOrState ? await vaultOrState.getState() : vaultOrState;
|
|
3229
3327
|
|
|
3230
3328
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
3231
|
-
const currentSlot = slot
|
|
3329
|
+
const currentSlot = slot ?? (await this.getConnection().getSlot({ commitment: 'confirmed' }).send());
|
|
3232
3330
|
|
|
3233
3331
|
const holdings = await this.getVaultHoldings(vaultState, currentSlot, vaultReservesState);
|
|
3234
3332
|
|
|
@@ -3264,7 +3362,6 @@ export class KaminoVaultClient {
|
|
|
3264
3362
|
kFarmsClient,
|
|
3265
3363
|
currentSlot,
|
|
3266
3364
|
reserveState.state,
|
|
3267
|
-
undefined,
|
|
3268
3365
|
tokensPrices
|
|
3269
3366
|
);
|
|
3270
3367
|
vaultReservesFarmsIncentives.set(reserveAddress, reserveFarmIncentives.collateralFarmIncentives);
|
|
@@ -3282,6 +3379,323 @@ export class KaminoVaultClient {
|
|
|
3282
3379
|
};
|
|
3283
3380
|
}
|
|
3284
3381
|
|
|
3382
|
+
/// reads the pending rewards for a user in the vault farm
|
|
3383
|
+
/// @param user - the user address
|
|
3384
|
+
/// @param vault - the vault
|
|
3385
|
+
/// @returns a map of the pending rewards token mint and amount in lamports
|
|
3386
|
+
async getUserPendingRewardsInVaultFarm(user: Address, vault: KaminoVault): Promise<Map<Address, Decimal>> {
|
|
3387
|
+
const vaultState = await vault.getState();
|
|
3388
|
+
const hasFarm = await vault.hasFarm();
|
|
3389
|
+
if (!hasFarm) {
|
|
3390
|
+
return new Map<Address, Decimal>();
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
const farmClient = new Farms(this.getConnection());
|
|
3394
|
+
const userState = await getUserStatePDA(farmClient.getProgramID(), vaultState.vaultFarm, user);
|
|
3395
|
+
return getUserPendingRewardsInFarm(this.getConnection(), userState, vaultState.vaultFarm);
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3398
|
+
/// reads the pending rewards for a user in a delegated vault farm
|
|
3399
|
+
/// @param user - the user address
|
|
3400
|
+
/// @param vaultAddress - the address of the vault
|
|
3401
|
+
/// @returns a map of the pending rewards token mint and amount in lamports
|
|
3402
|
+
async getUserPendingRewardsInVaultDelegatedFarm(
|
|
3403
|
+
user: Address,
|
|
3404
|
+
vaultAddress: Address
|
|
3405
|
+
): Promise<Map<Address, Decimal>> {
|
|
3406
|
+
const delegatedFarm = await this.getDelegatedFarmForVault(vaultAddress);
|
|
3407
|
+
if (!delegatedFarm) {
|
|
3408
|
+
return new Map<Address, Decimal>();
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
const farmClient = new Farms(this.getConnection());
|
|
3412
|
+
const userState = await this.computeUserStatePDAForUserInDelegatedVaultFarm(
|
|
3413
|
+
farmClient.getProgramID(),
|
|
3414
|
+
vaultAddress,
|
|
3415
|
+
delegatedFarm,
|
|
3416
|
+
user
|
|
3417
|
+
);
|
|
3418
|
+
|
|
3419
|
+
return getUserPendingRewardsInFarm(this.getConnection(), userState, delegatedFarm);
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3422
|
+
/// gets the delegated farm for a vault
|
|
3423
|
+
async getDelegatedFarmForVault(vault: Address): Promise<Address | undefined> {
|
|
3424
|
+
const response = await fetch(`${CDN_ENDPOINT}/resources.json`);
|
|
3425
|
+
if (!response.ok) {
|
|
3426
|
+
console.log(`Failed to fetch CDN for user pending rewards in vault delegated farm: ${response.statusText}`);
|
|
3427
|
+
return undefined;
|
|
3428
|
+
}
|
|
3429
|
+
const data = (await response.json()) as { 'mainnet-beta'?: { delegatedVaultFarms: any } };
|
|
3430
|
+
const delegatedVaultFarms = data['mainnet-beta']?.delegatedVaultFarms;
|
|
3431
|
+
if (!delegatedVaultFarms) {
|
|
3432
|
+
return undefined;
|
|
3433
|
+
}
|
|
3434
|
+
const delegatedFarmWithVault = delegatedVaultFarms.find((vaultWithFarm: any) => vaultWithFarm.vault === vault);
|
|
3435
|
+
if (!delegatedFarmWithVault) {
|
|
3436
|
+
return undefined;
|
|
3437
|
+
}
|
|
3438
|
+
return address(delegatedFarmWithVault.farm);
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
/// reads the pending rewards for a user in the reserves farms of a vault
|
|
3442
|
+
/// @param user - the user address
|
|
3443
|
+
/// @param vault - the vault
|
|
3444
|
+
/// @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
|
|
3445
|
+
/// @returns a map of the pending rewards token mint and amount in lamports
|
|
3446
|
+
async getUserPendingRewardsInVaultReservesFarms(
|
|
3447
|
+
user: Address,
|
|
3448
|
+
vault: KaminoVault,
|
|
3449
|
+
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
3450
|
+
): Promise<Map<Address, Decimal>> {
|
|
3451
|
+
const vaultState = await vault.getState();
|
|
3452
|
+
|
|
3453
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
3454
|
+
|
|
3455
|
+
const vaultReserves = vaultState.vaultAllocationStrategy
|
|
3456
|
+
.map((allocationStrategy) => allocationStrategy.reserve)
|
|
3457
|
+
.filter((reserve) => reserve !== DEFAULT_PUBLIC_KEY);
|
|
3458
|
+
const pendingRewardsPerToken: Map<Address, Decimal> = new Map();
|
|
3459
|
+
|
|
3460
|
+
const farmClient = new Farms(this.getConnection());
|
|
3461
|
+
for (const reserveAddress of vaultReserves) {
|
|
3462
|
+
const reserveState = vaultReservesState.get(reserveAddress);
|
|
3463
|
+
if (!reserveState) {
|
|
3464
|
+
console.log(`Reserve to read farm incentives for not found: ${reserveAddress}`);
|
|
3465
|
+
continue;
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
if (reserveState.state.farmCollateral === DEFAULT_PUBLIC_KEY) {
|
|
3469
|
+
continue;
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
const delegatee = await this.computeUserFarmStateDelegateePDAForUserInVault(
|
|
3473
|
+
farmClient.getProgramID(),
|
|
3474
|
+
vault.address,
|
|
3475
|
+
reserveAddress,
|
|
3476
|
+
user
|
|
3477
|
+
);
|
|
3478
|
+
const userState = await getUserStatePDA(
|
|
3479
|
+
farmClient.getProgramID(),
|
|
3480
|
+
reserveState.state.farmCollateral,
|
|
3481
|
+
delegatee[0]
|
|
3482
|
+
);
|
|
3483
|
+
const pendingRewards = await getUserPendingRewardsInFarm(
|
|
3484
|
+
this.getConnection(),
|
|
3485
|
+
userState,
|
|
3486
|
+
reserveState.state.farmCollateral
|
|
3487
|
+
);
|
|
3488
|
+
pendingRewards.forEach((reward, token) => {
|
|
3489
|
+
const existingReward = pendingRewardsPerToken.get(token);
|
|
3490
|
+
if (existingReward) {
|
|
3491
|
+
pendingRewardsPerToken.set(token, existingReward.add(reward));
|
|
3492
|
+
} else {
|
|
3493
|
+
pendingRewardsPerToken.set(token, reward);
|
|
3494
|
+
}
|
|
3495
|
+
});
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
return pendingRewardsPerToken;
|
|
3499
|
+
}
|
|
3500
|
+
|
|
3501
|
+
/// reads the pending rewards for a user in the vault farm, the reserves farms of the vault and the delegated vault farm
|
|
3502
|
+
/// @param user - the user address
|
|
3503
|
+
/// @param vault - the vault
|
|
3504
|
+
/// @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
|
|
3505
|
+
/// @returns a struct containing the pending rewards in the vault farm, the reserves farms of the vault and the delegated vault farm, and the total pending rewards in lamports
|
|
3506
|
+
async getAllPendingRewardsForUserInVault(
|
|
3507
|
+
user: Address,
|
|
3508
|
+
vault: KaminoVault,
|
|
3509
|
+
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
3510
|
+
): Promise<PendingRewardsForUserInVault> {
|
|
3511
|
+
const pendingRewardsInVaultFarm = await this.getUserPendingRewardsInVaultFarm(user, vault);
|
|
3512
|
+
const pendingRewardsInVaultReservesFarms = await this.getUserPendingRewardsInVaultReservesFarms(
|
|
3513
|
+
user,
|
|
3514
|
+
vault,
|
|
3515
|
+
vaultReservesMap
|
|
3516
|
+
);
|
|
3517
|
+
const pendingRewardsInVaultDelegatedFarm = await this.getUserPendingRewardsInVaultDelegatedFarm(
|
|
3518
|
+
user,
|
|
3519
|
+
vault.address
|
|
3520
|
+
);
|
|
3521
|
+
|
|
3522
|
+
const totalPendingRewards = new Map<Address, Decimal>();
|
|
3523
|
+
pendingRewardsInVaultFarm.forEach((reward, token) => {
|
|
3524
|
+
const existingReward = totalPendingRewards.get(token);
|
|
3525
|
+
if (existingReward) {
|
|
3526
|
+
totalPendingRewards.set(token, existingReward.add(reward));
|
|
3527
|
+
} else {
|
|
3528
|
+
totalPendingRewards.set(token, reward);
|
|
3529
|
+
}
|
|
3530
|
+
});
|
|
3531
|
+
pendingRewardsInVaultReservesFarms.forEach((reward, token) => {
|
|
3532
|
+
const existingReward = totalPendingRewards.get(token);
|
|
3533
|
+
if (existingReward) {
|
|
3534
|
+
totalPendingRewards.set(token, existingReward.add(reward));
|
|
3535
|
+
} else {
|
|
3536
|
+
totalPendingRewards.set(token, reward);
|
|
3537
|
+
}
|
|
3538
|
+
});
|
|
3539
|
+
pendingRewardsInVaultDelegatedFarm.forEach((reward, token) => {
|
|
3540
|
+
const existingReward = totalPendingRewards.get(token);
|
|
3541
|
+
if (existingReward) {
|
|
3542
|
+
totalPendingRewards.set(token, existingReward.add(reward));
|
|
3543
|
+
} else {
|
|
3544
|
+
totalPendingRewards.set(token, reward);
|
|
3545
|
+
}
|
|
3546
|
+
});
|
|
3547
|
+
|
|
3548
|
+
return {
|
|
3549
|
+
pendingRewardsInVaultFarm,
|
|
3550
|
+
pendingRewardsInVaultReservesFarms,
|
|
3551
|
+
pendingRewardsInVaultDelegatedFarm,
|
|
3552
|
+
totalPendingRewards,
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
/**
|
|
3557
|
+
* This function will return the instructions to claim the rewards for the farm of a vault, the delegated farm of the vault and the reserves farms of the vault
|
|
3558
|
+
* @param user - the user to claim the rewards
|
|
3559
|
+
* @param vault - the vault
|
|
3560
|
+
* @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
|
|
3561
|
+
* @returns the instructions to claim the rewards for the farm of the vault, the delegated farm of the vault and the reserves farms of the vault
|
|
3562
|
+
*/
|
|
3563
|
+
async getClaimAllRewardsForVaultIxs(
|
|
3564
|
+
user: TransactionSigner,
|
|
3565
|
+
vault: KaminoVault,
|
|
3566
|
+
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
3567
|
+
): Promise<Instruction[]> {
|
|
3568
|
+
const [vaultFarmIxs, delegatedFarmIxs, reservesFarmsIxs] = await Promise.all([
|
|
3569
|
+
this.getClaimVaultFarmRewardsIxs(user, vault),
|
|
3570
|
+
this.getClaimVaultDelegatedFarmRewardsIxs(user, vault),
|
|
3571
|
+
this.getClaimVaultReservesFarmsRewardsIxs(user, vault, vaultReservesMap),
|
|
3572
|
+
]);
|
|
3573
|
+
|
|
3574
|
+
return [...new Set([...vaultFarmIxs, ...delegatedFarmIxs, ...reservesFarmsIxs])];
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3577
|
+
/**
|
|
3578
|
+
* This function will return the instructions to claim the rewards for the farm of a vault
|
|
3579
|
+
* @param user - the user to claim the rewards
|
|
3580
|
+
* @param vault - the vault
|
|
3581
|
+
* @returns the instructions to claim the rewards for the farm of the vault
|
|
3582
|
+
*/
|
|
3583
|
+
async getClaimVaultFarmRewardsIxs(user: TransactionSigner, vault: KaminoVault): Promise<Instruction[]> {
|
|
3584
|
+
const vaultState = await vault.getState();
|
|
3585
|
+
const hasFarm = await vault.hasFarm();
|
|
3586
|
+
if (!hasFarm) {
|
|
3587
|
+
return [];
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
const farmClient = new Farms(this.getConnection());
|
|
3591
|
+
const pendingRewardsInVaultFarm = await this.getUserPendingRewardsInVaultFarm(user.address, vault);
|
|
3592
|
+
// if there are no pending rewards of their total is 0 no ix is needed
|
|
3593
|
+
const totalPendingRewards = Array.from(pendingRewardsInVaultFarm.values()).reduce(
|
|
3594
|
+
(acc, reward) => acc.add(reward),
|
|
3595
|
+
new Decimal(0)
|
|
3596
|
+
);
|
|
3597
|
+
if (totalPendingRewards.eq(0)) {
|
|
3598
|
+
return [];
|
|
3599
|
+
}
|
|
3600
|
+
return farmClient.claimForUserForFarmAllRewardsIx(user, vaultState.vaultFarm, false);
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
/**
|
|
3604
|
+
* This function will return the instructions to claim the rewards for the delegated farm of a vault
|
|
3605
|
+
* @param user - the user to claim the rewards
|
|
3606
|
+
* @param vault - the vault
|
|
3607
|
+
* @returns the instructions to claim the rewards for the delegated farm of the vault
|
|
3608
|
+
*/
|
|
3609
|
+
async getClaimVaultDelegatedFarmRewardsIxs(user: TransactionSigner, vault: KaminoVault): Promise<Instruction[]> {
|
|
3610
|
+
const delegatedFarm = await this.getDelegatedFarmForVault(vault.address);
|
|
3611
|
+
if (!delegatedFarm) {
|
|
3612
|
+
return [];
|
|
3613
|
+
}
|
|
3614
|
+
|
|
3615
|
+
const farmClient = new Farms(this.getConnection());
|
|
3616
|
+
|
|
3617
|
+
const delegatee = await this.computeDelegateeForUserInDelegatedFarm(
|
|
3618
|
+
farmClient.getProgramID(),
|
|
3619
|
+
vault.address,
|
|
3620
|
+
delegatedFarm,
|
|
3621
|
+
user.address
|
|
3622
|
+
);
|
|
3623
|
+
const userState = await getUserStatePDA(farmClient.getProgramID(), delegatedFarm, delegatee);
|
|
3624
|
+
// check if the user state exists
|
|
3625
|
+
const userStateExists = await fetchEncodedAccount(this.getConnection(), userState);
|
|
3626
|
+
if (!userStateExists.exists) {
|
|
3627
|
+
return [];
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
return farmClient.claimForUserForFarmAllRewardsIx(user, delegatedFarm, true, [delegatee]);
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
/**
|
|
3634
|
+
* This function will return the instructions to claim the rewards for the reserves farms of a vault
|
|
3635
|
+
* @param user - the user to claim the rewards
|
|
3636
|
+
* @param vault - the vault
|
|
3637
|
+
* @param [vaultReservesMap] - the vault reserves map to get the reserves for; if not provided, the function will fetch the reserves
|
|
3638
|
+
* @returns the instructions to claim the rewards for the reserves farms of the vault
|
|
3639
|
+
*/
|
|
3640
|
+
async getClaimVaultReservesFarmsRewardsIxs(
|
|
3641
|
+
user: TransactionSigner,
|
|
3642
|
+
vault: KaminoVault,
|
|
3643
|
+
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
3644
|
+
): Promise<Instruction[]> {
|
|
3645
|
+
const vaultState = await vault.getState();
|
|
3646
|
+
|
|
3647
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
3648
|
+
|
|
3649
|
+
const vaultReserves = vaultState.vaultAllocationStrategy
|
|
3650
|
+
.map((allocationStrategy) => allocationStrategy.reserve)
|
|
3651
|
+
.filter((reserve) => reserve !== DEFAULT_PUBLIC_KEY);
|
|
3652
|
+
|
|
3653
|
+
const ixs: Instruction[] = [];
|
|
3654
|
+
const farmClient = new Farms(this.getConnection());
|
|
3655
|
+
for (const reserveAddress of vaultReserves) {
|
|
3656
|
+
const reserveState = vaultReservesState.get(reserveAddress);
|
|
3657
|
+
if (!reserveState) {
|
|
3658
|
+
console.log(`Reserve to read farm incentives for not found: ${reserveAddress}`);
|
|
3659
|
+
continue;
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3662
|
+
if (reserveState.state.farmCollateral === DEFAULT_PUBLIC_KEY) {
|
|
3663
|
+
continue;
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
const delegatee = await this.computeUserFarmStateDelegateePDAForUserInVault(
|
|
3667
|
+
farmClient.getProgramID(),
|
|
3668
|
+
vault.address,
|
|
3669
|
+
reserveAddress,
|
|
3670
|
+
user.address
|
|
3671
|
+
);
|
|
3672
|
+
const userState = await getUserStatePDA(
|
|
3673
|
+
farmClient.getProgramID(),
|
|
3674
|
+
reserveState.state.farmCollateral,
|
|
3675
|
+
delegatee[0]
|
|
3676
|
+
);
|
|
3677
|
+
|
|
3678
|
+
const pendingRewards = await getUserPendingRewardsInFarm(
|
|
3679
|
+
this.getConnection(),
|
|
3680
|
+
userState,
|
|
3681
|
+
reserveState.state.farmCollateral
|
|
3682
|
+
);
|
|
3683
|
+
const totalPendingRewards = Array.from(pendingRewards.values()).reduce(
|
|
3684
|
+
(acc, reward) => acc.add(reward),
|
|
3685
|
+
new Decimal(0)
|
|
3686
|
+
);
|
|
3687
|
+
if (totalPendingRewards.eq(0)) {
|
|
3688
|
+
continue;
|
|
3689
|
+
}
|
|
3690
|
+
const ix = await farmClient.claimForUserForFarmAllRewardsIx(user, reserveState.state.farmCollateral, true, [
|
|
3691
|
+
delegatee[0],
|
|
3692
|
+
]);
|
|
3693
|
+
ixs.push(...ix);
|
|
3694
|
+
}
|
|
3695
|
+
|
|
3696
|
+
return ixs;
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3285
3699
|
private appendRemainingAccountsForVaultReserves(
|
|
3286
3700
|
ix: Instruction,
|
|
3287
3701
|
vaultReserves: Address[],
|
|
@@ -3310,16 +3724,33 @@ export class KaminoVault {
|
|
|
3310
3724
|
readonly address: Address;
|
|
3311
3725
|
state: VaultState | undefined | null;
|
|
3312
3726
|
programId: Address;
|
|
3727
|
+
client: KaminoVaultClient;
|
|
3728
|
+
vaultReservesStateCache: Map<Address, KaminoReserve> | undefined;
|
|
3313
3729
|
|
|
3314
|
-
constructor(
|
|
3730
|
+
constructor(
|
|
3731
|
+
rpc: Rpc<SolanaRpcApi>,
|
|
3732
|
+
vaultAddress: Address,
|
|
3733
|
+
state?: VaultState,
|
|
3734
|
+
programId: Address = kaminoVaultId,
|
|
3735
|
+
recentSlotDurationMs: number = DEFAULT_RECENT_SLOT_DURATION_MS
|
|
3736
|
+
) {
|
|
3315
3737
|
this.address = vaultAddress;
|
|
3316
3738
|
this.state = state;
|
|
3317
3739
|
this.programId = programId;
|
|
3740
|
+
this.client = new KaminoVaultClient(rpc, recentSlotDurationMs);
|
|
3318
3741
|
}
|
|
3319
3742
|
|
|
3320
|
-
|
|
3743
|
+
static loadWithClientAndState(client: KaminoVaultClient, vaultAddress: Address, state: VaultState): KaminoVault {
|
|
3744
|
+
const vault = new KaminoVault(client.getConnection(), vaultAddress);
|
|
3745
|
+
vault.state = state;
|
|
3746
|
+
vault.programId = client.getProgramID();
|
|
3747
|
+
vault.client = client;
|
|
3748
|
+
return vault;
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3751
|
+
async getState(): Promise<VaultState> {
|
|
3321
3752
|
if (!this.state) {
|
|
3322
|
-
const res = await VaultState.fetch(
|
|
3753
|
+
const res = await VaultState.fetch(this.client.getConnection(), this.address, this.programId);
|
|
3323
3754
|
if (!res) {
|
|
3324
3755
|
throw new Error('Invalid vault');
|
|
3325
3756
|
}
|
|
@@ -3330,18 +3761,141 @@ export class KaminoVault {
|
|
|
3330
3761
|
}
|
|
3331
3762
|
}
|
|
3332
3763
|
|
|
3333
|
-
async
|
|
3334
|
-
this.
|
|
3764
|
+
async reloadVaultReserves(): Promise<void> {
|
|
3765
|
+
this.vaultReservesStateCache = await this.client.loadVaultReserves(this.state!);
|
|
3766
|
+
}
|
|
3767
|
+
|
|
3768
|
+
async reloadState(): Promise<VaultState> {
|
|
3769
|
+
this.state = await VaultState.fetch(this.client.getConnection(), this.address, this.programId);
|
|
3335
3770
|
if (!this.state) {
|
|
3336
3771
|
throw new Error('Could not fetch vault');
|
|
3337
3772
|
}
|
|
3338
3773
|
return this.state;
|
|
3339
3774
|
}
|
|
3340
3775
|
|
|
3341
|
-
async hasFarm(
|
|
3342
|
-
const state = await this.getState(
|
|
3776
|
+
async hasFarm(): Promise<boolean> {
|
|
3777
|
+
const state = await this.getState();
|
|
3343
3778
|
return state.vaultFarm !== DEFAULT_PUBLIC_KEY;
|
|
3344
3779
|
}
|
|
3780
|
+
|
|
3781
|
+
/**
|
|
3782
|
+
* 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
|
|
3783
|
+
* @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
|
|
3784
|
+
*/
|
|
3785
|
+
async getVaultHoldings(): Promise<VaultHoldings> {
|
|
3786
|
+
if (!this.state || !this.vaultReservesStateCache) {
|
|
3787
|
+
await this.reloadState();
|
|
3788
|
+
await this.reloadVaultReserves();
|
|
3789
|
+
}
|
|
3790
|
+
|
|
3791
|
+
return await this.client.getVaultHoldings(this.state!, undefined, this.vaultReservesStateCache!, undefined);
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3794
|
+
/**
|
|
3795
|
+
* This will return the a map between reserve pubkey and the allocation overview for the reserve
|
|
3796
|
+
* @returns a map between reserve pubkey and the allocation overview for the reserve
|
|
3797
|
+
*/
|
|
3798
|
+
async getVaultAllocations(): Promise<Map<Address, ReserveAllocationOverview>> {
|
|
3799
|
+
if (!this.state) {
|
|
3800
|
+
await this.reloadState();
|
|
3801
|
+
}
|
|
3802
|
+
|
|
3803
|
+
return this.client.getVaultAllocations(this.state!);
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
/**
|
|
3807
|
+
* This will return the APY of the vault based on the current invested amounts and the theoretical APY if all the available tokens were invested
|
|
3808
|
+
* @returns a struct containing actualAPY and theoreticalAPY for the vault
|
|
3809
|
+
*/
|
|
3810
|
+
async getAPYs(slot?: Slot): Promise<VaultAPYs> {
|
|
3811
|
+
if (!this.state || !this.vaultReservesStateCache) {
|
|
3812
|
+
await this.reloadState();
|
|
3813
|
+
await this.reloadVaultReserves();
|
|
3814
|
+
}
|
|
3815
|
+
|
|
3816
|
+
const latestSlot = slot ?? (await this.client.getConnection().getSlot({ commitment: 'confirmed' }).send());
|
|
3817
|
+
const actualApy = await this.client.getVaultActualAPY(this.state!, latestSlot, this.vaultReservesStateCache!);
|
|
3818
|
+
const theoreticalApy = await this.client.getVaultTheoreticalAPY(
|
|
3819
|
+
this.state!,
|
|
3820
|
+
latestSlot,
|
|
3821
|
+
this.vaultReservesStateCache!
|
|
3822
|
+
);
|
|
3823
|
+
|
|
3824
|
+
return {
|
|
3825
|
+
actualAPY: actualApy,
|
|
3826
|
+
theoreticalAPY: theoreticalApy,
|
|
3827
|
+
};
|
|
3828
|
+
}
|
|
3829
|
+
|
|
3830
|
+
/**
|
|
3831
|
+
* This method returns the exchange rate of the vault (tokens per share)
|
|
3832
|
+
* @returns - Decimal representing the exchange rate (tokens per share)
|
|
3833
|
+
*/
|
|
3834
|
+
async getExchangeRate(slot?: Slot): Promise<Decimal> {
|
|
3835
|
+
if (!this.state || !this.vaultReservesStateCache) {
|
|
3836
|
+
await this.reloadState();
|
|
3837
|
+
await this.reloadVaultReserves();
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
const latestSlot = slot ?? (await this.client.getConnection().getSlot({ commitment: 'confirmed' }).send());
|
|
3841
|
+
const tokensPerShare = await this.client.getTokensPerShareSingleVault(this.state!, latestSlot);
|
|
3842
|
+
return tokensPerShare;
|
|
3843
|
+
}
|
|
3844
|
+
|
|
3845
|
+
/**
|
|
3846
|
+
* This method returns the user shares balance for a given vault
|
|
3847
|
+
* @param user - user to calculate the shares balance for
|
|
3848
|
+
* @param vault - vault to calculate shares balance for
|
|
3849
|
+
* @returns - a struct of user share balance (staked in vault farm if the vault has a farm and unstaked) in decimal (not lamports)
|
|
3850
|
+
*/
|
|
3851
|
+
async getUserShares(user: Address): Promise<UserSharesForVault> {
|
|
3852
|
+
return this.client.getUserSharesBalanceSingleVault(user, this);
|
|
3853
|
+
}
|
|
3854
|
+
|
|
3855
|
+
/**
|
|
3856
|
+
* 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
|
|
3857
|
+
* @param user - user to deposit
|
|
3858
|
+
* @param tokenAmount - token amount to be deposited, in decimals (will be converted in lamports)
|
|
3859
|
+
* @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
|
|
3860
|
+
* @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
|
|
3861
|
+
* @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
|
|
3862
|
+
*/
|
|
3863
|
+
async depositIxs(
|
|
3864
|
+
user: TransactionSigner,
|
|
3865
|
+
tokenAmount: Decimal,
|
|
3866
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
3867
|
+
farmState?: FarmState
|
|
3868
|
+
): Promise<DepositIxs> {
|
|
3869
|
+
if (vaultReservesMap) {
|
|
3870
|
+
this.vaultReservesStateCache = vaultReservesMap;
|
|
3871
|
+
}
|
|
3872
|
+
return this.client.depositIxs(user, this, tokenAmount, this.vaultReservesStateCache, farmState);
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
/**
|
|
3876
|
+
* 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
|
|
3877
|
+
* @param user - user to withdraw
|
|
3878
|
+
* @param shareAmount - share amount to withdraw (in tokens, not lamports), in order to withdraw everything, any value > user share amount
|
|
3879
|
+
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
3880
|
+
* @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
|
|
3881
|
+
* @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
|
|
3882
|
+
* @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
|
|
3883
|
+
*/
|
|
3884
|
+
async withdrawIxs(
|
|
3885
|
+
user: TransactionSigner,
|
|
3886
|
+
shareAmount: Decimal,
|
|
3887
|
+
slot?: Slot,
|
|
3888
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
3889
|
+
farmState?: FarmState
|
|
3890
|
+
): Promise<WithdrawIxs> {
|
|
3891
|
+
if (vaultReservesMap) {
|
|
3892
|
+
this.vaultReservesStateCache = vaultReservesMap;
|
|
3893
|
+
}
|
|
3894
|
+
|
|
3895
|
+
const currentSlot = slot ?? (await this.client.getConnection().getSlot({ commitment: 'confirmed' }).send());
|
|
3896
|
+
|
|
3897
|
+
return this.client.withdrawIxs(user, this, shareAmount, currentSlot, this.vaultReservesStateCache, farmState);
|
|
3898
|
+
}
|
|
3345
3899
|
}
|
|
3346
3900
|
|
|
3347
3901
|
/**
|
|
@@ -3456,13 +4010,56 @@ export type VaultHolder = {
|
|
|
3456
4010
|
amount: Decimal;
|
|
3457
4011
|
};
|
|
3458
4012
|
|
|
3459
|
-
export type
|
|
4013
|
+
export type APY = {
|
|
4014
|
+
grossAPY: Decimal;
|
|
4015
|
+
netAPY: Decimal;
|
|
4016
|
+
};
|
|
4017
|
+
|
|
4018
|
+
export type VaultAPYs = {
|
|
4019
|
+
theoreticalAPY: APY;
|
|
4020
|
+
actualAPY: APY;
|
|
4021
|
+
};
|
|
4022
|
+
|
|
4023
|
+
export class VaultHoldings {
|
|
3460
4024
|
available: Decimal;
|
|
3461
4025
|
invested: Decimal;
|
|
3462
4026
|
investedInReserves: Map<Address, Decimal>;
|
|
3463
4027
|
pendingFees: Decimal;
|
|
3464
4028
|
totalAUMIncludingFees: Decimal;
|
|
3465
|
-
|
|
4029
|
+
|
|
4030
|
+
constructor(params: {
|
|
4031
|
+
available: Decimal;
|
|
4032
|
+
invested: Decimal;
|
|
4033
|
+
investedInReserves: Map<Address, Decimal>;
|
|
4034
|
+
pendingFees: Decimal;
|
|
4035
|
+
totalAUMIncludingFees: Decimal;
|
|
4036
|
+
}) {
|
|
4037
|
+
this.available = params.available;
|
|
4038
|
+
this.invested = params.invested;
|
|
4039
|
+
this.investedInReserves = params.investedInReserves;
|
|
4040
|
+
this.pendingFees = params.pendingFees;
|
|
4041
|
+
this.totalAUMIncludingFees = params.totalAUMIncludingFees;
|
|
4042
|
+
}
|
|
4043
|
+
|
|
4044
|
+
asJSON() {
|
|
4045
|
+
return {
|
|
4046
|
+
available: this.available.toString(),
|
|
4047
|
+
invested: this.invested.toString(),
|
|
4048
|
+
totalAUMIncludingFees: this.totalAUMIncludingFees.toString(),
|
|
4049
|
+
pendingFees: this.pendingFees.toString(),
|
|
4050
|
+
investedInReserves: pubkeyHashMapToJson(this.investedInReserves),
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
print() {
|
|
4055
|
+
console.log('Holdings:');
|
|
4056
|
+
console.log(' Available:', this.available.toString());
|
|
4057
|
+
console.log(' Invested:', this.invested.toString());
|
|
4058
|
+
console.log(' Total AUM including fees:', this.totalAUMIncludingFees.toString());
|
|
4059
|
+
console.log(' Pending fees:', this.pendingFees.toString());
|
|
4060
|
+
console.log(' Invested in reserves:', pubkeyHashMapToJson(this.investedInReserves));
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
3466
4063
|
|
|
3467
4064
|
/**
|
|
3468
4065
|
* earnedInterest represents the interest earned from now until the slot provided in the future
|
|
@@ -3518,6 +4115,7 @@ export type VaultOverview = {
|
|
|
3518
4115
|
actualSupplyAPY: APYs;
|
|
3519
4116
|
vaultFarmIncentives: FarmIncentives;
|
|
3520
4117
|
reservesFarmsIncentives: VaultReservesFarmsIncentives;
|
|
4118
|
+
delegatedFarmIncentives: FarmIncentives;
|
|
3521
4119
|
totalBorrowed: Decimal;
|
|
3522
4120
|
totalBorrowedUSD: Decimal;
|
|
3523
4121
|
totalSupplied: Decimal;
|
|
@@ -3545,11 +4143,9 @@ export type VaultCumulativeInterestWithTimestamp = {
|
|
|
3545
4143
|
timestamp: number;
|
|
3546
4144
|
};
|
|
3547
4145
|
|
|
3548
|
-
export
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
console.log(' Invested in reserves:', pubkeyHashMapToJson(holdings.investedInReserves));
|
|
3555
|
-
}
|
|
4146
|
+
export type PendingRewardsForUserInVault = {
|
|
4147
|
+
pendingRewardsInVaultFarm: Map<Address, Decimal>;
|
|
4148
|
+
pendingRewardsInVaultDelegatedFarm: Map<Address, Decimal>;
|
|
4149
|
+
pendingRewardsInVaultReservesFarms: Map<Address, Decimal>;
|
|
4150
|
+
totalPendingRewards: Map<Address, Decimal>;
|
|
4151
|
+
};
|