@scallop-io/sui-scallop-sdk 1.4.15-rc.2 → 1.4.16

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.
Files changed (69) hide show
  1. package/dist/constants/common.d.ts +6 -6
  2. package/dist/constants/enum.d.ts +2 -2
  3. package/dist/constants/index.d.ts +0 -1
  4. package/dist/constants/poolAddress.d.ts +2 -0
  5. package/dist/constants/queryKeys.d.ts +3 -4
  6. package/dist/index.d.ts +0 -1
  7. package/dist/index.js +2087 -1617
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +2054 -1579
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/models/scallop.d.ts +1 -2
  12. package/dist/models/scallopBuilder.d.ts +2 -1
  13. package/dist/models/scallopCache.d.ts +18 -12
  14. package/dist/models/scallopQuery.d.ts +98 -11
  15. package/dist/models/scallopUtils.d.ts +4 -4
  16. package/dist/queries/borrowIncentiveQuery.d.ts +6 -1
  17. package/dist/queries/coreQuery.d.ts +2 -0
  18. package/dist/queries/objectsQuery.d.ts +1 -2
  19. package/dist/queries/poolAddressesQuery.d.ts +5 -1
  20. package/dist/queries/portfolioQuery.d.ts +71 -5
  21. package/dist/queries/priceQuery.d.ts +4 -0
  22. package/dist/queries/sCoinQuery.d.ts +1 -1
  23. package/dist/types/builder/core.d.ts +6 -6
  24. package/dist/types/model.d.ts +8 -2
  25. package/dist/utils/index.d.ts +0 -2
  26. package/package.json +7 -7
  27. package/src/builders/borrowIncentiveBuilder.ts +11 -5
  28. package/src/builders/coreBuilder.ts +62 -33
  29. package/src/builders/loyaltyProgramBuilder.ts +3 -2
  30. package/src/builders/referralBuilder.ts +16 -6
  31. package/src/builders/sCoinBuilder.ts +6 -4
  32. package/src/builders/spoolBuilder.ts +14 -7
  33. package/src/builders/vescaBuilder.ts +13 -7
  34. package/src/constants/coinGecko.ts +2 -0
  35. package/src/constants/common.ts +7 -1
  36. package/src/constants/enum.ts +46 -20
  37. package/src/constants/index.ts +0 -1
  38. package/src/constants/poolAddress.ts +252 -66
  39. package/src/constants/pyth.ts +2 -0
  40. package/src/constants/queryKeys.ts +7 -9
  41. package/src/constants/testAddress.ts +24 -0
  42. package/src/index.ts +0 -1
  43. package/src/models/scallop.ts +9 -13
  44. package/src/models/scallopAddress.ts +2 -9
  45. package/src/models/scallopBuilder.ts +62 -8
  46. package/src/models/scallopCache.ts +236 -82
  47. package/src/models/scallopClient.ts +4 -6
  48. package/src/models/scallopIndexer.ts +1 -5
  49. package/src/models/scallopQuery.ts +62 -25
  50. package/src/models/scallopUtils.ts +9 -13
  51. package/src/queries/borrowIncentiveQuery.ts +6 -13
  52. package/src/queries/coreQuery.ts +88 -54
  53. package/src/queries/loyaltyProgramQuery.ts +1 -3
  54. package/src/queries/objectsQuery.ts +1 -3
  55. package/src/queries/poolAddressesQuery.ts +16 -7
  56. package/src/queries/portfolioQuery.ts +253 -21
  57. package/src/queries/priceQuery.ts +2 -7
  58. package/src/queries/sCoinQuery.ts +2 -2
  59. package/src/queries/spoolQuery.ts +21 -20
  60. package/src/queries/vescaQuery.ts +3 -7
  61. package/src/types/builder/core.ts +24 -5
  62. package/src/types/model.ts +13 -2
  63. package/src/utils/index.ts +0 -2
  64. package/src/utils/indexer.ts +3 -1
  65. package/src/utils/query.ts +2 -2
  66. package/dist/constants/tokenBucket.d.ts +0 -2
  67. package/dist/utils/tokenBucket.d.ts +0 -11
  68. package/src/constants/tokenBucket.ts +0 -2
  69. package/src/utils/tokenBucket.ts +0 -68
@@ -7,7 +7,13 @@ import { ScallopQuery } from './scallopQuery';
7
7
  import { ScallopUtils } from './scallopUtils';
