@scallop-io/sui-scallop-sdk 1.4.6 → 1.4.8
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/constants/index.d.ts +0 -1
- package/dist/constants/poolAddress.d.ts +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1657 -1472
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1866 -1677
- package/dist/index.mjs.map +1 -1
- package/dist/models/scallop.d.ts +1 -2
- package/dist/models/scallopCache.d.ts +16 -10
- package/dist/models/scallopQuery.d.ts +75 -3
- package/dist/queries/poolAddressesQuery.d.ts +2 -0
- package/dist/queries/portfolioQuery.d.ts +66 -3
- package/dist/types/model.d.ts +8 -2
- package/dist/utils/index.d.ts +0 -2
- package/package.json +1 -1
- package/src/constants/index.ts +0 -1
- package/src/constants/poolAddress.ts +93 -25
- package/src/index.ts +0 -1
- package/src/models/scallop.ts +8 -13
- package/src/models/scallopAddress.ts +2 -9
- package/src/models/scallopBuilder.ts +3 -6
- package/src/models/scallopCache.ts +88 -47
- package/src/models/scallopClient.ts +3 -6
- package/src/models/scallopIndexer.ts +1 -5
- package/src/models/scallopQuery.ts +49 -16
- package/src/models/scallopUtils.ts +7 -11
- package/src/queries/coreQuery.ts +4 -4
- package/src/queries/poolAddressesQuery.ts +6 -0
- package/src/queries/portfolioQuery.ts +238 -12
- package/src/queries/sCoinQuery.ts +2 -2
- package/src/types/model.ts +13 -2
- package/src/utils/index.ts +0 -2
- package/src/utils/indexer.ts +3 -1
- package/dist/constants/tokenBucket.d.ts +0 -2
- package/dist/utils/tokenBucket.d.ts +0 -11
- package/src/constants/tokenBucket.ts +0 -2
- package/src/utils/tokenBucket.ts +0 -68
|
@@ -26,9 +26,12 @@ import type {
|
|
|
26
26
|
ObligationBorrowIcentiveReward,
|
|
27
27
|
SupportBorrowIncentiveRewardCoins,
|
|
28
28
|
SupportAssetCoins,
|
|
29
|
+
MarketPools,
|
|
30
|
+
MarketCollaterals,
|
|
29
31
|
} from '../types';
|
|
30
32
|
import { SuiObjectRef } from '@mysten/sui/client';
|
|
31
33
|
import { queryMultipleObjects } from './objectsQuery';
|
|
34
|
+
import { normalizeStructTag, SUI_TYPE_ARG } from '@scallop-io/sui-kit';
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
37
|
* Get user lending infomation for specific pools.
|
|
@@ -43,6 +46,8 @@ export const getLendings = async (
|
|
|
43
46
|
query: ScallopQuery,
|
|
44
47
|
poolCoinNames: SupportPoolCoins[] = [...SUPPORT_POOLS],
|
|
45
48
|
ownerAddress?: string,
|
|
49
|
+
marketPools?: MarketPools,
|
|
50
|
+
coinPrices?: CoinPrices,
|
|
46
51
|
indexer: boolean = false
|
|
47
52
|
) => {
|
|
48
53
|
const marketCoinNames = poolCoinNames.map((poolCoinName) =>
|
|
@@ -52,13 +57,15 @@ export const getLendings = async (
|
|
|
52
57
|
(SUPPORT_SPOOLS as readonly SupportMarketCoins[]).includes(marketCoinName)
|
|
53
58
|
) as SupportStakeMarketCoins[];
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
coinPrices = coinPrices ?? (await query.utils.getCoinPrices());
|
|
61
|
+
marketPools =
|
|
62
|
+
marketPools ??
|
|
63
|
+
(
|
|
64
|
+
await query.getMarketPools(poolCoinNames, {
|
|
65
|
+
indexer,
|
|
66
|
+
coinPrices,
|
|
67
|
+
})
|
|
68
|
+
).pools;
|
|
62
69
|
|
|
63
70
|
const spools = await query.getSpools(stakeMarketCoinNames, {
|
|
64
71
|
indexer,
|
|
@@ -311,12 +318,19 @@ export const getLending = async (
|
|
|
311
318
|
export const getObligationAccounts = async (
|
|
312
319
|
query: ScallopQuery,
|
|
313
320
|
ownerAddress?: string,
|
|
321
|
+
market?: {
|
|
322
|
+
pools: MarketPools;
|
|
323
|
+
collaterals: MarketCollaterals;
|
|
324
|
+
},
|
|
325
|
+
coinPrices?: CoinPrices,
|
|
314
326
|
indexer: boolean = false
|
|
315
327
|
) => {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
328
|
+
market = market ?? (await query.getMarketPools(undefined, { indexer }));
|
|
329
|
+
coinPrices =
|
|
330
|
+
coinPrices ??
|
|
331
|
+
(await query.getAllCoinPrices({
|
|
332
|
+
marketPools: market.pools,
|
|
333
|
+
}));
|
|
320
334
|
const [coinAmounts, obligations] = await Promise.all([
|
|
321
335
|
query.getCoinAmounts(undefined, ownerAddress),
|
|
322
336
|
query.getObligations(ownerAddress),
|
|
@@ -379,7 +393,6 @@ export const getObligationAccount = async (
|
|
|
379
393
|
query.queryObligation(obligation),
|
|
380
394
|
query.getBorrowIncentivePools(undefined, {
|
|
381
395
|
coinPrices,
|
|
382
|
-
indexer,
|
|
383
396
|
marketPools: market.pools,
|
|
384
397
|
}),
|
|
385
398
|
query.getBorrowIncentiveAccounts(obligation),
|
|
@@ -838,3 +851,216 @@ export const getTotalValueLocked = async (
|
|
|
838
851
|
|
|
839
852
|
return tvl;
|
|
840
853
|
};
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Get user portfolio by wallet address
|
|
857
|
+
*/
|
|
858
|
+
export const getUserPortfolio = async (
|
|
859
|
+
query: ScallopQuery,
|
|
860
|
+
walletAddress: string,
|
|
861
|
+
indexer: boolean = false
|
|
862
|
+
) => {
|
|
863
|
+
const coinPrices = await query.utils.getCoinPrices();
|
|
864
|
+
const market = await query.getMarketPools(undefined, { indexer, coinPrices });
|
|
865
|
+
|
|
866
|
+
const [lendings, obligationAccounts, borrowIncentivePools, veScas] =
|
|
867
|
+
await Promise.all([
|
|
868
|
+
query.getLendings(undefined, walletAddress, {
|
|
869
|
+
indexer,
|
|
870
|
+
marketPools: market.pools,
|
|
871
|
+
coinPrices,
|
|
872
|
+
}),
|
|
873
|
+
query.getObligationAccounts(walletAddress, {
|
|
874
|
+
indexer,
|
|
875
|
+
market: market,
|
|
876
|
+
coinPrices,
|
|
877
|
+
}),
|
|
878
|
+
query.getBorrowIncentivePools(undefined, {
|
|
879
|
+
marketPools: market.pools,
|
|
880
|
+
coinPrices,
|
|
881
|
+
}),
|
|
882
|
+
query.getVeScas({ walletAddress, excludeEmpty: true }),
|
|
883
|
+
]);
|
|
884
|
+
|
|
885
|
+
// get pending rewards (spool and borrow incentive)
|
|
886
|
+
const parsedLendings = Object.values(lendings)
|
|
887
|
+
.filter((t) => t.availableWithdrawCoin > 0)
|
|
888
|
+
.map((lending) => ({
|
|
889
|
+
suppliedCoin: lending.availableWithdrawCoin,
|
|
890
|
+
suppliedValue: lending.suppliedValue,
|
|
891
|
+
stakedCoin: lending.availableUnstakeCoin,
|
|
892
|
+
coinName: lending.coinName,
|
|
893
|
+
symbol: lending.symbol,
|
|
894
|
+
coinType: lending.coinType,
|
|
895
|
+
coinPrice: lending.coinPrice,
|
|
896
|
+
coinDecimals: lending.coinDecimal,
|
|
897
|
+
supplyApr: lending.supplyApr,
|
|
898
|
+
supplyApy: lending.supplyApy,
|
|
899
|
+
incentiveApr: isFinite(lending.rewardApr) ? lending.rewardApr : 0,
|
|
900
|
+
}));
|
|
901
|
+
|
|
902
|
+
const parsedObligationAccounts = Object.values(obligationAccounts)
|
|
903
|
+
.filter(
|
|
904
|
+
(t): t is NonNullable<typeof t> =>
|
|
905
|
+
!!t && t.totalBorrowedValueWithWeight > 0
|
|
906
|
+
)
|
|
907
|
+
.map((obligationAccount) => {
|
|
908
|
+
return {
|
|
909
|
+
obligationId: obligationAccount.obligationId,
|
|
910
|
+
totalDebtsInUsd: obligationAccount.totalBorrowedValueWithWeight,
|
|
911
|
+
totalCollateralInUsd: obligationAccount.totalDepositedValue,
|
|
912
|
+
riskLevel: obligationAccount.totalRiskLevel,
|
|
913
|
+
availableCollateralInUsd:
|
|
914
|
+
obligationAccount.totalAvailableCollateralValue,
|
|
915
|
+
totalUnhealthyCollateralInUsd:
|
|
916
|
+
obligationAccount.totalUnhealthyCollateralValue,
|
|
917
|
+
borrowedPools: Object.values(obligationAccount.debts)
|
|
918
|
+
.filter((debt) => debt.borrowedCoin > 0)
|
|
919
|
+
.map((debt) => ({
|
|
920
|
+
coinName: debt.coinName,
|
|
921
|
+
symbol: debt.symbol,
|
|
922
|
+
coinDecimals: debt.coinDecimal,
|
|
923
|
+
coinType: debt.coinType,
|
|
924
|
+
coinPrice: debt.coinPrice,
|
|
925
|
+
borrowedCoin: debt.borrowedCoin,
|
|
926
|
+
borrowedValueInUsd: debt.borrowedValueWithWeight,
|
|
927
|
+
borrowApr: market.pools[debt.coinName]?.borrowApr,
|
|
928
|
+
borrowApy: market.pools[debt.coinName]?.borrowApy,
|
|
929
|
+
incentiveInfos: Object.values(
|
|
930
|
+
borrowIncentivePools[debt.coinName]?.points ?? {}
|
|
931
|
+
)
|
|
932
|
+
.filter((t) => isFinite(t.rewardApr))
|
|
933
|
+
.map((t) => ({
|
|
934
|
+
coinName: t.coinName,
|
|
935
|
+
symbol: t.symbol,
|
|
936
|
+
coinType: t.coinType,
|
|
937
|
+
incentiveApr: t.rewardApr,
|
|
938
|
+
})),
|
|
939
|
+
})),
|
|
940
|
+
};
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
const pendingLendingRewards = Object.values(lendings).reduce(
|
|
944
|
+
(acc, reward) => {
|
|
945
|
+
if (reward.availableClaimCoin === 0) return acc;
|
|
946
|
+
if (!acc[reward.symbol]) {
|
|
947
|
+
acc[reward.symbol] = {
|
|
948
|
+
symbol: reward.symbol,
|
|
949
|
+
coinType: normalizeStructTag(SUI_TYPE_ARG), // @TODO: for now lending reward is all in SUI
|
|
950
|
+
coinPrice: reward.coinPrice,
|
|
951
|
+
pendingRewardInCoin: reward.availableClaimCoin,
|
|
952
|
+
};
|
|
953
|
+
} else {
|
|
954
|
+
acc[reward.symbol].pendingRewardInCoin += reward.availableClaimCoin;
|
|
955
|
+
}
|
|
956
|
+
return acc;
|
|
957
|
+
},
|
|
958
|
+
{} as Record<
|
|
959
|
+
string,
|
|
960
|
+
{
|
|
961
|
+
coinType: string;
|
|
962
|
+
symbol: string;
|
|
963
|
+
coinPrice: number;
|
|
964
|
+
pendingRewardInCoin: number;
|
|
965
|
+
}
|
|
966
|
+
>
|
|
967
|
+
);
|
|
968
|
+
|
|
969
|
+
const pendingBorrowIncentiveRewards = Object.values(obligationAccounts)
|
|
970
|
+
.filter((t): t is NonNullable<typeof t> => !!t)
|
|
971
|
+
.reduce(
|
|
972
|
+
(acc, curr) => {
|
|
973
|
+
Object.values(curr.borrowIncentives).forEach((incentive) => {
|
|
974
|
+
incentive.rewards.forEach((reward) => {
|
|
975
|
+
if (reward.availableClaimCoin === 0) return acc;
|
|
976
|
+
if (!acc[reward.coinName]) {
|
|
977
|
+
acc[reward.coinName] = {
|
|
978
|
+
symbol: reward.symbol,
|
|
979
|
+
coinType: reward.coinType,
|
|
980
|
+
coinPrice: reward.coinPrice,
|
|
981
|
+
pendingRewardInCoin: reward.availableClaimCoin,
|
|
982
|
+
};
|
|
983
|
+
} else {
|
|
984
|
+
acc[reward.coinName].pendingRewardInCoin +=
|
|
985
|
+
reward.availableClaimCoin;
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
});
|
|
989
|
+
return acc;
|
|
990
|
+
},
|
|
991
|
+
{} as Record<
|
|
992
|
+
string,
|
|
993
|
+
{
|
|
994
|
+
coinType: string;
|
|
995
|
+
symbol: string;
|
|
996
|
+
coinPrice: number;
|
|
997
|
+
pendingRewardInCoin: number;
|
|
998
|
+
}
|
|
999
|
+
>
|
|
1000
|
+
);
|
|
1001
|
+
|
|
1002
|
+
const parsedVeScas = veScas.map(
|
|
1003
|
+
({ keyId, lockedScaCoin, currentVeScaBalance, unlockAt }) => ({
|
|
1004
|
+
veScaKey: keyId,
|
|
1005
|
+
coinPrice: coinPrices.sca ?? 0,
|
|
1006
|
+
lockedScaInCoin: lockedScaCoin,
|
|
1007
|
+
lockedScaInUsd: lockedScaCoin * (coinPrices.sca ?? 0),
|
|
1008
|
+
currentVeScaBalance,
|
|
1009
|
+
remainingLockPeriodInDays:
|
|
1010
|
+
unlockAt - Date.now() > 0 ? (unlockAt - Date.now()) / 86400000 : 0,
|
|
1011
|
+
unlockAt,
|
|
1012
|
+
})
|
|
1013
|
+
);
|
|
1014
|
+
|
|
1015
|
+
return {
|
|
1016
|
+
totalSupplyValue: parsedLendings.reduce((acc, curr) => {
|
|
1017
|
+
acc += curr.suppliedValue;
|
|
1018
|
+
return acc;
|
|
1019
|
+
}, 0),
|
|
1020
|
+
...parsedObligationAccounts.reduce(
|
|
1021
|
+
(acc, curr) => {
|
|
1022
|
+
acc.totalDebtValue += curr.totalDebtsInUsd;
|
|
1023
|
+
acc.totalCollateralValue += curr.totalCollateralInUsd;
|
|
1024
|
+
return acc;
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
totalDebtValue: 0,
|
|
1028
|
+
totalCollateralValue: 0,
|
|
1029
|
+
} as {
|
|
1030
|
+
totalDebtValue: number;
|
|
1031
|
+
totalCollateralValue: number;
|
|
1032
|
+
}
|
|
1033
|
+
),
|
|
1034
|
+
totalLockedScaValue: parsedVeScas.reduce((acc, curr) => {
|
|
1035
|
+
acc += curr.lockedScaInUsd;
|
|
1036
|
+
return acc;
|
|
1037
|
+
}, 0),
|
|
1038
|
+
lendings: parsedLendings,
|
|
1039
|
+
borrowings: parsedObligationAccounts,
|
|
1040
|
+
pendingRewards: {
|
|
1041
|
+
lendings: Object.entries(pendingLendingRewards).reduce(
|
|
1042
|
+
(acc, [key, value]) => {
|
|
1043
|
+
acc.push({
|
|
1044
|
+
...value,
|
|
1045
|
+
coinName: key,
|
|
1046
|
+
pendingRewardInUsd: value.coinPrice * value.pendingRewardInCoin,
|
|
1047
|
+
});
|
|
1048
|
+
return acc;
|
|
1049
|
+
},
|
|
1050
|
+
[] as any
|
|
1051
|
+
),
|
|
1052
|
+
borrowIncentives: Object.entries(pendingBorrowIncentiveRewards).reduce(
|
|
1053
|
+
(acc, [key, value]) => {
|
|
1054
|
+
acc.push({
|
|
1055
|
+
coinName: key,
|
|
1056
|
+
...value,
|
|
1057
|
+
pendingRewardInUsd: value.coinPrice * value.pendingRewardInCoin,
|
|
1058
|
+
});
|
|
1059
|
+
return acc;
|
|
1060
|
+
},
|
|
1061
|
+
[] as any
|
|
1062
|
+
),
|
|
1063
|
+
},
|
|
1064
|
+
veScas: parsedVeScas,
|
|
1065
|
+
};
|
|
1066
|
+
};
|
|
@@ -95,11 +95,11 @@ export const getSCoinAmount = async (
|
|
|
95
95
|
) => {
|
|
96
96
|
const owner = ownerAddress || utils.suiKit.currentAddress();
|
|
97
97
|
const sCoinType = utils.parseSCoinType(sCoinName);
|
|
98
|
-
const
|
|
98
|
+
const coinBalance = await utils.cache.queryGetCoinBalance({
|
|
99
99
|
owner,
|
|
100
100
|
coinType: sCoinType,
|
|
101
101
|
});
|
|
102
|
-
return BigNumber(
|
|
102
|
+
return BigNumber(coinBalance?.totalBalance ?? '0').toNumber();
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
const isSupportStakeCoins = (value: string): value is SupportSCoin => {
|
package/src/types/model.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
} from '../models';
|
|
11
11
|
import { ScallopCache } from 'src/models/scallopCache';
|
|
12
12
|
import { AddressesInterface } from './address';
|
|
13
|
+
import { QueryClient, QueryClientConfig } from '@tanstack/query-core';
|
|
13
14
|
|
|
14
15
|
export type ScallopClientFnReturnType<T extends boolean> = T extends true
|
|
15
16
|
? SuiTransactionBlockResponse
|
|
@@ -26,7 +27,9 @@ export type ScallopBaseInstanceParams = {
|
|
|
26
27
|
suiKit?: SuiKit;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
export type ScallopCacheInstanceParams = ScallopBaseInstanceParams
|
|
30
|
+
export type ScallopCacheInstanceParams = ScallopBaseInstanceParams & {
|
|
31
|
+
queryClient?: QueryClient;
|
|
32
|
+
};
|
|
30
33
|
|
|
31
34
|
export type ScallopAddressInstanceParams = ScallopBaseInstanceParams & {
|
|
32
35
|
cache?: ScallopCache;
|
|
@@ -69,7 +72,8 @@ export type ScallopParams = {
|
|
|
69
72
|
export type ScallopClientParams = ScallopParams &
|
|
70
73
|
ScallopBuilderParams &
|
|
71
74
|
ScallopQueryParams &
|
|
72
|
-
ScallopUtilsParams
|
|
75
|
+
ScallopUtilsParams &
|
|
76
|
+
ScallopCacheParams;
|
|
73
77
|
|
|
74
78
|
export type ScallopBuilderParams = ScallopParams & {
|
|
75
79
|
pythEndpoints?: string[];
|
|
@@ -81,3 +85,10 @@ export type ScallopQueryParams = ScallopParams & ScallopUtilsParams;
|
|
|
81
85
|
export type ScallopUtilsParams = ScallopParams & {
|
|
82
86
|
pythEndpoints?: string[];
|
|
83
87
|
};
|
|
88
|
+
|
|
89
|
+
export type ScallopCacheParams = Omit<
|
|
90
|
+
ScallopParams,
|
|
91
|
+
'addressId' | 'forceAddressesInterface'
|
|
92
|
+
> & {
|
|
93
|
+
cacheOptions?: QueryClientConfig;
|
|
94
|
+
};
|
package/src/utils/index.ts
CHANGED
package/src/utils/indexer.ts
CHANGED
|
@@ -17,7 +17,9 @@ export async function callMethodWithIndexerFallback(
|
|
|
17
17
|
try {
|
|
18
18
|
return await method.apply(context, args);
|
|
19
19
|
} catch (e: any) {
|
|
20
|
-
console.warn(
|
|
20
|
+
console.warn(
|
|
21
|
+
`Indexer requests failed: ${e.message}. Retrying without indexer..`
|
|
22
|
+
);
|
|
21
23
|
return await method.apply(context, [
|
|
22
24
|
...args.slice(0, -1),
|
|
23
25
|
{
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
declare class TokenBucket {
|
|
2
|
-
private tokensPerInterval;
|
|
3
|
-
private interval;
|
|
4
|
-
private tokens;
|
|
5
|
-
private lastRefill;
|
|
6
|
-
constructor(tokensPerInterval: number, intervalInMs: number);
|
|
7
|
-
refill(): void;
|
|
8
|
-
removeTokens(count: number): boolean;
|
|
9
|
-
}
|
|
10
|
-
declare const callWithRateLimit: <T>(tokenBucket: TokenBucket, fn: () => Promise<T>, retryDelayInMs?: number, maxRetries?: number, backoffFactor?: number) => Promise<T | null>;
|
|
11
|
-
export { TokenBucket, callWithRateLimit };
|
package/src/utils/tokenBucket.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_INTERVAL_IN_MS } from 'src/constants/tokenBucket';
|
|
2
|
-
|
|
3
|
-
class TokenBucket {
|
|
4
|
-
private tokensPerInterval: number;
|
|
5
|
-
private interval: number;
|
|
6
|
-
private tokens: number;
|
|
7
|
-
private lastRefill: number;
|
|
8
|
-
|
|
9
|
-
constructor(tokensPerInterval: number, intervalInMs: number) {
|
|
10
|
-
this.tokensPerInterval = tokensPerInterval;
|
|
11
|
-
this.interval = intervalInMs;
|
|
12
|
-
this.tokens = tokensPerInterval;
|
|
13
|
-
this.lastRefill = Date.now();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
refill() {
|
|
17
|
-
const now = Date.now();
|
|
18
|
-
const elapsed = now - this.lastRefill;
|
|
19
|
-
|
|
20
|
-
if (elapsed >= this.interval) {
|
|
21
|
-
const tokensToAdd =
|
|
22
|
-
Math.floor(elapsed / this.interval) * this.tokensPerInterval;
|
|
23
|
-
this.tokens = Math.min(this.tokens + tokensToAdd, this.tokensPerInterval);
|
|
24
|
-
|
|
25
|
-
// Update lastRefill to reflect the exact time of the last "refill"
|
|
26
|
-
this.lastRefill += Math.floor(elapsed / this.interval) * this.interval;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
removeTokens(count: number) {
|
|
31
|
-
this.refill();
|
|
32
|
-
if (this.tokens >= count) {
|
|
33
|
-
this.tokens -= count;
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const callWithRateLimit = async <T>(
|
|
41
|
-
tokenBucket: TokenBucket,
|
|
42
|
-
fn: () => Promise<T>,
|
|
43
|
-
retryDelayInMs = DEFAULT_INTERVAL_IN_MS,
|
|
44
|
-
maxRetries = 15,
|
|
45
|
-
backoffFactor = 1.25 // The factor by which to increase the delay
|
|
46
|
-
): Promise<T | null> => {
|
|
47
|
-
let retries = 0;
|
|
48
|
-
|
|
49
|
-
const tryRequest = async (): Promise<T | null> => {
|
|
50
|
-
if (tokenBucket.removeTokens(1)) {
|
|
51
|
-
const result = await fn();
|
|
52
|
-
return result;
|
|
53
|
-
} else if (retries < maxRetries) {
|
|
54
|
-
retries++;
|
|
55
|
-
const delay = retryDelayInMs * Math.pow(backoffFactor, retries);
|
|
56
|
-
// console.error(`Rate limit exceeded, retrying in ${delay} ms`);
|
|
57
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
58
|
-
return tryRequest();
|
|
59
|
-
} else {
|
|
60
|
-
console.error('Maximum retries reached');
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
return tryRequest();
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export { TokenBucket, callWithRateLimit };
|