@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.
- package/dist/constants/common.d.ts +6 -6
- package/dist/constants/enum.d.ts +2 -2
- package/dist/constants/index.d.ts +0 -1
- package/dist/constants/poolAddress.d.ts +2 -0
- package/dist/constants/queryKeys.d.ts +3 -4
- package/dist/index.d.ts +0 -1
- package/dist/index.js +2087 -1617
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2054 -1579
- package/dist/index.mjs.map +1 -1
- package/dist/models/scallop.d.ts +1 -2
- package/dist/models/scallopBuilder.d.ts +2 -1
- package/dist/models/scallopCache.d.ts +18 -12
- package/dist/models/scallopQuery.d.ts +98 -11
- package/dist/models/scallopUtils.d.ts +4 -4
- package/dist/queries/borrowIncentiveQuery.d.ts +6 -1
- package/dist/queries/coreQuery.d.ts +2 -0
- package/dist/queries/objectsQuery.d.ts +1 -2
- package/dist/queries/poolAddressesQuery.d.ts +5 -1
- package/dist/queries/portfolioQuery.d.ts +71 -5
- package/dist/queries/priceQuery.d.ts +4 -0
- package/dist/queries/sCoinQuery.d.ts +1 -1
- package/dist/types/builder/core.d.ts +6 -6
- package/dist/types/model.d.ts +8 -2
- package/dist/utils/index.d.ts +0 -2
- package/package.json +7 -7
- package/src/builders/borrowIncentiveBuilder.ts +11 -5
- package/src/builders/coreBuilder.ts +62 -33
- package/src/builders/loyaltyProgramBuilder.ts +3 -2
- package/src/builders/referralBuilder.ts +16 -6
- package/src/builders/sCoinBuilder.ts +6 -4
- package/src/builders/spoolBuilder.ts +14 -7
- package/src/builders/vescaBuilder.ts +13 -7
- package/src/constants/coinGecko.ts +2 -0
- package/src/constants/common.ts +7 -1
- package/src/constants/enum.ts +46 -20
- package/src/constants/index.ts +0 -1
- package/src/constants/poolAddress.ts +252 -66
- package/src/constants/pyth.ts +2 -0
- package/src/constants/queryKeys.ts +7 -9
- package/src/constants/testAddress.ts +24 -0
- package/src/index.ts +0 -1
- package/src/models/scallop.ts +9 -13
- package/src/models/scallopAddress.ts +2 -9
- package/src/models/scallopBuilder.ts +62 -8
- package/src/models/scallopCache.ts +236 -82
- package/src/models/scallopClient.ts +4 -6
- package/src/models/scallopIndexer.ts +1 -5
- package/src/models/scallopQuery.ts +62 -25
- package/src/models/scallopUtils.ts +9 -13
- package/src/queries/borrowIncentiveQuery.ts +6 -13
- package/src/queries/coreQuery.ts +88 -54
- package/src/queries/loyaltyProgramQuery.ts +1 -3
- package/src/queries/objectsQuery.ts +1 -3
- package/src/queries/poolAddressesQuery.ts +16 -7
- package/src/queries/portfolioQuery.ts +253 -21
- package/src/queries/priceQuery.ts +2 -7
- package/src/queries/sCoinQuery.ts +2 -2
- package/src/queries/spoolQuery.ts +21 -20
- package/src/queries/vescaQuery.ts +3 -7
- package/src/types/builder/core.ts +24 -5
- package/src/types/model.ts +13 -2
- package/src/utils/index.ts +0 -2
- package/src/utils/indexer.ts +3 -1
- package/src/utils/query.ts +2 -2
- 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
|
@@ -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 {
|
|
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
|
-
|
|
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
|
|
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
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
55
|
-
|
|
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 ??
|
|
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.
|
|
74
|
-
this.
|
|
75
|
-
|
|
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
|
|
81
|
-
|
|
82
|
-
|
|
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
|
|
88
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
131
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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]:
|
|
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]:
|
|
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(
|
|
308
|
-
|
|
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
|
-
|
|
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: {
|