8
8
  import type { SuiTransactionBlockResponse } from '@mysten/sui/client';
9
9
  import type { Transaction } from '@mysten/sui/transactions';
10
- import type { SuiTxBlock as SuiKitTxBlock } from '@scallop-io/sui-kit';
10
+ import type {
11
+ SuiAmountsArg,
12
+ SuiTxBlock as SuiKitTxBlock,
13
+ SuiObjectArg,
14
+ SuiTxArg,
15
+ SuiVecTxArg,
16
+ } from '@scallop-io/sui-kit';
11
17
  import type {
12
18
  ScallopBuilderParams,
13
19
  ScallopTxBlock,
@@ -18,7 +24,6 @@ import type {
18
24
  SelectCoinReturnType,
19
25
  } from '../types';
20
26
  import { ScallopCache } from './scallopCache';
21
- import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
22
27
  import { newSuiKit } from './suiKit';
23
28
 
24
29
  /**
@@ -60,11 +65,9 @@ export class ScallopBuilder {
60
65
  this.address = this.utils.address;
61
66
  this.cache = this.address.cache;
62
67
  } else {
63
- this.cache = new ScallopCache(
64
- this.suiKit,
65
- this.walletAddress,
66
- DEFAULT_CACHE_OPTIONS
67
- );
68
+ this.cache = new ScallopCache(this.params, {
69
+ suiKit: this.suiKit,
70
+ });
68
71
  this.address = new ScallopAddress(
69
72
  {
70
73
  id: params?.addressesId ?? ADDRESSES_ID,
@@ -104,7 +107,7 @@ export class ScallopBuilder {
104
107
  await this.address.read();
105
108
  }
106
109
  await this.query.init(force, this.address);
107
- await this.utils.init(force, this.address);
110
+ // await this.utils.init(force, this.address);
108
111
  }
109
112
 
110
113
  /**
@@ -215,4 +218,55 @@ export class ScallopBuilder {
215
218
  txBlock
216
219
  )) as SuiTransactionBlockResponse;
217
220
  }
221
+
222
+ public moveCall(
223
+ txb: ScallopTxBlock | SuiKitTxBlock,
224
+ target: string,
225
+ args?: (SuiTxArg | SuiVecTxArg | SuiObjectArg | SuiAmountsArg)[],
226
+ typeArgs?: string[]
227
+ ) {
228
+ // Disable for now
229
+ // const resolvedQueryTarget =
230
+ // await this.cache.queryGetNormalizedMoveFunction(target);
231
+ // if (!resolvedQueryTarget) throw new Error('Invalid query target');
232
+
233
+ // const { parameters } = resolvedQueryTarget;
234
+ // try {
235
+ // // we can try resolve the args first
236
+ // const resolvedArgs = await Promise.all(
237
+ // (args ?? []).map(async (arg, idx) => {
238
+ // if (typeof arg !== 'string') return arg;
239
+
240
+ // const cachedData = (await this.cache.queryGetObject(arg))?.data;
241
+ // if (!cachedData) return arg;
242
+
243
+ // const owner = cachedData.owner;
244
+ // if (!owner || typeof owner !== 'object' || !('Shared' in owner))
245
+ // return {
246
+ // objectId: cachedData.objectId,
247
+ // version: cachedData.version,
248
+ // digest: cachedData.digest,
249
+ // };
250
+
251
+ // const parameter = parameters[idx];
252
+ // if (
253
+ // typeof parameter !== 'object' ||
254
+ // !('MutableReference' in parameter || 'Reference' in parameter)
255
+ // )
256
+ // return arg;
257
+
258
+ // return {
259
+ // objectId: cachedData.objectId,
260
+ // initialSharedVersion: owner.Shared.initial_shared_version,
261
+ // mutable: 'MutableReference' in parameter,
262
+ // };
263
+ // })
264
+ // );
265
+ // return txb.moveCall(target, resolvedArgs, typeArgs);
266
+ // } catch (e: any) {
267
+ // console.error(e.message);
268
+ // return txb.moveCall(target, args, typeArgs);
269
+ // }
270
+ return txb.moveCall(target, args, typeArgs);
271
+ }
218
272
  }
@@ -1,8 +1,9 @@
1
- import { QueryClient, QueryClientConfig } from '@tanstack/query-core';
1
+ import { QueryClient } from '@tanstack/query-core';
2
2
  import {
3
3
  SuiObjectArg,
4
4
  SuiTxBlock,
5
5
  normalizeStructTag,
6
+ parseStructTag,
6
7
  } from '@scallop-io/sui-kit';
7
8
  import { SuiKit } from '@scallop-io/sui-kit';
8
9
  import type {
@@ -16,14 +17,12 @@ import type {
16
17
  GetDynamicFieldObjectParams,
17
18
  GetBalanceParams,
18
19
  SuiClient,
20
+ CoinBalance,
19
21
  } from '@mysten/sui/client';
20
22
  import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
21
- import { callWithRateLimit, TokenBucket } from 'src/utils';
22
- import {
23
- DEFAULT_INTERVAL_IN_MS,
24
- DEFAULT_TOKENS_PER_INTERVAL,
25
- } from 'src/constants/tokenBucket';
26
23
  import { queryKeys } from 'src/constants';
24
+ import { ScallopCacheInstanceParams, ScallopCacheParams } from 'src/types';
25
+ import { newSuiKit } from './suiKit';
27
26
 
28
27
  type QueryInspectTxnParams = {
29
28
  queryTarget: string;
@@ -31,6 +30,32 @@ type QueryInspectTxnParams = {
31
30
  typeArgs?: any[];
32
31
  };
33
32
 
33
+ const DEFAULT_TOKENS_PER_INTERVAL = 10;
34
+ const DEFAULT_INTERVAL_IN_MS = 250;
35
+
36
+ const deepMergeObject = <T>(curr: T, update: T): T => {
37
+ const result = { ...curr }; // Clone the current object to avoid mutation
38
+
39
+ for (const key in update) {
40
+ if (
41
+ update[key] &&
42
+ typeof update[key] === 'object' &&
43
+ !Array.isArray(update[key])
44
+ ) {
45
+ // If the value is an object, recurse
46
+ result[key] = deepMergeObject(
47
+ curr[key] || ({} as T[Extract<keyof T, string>]),
48
+ update[key]
49
+ );
50
+ } else {
51
+ // Otherwise, directly assign the value
52
+ result[key] = update[key];
53
+ }
54
+ }
55
+
56
+ return result;
57
+ };
58
+
34
59
  /**
35
60
  * @description
36
61
  * It provides caching for moveCall, RPC Request, and API Request.
@@ -45,20 +70,26 @@ type QueryInspectTxnParams = {
45
70
  */
46
71
 
47
72
  export class ScallopCache {
48
- public readonly queryClient: QueryClient;
49
- public readonly _suiKit: SuiKit;
50
- private tokenBucket: TokenBucket;
73
+ public readonly params: ScallopCacheParams;
74
+
75
+ public queryClient: QueryClient;
76
+ public suiKit: SuiKit;
77
+ // private tokenBucket: TokenBucket;
51
78
  public walletAddress: string;
79
+ private tokensPerInterval: number = DEFAULT_TOKENS_PER_INTERVAL;
80
+ private interval: number = DEFAULT_INTERVAL_IN_MS;
81
+ private tokens: number;
82
+ private lastRefill: number;
52
83
 
53
84
  public constructor(
54
- suiKit: SuiKit,
55
- walletAddress?: string,
56
- cacheOptions?: QueryClientConfig,
57
- tokenBucket?: TokenBucket,
58
- queryClient?: QueryClient
85
+ params: ScallopCacheParams,
86
+ instance?: ScallopCacheInstanceParams
59
87
  ) {
88
+ this.params = params;
89
+ this.suiKit = instance?.suiKit ?? newSuiKit(params);
60
90
  this.queryClient =
61
- queryClient ?? new QueryClient(cacheOptions ?? DEFAULT_CACHE_OPTIONS);
91
+ instance?.queryClient ??
92
+ new QueryClient(params?.cacheOptions ?? DEFAULT_CACHE_OPTIONS);
62
93
 
63
94
  // handle case where there's existing queryClient and cacheOptions is also passed
64
95
  // if (queryClient && cacheOptions) {
@@ -70,22 +101,62 @@ export class ScallopCache {
70
101
  // // if(cacheOptions.mutations)this.queryClient.setMutationDefaults(cacheOptions.mutations);
71
102
  // }
72
103
 
73
- this._suiKit = suiKit;
74
- this.tokenBucket =
75
- tokenBucket ??
76
- new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS);
77
- this.walletAddress = walletAddress ?? suiKit.currentAddress();
104
+ this.tokens = this.tokensPerInterval;
105
+ this.lastRefill = Date.now();
106
+ this.walletAddress = params.walletAddress ?? this.suiKit.currentAddress();
78
107
  }
79
108
 
80
- private get suiKit(): SuiKit {
81
- if (!this._suiKit) {
82
- throw new Error('SuiKit instance is not initialized');
109
+ private get client(): SuiClient {
110
+ return this.suiKit.client();
111
+ }
112
+
113
+ private refill() {
114
+ const now = Date.now();
115
+ const elapsed = now - this.lastRefill;
116
+
117
+ if (elapsed >= this.interval) {
118
+ const tokensToAdd =
119
+ Math.floor(elapsed / this.interval) * this.tokensPerInterval;
120
+ this.tokens = Math.min(this.tokens + tokensToAdd, this.tokensPerInterval);
121
+
122
+ // Update lastRefill to reflect the exact time of the last "refill"
123
+ this.lastRefill += Math.floor(elapsed / this.interval) * this.interval;
83
124
  }
84
- return this._suiKit;
85
125
  }
86
126
 
87
- private get client(): SuiClient {
88
- return this.suiKit.client();
127
+ private removeTokens(count: number) {
128
+ this.refill();
129
+ if (this.tokens >= count) {
130
+ this.tokens -= count;
131
+ return true;
132
+ }
133
+ return false;
134
+ }
135
+
136
+ private async callWithRateLimit<T>(
137
+ fn: () => Promise<T>,
138
+ maxRetries = 15,
139
+ backoffFactor = 1.25 // The factor by which to increase the delay
140
+ ): Promise<T | null> {
141
+ let retries = 0;
142
+
143
+ const tryRequest = async (): Promise<T | null> => {
144
+ if (this.removeTokens(1)) {
145
+ const result = await fn();
146
+ return result;
147
+ } else if (retries < maxRetries) {
148
+ retries++;
149
+ const delay = this.interval * Math.pow(backoffFactor, retries);
150
+ // console.error(`Rate limit exceeded, retrying in ${delay} ms`);
151
+ await new Promise((resolve) => setTimeout(resolve, delay));
152
+ return tryRequest();
153
+ } else {
154
+ console.error('Maximum retries reached');
155
+ return null;
156
+ }
157
+ };
158
+
159
+ return tryRequest();
89
160
  }
90
161
 
91
162
  /**
@@ -97,14 +168,14 @@ export class ScallopCache {
97
168
  * - `all`: All queries that match the refetch predicate will be refetched in the background.
98
169
  * - `none`: No queries will be refetched. Queries that match the refetch predicate will only be marked as invalid.
99
170
  */
100
- public async invalidateAllCache() {
101
- return Object.values(queryKeys.rpc).map((t) =>
102
- this.queryClient.invalidateQueries({
103
- queryKey: t(),
104
- type: 'all',
105
- })
106
- );
107
- }
171
+ // public async invalidateAllCache() {
172
+ // return Object.values(queryKeys.rpc).map((t) =>
173
+ // this.queryClient.invalidateQueries({
174
+ // queryKey: t(),
175
+ // type: 'all',
176
+ // })
177
+ // );
178
+ // }
108
179
 
109
180
  private retryFn(errCount: number, e: any) {
110
181
  if (errCount === 5) return false;
@@ -125,12 +196,39 @@ export class ScallopCache {
125
196
  }: QueryInspectTxnParams): Promise<DevInspectResults | null> {
126
197
  const txBlock = new SuiTxBlock();
127
198
 
199
+ const resolvedQueryTarget =
200
+ await this.queryGetNormalizedMoveFunction(queryTarget);
201
+ if (!resolvedQueryTarget) throw new Error('Invalid query target');
202
+
203
+ const { parameters } = resolvedQueryTarget;
204
+
128
205
  const resolvedArgs = await Promise.all(
129
- args.map(async (arg) => {
130
- if (typeof arg === 'string') {
131
- return (await this.queryGetObject(arg))?.data;
132
- }
133
- return arg;
206
+ (args ?? []).map(async (arg, idx) => {
207
+ if (typeof arg !== 'string') return arg;
208
+
209
+ const cachedData = (await this.queryGetObject(arg))?.data;
210
+ if (!cachedData) return arg;
211
+
212
+ const owner = cachedData.owner;
213
+ if (!owner || typeof owner !== 'object' || !('Shared' in owner))
214
+ return {
215
+ objectId: cachedData.objectId,
216
+ version: cachedData.version,
217
+ digest: cachedData.digest,
218
+ };
219
+
220
+ const parameter = parameters[idx];
221
+ if (
222
+ typeof parameter !== 'object' ||
223
+ !('MutableReference' in parameter || 'Reference' in parameter)
224
+ )
225
+ return arg;
226
+
227
+ return {
228
+ objectId: cachedData.objectId,
229
+ initialSharedVersion: owner.Shared.initial_shared_version,
230
+ mutable: 'MutableReference' in parameter,
231
+ };
134
232
  })
135
233
  );
136
234
  txBlock.moveCall(queryTarget, resolvedArgs, typeArgs);
@@ -140,8 +238,7 @@ export class ScallopCache {
140
238
  retryDelay: 1000,
141
239
  queryKey: queryKeys.rpc.getInspectTxn(queryTarget, args, typeArgs),
142
240
  queryFn: async () => {
143
- return await callWithRateLimit(
144
- this.tokenBucket,
241
+ return await this.callWithRateLimit(
145
242
  async () => await this.suiKit.inspectTxn(txBlock)
146
243
  );
147
244
  },
@@ -149,6 +246,23 @@ export class ScallopCache {
149
246
  return query;
150
247
  }
151
248
 
249
+ public async queryGetNormalizedMoveFunction(target: string) {
250
+ const { address, module, name } = parseStructTag(target);
251
+ return this.queryClient.fetchQuery({
252
+ queryKey: queryKeys.rpc.getNormalizedMoveFunction(target),
253
+ queryFn: async () => {
254
+ return await this.callWithRateLimit(
255
+ async () =>
256
+ await this.suiKit.client().getNormalizedMoveFunction({
257
+ package: address,
258
+ module,
259
+ function: name,
260
+ })
261
+ );
262
+ },
263
+ });
264
+ }
265
+
152
266
  /**
153
267
  * @description Provides cache for getObject of the SuiKit.
154
268
  * @param objectId
@@ -159,13 +273,18 @@ export class ScallopCache {
159
273
  objectId: string,
160
274
  options?: SuiObjectDataOptions
161
275
  ) {
276
+ options = {
277
+ ...options,
278
+ showOwner: true,
279
+ showContent: true,
280
+ showType: true,
281
+ };
162
282
  return this.queryClient.fetchQuery({
163
283
  retry: this.retryFn,
164
284
  retryDelay: 1000,
165
285
  queryKey: queryKeys.rpc.getObject(objectId, options),
166
286
  queryFn: async () => {
167
- return await callWithRateLimit(
168
- this.tokenBucket,
287
+ return await this.callWithRateLimit(
169
288
  async () =>
170
289
  await this.client.getObject({
171
290
  id: objectId,
@@ -181,43 +300,38 @@ export class ScallopCache {
181
300
  * @param objectIds
182
301
  * @returns Promise<SuiObjectData[]>
183
302
  */
184
- public async queryGetObjects(
185
- objectIds: string[],
186
- options: SuiObjectDataOptions = {
187
- showContent: true,
188
- }
189
- ): Promise<SuiObjectData[]> {
303
+ public async queryGetObjects(objectIds: string[]): Promise<SuiObjectData[]> {
190
304
  if (objectIds.length === 0) return [];
191
- // objectIds.sort();
305
+ const options: SuiObjectDataOptions = {
306
+ showContent: true,
307
+ showOwner: true,
308
+ showType: true,
309
+ };
192
310
 
193
311
  return this.queryClient.fetchQuery({
194
312
  retry: this.retryFn,
195
313
  retryDelay: 1000,
196
- queryKey: queryKeys.rpc.getObjects(
197
- objectIds,
198
- this.walletAddress,
199
- options
200
- ),
314
+ queryKey: queryKeys.rpc.getObjects(objectIds),
201
315
  queryFn: async () => {
202
- const results = await callWithRateLimit(
203
- this.tokenBucket,
316
+ const results = await this.callWithRateLimit(
204
317
  async () => await this.suiKit.getObjects(objectIds, options)
205
318
  );
206
319
  if (results) {
207
320
  results.forEach((result) => {
208
- this.queryClient.setQueriesData(
209
- {
321
+ // fetch previous data
322
+ const queryKey = queryKeys.rpc.getObject(result.objectId);
323
+ const prevDatas =
324
+ this.queryClient.getQueriesData<SuiObjectResponse>({
210
325
  exact: false,
211
- queryKey: queryKeys.rpc.getObject(result.objectId, options),
212
- },
213
- {
214
- data: result,
215
- error: null,
216
- },
217
- {
218
- updatedAt: Date.now(),
219
- }
220
- );
326
+ queryKey,
327
+ });
328
+ prevDatas.forEach(([key, prevData]) => {
329
+ this.queryClient.setQueryData(
330
+ key,
331
+ deepMergeObject(prevData, { data: result, error: null }),
332
+ { updatedAt: Date.now() }
333
+ );
334
+ });
221
335
  });
222
336
  }
223
337
  return results;
@@ -231,15 +345,41 @@ export class ScallopCache {
231
345
  * @returns Promise<PaginatedObjectsResponse>
232
346
  */
233
347
  public async queryGetOwnedObjects(input: GetOwnedObjectsParams) {
348
+ // @TODO: This query need its own separate rate limiter (as owned objects can theoretically be infinite), need a better way to handle this
234
349
  return this.queryClient.fetchQuery({
235
350
  retry: this.retryFn,
236
351
  retryDelay: 1000,
237
352
  queryKey: queryKeys.rpc.getOwnedObjects(input),
238
353
  queryFn: async () => {
239
- return await callWithRateLimit(
240
- this.tokenBucket,
354
+ const results = await this.callWithRateLimit(
241
355
  async () => await this.client.getOwnedObjects(input)
242
356
  );
357
+ if (results && results.data.length > 0) {
358
+ results.data
359
+ .filter(
360
+ (
361
+ result
362
+ ): result is typeof result &
363
+ NonNullable<{ data: SuiObjectData }> => !!result.data
364
+ )
365
+ .forEach((result) => {
366
+ // fetch previous data
367
+ const queryKey = queryKeys.rpc.getObject(result.data.objectId);
368
+ const prevDatas =
369
+ this.queryClient.getQueriesData<SuiObjectResponse>({
370
+ exact: false,
371
+ queryKey,
372
+ });
373
+ prevDatas.forEach(([key, prevData]) => {
374
+ this.queryClient.setQueryData(
375
+ key,
376
+ deepMergeObject(prevData, { data: result.data, error: null }),
377
+ { updatedAt: Date.now() }
378
+ );
379
+ });
380
+ });
381
+ }
382
+ return results;
243
383
  },
244
384
  });
245
385
  }
@@ -252,8 +392,7 @@ export class ScallopCache {
252
392
  retryDelay: 1000,
253
393
  queryKey: queryKeys.rpc.getDynamicFields(input),
254
394
  queryFn: async () => {
255
- return await callWithRateLimit(
256
- this.tokenBucket,
395
+ return await this.callWithRateLimit(
257
396
  async () => await this.client.getDynamicFields(input)
258
397
  );
259
398
  },
@@ -268,35 +407,48 @@ export class ScallopCache {
268
407
  retryDelay: (attemptIndex) => Math.min(1000 * attemptIndex, 8000),
269
408
  queryKey: queryKeys.rpc.getDynamicFieldObject(input),
270
409
  queryFn: async () => {
271
- return await callWithRateLimit(this.tokenBucket, () =>
410
+ const result = await this.callWithRateLimit(() =>
272
411
  this.client.getDynamicFieldObject(input)
273
412
  );
413
+ if (result?.data) {
414
+ const queryKey = queryKeys.rpc.getObject(result.data.objectId);
415
+ const prevDatas = this.queryClient.getQueriesData<SuiObjectResponse>({
416
+ exact: false,
417
+ queryKey,
418
+ });
419
+ prevDatas.forEach(([key, prevData]) => {
420
+ this.queryClient.setQueryData(
421
+ key,
422
+ deepMergeObject(prevData, { data: result.data, error: null }),
423
+ { updatedAt: Date.now() }
424
+ );
425
+ });
426
+ }
427
+ return result;
274
428
  },
275
429
  });
276
430
  }
277
431
 
278
432
  public async queryGetAllCoinBalances(
279
433
  owner: string
280
- ): Promise<{ [k: string]: string }> {
434
+ ): Promise<{ [k: string]: CoinBalance }> {
281
435
  return this.queryClient.fetchQuery({
282
436
  retry: this.retryFn,
283
437
  retryDelay: 1000,
284
438
  queryKey: queryKeys.rpc.getAllCoinBalances(owner),
285
439
  queryFn: async () => {
286
- const allBalances = await callWithRateLimit(
287
- this.tokenBucket,
440
+ const allBalances = await this.callWithRateLimit(
288
441
  async () => await this.client.getAllBalances({ owner })
289
442
  );
290
443
  if (!allBalances) return {};
291
444
  const balances = allBalances.reduce(
292
445
  (acc, coinBalance) => {
293
446
  if (coinBalance.totalBalance !== '0') {
294
- acc[normalizeStructTag(coinBalance.coinType)] =
295
- coinBalance.totalBalance;
447
+ acc[normalizeStructTag(coinBalance.coinType)] = coinBalance;
296
448
  }
297
449
  return acc;
298
450
  },
299
- {} as { [k: string]: string }
451
+ {} as { [k: string]: CoinBalance }
300
452
  );
301
453
 
302
454
  return balances;
@@ -304,8 +456,10 @@ export class ScallopCache {
304
456
  });
305
457
  }
306
458
 
307
- public async queryGetCoinBalance(input: GetBalanceParams): Promise<string> {
308
- if (!input.coinType) return '0';
459
+ public async queryGetCoinBalance(
460
+ input: GetBalanceParams
461
+ ): Promise<CoinBalance | null> {
462
+ if (!input.coinType) return null;
309
463
 
310
464
  return (
311
465
  ((await this.queryGetAllCoinBalances(input.owner)) ?? {})[
@@ -1,6 +1,5 @@
1
1
  import { normalizeSuiAddress } from '@mysten/sui/utils';
2
2
  import { SuiKit } from '@scallop-io/sui-kit';
3
- import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
4
3
  import {
5
4
  ADDRESSES_ID,
6
5
  SUPPORT_BORROW_INCENTIVE_POOLS,
@@ -75,11 +74,9 @@ export class ScallopClient {
75
74
  this.address = this.utils.address;
76
75
  this.cache = this.address.cache;
77
76
  } else {
78
- this.cache = new ScallopCache(
79
- this.suiKit,
80
- this.walletAddress,
81
- DEFAULT_CACHE_OPTIONS
82
- );
77
+ this.cache = new ScallopCache(this.params, {
78
+ suiKit: this.suiKit,
79
+ });
83
80
  this.address = new ScallopAddress(
84
81
  {
85
82
  id: params?.addressesId ?? ADDRESSES_ID,
@@ -965,6 +962,7 @@ export class ScallopClient {
965
962
  const rewardCoinsCollection: Record<string, TransactionResult[]> = {};
966
963
  const obligationAccount =
967
964
  await this.query.getObligationAccount(obligationId);
965
+ if (!obligationAccount) throw new Error('Obligation not found');
968
966
  const rewardCoinNames = Object.values(obligationAccount.borrowIncentives)
969
967
  .flatMap(({ rewards }) =>
970
968
  rewards.filter(({ availableClaimAmount }) => availableClaimAmount > 0)
@@ -22,8 +22,6 @@ import type {
22
22
  ScallopIndexerInstanceParams,
23
23
  } from '../types';
24
24
  import { ScallopCache } from './scallopCache';
25
- import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
26
- import { SuiKit } from '@scallop-io/sui-kit';
27
25
  import { queryKeys } from 'src/constants';
28
26
 
29
27
  /**
@@ -48,9 +46,7 @@ export class ScallopIndexer {
48
46
  instance?: ScallopIndexerInstanceParams
49
47
  ) {
50
48
  this.params = params;
51
- this.cache =
52
- instance?.cache ??
53
- new ScallopCache(new SuiKit({}), undefined, DEFAULT_CACHE_OPTIONS);
49
+ this.cache = instance?.cache ?? new ScallopCache(this.params);
54
50
  this._requestClient = axios.create({
55
51
  baseURL: SDK_API_BASE_URL,
56
52
  headers: {