@scallop-io/sui-scallop-sdk 0.46.56 → 0.46.58-alpha.1

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.
@@ -5,7 +5,7 @@ import { ScallopUtils } from './scallopUtils';
5
5
  import type { SuiTransactionBlockResponse } from '@mysten/sui.js/client';
6
6
  import type { TransactionBlock } from '@mysten/sui.js/transactions';
7
7
  import type { SuiTxBlock as SuiKitTxBlock } from '@scallop-io/sui-kit';
8
- import type { ScallopBuilderParams, ScallopTxBlock, SupportMarketCoins, SupportAssetCoins, SupportSCoin, ScallopBuilderInstanceParams } from '../types';
8
+ import type { ScallopBuilderParams, ScallopTxBlock, SupportMarketCoins, SupportAssetCoins, SupportSCoin, ScallopBuilderInstanceParams, SelectCoinReturnType } from '../types';
9
9
  import { ScallopCache } from './scallopCache';
10
10
  /**
11
11
  * @description
@@ -51,10 +51,7 @@ export declare class ScallopBuilder {
51
51
  * @param sender - Sender address.
52
52
  * @return Take coin and left coin.
53
53
  */
54
- selectCoin(txBlock: ScallopTxBlock | SuiKitTxBlock, assetCoinName: SupportAssetCoins, amount: number, sender?: string): Promise<{
55
- takeCoin: import("@scallop-io/sui-kit").TransactionObjectArgument;
56
- leftCoin: import("@scallop-io/sui-kit").TransactionObjectArgument;
57
- }>;
54
+ selectCoin<T extends SupportAssetCoins>(txBlock: ScallopTxBlock | SuiKitTxBlock, assetCoinName: T, amount: number, sender?: string): Promise<SelectCoinReturnType<T>>;
58
55
  /**
59
56
  * Specifying the sender's amount of market coins to get coins args from transaction result.
60
57
  *
@@ -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
  /**
@@ -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
  *
@@ -1,10 +1,11 @@
1
- import type { CoreTxBlock } from './core';
1
+ import type { CoreTxBlock, NestedResult } from './core';
2
2
  import type { SpoolTxBlock } from './spool';
3
3
  import type { BorrowIncentiveTxBlock } from './borrowIncentive';
4
4
  import type { VeScaTxBlock } from './vesca';
5
5
  import type { ReferralTxBlock } from './referral';
6
6
  import { LoyaltyProgramTxBlock } from './loyaltyProgram';
7
7
  import { SCoinTxBlock } from './sCoin';
8
+ import { SupportAssetCoins } from '../constant';
8
9
  export type * from './core';
9
10
  export type * from './spool';
10
11
  export type * from './borrowIncentive';
@@ -15,3 +16,9 @@ export type BaseScallopTxBlock = ReferralTxBlock & LoyaltyProgramTxBlock & Borro
15
16
  export type SuiTxBlockWithSCoin = BaseScallopTxBlock & SCoinTxBlock;
16
17
  export type SuiTxBlockWithSpool = SuiTxBlockWithSCoin & SpoolTxBlock;
17
18
  export type ScallopTxBlock = SuiTxBlockWithSpool & CoreTxBlock;
19
+ export type SelectCoinReturnType<T extends SupportAssetCoins> = T extends 'sui' ? {
20
+ takeCoin: NestedResult;
21
+ } : {
22
+ takeCoin: NestedResult;
23
+ leftCoin: NestedResult;
24
+ };
@@ -53,7 +53,7 @@ export declare const parseOriginBorrowIncentiveAccountData: (originBorrowIncenti
53
53
  export declare const minBigNumber: (...args: BigNumber.Value[]) => BigNumber;
54
54
  export declare const maxBigNumber: (...args: BigNumber.Value[]) => BigNumber;
55
55
  /**
56
- * Dynamically adjust the decrease or increase ratio according to the amout
56
+ * Dynamically adjust the decrease or increase ratio according to the amount
57
57
  * @param amount - The amount required to calculate factor.
58
58
  * @param scaleStep - The scale step required to determine the factor..
59
59
  * @param type - The type of the calculation.
@@ -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.56",
3
+ "version": "0.46.58-alpha.1",
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
 
@@ -15,6 +15,7 @@ import type {
15
15
  SupportAssetCoins,
16
16
  SupportSCoin,
17
17
  ScallopBuilderInstanceParams,
18
+ SelectCoinReturnType,
18
19
  } from '../types';
19
20
  import { ScallopCache } from './scallopCache';
20
21
  import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
@@ -58,7 +59,11 @@ export class ScallopBuilder {
58
59
  this.address = this.utils.address;
59
60
  this.cache = this.address.cache;
60
61
  } else {
61
- 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
+ );
62
67
  this.address = new ScallopAddress(
63
68
  {
64
69
  id: params?.addressesId || ADDRESSES_ID,
@@ -122,16 +127,21 @@ export class ScallopBuilder {
122
127
  * @param sender - Sender address.
123
128
  * @return Take coin and left coin.
124
129
  */
