@scallop-io/sui-scallop-sdk 2.0.13-merge-split-ve-sca-alpha.5 → 2.1.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.
Files changed (55) hide show
  1. package/dist/index.d.mts +622 -697
  2. package/dist/index.d.ts +622 -697
  3. package/dist/index.js +32 -33
  4. package/dist/index.mjs +10 -10
  5. package/package.json +8 -18
  6. package/src/builders/borrowIncentiveBuilder.ts +9 -21
  7. package/src/builders/coreBuilder.ts +2 -2
  8. package/src/builders/index.ts +2 -2
  9. package/src/builders/oracles/index.ts +2 -3
  10. package/src/builders/oracles/pyth.ts +2 -2
  11. package/src/builders/spoolBuilder.ts +2 -2
  12. package/src/builders/vescaBuilder.ts +14 -132
  13. package/src/constants/queryKeys.ts +29 -54
  14. package/src/constants/testAddress.ts +6 -12
  15. package/src/index.ts +11 -1
  16. package/src/models/index.ts +11 -9
  17. package/src/models/interface.ts +36 -0
  18. package/src/models/scallop.ts +38 -133
  19. package/src/models/scallopAddress.ts +127 -142
  20. package/src/models/scallopAxios.ts +185 -0
  21. package/src/models/scallopBuilder.ts +45 -75
  22. package/src/models/scallopClient.ts +124 -154
  23. package/src/models/scallopConstants.ts +248 -323
  24. package/src/models/scallopIndexer.ts +54 -98
  25. package/src/models/scallopQuery.ts +145 -190
  26. package/src/models/scallopQueryClient.ts +29 -0
  27. package/src/models/scallopSuiKit.ts +432 -0
  28. package/src/models/scallopUtils.ts +260 -164
  29. package/src/queries/borrowIncentiveQuery.ts +28 -16
  30. package/src/queries/borrowLimitQuery.ts +1 -1
  31. package/src/queries/coreQuery.ts +148 -107
  32. package/src/queries/flashloanFeeQuery.ts +12 -6
  33. package/src/queries/index.ts +0 -1
  34. package/src/queries/isolatedAssetQuery.ts +3 -3
  35. package/src/queries/loyaltyProgramQuery.ts +10 -8
  36. package/src/queries/ownerQuery.ts +32 -0
  37. package/src/queries/portfolioQuery.ts +4 -5
  38. package/src/queries/priceQuery.ts +14 -8
  39. package/src/queries/referralQuery.ts +9 -3
  40. package/src/queries/sCoinQuery.ts +4 -4
  41. package/src/queries/spoolQuery.ts +11 -11
  42. package/src/queries/supplyLimitQuery.ts +1 -1
  43. package/src/queries/switchboardQuery.ts +1 -1
  44. package/src/queries/vescaQuery.ts +31 -27
  45. package/src/queries/xOracleQuery.ts +13 -8
  46. package/src/types/address.ts +0 -3
  47. package/src/types/builder/core.ts +1 -1
  48. package/src/types/builder/vesca.ts +10 -20
  49. package/src/types/constant/queryKeys.ts +48 -0
  50. package/src/types/index.ts +0 -1
  51. package/src/utils/builder.ts +1 -1
  52. package/src/utils/util.ts +1 -33
  53. package/src/models/scallopCache.ts +0 -428
  54. package/src/queries/objectsQuery.ts +0 -18
  55. package/src/types/model.ts +0 -117
package/src/utils/util.ts CHANGED
@@ -1,37 +1,5 @@
1
- import type { PriceFeed } from '@pythnetwork/pyth-sui-js';
2
1
  import { MAX_LOCK_DURATION } from 'src/constants';
