@scallop-io/sui-scallop-sdk 1.3.41 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -305,222 +305,217 @@ export const getMarketPool = async (
305
305
  marketObject?: SuiObjectData | null,
306
306
  coinPrice?: number
307
307
  ): Promise<MarketPool | undefined> => {
308
- try {
309
- coinPrice =
310
- coinPrice ||
311
- (await query.utils.getCoinPrices([poolCoinName]))?.[poolCoinName];
312
-
313
- if (indexer) {
314
- const marketPoolIndexer = await query.indexer.getMarketPool(poolCoinName);
315
- if (!marketPoolIndexer) {
316
- return undefined;
317
- }
318
- marketPoolIndexer.coinPrice = coinPrice ?? marketPoolIndexer.coinPrice;
319
- marketPoolIndexer.coinWrappedType = query.utils.getCoinWrappedType(
320
- marketPoolIndexer.coinName
321
- );
308
+ coinPrice =
309
+ coinPrice ||
310
+ (await query.utils.getCoinPrices([poolCoinName]))?.[poolCoinName];
322
311
 
323
- return marketPoolIndexer;
312
+ if (indexer) {
313
+ const marketPoolIndexer = await query.indexer.getMarketPool(poolCoinName);
314
+ if (!marketPoolIndexer) {
315
+ return undefined;
324
316
  }
317
+ marketPoolIndexer.coinPrice = coinPrice ?? marketPoolIndexer.coinPrice;
318
+ marketPoolIndexer.coinWrappedType = query.utils.getCoinWrappedType(
319
+ marketPoolIndexer.coinName
320
+ );
325
321
 
326
- const marketId = query.address.get('core.market');
327
- marketObject =
328
- marketObject ||
329
- (
330
- await query.cache.queryGetObject(marketId, {
331
- showContent: true,
332
- })
333
- )?.data;
322
+ return marketPoolIndexer;
323
+ }
334
324
 
335
- if (!(marketObject && marketObject.content?.dataType === 'moveObject'))
336
- throw new Error(`Failed to fetch marketObject`);
325
+ const marketId = query.address.get('core.market');
326
+ marketObject =
327
+ marketObject ||
328
+ (
329
+ await query.cache.queryGetObject(marketId, {
330
+ showContent: true,
331
+ })
332
+ )?.data;
337
333
 
338
- const fields = marketObject.content.fields as any;
339
- const coinType = query.utils.parseCoinType(poolCoinName);
340
- // Get balance sheet.
341
- const balanceSheetParentId =
342
- fields.vault.fields.balance_sheets.fields.table.fields.id.id;
343
- const balanceSheetDynamicFieldObjectResponse =
344
- await query.cache.queryGetDynamicFieldObject({
345
- parentId: balanceSheetParentId,
346
- name: {
347
- type: '0x1::type_name::TypeName',
348
- value: {
349
- name: coinType.substring(2),
350
- },
334
+ if (!(marketObject && marketObject.content?.dataType === 'moveObject'))
335
+ throw new Error(`Failed to fetch marketObject`);
336
+
337
+ const fields = marketObject.content.fields as any;
338
+ const coinType = query.utils.parseCoinType(poolCoinName);
339
+ // Get balance sheet.
340
+ const balanceSheetParentId =
341
+ fields.vault.fields.balance_sheets.fields.table.fields.id.id;
342
+ const balanceSheetDynamicFieldObjectResponse =
343
+ await query.cache.queryGetDynamicFieldObject({
344
+ parentId: balanceSheetParentId,
345
+ name: {
346
+ type: '0x1::type_name::TypeName',
347
+ value: {
348
+ name: coinType.substring(2),
351
349
  },
352
- });
350
+ },
351
+ });
353
352
 
354
- const balanceSheetDynamicFieldObject =
355
- balanceSheetDynamicFieldObjectResponse?.data;
353
+ const balanceSheetDynamicFieldObject =
354
+ balanceSheetDynamicFieldObjectResponse?.data;
356
355
 
357
- if (
358
- !(
359
- balanceSheetDynamicFieldObject &&
360
- balanceSheetDynamicFieldObject.content &&
361
- 'fields' in balanceSheetDynamicFieldObject.content
362
- )
356
+ if (
357
+ !(
358
+ balanceSheetDynamicFieldObject &&
359
+ balanceSheetDynamicFieldObject.content &&
360
+ 'fields' in balanceSheetDynamicFieldObject.content
363
361
  )
364
- throw new Error(
365
- `Failed to fetch balanceSheetDynamicFieldObject for ${poolCoinName}: ${balanceSheetDynamicFieldObjectResponse?.error?.code.toString()}`
366
- );
367
- const balanceSheet: BalanceSheet = (
368
- balanceSheetDynamicFieldObject.content.fields as any
369
- ).value.fields;
370
-
371
- // Get borrow index.
372
- const borrowIndexParentId =
373
- fields.borrow_dynamics.fields.table.fields.id.id;
374
- const borrowIndexDynamicFieldObjectResponse =
375
- await query.cache.queryGetDynamicFieldObject({
376
- parentId: borrowIndexParentId,
377
- name: {
378
- type: '0x1::type_name::TypeName',
379
- value: {
380
- name: coinType.substring(2),
381
- },
362
+ )
363
+ throw new Error(
364
+ `Failed to fetch balanceSheetDynamicFieldObject for ${poolCoinName}: ${balanceSheetDynamicFieldObjectResponse?.error?.code.toString()}`
365
+ );
366
+ const balanceSheet: BalanceSheet = (
367
+ balanceSheetDynamicFieldObject.content.fields as any
368
+ ).value.fields;
369
+
370
+ // Get borrow index.
371
+ const borrowIndexParentId = fields.borrow_dynamics.fields.table.fields.id.id;
372
+ const borrowIndexDynamicFieldObjectResponse =
373
+ await query.cache.queryGetDynamicFieldObject({
374
+ parentId: borrowIndexParentId,
375
+ name: {
376
+ type: '0x1::type_name::TypeName',
377
+ value: {
378
+ name: coinType.substring(2),
382
379
  },
383
- });
380
+ },
381
+ });
384
382
 
385
- const borrowIndexDynamicFieldObject =
386
- borrowIndexDynamicFieldObjectResponse?.data;
387
- if (
388
- !(
389
- borrowIndexDynamicFieldObject &&
390
- borrowIndexDynamicFieldObject.content &&
391
- 'fields' in borrowIndexDynamicFieldObject.content
392
- )
383
+ const borrowIndexDynamicFieldObject =
384
+ borrowIndexDynamicFieldObjectResponse?.data;
385
+ if (
386
+ !(
387
+ borrowIndexDynamicFieldObject &&
388
+ borrowIndexDynamicFieldObject.content &&
389
+ 'fields' in borrowIndexDynamicFieldObject.content
393
390
  )
394
- throw new Error(
395
- `Failed to fetch borrowIndexDynamicFieldObject for ${poolCoinName}`
396
- );
397
- const borrowIndex: BorrowIndex = (
398
- borrowIndexDynamicFieldObject.content.fields as any
399
- ).value.fields;
400
-
401
- // Get interest models.
402
- const interestModelParentId =
403
- fields.interest_models.fields.table.fields.id.id;
404
- const interestModelDynamicFieldObjectResponse =
391
+ )
392
+ throw new Error(
393
+ `Failed to fetch borrowIndexDynamicFieldObject for ${poolCoinName}`
394
+ );
395
+ const borrowIndex: BorrowIndex = (
396
+ borrowIndexDynamicFieldObject.content.fields as any
397
+ ).value.fields;
398
+
399
+ // Get interest models.
400
+ const interestModelParentId =
401
+ fields.interest_models.fields.table.fields.id.id;
402
+ const interestModelDynamicFieldObjectResponse =
403
+ await query.cache.queryGetDynamicFieldObject({
404
+ parentId: interestModelParentId,
405
+ name: {
406
+ type: '0x1::type_name::TypeName',
407
+ value: {
408
+ name: coinType.substring(2),
409
+ },
410
+ },
411
+ });
412
+
413
+ const interestModelDynamicFieldObject =
414
+ interestModelDynamicFieldObjectResponse?.data;
415
+ if (
416
+ !(
417
+ interestModelDynamicFieldObject &&
418
+ interestModelDynamicFieldObject.content &&
419
+ 'fields' in interestModelDynamicFieldObject.content
420
+ )
421
+ )
422
+ throw new Error(
423
+ `Failed to fetch interestModelDynamicFieldObject for ${poolCoinName}: ${interestModelDynamicFieldObject}`
424
+ );
425
+ const interestModel: InterestModel = (
426
+ interestModelDynamicFieldObject.content.fields as any
427
+ ).value.fields;
428
+
429
+ // Get borrow fee.
430
+ const getBorrowFee = async () => {
431
+ const borrowFeeDynamicFieldObjectResponse =
405
432
  await query.cache.queryGetDynamicFieldObject({
406
- parentId: interestModelParentId,
433
+ parentId: marketId,
407
434
  name: {
408
- type: '0x1::type_name::TypeName',
435
+ type: `${BORROW_FEE_PROTOCOL_ID}::market_dynamic_keys::BorrowFeeKey`,
409
436
  value: {
410
- name: coinType.substring(2),
437
+ type: {
438
+ name: coinType.substring(2),
439
+ },
411
440
  },
412
441
  },
413
442
  });
414
443
 
415
- const interestModelDynamicFieldObject =
416
- interestModelDynamicFieldObjectResponse?.data;
444
+ const borrowFeeDynamicFieldObject =
445
+ borrowFeeDynamicFieldObjectResponse?.data;
417
446
  if (
418
447
  !(
419
- interestModelDynamicFieldObject &&
420
- interestModelDynamicFieldObject.content &&
421
- 'fields' in interestModelDynamicFieldObject.content
448
+ borrowFeeDynamicFieldObject &&
449
+ borrowFeeDynamicFieldObject.content &&
450
+ 'fields' in borrowFeeDynamicFieldObject.content
422
451
  )
423
452
  )
424
- throw new Error(
425
- `Failed to fetch interestModelDynamicFieldObject for ${poolCoinName}: ${interestModelDynamicFieldObject}`
426
- );
427
- const interestModel: InterestModel = (
428
- interestModelDynamicFieldObject.content.fields as any
429
- ).value.fields;
430
-
431
- // Get borrow fee.
432
- const getBorrowFee = async () => {
433
- const borrowFeeDynamicFieldObjectResponse =
434
- await query.cache.queryGetDynamicFieldObject({
435
- parentId: marketId,
436
- name: {
437
- type: `${BORROW_FEE_PROTOCOL_ID}::market_dynamic_keys::BorrowFeeKey`,
438
- value: {
439
- type: {
440
- name: coinType.substring(2),
441
- },
442
- },
443
- },
444
- });
445
-
446
- const borrowFeeDynamicFieldObject =
447
- borrowFeeDynamicFieldObjectResponse?.data;
448
- if (
449
- !(
450
- borrowFeeDynamicFieldObject &&
451
- borrowFeeDynamicFieldObject.content &&
452
- 'fields' in borrowFeeDynamicFieldObject.content
453
- )
454
- )
455
- return { value: '0' };
456
- return (borrowFeeDynamicFieldObject.content.fields as any).value.fields;
457
- };
453
+ return { value: '0' };
454
+ return (borrowFeeDynamicFieldObject.content.fields as any).value.fields;
455
+ };
458
456
 
459
- const parsedMarketPoolData = parseOriginMarketPoolData({
460
- type: interestModel.type.fields,
461
- maxBorrowRate: interestModel.max_borrow_rate.fields,
462
- interestRate: borrowIndex.interest_rate.fields,
463
- interestRateScale: borrowIndex.interest_rate_scale,
464
- borrowIndex: borrowIndex.borrow_index,
465
- lastUpdated: borrowIndex.last_updated,
466
- cash: balanceSheet.cash,
467
- debt: balanceSheet.debt,
468
- marketCoinSupply: balanceSheet.market_coin_supply,
469
- reserve: balanceSheet.revenue,
470
- reserveFactor: interestModel.revenue_factor.fields,
471
- borrowWeight: interestModel.borrow_weight.fields,
472
- borrowFeeRate: await getBorrowFee(),
473
- baseBorrowRatePerSec: interestModel.base_borrow_rate_per_sec.fields,
474
- borrowRateOnHighKink: interestModel.borrow_rate_on_high_kink.fields,
475
- borrowRateOnMidKink: interestModel.borrow_rate_on_mid_kink.fields,
476
- highKink: interestModel.high_kink.fields,
477
- midKink: interestModel.mid_kink.fields,
478
- minBorrowAmount: interestModel.min_borrow_amount,
479
- });
457
+ const parsedMarketPoolData = parseOriginMarketPoolData({
458
+ type: interestModel.type.fields,
459
+ maxBorrowRate: interestModel.max_borrow_rate.fields,
460
+ interestRate: borrowIndex.interest_rate.fields,
461
+ interestRateScale: borrowIndex.interest_rate_scale,
462
+ borrowIndex: borrowIndex.borrow_index,
463
+ lastUpdated: borrowIndex.last_updated,
464
+ cash: balanceSheet.cash,
465
+ debt: balanceSheet.debt,
466
+ marketCoinSupply: balanceSheet.market_coin_supply,
467
+ reserve: balanceSheet.revenue,
468
+ reserveFactor: interestModel.revenue_factor.fields,
469
+ borrowWeight: interestModel.borrow_weight.fields,
470
+ borrowFeeRate: await getBorrowFee(),
471
+ baseBorrowRatePerSec: interestModel.base_borrow_rate_per_sec.fields,
472
+ borrowRateOnHighKink: interestModel.borrow_rate_on_high_kink.fields,
473
+ borrowRateOnMidKink: interestModel.borrow_rate_on_mid_kink.fields,
474
+ highKink: interestModel.high_kink.fields,
475
+ midKink: interestModel.mid_kink.fields,
476
+ minBorrowAmount: interestModel.min_borrow_amount,
477
+ });
480
478
 
481
- const calculatedMarketPoolData = calculateMarketPoolData(
482
- query.utils,
483
- parsedMarketPoolData
484
- );
479
+ const calculatedMarketPoolData = calculateMarketPoolData(
480
+ query.utils,
481
+ parsedMarketPoolData
482
+ );
485
483
 
486
- const coinDecimal = query.utils.getCoinDecimal(poolCoinName);
487
- const maxSupplyCoin = BigNumber(
488
- (await getSupplyLimit(query.utils, poolCoinName)) ?? '0'
489
- )
490
- .shiftedBy(-coinDecimal)
491
- .toNumber();
492
- const maxBorrowCoin = BigNumber(
493
- (await getBorrowLimit(query.utils, poolCoinName)) ?? '0'
494
- )
495
- .shiftedBy(-coinDecimal)
496
- .toNumber();
484
+ const coinDecimal = query.utils.getCoinDecimal(poolCoinName);
485
+ const maxSupplyCoin = BigNumber(
486
+ (await getSupplyLimit(query.utils, poolCoinName)) ?? '0'
487
+ )
488
+ .shiftedBy(-coinDecimal)
489
+ .toNumber();
490
+ const maxBorrowCoin = BigNumber(
491
+ (await getBorrowLimit(query.utils, poolCoinName)) ?? '0'
492
+ )
493
+ .shiftedBy(-coinDecimal)
494
+ .toNumber();
497
495
 
498
- return {
499
- coinName: poolCoinName,
500
- symbol: query.utils.parseSymbol(poolCoinName),
501
- coinType: query.utils.parseCoinType(poolCoinName),
502
- marketCoinType: query.utils.parseMarketCoinType(poolCoinName),
503
- sCoinType: query.utils.parseSCoinType(
504
- query.utils.parseMarketCoinName(poolCoinName)
505
- ),
506
- coinWrappedType: query.utils.getCoinWrappedType(poolCoinName),
507
- coinDecimal,
508
- coinPrice: coinPrice ?? 0,
509
- highKink: parsedMarketPoolData.highKink,
510
- midKink: parsedMarketPoolData.midKink,
511
- reserveFactor: parsedMarketPoolData.reserveFactor,
512
- borrowWeight: parsedMarketPoolData.borrowWeight,
513
- borrowFee: parsedMarketPoolData.borrowFee,
514
- marketCoinSupplyAmount: parsedMarketPoolData.marketCoinSupplyAmount,
515
- minBorrowAmount: parsedMarketPoolData.minBorrowAmount,
516
- maxSupplyCoin,
517
- maxBorrowCoin,
518
- isIsolated: await isIsolatedAsset(query.utils, poolCoinName),
519
- ...calculatedMarketPoolData,
520
- };
521
- } catch (e: any) {
522
- console.error(e.message);
523
- }
496
+ return {
497
+ coinName: poolCoinName,
498
+ symbol: query.utils.parseSymbol(poolCoinName),
499
+ coinType: query.utils.parseCoinType(poolCoinName),
500
+ marketCoinType: query.utils.parseMarketCoinType(poolCoinName),
501
+ sCoinType: query.utils.parseSCoinType(
502
+ query.utils.parseMarketCoinName(poolCoinName)
503
+ ),
504
+ coinWrappedType: query.utils.getCoinWrappedType(poolCoinName),
505
+ coinDecimal,
506
+ coinPrice: coinPrice ?? 0,
507
+ highKink: parsedMarketPoolData.highKink,
508
+ midKink: parsedMarketPoolData.midKink,
509
+ reserveFactor: parsedMarketPoolData.reserveFactor,
510
+ borrowWeight: parsedMarketPoolData.borrowWeight,
511
+ borrowFee: parsedMarketPoolData.borrowFee,
512
+ marketCoinSupplyAmount: parsedMarketPoolData.marketCoinSupplyAmount,
513
+ minBorrowAmount: parsedMarketPoolData.minBorrowAmount,
514
+ maxSupplyCoin,
515
+ maxBorrowCoin,
516
+ isIsolated: await isIsolatedAsset(query.utils, poolCoinName),
517
+ ...calculatedMarketPoolData,
518
+ };
524
519
  };
525
520
 
526
521
  /**
@@ -51,10 +51,12 @@ export const getLendings = async (
51
51
  ) as SupportStakeMarketCoins[];
52
52
 
53
53
  const coinPrices = await query.utils.getCoinPrices(poolCoinNames);
54
- const marketPools = await query.getMarketPools(poolCoinNames, indexer, {
54
+ const marketPools = await query.getMarketPools(poolCoinNames, {
55
+ indexer,
55
56
  coinPrices,
56
57
  });
57
- const spools = await query.getSpools(stakeMarketCoinNames, indexer, {
58
+ const spools = await query.getSpools(stakeMarketCoinNames, {
59
+ indexer,
58
60
  marketPools,
59
61
  coinPrices,
60
62
  });
@@ -128,7 +130,8 @@ export const getLending = async (
128
130
 
129
131
  marketPool =
130
132
  marketPool ??
131
- (await query.getMarketPool(poolCoinName, indexer, {
133
+ (await query.getMarketPool(poolCoinName, {
134
+ indexer,
132
135
  coinPrice,
133
136
  }));
134
137
 
@@ -138,16 +141,13 @@ export const getLending = async (
138
141
  spool =
139
142
  (spool ??
140
143
  (SUPPORT_SPOOLS as readonly SupportMarketCoins[]).includes(marketCoinName))
141
- ? await query.getSpool(
142
- marketCoinName as SupportStakeMarketCoins,
144
+ ? await query.getSpool(marketCoinName as SupportStakeMarketCoins, {
143
145
  indexer,
144
- {
145
- marketPool,
146
- coinPrices: {
147
- [poolCoinName]: coinPrice,
148
- },
149
- }
150
- )
146
+ marketPool,
147
+ coinPrices: {
148
+ [poolCoinName]: coinPrice,
149
+ },
150
+ })
151
151
  : undefined;
152
152
  // some pool does not have spool
153
153
  // if (!spool) throw new Error(`Failed to fetch spool for ${poolCoinName}`);
@@ -311,7 +311,7 @@ export const getObligationAccounts = async (
311
311
  indexer: boolean = false
312
312
  ) => {
313
313
  const coinPrices = await query.utils.getCoinPrices();
314
- const market = await query.queryMarket(indexer, { coinPrices });
314
+ const market = await query.queryMarket({ indexer, coinPrices });
315
315
  const [coinAmounts, obligations] = await Promise.all([
316
316
  query.getCoinAmounts(undefined, ownerAddress),
317
317
  query.getObligations(ownerAddress),
@@ -357,7 +357,7 @@ export const getObligationAccount = async (
357
357
  ];
358
358
  coinPrices =
359
359
  coinPrices ?? (await query.utils.getCoinPrices(collateralAssetCoinNames));
360
- market = market ?? (await query.queryMarket(indexer, { coinPrices }));
360
+ market = market ?? (await query.queryMarket({ indexer, coinPrices }));
361
361
  coinAmounts =
362
362
  coinAmounts ||
363
363
  (await query.getCoinAmounts(collateralAssetCoinNames, ownerAddress));
@@ -365,8 +365,9 @@ export const getObligationAccount = async (
365
365
  const [obligationQuery, borrowIncentivePools, borrowIncentiveAccounts] =
366
366
  await Promise.all([
367
367
  query.queryObligation(obligationId),
368
- query.getBorrowIncentivePools(undefined, indexer, {
368
+ query.getBorrowIncentivePools(undefined, {
369
369
  coinPrices,
370
+ indexer,
370
371
  }),
371
372
  query.getBorrowIncentiveAccounts(obligationId),
372
373
  ]);
@@ -770,7 +771,7 @@ export const getTotalValueLocked = async (
770
771
  query: ScallopQuery,
771
772
  indexer: boolean = false
772
773
  ) => {
773
- const market = await query.queryMarket(indexer);
774
+ const market = await query.queryMarket({ indexer });
774
775
 
775
776
  let supplyValue = BigNumber(0);
776
777
  let borrowValue = BigNumber(0);
@@ -139,8 +139,8 @@ export const getSCoinSwapRate = async (
139
139
 
140
140
  // Get lending data for both sCoin A and sCoin B
141
141
  const marketPools = await Promise.all([
142
- query.getMarketPool(fromCoinName, false),
143
- query.getMarketPool(toCoinName, false),
142
+ query.getMarketPool(fromCoinName),
143
+ query.getMarketPool(toCoinName),
144
144
  ]);
145
145
  if (marketPools.some((pool) => !pool))
146
146
  throw new Error('Failed to fetch the lendings data');
@@ -43,7 +43,7 @@ export const getSpools = async (
43
43
  coinPrices = coinPrices ?? (await query.utils.getCoinPrices()) ?? {};
44
44
 
45
45
  marketPools =
46
- marketPools ?? (await query.getMarketPools(stakeCoinNames, indexer));
46
+ marketPools ?? (await query.getMarketPools(stakeCoinNames, { indexer }));
47
47
  if (!marketPools)
48
48
  throw new Error(`Fail to fetch marketPools for ${stakeCoinNames}`);
49
49
 
@@ -112,7 +112,7 @@ export const getSpool = async (
112
112
  coinPrices?: CoinPrices
113
113
  ) => {
114
114
  const coinName = query.utils.parseCoinName<SupportStakeCoins>(marketCoinName);
115
- marketPool = marketPool || (await query.getMarketPool(coinName, indexer));
115
+ marketPool = marketPool || (await query.getMarketPool(coinName, { indexer }));
116
116
  if (!marketPool) {
117
117
  throw new Error(`Failed to fetch marketPool for ${marketCoinName}`);
118
118
  }
@@ -11,14 +11,20 @@ export async function callMethodWithIndexerFallback(
11
11
  context: any,
12
12
  ...args: any[]
13
13
  ) {
14
- const indexer = args[args.length - 1]; // Assume last argument is always `indexer`
14
+ const lastArgs = args[args.length - 1]; // Assume last argument is always `indexer`
15
15
 
16
- if (indexer) {
16
+ if (typeof lastArgs === 'object' && lastArgs.indexer) {
17
17
  try {
18
18
  return await method.apply(context, args);
19
19
  } catch (e: any) {
20
20
  console.warn(`Indexer requests failed: ${e}. Retrying without indexer..`);
21
- return await method.apply(context, [...args.slice(0, -1), false]);
21
+ return await method.apply(context, [
22
+ ...args.slice(0, -1),
23
+ {
24
+ ...lastArgs,
25
+ indexer: false,
26
+ },
27
+ ]);
22
28
  }
23
29
  }
24
30
  return await method.apply(context, args);
@@ -38,8 +38,8 @@ const callWithRateLimit = async <T>(
38
38
  tokenBucket: TokenBucket,
39
39
  fn: () => Promise<T>,
40
40
  retryDelayInMs = DEFAULT_INTERVAL_IN_MS,
41
- maxRetries = 30,
42
- backoffFactor = 1.25 // The factor by which to increase the delay
41
+ maxRetries = 15,
42
+ backoffFactor = 2 // The factor by which to increase the delay
43
43
  ): Promise<T | null> => {
44
44
  let retries = 0;
45
45