125
- public async selectCoin(
130
+ public async selectCoin<T extends SupportAssetCoins>(
126
131
  txBlock: ScallopTxBlock | SuiKitTxBlock,
127
- assetCoinName: SupportAssetCoins,
132
+ assetCoinName: T,
128
133
  amount: number,
129
134
  sender: string = this.walletAddress
130
- ) {
131
- const coinType = this.utils.parseCoinType(assetCoinName);
132
- const coins = await this.utils.selectCoins(amount, coinType, sender);
133
- const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(coins, amount);
134
- return { takeCoin, leftCoin };
135
+ ): Promise<SelectCoinReturnType<T>> {
136
+ if (assetCoinName === 'sui') {
137
+ const [takeCoin] = txBlock.splitSUIFromGas([amount]);
138
+ return { takeCoin } as SelectCoinReturnType<T>;
139
+ } else {
140
+ const coinType = this.utils.parseCoinType(assetCoinName);
141
+ const coins = await this.utils.selectCoins(amount, coinType, sender);
142
+ const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(coins, amount);
143
+ return { takeCoin, leftCoin } as SelectCoinReturnType<T>;
144
+ }
135
145
  }
136
146
 
137
147
  /**
@@ -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,
@@ -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 {
@@ -183,7 +183,7 @@ export const queryBorrowIncentiveAccounts = async (
183
183
 
184
184
  const queryResult = await utils.cache.queryInspectTxn({ queryTarget, args });
185
185
  const borrowIncentiveAccountsQueryData = queryResult?.events[0]
186
- .parsedJson as BorrowIncentiveAccountsQueryInterface;
186
+ ?.parsedJson as BorrowIncentiveAccountsQueryInterface | undefined;
187
187
 
188
188
  const borrowIncentiveAccounts: BorrowIncentiveAccounts = Object.values(
189
189
  borrowIncentiveAccountsQueryData?.pool_records ?? []
@@ -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;
@@ -802,7 +803,7 @@ export const queryObligation = async (
802
803
  { queryTarget, args }
803
804
  // txBlock
804
805
  );
805
- return queryResult?.events[0].parsedJson as
806
+ return queryResult?.events[0]?.parsedJson as
806
807
  | ObligationQueryInterface
807
808
  | undefined;
808
809
  };
@@ -972,7 +973,7 @@ export const getFlashLoanFees = async (
972
973
  // the balance sheet is a VecSet<0x1::type_name::TypeName
973
974
  const balanceSheetDynamicFields = await query.cache.queryGetDynamicFields({
974
975
  parentId: flashloanFeesTableId,
975
- limit: 50,
976
+ limit: 10,
976
977
  });
977
978
 
978
979
  // get the dynamic object ids
@@ -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
 
@@ -1,10 +1,11 @@
1
- import type { CoreTxBlock } from './core';
1
+ import type { CoreTxBlock, NestedResult } from './core';
2
2
  import type { SpoolTxBlock } from './spool';
3
3
  import type { BorrowIncentiveTxBlock } from './borrowIncentive';
4
4
  import type { VeScaTxBlock } from './vesca';
5
5
  import type { ReferralTxBlock } from './referral';
6
6
  import { LoyaltyProgramTxBlock } from './loyaltyProgram';
7
7
  import { SCoinTxBlock } from './sCoin';
8
+ import { SupportAssetCoins } from '../constant';
8
9
 
9
10
  export type * from './core';
10
11
  export type * from './spool';
@@ -21,3 +22,12 @@ export type BaseScallopTxBlock = ReferralTxBlock &
21
22
  export type SuiTxBlockWithSCoin = BaseScallopTxBlock & SCoinTxBlock;
22
23
  export type SuiTxBlockWithSpool = SuiTxBlockWithSCoin & SpoolTxBlock;
23
24
  export type ScallopTxBlock = SuiTxBlockWithSpool & CoreTxBlock;
25
+
26
+ export type SelectCoinReturnType<T extends SupportAssetCoins> = T extends 'sui'
27
+ ? {
28
+ takeCoin: NestedResult;
29
+ }
30
+ : {
31
+ takeCoin: NestedResult;
32
+ leftCoin: NestedResult;
33
+ };
@@ -697,7 +697,7 @@ export const maxBigNumber = (...args: BigNumber.Value[]) => {
697
697
  };
698
698
 
699
699
  /**
700
- * Dynamically adjust the decrease or increase ratio according to the amout
700
+ * Dynamically adjust the decrease or increase ratio according to the amount
701
701
  * @param amount - The amount required to calculate factor.
702
702
  * @param scaleStep - The scale step required to determine the factor..
703
703
  * @param type - The type of the calculation.
@@ -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
  }