3
- import { ScallopConstants } from 'src/models/scallopConstants';
4
-
5
- /**
6
- * Parse price from pyth price feed.
7
- *
8
- * @param feed - Price feed object from pyth.
9
- * @param address - Scallop address instance.
10
- * @return Price Data inclue coin name, price, and publish time.
11
- */
12
- export const parseDataFromPythPriceFeed = (
13
- feed: PriceFeed,
14
- constants: ScallopConstants
15
- ) => {
16
- const assetCoinNames = [...constants.whitelist.lending] as string[];
17
- const assetCoinName = assetCoinNames.find((assetCoinName) => {
18
- return (
19
- constants.address.get(`core.coins.${assetCoinName}.oracle.pyth.feed`) ===
20
- feed.id
21
- );
22
- });
23
- if (assetCoinName) {
24
- const price = feed.price.price * 10 ** feed.price.expo;
25
-
26
- return {
27
- coinName: assetCoinName,
28
- price,
29
- publishTime: Number(feed.price.publishTime) * 10 ** 3,
30
- };
31
- } else {
32
- throw new Error(`Invalid feed id: ${feed.id}`);
33
- }
34
- };
2
+ // import { ScallopConstants } from 'src/models/scallopConstants';
35
3
 
36
4
  /**
37
5
  * Find the closest unlock round timestamp (12AM) to the given unlock at timestamp in seconds.
@@ -1,428 +0,0 @@
1
- import { QueryClient } from '@tanstack/query-core';
2
- import {
3
- SuiObjectArg,
4
- SuiTxBlock,
5
- normalizeStructTag,
6
- parseStructTag,
7
- } from '@scallop-io/sui-kit';
8
- import { SuiKit } from '@scallop-io/sui-kit';
9
- import type {
10
- SuiObjectResponse,
11
- SuiObjectDataOptions,
12
- SuiObjectData,
13
- GetOwnedObjectsParams,
14
- DevInspectResults,
15
- GetDynamicFieldsParams,
16
- DynamicFieldPage,
17
- GetDynamicFieldObjectParams,
18
- GetBalanceParams,
19
- SuiClient,
20
- CoinBalance,
21
- } from '@mysten/sui/client';
22
- import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
23
- import { queryKeys } from 'src/constants';
24
- import { ScallopCacheInstanceParams, ScallopCacheParams } from 'src/types';
25
- import { newSuiKit } from './suiKit';
26
-
27
- type QueryInspectTxnParams = {
28
- queryTarget: string;
29
- args: SuiObjectArg[];
30
- typeArgs?: any[];
31
- };
32
-
33
- const DEFAULT_TOKENS_PER_INTERVAL = 10;
34
-
35
- const deepMergeObject = <T>(curr: T, update: T): T => {
36
- const result = { ...curr }; // Clone the current object to avoid mutation
37
-
38
- for (const key in update) {
39
- if (
40
- update[key] &&
41
- typeof update[key] === 'object' &&
42
- !Array.isArray(update[key])
43
- ) {
44
- // If the value is an object, recurse
45
- result[key] = deepMergeObject(
46
- curr[key] || ({} as T[Extract<keyof T, string>]),
47
- update[key]
48
- );
49
- } else {
50
- // Otherwise, directly assign the value
51
- result[key] = update[key];
52
- }
53
- }
54
-
55
- return result;
56
- };
57
-
58
- export class RateLimiter {
59
- private tokens: number;
60
- private lastRefillTime: number;
61
- private readonly refillRate: number; // tokens per millisecond
62
-
63
- constructor(private readonly capacity: number = 10) {
64
- this.refillRate = this.capacity / 1000; // 10 tokens per second = 0.01 tokens/ms
65
- this.tokens = this.capacity;
66
- this.lastRefillTime = Date.now();
67
- }
68
-
69
- private refill() {
70
- const now = Date.now();
71
- const elapsed = now - this.lastRefillTime;
72
- const newTokens = elapsed * this.refillRate;
73
-
74
- this.tokens = Math.min(this.capacity, this.tokens + newTokens);
75
- this.lastRefillTime = now;
76
- }
77
-
78
- private getTimeToNextToken(): number {
79
- this.refill();
80
-
81
- if (this.tokens >= 1) {
82
- return 0;
83
- }
84
-
85
- // Calculate exact milliseconds needed for 1 full token
86
- const deficit = 1 - this.tokens;
87
- return Math.ceil(deficit / this.refillRate);
88
- }
89
-
90
- async acquireToken(): Promise<void> {
91
- // eslint-disable-next-line no-constant-condition
92
- while (true) {
93
- const waitTime = this.getTimeToNextToken();
94
-
95
- if (waitTime === 0) {
96
- if (this.tokens >= 1) {
97
- this.tokens -= 1;
98
- return;
99
- }
100
- continue;
101
- }
102
-
103
- await new Promise((resolve) => setTimeout(resolve, waitTime));
104
- this.refill();
105
- }
106
- }
107
-
108
- async execute<T>(fn: () => Promise<T>): Promise<T> {
109
- await this.acquireToken();
110
- return await fn();
111
- }
112
- }
113
- /**
114
- * @description
115
- * It provides caching for moveCall, RPC Request, and API Request.
116
- *
117
- *
118
- * @example
119
- * ```typescript
120
- * const scallopCache = new scallopCache(<parameters>);
121
- * scallopCache.<indexer functions>();
122
- * await scallopCache.<indexer async functions>();
123
- * ```
124
- */
125
-
126
- export class ScallopCache {
127
- public readonly params: ScallopCacheParams;
128
-
129
- public queryClient: QueryClient;
130
- public suiKit: SuiKit;
131
- public walletAddress: string;
132
- private limiter: RateLimiter;
133
-
134
- public constructor(
135
- params: ScallopCacheParams = {},
136
- instance?: ScallopCacheInstanceParams
137
- ) {
138
- this.params = params;
139
- this.suiKit = instance?.suiKit ?? newSuiKit(params);
140
- this.queryClient =
141
- instance?.queryClient ??
142
- new QueryClient(params?.cacheOptions ?? DEFAULT_CACHE_OPTIONS);
143
-
144
- // handle case where there's existing queryClient and cacheOptions is also passed
145
- // if (queryClient && cacheOptions) {
146
- // // override the default options with the cacheOptions
147
- // if (cacheOptions.defaultOptions)
148
- // this.queryClient.setDefaultOptions(cacheOptions.defaultOptions);
149
- // // if (cacheOptions.queryCache)
150
- // // this.queryClient.defaultQueryOptions(cacheOptions.queryCache);
151
- // // if(cacheOptions.mutations)this.queryClient.setMutationDefaults(cacheOptions.mutations);
152
- // }
153
-
154
- this.limiter = new RateLimiter(
155
- this.params.tokensPerSecond ?? DEFAULT_TOKENS_PER_INTERVAL
156
- );
157
- this.walletAddress = params.walletAddress ?? this.suiKit.currentAddress();
158
- }
159
-
160
- private get client(): SuiClient {
161
- return this.suiKit.client();
162
- }
163
-
164
- /**
165
- * @description Provides cache for inspectTxn of the SuiKit.
166
- * @param QueryInspectTxnParams
167
- * @param txBlock
168
- * @returns Promise<DevInspectResults>
169
- */
170
- public async queryInspectTxn({
171
- queryTarget,
172
- args,
173
- typeArgs,
174
- }: QueryInspectTxnParams): Promise<DevInspectResults | null> {
175
- const txBlock = new SuiTxBlock();
176
-
177
- const resolvedQueryTarget =
178
- await this.queryGetNormalizedMoveFunction(queryTarget);
179
- if (!resolvedQueryTarget) throw new Error('Invalid query target');
180
-
181
- const { parameters } = resolvedQueryTarget;
182
-
183
- const resolvedArgs = await Promise.all(
184
- (args ?? []).map(async (arg, idx) => {
185
- if (typeof arg !== 'string') return arg;
186
-
187
- const cachedData = (await this.queryGetObject(arg))?.data;
188
- if (!cachedData) return arg;
189
-
190
- const owner = cachedData.owner;
191
- if (!owner || typeof owner !== 'object' || !('Shared' in owner))
192
- return {
193
- objectId: cachedData.objectId,
194
- version: cachedData.version,
195
- digest: cachedData.digest,
196
- };
197
-
198
- const parameter = parameters[idx];
199
- if (
200
- typeof parameter !== 'object' ||
201
- !('MutableReference' in parameter || 'Reference' in parameter)
202
- )
203
- return arg;
204
-
205
- return {
206
- objectId: cachedData.objectId,
207
- initialSharedVersion: owner.Shared.initial_shared_version,
208
- mutable: 'MutableReference' in parameter,
209
- };
210
- })
211
- );
212
- txBlock.moveCall(queryTarget, resolvedArgs, typeArgs);
213
-
214
- const query = await this.queryClient.fetchQuery({
215
- queryKey: queryKeys.rpc.getInspectTxn(queryTarget, args, typeArgs),
216
- queryFn: async () => {
217
- return await this.limiter.execute(() =>
218
- this.suiKit.inspectTxn(txBlock)
219
- );
220
- },
221
- });
222
- return query;
223
- }
224
-
225
- private async queryGetNormalizedMoveFunction(target: string) {
226
- const { address, module, name } = parseStructTag(target);
227
- return this.queryClient.fetchQuery({
228
- queryKey: queryKeys.rpc.getNormalizedMoveFunction(target),
229
- queryFn: async () => {
230
- return await this.limiter.execute(() =>
231
- this.client.getNormalizedMoveFunction({
232
- package: address,
233
- module,
234
- function: name,
235
- })
236
- );
237
- },
238
- });
239
- }
240
-
241
- /**
242
- * @description Provides cache for getObject of the SuiKit.
243
- * @param objectId
244
- * @param QueryObjectParams
245
- * @returns Promise<SuiObjectResponse>
246
- */
247
- public async queryGetObject(
248
- objectId: string,
249
- options?: SuiObjectDataOptions
250
- ) {
251
- options = {
252
- ...options,
253
- showOwner: true,
254
- showContent: true,
255
- showType: true,
256
- };
257
- return this.queryClient.fetchQuery({
258
- queryKey: queryKeys.rpc.getObject(objectId, options),
259
- queryFn: async () => {
260
- return await this.limiter.execute(() =>
261
- this.client.getObject({
262
- id: objectId,
263
- options,
264
- })
265
- );
266
- },
267
- });
268
- }
269
-
270
- /**
271
- * @description Provides cache for getObjects of the SuiKit.
272
- * @param objectIds
273
- * @returns Promise<SuiObjectData[]>
274
- */
275
- public async queryGetObjects(objectIds: string[]): Promise<SuiObjectData[]> {
276
- if (objectIds.length === 0) return [];
277
- const options: SuiObjectDataOptions = {
278
- showContent: true,
279
- showOwner: true,
280
- showType: true,
281
- };
282
-
283
- return this.queryClient.fetchQuery({
284
- queryKey: queryKeys.rpc.getObjects(objectIds),
285
- queryFn: async () => {
286
- const results = await this.limiter.execute(() =>
287
- this.suiKit.getObjects(objectIds, options)
288
- );
289
- if (results) {
290
- results.forEach((result) => {
291
- // fetch previous data
292
- const queryKey = queryKeys.rpc.getObject(result.objectId);
293
- const prevDatas =
294
- this.queryClient.getQueriesData<SuiObjectResponse>({
295
- exact: false,
296
- queryKey,
297
- });
298
- prevDatas.forEach(([key, prevData]) => {
299
- this.queryClient.setQueryData(
300
- key,
301
- deepMergeObject(prevData, { data: result, error: null }),
302
- { updatedAt: Date.now() }
303
- );
304
- });
305
- });
306
- }
307
- return results;
308
- },
309
- });
310
- }
311
-
312
- /**
313
- * @description Provides cache for getOwnedObjects of the SuiKit.
314
- * @param input
315
- * @returns Promise<PaginatedObjectsResponse>
316
- */
317
- public async queryGetOwnedObjects(input: GetOwnedObjectsParams) {
318
- // @TODO: This query need its own separate rate limiter (as owned objects can theoretically be infinite), need a better way to handle this
319
- return this.queryClient.fetchQuery({
320
- queryKey: queryKeys.rpc.getOwnedObjects(input),
321
- queryFn: async () => {
322
- const results = await this.limiter.execute(() =>
323
- this.client.getOwnedObjects(input)
324
- );
325
- if (results && results.data.length > 0) {
326
- results.data
327
- .filter(
328
- (
329
- result
330
- ): result is typeof result &
331
- NonNullable<{ data: SuiObjectData }> => !!result.data
332
- )
333
- .forEach((result) => {
334
- // fetch previous data
335
- const queryKey = queryKeys.rpc.getObject(result.data.objectId);
336
- const prevDatas =
337
- this.queryClient.getQueriesData<SuiObjectResponse>({
338
- exact: false,
339
- queryKey,
340
- });
341
- prevDatas.forEach(([key, prevData]) => {
342
- this.queryClient.setQueryData(
343
- key,
344
- deepMergeObject(prevData, { data: result.data, error: null }),
345
- { updatedAt: Date.now() }
346
- );
347
- });
348
- });
349
- }
350
- return results;
351
- },
352
- });
353
- }
354
-
355
- public async queryGetDynamicFields(
356
- input: GetDynamicFieldsParams
357
- ): Promise<DynamicFieldPage | null> {
358
- return this.queryClient.fetchQuery({
359
- queryKey: queryKeys.rpc.getDynamicFields(input),
360
- queryFn: async () => {
361
- return await this.limiter.execute(() =>
362
- this.client.getDynamicFields(input)
363
- );
364
- },
365
- });
366
- }
367
-
368
- public async queryGetDynamicFieldObject(
369
- input: GetDynamicFieldObjectParams
370
- ): Promise<SuiObjectResponse | null> {
371
- return this.queryClient.fetchQuery({
372
- queryKey: queryKeys.rpc.getDynamicFieldObject(input),
373
- queryFn: async () => {
374
- const result = await this.limiter.execute(() =>
375
- this.client.getDynamicFieldObject(input)
376
- );
377
- if (result?.data) {
378
- const queryKey = queryKeys.rpc.getObject(result.data.objectId);
379
- const prevDatas = this.queryClient.getQueriesData<SuiObjectResponse>({
380
- exact: false,
381
- queryKey,
382
- });
383
- prevDatas.forEach(([key, prevData]) => {
384
- this.queryClient.setQueryData(
385
- key,
386
- deepMergeObject(prevData, { data: result.data, error: null }),
387
- { updatedAt: Date.now() }
388
- );
389
- });
390
- }
391
- return result;
392
- },
393
- });
394
- }
395
-
396
- public async queryGetAllCoinBalances(
397
- owner: string
398
- ): Promise<{ [k: string]: CoinBalance }> {
399
- return this.queryClient.fetchQuery({
400
- queryKey: queryKeys.rpc.getAllCoinBalances(owner),
401
- queryFn: async () => {
402
- const allBalances = await this.limiter.execute(() =>
403
- this.client.getAllBalances({ owner })
404
- );
405
- if (!allBalances) return {};
406
- const balances = allBalances.reduce(
407
- (acc, coinBalance) => {
408
- if (coinBalance.totalBalance !== '0') {
409
- acc[normalizeStructTag(coinBalance.coinType)] = coinBalance;
410
- }
411
- return acc;
412
- },
413
- {} as { [k: string]: CoinBalance }
414
- );
415
-
416
- return balances;
417
- },
418
- });
419
- }
420
-
421
- public async queryGetCoinBalance(
422
- input: GetBalanceParams
423
- ): Promise<CoinBalance | null> {
424
- if (!input.coinType) return null;
425
- const coinBalances = await this.queryGetAllCoinBalances(input.owner);
426
- return coinBalances[normalizeStructTag(input.coinType)] ?? null;
427
- }
428
- }
@@ -1,18 +0,0 @@
1
- import { ScallopCache } from 'src/models/scallopCache';
2
- import { partitionArray } from 'src/utils';
3
-
4
- export const queryMultipleObjects = async (
5
- cache: ScallopCache,
6
- rawObjectIds: string[],
7
- partitionSize = 50
8
- ) => {
9
- const objectIdsPartition = partitionArray(rawObjectIds, partitionSize);
10
-
11
- const objects = [];
12
- for (const objectIds of objectIdsPartition) {
13
- const result = await cache.queryGetObjects(objectIds);
14
- objects.push(...result);
15
- }
16
-
17
- return objects;
18
- };
@@ -1,117 +0,0 @@
1
- import type { SuiTransactionBlockResponse } from '@mysten/sui/client';
2
- import type { Transaction, TransactionResult } from '@mysten/sui/transactions';
3
- import type { SuiKit, SuiKitParams, NetworkType } from '@scallop-io/sui-kit';
4
- import type {
5
- ScallopAddress,
6
- ScallopQuery,
7
- ScallopUtils,
8
- ScallopBuilder,
9
- ScallopIndexer,
10
- } from 'src/models';
11
- import { ScallopCache } from 'src/models/scallopCache';
12
- import { AddressesInterface } from './address';
13
- import { QueryClient, QueryClientConfig } from '@tanstack/query-core';
14
- import { AxiosInstance } from 'axios';
15
- import { PoolAddress, Whitelist } from './constant';
16
- import { ScallopConstants } from 'src/models/scallopConstants';
17
-
18
- export type ScallopClientFnReturnType<T extends boolean> = T extends true
19
- ? SuiTransactionBlockResponse
20
- : Transaction;
21
-
22
- export type ScallopClientVeScaReturnType<T extends boolean> = T extends true
23
- ? SuiTransactionBlockResponse
24
- : {
25
- tx: Transaction;
26
- scaCoin: TransactionResult;
27
- };
28
-
29
- export type ScallopBaseInstanceParams = {
30
- suiKit?: SuiKit;
31
- cache?: ScallopCache;
32
- };
33
-
34
- export type ScallopCacheInstanceParams = ScallopBaseInstanceParams & {
35
- queryClient?: QueryClient;
36
- };
37
-
38
- export type ScallopAddressInstanceParams = ScallopBaseInstanceParams & {
39
- cache?: ScallopCache;
40
- };
41
-
42
- export type ScallopConstantsInstanceParams = {
43
- address?: ScallopAddress;
44
- cache?: ScallopCache;
45
- };
46
-
47
- export type ScallopIndexerInstanceParams = {
48
- cache?: ScallopCache;
49
- };
50
-
51
- export type ScallopUtilsInstanceParams = ScallopBaseInstanceParams & {
52
- constants?: ScallopConstants;
53
- };
54
-
55
- export type ScallopQueryInstanceParams = ScallopBaseInstanceParams & {
56
- utils?: ScallopUtils;
57
- indexer?: ScallopIndexer;
58
- };
59
-
60
- export type ScallopBuilderInstanceParams = ScallopBaseInstanceParams & {
61
- query?: ScallopQuery;
62
- };
63
-
64
- export type ScallopClientInstanceParams = ScallopBaseInstanceParams & {
65
- builder?: ScallopBuilder;
66
- };
67
-
68
- export type ScallopCacheConfig = {
69
- tokensPerInterval?: number; // How many requests per interval
70
- interval?: number; // Interval in milliseconds
71
- };
72
-
73
- export type ScallopCacheParams = {
74
- walletAddress?: string;
75
- cacheOptions?: QueryClientConfig;
76
- config?: ScallopCacheConfig;
77
- tokensPerSecond?: number; // for rate limit
78
- } & Partial<SuiKitParams>;
79
-
80
- export type ScallopIndexerParams = ScallopCacheParams & {
81
- indexerApiUrl?: string;
82
- axios?: AxiosInstance;
83
- };
84
-
85
- export type ScallopAddressParams = ScallopCacheParams & {
86
- addressApiUrl?: string;
87
- addressId: string;
88
- auth?: string;
89
- network?: NetworkType;
90
- forceAddressesInterface?: Partial<Record<NetworkType, AddressesInterface>>;
91
- };
92
-
93
- export type ScallopConstantsParams = ScallopAddressParams & {
94
- poolAddressesApiUrl?: string;
95
- whitelistApiUrl?: string;
96
- forcePoolAddressInterface?: Record<string, PoolAddress>;
97
- forceWhitelistInterface?: Whitelist;
98
- };
99
-
100
- export type ScallopUtilsParams = ScallopAddressParams &
101
- ScallopConstantsParams & {
102
- pythEndpoints?: string[];
103
- };
104
-
105
- export type ScallopQueryParams = ScallopUtilsParams & ScallopIndexerParams;
106
-
107
- export type ScallopBuilderParams = ScallopQueryParams & {
108
- usePythPullModel?: boolean;
109
- useOnChainXOracleList?: boolean;
110
- };
111
-
112
- export type ScallopClientParams = ScallopBuilderParams;
113
- export type ScallopParams = Partial<SuiKitParams> &
114
- ScallopAddressParams &
115
- ScallopConstantsParams & {
116
- walletAddress?: string;
117
- };