@kamino-finance/klend-sdk 7.3.2 → 7.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -49,6 +49,9 @@ import {
49
49
  buy,
50
50
  BuyAccounts,
51
51
  BuyArgs,
52
+ deposit,
53
+ DepositAccounts,
54
+ DepositArgs,
52
55
  giveUpPendingFees,
53
56
  GiveUpPendingFeesAccounts,
54
57
  GiveUpPendingFeesArgs,
@@ -70,6 +73,9 @@ import {
70
73
  updateVaultConfig,
71
74
  UpdateVaultConfigAccounts,
72
75
  UpdateVaultConfigArgs,
76
+ withdraw,
77
+ WithdrawAccounts,
78
+ WithdrawArgs,
73
79
  withdrawFromAvailable,
74
80
  WithdrawFromAvailableAccounts,
75
81
  WithdrawFromAvailableArgs,
@@ -139,6 +145,7 @@ import { Farms } from '@kamino-finance/farms-sdk';
139
145
  import { getFarmIncentives } from '@kamino-finance/farms-sdk/dist/utils/apy';
140
146
  import { computeReservesAllocation } from '../utils/vaultAllocation';
141
147
  import { getReserveFarmRewardsAPY } from '../utils/farmUtils';
148
+ import { fetchKaminoCdnData } from '../utils/readCdnData';
142
149
 
143
150
  export const kaminoVaultId = address('KvauGMspG5k6rtzrqqn7WNn3oZdyKqLKwK2XWQ8FLjd');
144
151
  export const kaminoVaultStagingId = address('stKvQfwRsQiKnLtMNVLHKS3exFJmZFsgfzBPWHECUYK');
@@ -1191,6 +1198,27 @@ export class KaminoVaultClient {
1191
1198
  tokenAmount: Decimal,
1192
1199
  vaultReservesMap?: Map<Address, KaminoReserve>,
1193
1200
  farmState?: FarmState
1201
+ ): Promise<DepositIxs> {
1202
+ return this.buildShareEntryIxs('deposit', user, vault, tokenAmount, vaultReservesMap, farmState);
1203
+ }
1204
+
1205
+ async buySharesIxs(
1206
+ user: TransactionSigner,
1207
+ vault: KaminoVault,
1208
+ tokenAmount: Decimal,
1209
+ vaultReservesMap?: Map<Address, KaminoReserve>,
1210
+ farmState?: FarmState
1211
+ ): Promise<DepositIxs> {
1212
+ return this.buildShareEntryIxs('buy', user, vault, tokenAmount, vaultReservesMap, farmState);
1213
+ }
1214
+
1215
+ private async buildShareEntryIxs(
1216
+ mode: 'deposit' | 'buy',
1217
+ user: TransactionSigner,
1218
+ vault: KaminoVault,
1219
+ tokenAmount: Decimal,
1220
+ vaultReservesMap?: Map<Address, KaminoReserve>,
1221
+ farmState?: FarmState
1194
1222
  ): Promise<DepositIxs> {
1195
1223
  const vaultState = await vault.getState();
1196
1224
 
@@ -1225,49 +1253,66 @@ export class KaminoVaultClient {
1225
1253
  createAtasIxs.push(createSharesAtaIxs);
1226
1254
 
1227
1255
  const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
1228
- const buyAccounts: BuyAccounts = {
1229
- user: user,
1230
- vaultState: vault.address,
1231
- tokenVault: vaultState.tokenVault,
1232
- tokenMint: vaultState.tokenMint,
1233
- baseVaultAuthority: vaultState.baseVaultAuthority,
1234
- sharesMint: vaultState.sharesMint,
1235
- userTokenAta: userTokenAta,
1236
- userSharesAta: userSharesAta,
1237
- tokenProgram: tokenProgramID,
1238
- klendProgram: this._kaminoLendProgramId,
1239
- sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
1240
- eventAuthority: eventAuthority,
1241
- program: this._kaminoVaultProgramId,
1242
- };
1243
-
1244
- const buyArgs: BuyArgs = {
1245
- maxAmount: new BN(
1246
- numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).floor().toString()
1247
- ),
1248
- };
1249
-
1250
- let buyIx = buy(buyArgs, buyAccounts, undefined, this._kaminoVaultProgramId);
1256
+ const tokenAmountLamports = numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).floor();
1257
+ let entryIx: Instruction;
1258
+ if (mode === 'deposit') {
1259
+ const depositAccounts: DepositAccounts = {
1260
+ user,
1261
+ vaultState: vault.address,
1262
+ tokenVault: vaultState.tokenVault,
1263
+ tokenMint: vaultState.tokenMint,
1264
+ baseVaultAuthority: vaultState.baseVaultAuthority,
1265
+ sharesMint: vaultState.sharesMint,
1266
+ userTokenAta,
1267
+ userSharesAta,
1268
+ tokenProgram: tokenProgramID,
1269
+ klendProgram: this._kaminoLendProgramId,
1270
+ sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
1271
+ eventAuthority,
1272
+ program: this._kaminoVaultProgramId,
1273
+ };
1274
+ const depositArgs: DepositArgs = {
1275
+ maxAmount: new BN(tokenAmountLamports.toString()),
1276
+ };
1277
+ entryIx = deposit(depositArgs, depositAccounts, undefined, this._kaminoVaultProgramId);
1278
+ } else {
1279
+ const buyAccounts: BuyAccounts = {
1280
+ user,
1281
+ vaultState: vault.address,
1282
+ tokenVault: vaultState.tokenVault,
1283
+ tokenMint: vaultState.tokenMint,
1284
+ baseVaultAuthority: vaultState.baseVaultAuthority,
1285
+ sharesMint: vaultState.sharesMint,
1286
+ userTokenAta,
1287
+ userSharesAta,
1288
+ tokenProgram: tokenProgramID,
1289
+ klendProgram: this._kaminoLendProgramId,
1290
+ sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
1291
+ eventAuthority,
1292
+ program: this._kaminoVaultProgramId,
1293
+ };
1294
+ const buyArgs: BuyArgs = {
1295
+ maxAmount: new BN(tokenAmountLamports.toString()),
1296
+ };
1297
+ entryIx = buy(buyArgs, buyAccounts, undefined, this._kaminoVaultProgramId);
1298
+ }
1251
1299
 
1252
1300
  const vaultReserves = this.getVaultReserves(vaultState);
1253
-
1254
1301
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
1255
- buyIx = this.appendRemainingAccountsForVaultReserves(buyIx, vaultReserves, vaultReservesState);
1302
+ entryIx = this.appendRemainingAccountsForVaultReserves(entryIx, vaultReserves, vaultReservesState);
1256
1303
 
1257
- const depositIxs: DepositIxs = {
1258
- depositIxs: [...createAtasIxs, buyIx, ...closeAtasIxs],
1304
+ const result: DepositIxs = {
1305
+ depositIxs: [...createAtasIxs, entryIx, ...closeAtasIxs],
1259
1306
  stakeInFarmIfNeededIxs: [],
1260
1307
  };
1261
1308
 
1262
- // if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
1263
1309
  if (!(await vault.hasFarm())) {
1264
- return depositIxs;
1310
+ return result;
1265
1311
  }
1266
1312
 
1267
- // if there is a farm, stake the shares
1268
1313
  const stakeSharesIxs = await this.stakeSharesIxs(user, vault, undefined, farmState);
1269
- depositIxs.stakeInFarmIfNeededIxs = stakeSharesIxs;
1270
- return depositIxs;
1314
+ result.stakeInFarmIfNeededIxs = stakeSharesIxs;
1315
+ return result;
1271
1316
  }
1272
1317
 
1273
1318
  /**
@@ -1317,6 +1362,39 @@ export class KaminoVaultClient {
1317
1362
  slot: Slot,
1318
1363
  vaultReservesMap?: Map<Address, KaminoReserve>,
1319
1364
  farmState?: FarmState
1365
+ ): Promise<WithdrawIxs> {
1366
+ return this.buildShareExitIxs('withdraw', user, vault, shareAmountToWithdraw, slot, vaultReservesMap, farmState);
1367
+ }
1368
+
1369
+ /**
1370
+ * 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
1371
+ * @param user - user to sell shares for vault tokens
1372
+ * @param vault - vault to sell shares from
1373
+ * @param shareAmount - share amount to sell (in tokens, not lamports), in order to withdraw everything, any value > user share amount
1374
+ * @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
1375
+ * @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
1376
+ * @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
1377
+ * @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
1378
+ */
1379
+ async sellSharesIxs(
1380
+ user: TransactionSigner,
1381
+ vault: KaminoVault,
1382
+ shareAmountToWithdraw: Decimal,
1383
+ slot: Slot,
1384
+ vaultReservesMap?: Map<Address, KaminoReserve>,
1385
+ farmState?: FarmState
1386
+ ): Promise<WithdrawIxs> {
1387
+ return this.buildShareExitIxs('sell', user, vault, shareAmountToWithdraw, slot, vaultReservesMap, farmState);
1388
+ }
1389
+
1390
+ private async buildShareExitIxs(
1391
+ mode: 'withdraw' | 'sell',
1392
+ user: TransactionSigner,
1393
+ vault: KaminoVault,
1394
+ shareAmountToWithdraw: Decimal,
1395
+ slot: Slot,
1396
+ vaultReservesMap?: Map<Address, KaminoReserve>,
1397
+ farmState?: FarmState
1320
1398
  ): Promise<WithdrawIxs> {
1321
1399
  const vaultState = await vault.getState();
1322
1400
  const hasFarm = await vault.hasFarm();
@@ -1388,20 +1466,47 @@ export class KaminoVaultClient {
1388
1466
  withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.withdrawIx);
1389
1467
  }
1390
1468
 
1391
- // if the vault has allocations withdraw otherwise wtihdraw from available ix
1392
- const vaultAllocation = vaultState.vaultAllocationStrategy.find(
1469
+ const hasAllocatedReserves = vaultState.vaultAllocationStrategy.some(
1393
1470
  (allocation) => allocation.reserve !== DEFAULT_PUBLIC_KEY
1394
1471
  );
1395
1472
 
1396
- if (vaultAllocation) {
1397
- const withdrawFromVaultIxs = await this.withdrawWithReserveIxs(
1473
+ if (hasAllocatedReserves) {
1474
+ const reserveExitBuilder: ReserveExitInstructionBuilder =
1475
+ mode === 'withdraw'
1476
+ ? (params) =>
1477
+ this.withdrawIx(
1478
+ params.user,
1479
+ params.vault,
1480
+ params.vaultState,
1481
+ params.marketAddress,
1482
+ params.reserve,
1483
+ params.userSharesAta,
1484
+ params.userTokenAta,
1485
+ params.shareAmountLamports,
1486
+ params.vaultReservesState
1487
+ )
1488
+ : (params) =>
1489
+ this.sellIx(
1490
+ params.user,
1491
+ params.vault,
1492
+ params.vaultState,
1493
+ params.marketAddress,
1494
+ params.reserve,
1495
+ params.userSharesAta,
1496
+ params.userTokenAta,
1497
+ params.shareAmountLamports,
1498
+ params.vaultReservesState
1499
+ );
1500
+ const withdrawFromVaultIxs = await this.buildReserveExitIxs({
1398
1501
  user,
1399
1502
  vault,
1400
- sharesToWithdraw,
1401
- totalUserShares,
1503
+ vaultState,
1504
+ shareAmount: sharesToWithdraw,
1505
+ allUserShares: totalUserShares,
1402
1506
  slot,
1403
- vaultReservesMap
1404
- );
1507
+ vaultReservesMap,
1508
+ builder: reserveExitBuilder,
1509
+ });
1405
1510
  withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
1406
1511
  } else {
1407
1512
  const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, vault, sharesToWithdraw);
@@ -1467,16 +1572,16 @@ export class KaminoVaultClient {
1467
1572
  return [createAtaIx, withdrawFromAvailableIxn];
1468
1573
  }
1469
1574
 
1470
- private async withdrawWithReserveIxs(
1471
- user: TransactionSigner,
1472
- vault: KaminoVault,
1473
- shareAmount: Decimal,
1474
- allUserShares: Decimal,
1475
- slot: Slot,
1476
- vaultReservesMap?: Map<Address, KaminoReserve>
1477
- ): Promise<Instruction[]> {
1478
- const vaultState = await vault.getState();
1479
-
1575
+ private async buildReserveExitIxs({
1576
+ user,
1577
+ vault,
1578
+ vaultState,
1579
+ shareAmount,
1580
+ allUserShares,
1581
+ slot,
1582
+ vaultReservesMap,
1583
+ builder,
1584
+ }: BuildReserveExitIxsParams): Promise<Instruction[]> {
1480
1585
  const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
1481
1586
  const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
1482
1587
  const [{ ata: userTokenAta, createAtaIx }] = await createAtasIdempotent(user, [
@@ -1505,32 +1610,32 @@ export class KaminoVaultClient {
1505
1610
  let isFirstWithdraw = true;
1506
1611
 
1507
1612
  if (tokenLeftToWithdraw.lte(0)) {
1508
- // Availabe enough to withdraw all - using the first existent reserve
1509
1613
  const firstReserve = vaultState.vaultAllocationStrategy.find((reserve) => reserve.reserve !== DEFAULT_PUBLIC_KEY);
1614
+ if (!firstReserve) {
1615
+ throw new Error('No reserve available to satisfy withdraw request');
1616
+ }
1510
1617
  if (withdrawAllShares) {
1511
1618
  reserveWithSharesAmountToWithdraw.push({
1512
- reserve: firstReserve!.reserve,
1619
+ reserve: firstReserve.reserve,
1513
1620
  shares: new Decimal(U64_MAX.toString()),
1514
1621
  });
1515
1622
  } else {
1516
1623
  reserveWithSharesAmountToWithdraw.push({
1517
- reserve: firstReserve!.reserve,
1624
+ reserve: firstReserve.reserve,
1518
1625
  shares: shareLamportsToWithdraw,
1519
1626
  });
1520
1627
  }
1521
1628
  } else {
1522
- // Get decreasing order sorted available liquidity to withdraw from each reserve allocated to
1523
1629
  const reserveAllocationAvailableLiquidityToWithdraw = await this.getReserveAllocationAvailableLiquidityToWithdraw(
1524
1630
  vault,
1525
1631
  slot,
1526
1632
  vaultReservesState
1527
1633
  );
1528
- // sort
1529
1634
  const reserveAllocationAvailableLiquidityToWithdrawSorted = [
1530
1635
  ...reserveAllocationAvailableLiquidityToWithdraw.entries(),
1531
1636
  ].sort((a, b) => b[1].sub(a[1]).toNumber());
1532
1637
 
1533
- reserveAllocationAvailableLiquidityToWithdrawSorted.forEach(([key, availableLiquidityToWithdraw], _) => {
1638
+ reserveAllocationAvailableLiquidityToWithdrawSorted.forEach(([key, availableLiquidityToWithdraw]) => {
1534
1639
  if (tokenLeftToWithdraw.gt(0)) {
1535
1640
  let tokensToWithdrawFromReserve = Decimal.min(tokenLeftToWithdraw, availableLiquidityToWithdraw);
1536
1641
  if (isFirstWithdraw) {
@@ -1540,7 +1645,6 @@ export class KaminoVaultClient {
1540
1645
  if (withdrawAllShares) {
1541
1646
  reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: new Decimal(U64_MAX.toString()) });
1542
1647
  } else {
1543
- // round up to the nearest integer the shares to withdraw
1544
1648
  const sharesToWithdrawFromReserve = tokensToWithdrawFromReserve.mul(sharesPerToken).floor();
1545
1649
  reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: sharesToWithdrawFromReserve });
1546
1650
  }
@@ -1552,26 +1656,25 @@ export class KaminoVaultClient {
1552
1656
 
1553
1657
  const withdrawIxs: Instruction[] = [];
1554
1658
  withdrawIxs.push(createAtaIx);
1555
- for (let reserveIndex = 0; reserveIndex < reserveWithSharesAmountToWithdraw.length; reserveIndex++) {
1556
- const reserveWithTokens = reserveWithSharesAmountToWithdraw[reserveIndex];
1659
+ for (const reserveWithTokens of reserveWithSharesAmountToWithdraw) {
1557
1660
  const reserveState = vaultReservesState.get(reserveWithTokens.reserve);
1558
1661
  if (reserveState === undefined) {
1559
1662
  throw new Error(`Reserve ${reserveWithTokens.reserve} not found in vault reserves map`);
1560
1663
  }
1561
1664
  const marketAddress = reserveState.state.lendingMarket;
1562
1665
 
1563
- const sellIx = await this.sellIx(
1666
+ const exitIx = await builder({
1564
1667
  user,
1565
1668
  vault,
1566
1669
  vaultState,
1567
1670
  marketAddress,
1568
- { address: reserveWithTokens.reserve, state: reserveState.state },
1671
+ reserve: { address: reserveWithTokens.reserve, state: reserveState.state },
1569
1672
  userSharesAta,
1570
1673
  userTokenAta,
1571
- reserveWithTokens.shares,
1572
- vaultReservesState
1573
- );
1574
- withdrawIxs.push(sellIx);
1674
+ shareAmountLamports: reserveWithTokens.shares,
1675
+ vaultReservesState,
1676
+ });
1677
+ withdrawIxs.push(exitIx);
1575
1678
  }
1576
1679
 
1577
1680
  return withdrawIxs;
@@ -1847,6 +1950,65 @@ export class KaminoVaultClient {
1847
1950
  return sellIxn;
1848
1951
  }
1849
1952
 
1953
+ private async withdrawIx(
1954
+ user: TransactionSigner,
1955
+ vault: KaminoVault,
1956
+ vaultState: VaultState,
1957
+ marketAddress: Address,
1958
+ reserve: ReserveWithAddress,
1959
+ userSharesAta: Address,
1960
+ userTokenAta: Address,
1961
+ shareAmountLamports: Decimal,
1962
+ vaultReservesState: Map<Address, KaminoReserve>
1963
+ ): Promise<Instruction> {
1964
+ const [lendingMarketAuth] = await lendingMarketAuthPda(marketAddress, this._kaminoLendProgramId);
1965
+
1966
+ const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
1967
+ const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
1968
+ const withdrawAccounts: WithdrawAccounts = {
1969
+ withdrawFromAvailable: {
1970
+ user,
1971
+ vaultState: vault.address,
1972
+ globalConfig: globalConfig,
1973
+ tokenVault: vaultState.tokenVault,
1974
+ baseVaultAuthority: vaultState.baseVaultAuthority,
1975
+ userTokenAta: userTokenAta,
1976
+ tokenMint: vaultState.tokenMint,
1977
+ userSharesAta: userSharesAta,
1978
+ sharesMint: vaultState.sharesMint,
1979
+ tokenProgram: vaultState.tokenProgram,
1980
+ sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
1981
+ klendProgram: this._kaminoLendProgramId,
1982
+ eventAuthority: eventAuthority,
1983
+ program: this._kaminoVaultProgramId,
1984
+ },
1985
+ withdrawFromReserveAccounts: {
1986
+ vaultState: vault.address,
1987
+ reserve: reserve.address,
1988
+ ctokenVault: await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId),
1989
+ lendingMarket: marketAddress,
1990
+ lendingMarketAuthority: lendingMarketAuth,
1991
+ reserveLiquiditySupply: reserve.state.liquidity.supplyVault,
1992
+ reserveCollateralMint: reserve.state.collateral.mintPubkey,
1993
+ reserveCollateralTokenProgram: TOKEN_PROGRAM_ADDRESS,
1994
+ instructionSysvarAccount: SYSVAR_INSTRUCTIONS_ADDRESS,
1995
+ },
1996
+ eventAuthority: eventAuthority,
1997
+ program: this._kaminoVaultProgramId,
1998
+ };
1999
+
2000
+ const withdrawArgs: WithdrawArgs = {
2001
+ sharesAmount: new BN(shareAmountLamports.floor().toString()),
2002
+ };
2003
+
2004
+ let withdrawIxn = withdraw(withdrawArgs, withdrawAccounts, undefined, this._kaminoVaultProgramId);
2005
+
2006
+ const vaultReserves = this.getVaultReserves(vaultState);
2007
+ withdrawIxn = this.appendRemainingAccountsForVaultReserves(withdrawIxn, vaultReserves, vaultReservesState);
2008
+
2009
+ return withdrawIxn;
2010
+ }
2011
+
1850
2012
  private async withdrawFromAvailableIx(
1851
2013
  user: TransactionSigner,
1852
2014
  vault: KaminoVault,
@@ -2581,7 +2743,10 @@ export class KaminoVaultClient {
2581
2743
  const deserializedReserves = await batchFetch(vaultReservesAddresses, (chunk) =>
2582
2744
  this.loadReserializedReserves(chunk)
2583
2745
  );
2584
- const reservesAndOracles = await getTokenOracleData(this.getConnection(), deserializedReserves, oracleAccounts);
2746
+ const [reservesAndOracles, cdnResourcesData] = await Promise.all([
2747
+ getTokenOracleData(this.getConnection(), deserializedReserves, oracleAccounts),
2748
+ fetchKaminoCdnData(),
2749
+ ]);
2585
2750
  const kaminoReserves = new Map<Address, KaminoReserve>();
2586
2751
  reservesAndOracles.forEach(([reserve, oracle], index) => {
2587
2752
  if (!oracle) {
@@ -2596,7 +2761,8 @@ export class KaminoVaultClient {
2596
2761
  reserve,
2597
2762
  oracle,
2598
2763
  this.getConnection(),
2599
- this.recentSlotDurationMs
2764
+ this.recentSlotDurationMs,
2765
+ cdnResourcesData
2600
2766
  );
2601
2767
  kaminoReserves.set(kaminoReserve.address, kaminoReserve);
2602
2768
  });
@@ -4432,3 +4598,28 @@ export type PendingRewardsForUserInVault = {
4432
4598
  pendingRewardsInVaultReservesFarms: Map<Address, Decimal>;
4433
4599
  totalPendingRewards: Map<Address, Decimal>;
4434
4600
  };
4601
+
4602
+ type ReserveExitBuilderParams = {
4603
+ user: TransactionSigner;
4604
+ vault: KaminoVault;
4605
+ vaultState: VaultState;
4606
+ marketAddress: Address;
4607
+ reserve: ReserveWithAddress;
4608
+ userSharesAta: Address;
4609
+ userTokenAta: Address;
4610
+ shareAmountLamports: Decimal;
4611
+ vaultReservesState: Map<Address, KaminoReserve>;
4612
+ };
4613
+
4614
+ type ReserveExitInstructionBuilder = (params: ReserveExitBuilderParams) => Promise<Instruction>;
4615
+
4616
+ type BuildReserveExitIxsParams = {
4617
+ user: TransactionSigner;
4618
+ vault: KaminoVault;
4619
+ vaultState: VaultState;
4620
+ shareAmount: Decimal;
4621
+ allUserShares: Decimal;
4622
+ slot: Slot;
4623
+ vaultReservesMap?: Map<Address, KaminoReserve>;
4624
+ builder: ReserveExitInstructionBuilder;
4625
+ };
@@ -0,0 +1,50 @@
1
+ import { CDN_ENDPOINT } from './constants';
2
+
3
+ /**
4
+ * CDN data structure containing Kamino resources for different networks
5
+ */
6
+ export interface AllKaminoCdnData {
7
+ 'mainnet-beta': KaminoCdnData;
8
+ devnet: KaminoCdnData;
9
+ }
10
+
11
+ /**
12
+ * Kamino CDN data structure
13
+ * This type can be extended with additional fields as needed
14
+ */
15
+ export interface KaminoCdnData {
16
+ /**
17
+ * List of deprecated reserve addresses (pubkeys as strings)
18
+ * Note: This field is named 'deprecatedAssets' in the CDN but represents deprecated reserves
19
+ */
20
+ deprecatedAssets: string[];
21
+ // Additional fields can be added here as they become relevant
22
+ [key: string]: unknown;
23
+ }
24
+
25
+ /**
26
+ * Fetches Kamino CDN data from the resources endpoint
27
+ * @returns Promise resolving to the CDN data for the specified cluster or undefined if fetching/parsing fails
28
+ */
29
+ export async function fetchKaminoCdnData(): Promise<KaminoCdnData | undefined> {
30
+ const url = `${CDN_ENDPOINT}/resources.json`;
31
+
32
+ try {
33
+ const response = await fetch(url);
34
+
35
+ if (!response.ok) {
36
+ throw new Error(`HTTP error! status: ${response.status}`);
37
+ }
38
+
39
+ const text = await response.text();
40
+
41
+ try {
42
+ const data: AllKaminoCdnData = JSON.parse(text);
43
+ return data['mainnet-beta'];
44
+ } catch (parseError) {
45
+ throw new Error('Invalid JSON in response');
46
+ }
47
+ } catch (error) {
48
+ return undefined;
49
+ }
50
+ }