@scallop-io/sui-scallop-sdk 0.46.57 → 0.46.58

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.
@@ -24,7 +24,8 @@ export declare class ScallopCache {
24
24
  readonly queryClient: QueryClient;
25
25
  readonly _suiKit: SuiKit;
26
26
  private tokenBucket;
27
- constructor(suiKit: SuiKit, cacheOptions?: QueryClientConfig, tokenBucket?: TokenBucket);
27
+ walletAddress: string;
28
+ constructor(suiKit: SuiKit, walletAddress?: string, cacheOptions?: QueryClientConfig, tokenBucket?: TokenBucket);
28
29
  private get suiKit();
29
30
  private get client();
30
31
  /**
@@ -298,7 +298,7 @@ export declare class ScallopClient {
298
298
  * Function to migrate all market coin in user wallet into sCoin
299
299
  * @returns Transaction response
300
300
  */
301
- migrateAllMarketCoin<S extends boolean>(sign?: S): Promise<ScallopClientFnReturnType<S>>;
301
+ migrateAllMarketCoin<S extends boolean>(includeStakePool?: boolean, sign?: S): Promise<ScallopClientFnReturnType<S>>;
302
302
  /**
303
303
  * Claim unlocked SCA from all veSCA accounts.
304
304
  */
@@ -21,6 +21,7 @@ export declare class ScallopUtils {
21
21
  suiKit: SuiKit;
22
22
  address: ScallopAddress;
23
23
  cache: ScallopCache;
24
+ walletAddress: string;
24
25
  private _priceMap;
25
26
  constructor(params: ScallopUtilsParams, instance?: ScallopUtilsInstanceParams);
26
27
  /**
@@ -156,7 +157,7 @@ export declare class ScallopUtils {
156
157
  * @param coinType
157
158
  * @param sender
158
159
  */
159
- mergeSimilarCoins(txBlock: SuiTxBlock, dest: SuiTxArg, coinType: string, sender: string): Promise<void>;
160
+ mergeSimilarCoins(txBlock: SuiTxBlock, dest: SuiTxArg, coinType: string, sender?: string): Promise<void>;
160
161
  /**
161
162
  * Get all asset coin names in the obligation record by obligation id.
162
163
  *
@@ -7,5 +7,5 @@ declare class TokenBucket {
7
7
  refill(): void;
8
8
  removeTokens(count: number): boolean;
9
9
  }
10
- declare const callWithRateLimit: <T>(tokenBucket: TokenBucket, fn: () => Promise<T>, retryDelayInMs?: number, maxRetries?: number) => Promise<T | null>;
10
+ declare const callWithRateLimit: <T>(tokenBucket: TokenBucket, fn: () => Promise<T>, retryDelayInMs?: number, maxRetries?: number, backoffFactor?: number) => Promise<T | null>;
11
11
  export { TokenBucket, callWithRateLimit };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scallop-io/sui-scallop-sdk",
3
- "version": "0.46.57",
3
+ "version": "0.46.58",
4
4
  "description": "Typescript sdk for interacting with Scallop contract on SUI",
5
5
  "keywords": [
6
6
  "sui",
@@ -9,7 +9,7 @@ import { QueryClientConfig } from '@tanstack/query-core';
9
9
  export const DEFAULT_CACHE_OPTIONS: QueryClientConfig = {
10
10
  defaultOptions: {
11
11
  queries: {
12
- staleTime: 1500,
12
+ staleTime: 2000,
13
13
  },
14
14
  },
15
15
  };
@@ -1,2 +1,2 @@
1
- export const DEFAULT_TOKENS_PER_INTERVAL = 10;
2
- export const DEFAULT_INTERVAL_IN_MS = 1000;
1
+ export const DEFAULT_TOKENS_PER_INTERVAL = 50;
2
+ export const DEFAULT_INTERVAL_IN_MS = 300;
@@ -49,6 +49,7 @@ export class Scallop {
49
49
  this.suiKit = new SuiKit(params);
50
50
  this.cache = new ScallopCache(
51
51
  this.suiKit,
52
+ params.walletAddress,
52
53
  cacheOptions ?? DEFAULT_CACHE_OPTIONS,
53
54
  tokenBucket ??
54
55
  new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS)
@@ -382,6 +382,7 @@ export class ScallopAddress {
382
382
  instance?.cache ??
383
383
  new ScallopCache(
384
384
  instance?.suiKit ?? new SuiKit({}),
385
+ undefined,
385
386
  DEFAULT_CACHE_OPTIONS
386
387
  );
387
388
 
@@ -59,7 +59,11 @@ export class ScallopBuilder {
59
59
  this.address = this.utils.address;
60
60
  this.cache = this.address.cache;
61
61
  } else {
62
- this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS);
62
+ this.cache = new ScallopCache(
63
+ this.suiKit,
64
+ this.walletAddress,
65
+ DEFAULT_CACHE_OPTIONS
66
+ );
63
67
  this.address = new ScallopAddress(
64
68
  {
65
69
  id: params?.addressesId || ADDRESSES_ID,
@@ -48,9 +48,11 @@ export class ScallopCache {
48
48
  public readonly queryClient: QueryClient;
49
49
  public readonly _suiKit: SuiKit;
50
50
  private tokenBucket: TokenBucket;
51
+ public walletAddress: string;
51
52
 
52
53
  public constructor(
53
54
  suiKit: SuiKit,
55
+ walletAddress?: string,
54
56
  cacheOptions?: QueryClientConfig,
55
57
  tokenBucket?: TokenBucket
56
58
  ) {
@@ -59,6 +61,7 @@ export class ScallopCache {
59
61
  this.tokenBucket =
60
62
  tokenBucket ??
61
63
  new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS);
64
+ this.walletAddress = walletAddress ?? suiKit.currentAddress();
62
65
  }
63
66
 
64
67
  private get suiKit(): SuiKit {
@@ -164,7 +167,7 @@ export class ScallopCache {
164
167
  objectId: string,
165
168
  options?: SuiObjectDataOptions
166
169
  ): Promise<SuiObjectResponse | null> {
167
- const queryKey = ['getObject', objectId, this.suiKit.currentAddress()];
170
+ const queryKey = ['getObject', objectId, this.walletAddress];
168
171
  if (options) {
169
172
  queryKey.push(JSON.stringify(options));
170
173
  }
@@ -188,13 +191,15 @@ export class ScallopCache {
188
191
  */
189
192
  public async queryGetObjects(
190
193
  objectIds: string[],
191
- options?: SuiObjectDataOptions
194
+ options: SuiObjectDataOptions = {
195
+ showContent: true,
196
+ }
192
197
  ): Promise<SuiObjectData[]> {
193
198
  if (objectIds.length === 0) return [];
194
199
  const queryKey = [
195
200
  'getObjects',
196
201
  JSON.stringify(objectIds),
197
- this.suiKit.currentAddress(),
202
+ this.walletAddress,
198
203
  ];
199
204
  if (options) {
200
205
  queryKey.push(JSON.stringify(options));
@@ -76,7 +76,11 @@ export class ScallopClient {
76
76
  this.address = this.utils.address;
77
77
  this.cache = this.address.cache;
78
78
  } else {
79
- this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS);
79
+ this.cache = new ScallopCache(
80
+ this.suiKit,
81
+ this.walletAddress,
82
+ DEFAULT_CACHE_OPTIONS
83
+ );
80
84
  this.address = new ScallopAddress(
81
85
  {
82
86
  id: params?.addressesId || ADDRESSES_ID,
@@ -985,6 +989,7 @@ export class ScallopClient {
985
989
  * @returns Transaction response
986
990
  */
987
991
  public async migrateAllMarketCoin<S extends boolean>(
992
+ includeStakePool: boolean = true,
988
993
  sign: S = true as S
989
994
  ): Promise<ScallopClientFnReturnType<S>> {
990
995
  const txBlock = this.builder.createTxBlock();
@@ -1036,18 +1041,20 @@ export class ScallopClient {
1036
1041
  );
1037
1042
  sCoins.push(sCoin);
1038
1043
  }
1039
- // check for staked market coin in spool
1040
- if (SUPPORT_SPOOLS.includes(sCoinName as SupportStakeMarketCoins)) {
1041
- try {
1042
- const sCoin = await txBlock.unstakeQuick(
1043
- Number.MAX_SAFE_INTEGER,
1044
- sCoinName as SupportStakeMarketCoins
1045
- );
1046
- if (sCoin) {
1047
- sCoins.push(sCoin);
1044
+ if (includeStakePool) {
1045
+ // check for staked market coin in spool
1046
+ if (SUPPORT_SPOOLS.includes(sCoinName as SupportStakeMarketCoins)) {
1047
+ try {
1048
+ const sCoin = await txBlock.unstakeQuick(
1049
+ Number.MAX_SAFE_INTEGER,
1050
+ sCoinName as SupportStakeMarketCoins
1051
+ );
1052
+ if (sCoin) {
1053
+ sCoins.push(sCoin);
1054
+ }
1055
+ } catch (e: any) {
1056
+ // ignore
1048
1057
  }
1049
- } catch (e: any) {
1050
- // ignore
1051
1058
  }
1052
1059
  }
1053
1060
 
@@ -49,7 +49,7 @@ export class ScallopIndexer {
49
49
  this.params = params;
50
50
  this.cache =
51
51
  instance?.cache ??
52
- new ScallopCache(new SuiKit({}), DEFAULT_CACHE_OPTIONS);
52
+ new ScallopCache(new SuiKit({}), undefined, DEFAULT_CACHE_OPTIONS);
53
53
  this._requestClient = axios.create({
54
54
  baseURL: SDK_API_BASE_URL,
55
55
  headers: {
@@ -90,12 +90,21 @@ export class ScallopQuery {
90
90
  this.params = params;
91
91
  this.suiKit =
92
92
  instance?.suiKit ?? instance?.utils?.suiKit ?? new SuiKit(params);
93
+
94
+ this.walletAddress = normalizeSuiAddress(
95
+ params.walletAddress || this.suiKit.currentAddress()
96
+ );
97
+
93
98
  if (instance?.utils) {
94
99
  this.utils = instance.utils;
95
100
  this.address = instance.utils.address;
96
101
  this.cache = this.address.cache;
97
102
  } else {
98
- this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS);
103
+ this.cache = new ScallopCache(
104
+ this.suiKit,
105
+ this.walletAddress,
106
+ DEFAULT_CACHE_OPTIONS
107
+ );
99
108
  this.address = new ScallopAddress(
100
109
  {
101
110
  id: params?.addressesId || ADDRESSES_ID,
@@ -112,10 +121,6 @@ export class ScallopQuery {
112
121
  this.indexer =
113
122
  instance?.indexer ??
114
123
  new ScallopIndexer(this.params, { cache: this.cache });
115
-
116
- this.walletAddress = normalizeSuiAddress(
117
- params.walletAddress || this.suiKit.currentAddress()
118
- );
119
124
  }
120
125
 
121
126
  /**
@@ -62,6 +62,7 @@ export class ScallopUtils {
62
62
  public suiKit: SuiKit;
63
63
  public address: ScallopAddress;
64
64
  public cache: ScallopCache;
65
+ public walletAddress: string;
65
66
  private _priceMap: PriceMap = new Map();
66
67
 
67
68
  public constructor(
@@ -77,12 +78,18 @@ export class ScallopUtils {
77
78
  instance?.address?.cache._suiKit ??
78
79
  new SuiKit(params);
79
80
 
81
+ this.walletAddress = params.walletAddress ?? this.suiKit.currentAddress();
82
+
80
83
  if (instance?.address) {
81
84
  this.address = instance.address;
82
85
  this.cache = this.address.cache;
83
86
  this.suiKit = this.address.cache._suiKit;
84
87
  } else {
85
- this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS);
88
+ this.cache = new ScallopCache(
89
+ this.suiKit,
90
+ this.walletAddress,
91
+ DEFAULT_CACHE_OPTIONS
92
+ );
86
93
  this.address =
87
94
  instance?.address ??
88
95
  new ScallopAddress(
@@ -409,7 +416,7 @@ export class ScallopUtils {
409
416
  txBlock: SuiTxBlock,
410
417
  dest: SuiTxArg,
411
418
  coinType: string,
412
- sender: string
419
+ sender: string = this.walletAddress
413
420
  ): Promise<void> {
414
421
  // merge to existing coins if exist
415
422
  try {
@@ -709,6 +709,7 @@ export const getObligations = async (
709
709
  StructType: `${protocolObjectId}::obligation::ObligationKey`,
710
710
  },
711
711
  cursor: nextCursor,
712
+ limit: 10,
712
713
  });
713
714
 
714
715
  if (!paginatedKeyObjectsResponse) break;
@@ -251,9 +251,9 @@ export const getStakeAccounts = async (
251
251
  filter: { StructType: stakeAccountType },
252
252
  options: {
253
253
  showContent: true,
254
- showType: true,
255
254
  },
256
255
  cursor: nextCursor,
256
+ limit: 10,
257
257
  });
258
258
  if (!paginatedStakeObjectsResponse) continue;
259
259
 
@@ -299,7 +299,10 @@ export const getStakeAccounts = async (
299
299
  const stakeObjectIds: string[] = stakeObjectsResponse
300
300
  .map((ref: any) => ref?.data?.objectId)
301
301
  .filter((id: any) => id !== undefined);
302
- const stakeObjects = await utils.cache.queryGetObjects(stakeObjectIds);
302
+ const stakeObjects = await utils.cache.queryGetObjects(stakeObjectIds, {
303
+ showContent: true,
304
+ showType: true,
305
+ });
303
306
  for (const stakeObject of stakeObjects) {
304
307
  const id = stakeObject.objectId;
305
308
  const type = stakeObject.type!;
@@ -34,6 +34,7 @@ export const getVescaKeys = async (
34
34
  StructType: veScaKeyType,
35
35
  },
36
36
  cursor: nextCursor,
37
+ limit: 10,
37
38
  });
38
39
  if (!paginatedKeyObjectsResponse) continue;
39
40
 
@@ -38,20 +38,44 @@ const callWithRateLimit = async <T>(
38
38
  tokenBucket: TokenBucket,
39
39
  fn: () => Promise<T>,
40
40
  retryDelayInMs = DEFAULT_INTERVAL_IN_MS,
41
- maxRetries = 5 // Adding a maximum retries limit,
41
+ maxRetries = 15,
42
+ backoffFactor = 1.25 // The factor by which to increase the delay
42
43
  ): Promise<T | null> => {
43
44
  let retries = 0;
44
45
 
45
46
  const tryRequest = async (): Promise<T | null> => {
46
47
  if (tokenBucket.removeTokens(1)) {
47
- return await fn();
48
+ try {
49
+ const result = await fn();
50
+
51
+ // Check if the result is an object with status code (assuming the response has a status property)
52
+ if (result && (result as any).status === 429) {
53
+ throw new Error('Unexpected status code: 429');
54
+ }
55
+
56
+ return result;
57
+ } catch (error: any) {
58
+ if (
59
+ error.message === 'Unexpected status code: 429' &&
60
+ retries < maxRetries
61
+ ) {
62
+ retries++;
63
+ const delay = retryDelayInMs * Math.pow(backoffFactor, retries);
64
+ // console.warn(`429 encountered, retrying in ${delay} ms`);
65
+ await new Promise((resolve) => setTimeout(resolve, delay));
66
+ return tryRequest();
67
+ } else {
68
+ console.error('An error occurred:', error);
69
+ return null;
70
+ }
71
+ }
48
72
  } else if (retries < maxRetries) {
49
73
  retries++;
50
- // Use a Promise to correctly handle the async operation with setTimeout
51
- await new Promise((resolve) => setTimeout(resolve, retryDelayInMs));
74
+ const delay = retryDelayInMs * Math.pow(backoffFactor, retries);
75
+ // console.warn(`Rate limit exceeded, retrying in ${delay} ms`);
76
+ await new Promise((resolve) => setTimeout(resolve, delay));
52
77
  return tryRequest();
53
78
  } else {
54
- // Optionally, handle the case where the maximum number of retries is reached
55
79
  console.error('Maximum retries reached');
56
80
  return null;
57
81
  }