@scallop-io/sui-scallop-sdk 0.46.52 → 0.46.54
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/tokenBucket.d.ts +2 -0
- package/dist/index.js +1995 -1913
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1944 -1862
- package/dist/index.mjs.map +1 -1
- package/dist/models/scallop.d.ts +2 -1
- package/dist/models/scallopCache.d.ts +11 -8
- package/dist/models/scallopClient.d.ts +2 -2
- package/dist/models/scallopQuery.d.ts +1 -1
- package/dist/models/scallopUtils.d.ts +9 -1
- package/dist/queries/coreQuery.d.ts +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/tokenBucket.d.ts +11 -0
- package/package.json +1 -1
- package/src/builders/loyaltyProgramBuilder.ts +6 -12
- package/src/builders/spoolBuilder.ts +9 -45
- package/src/constants/tokenBucket.ts +2 -0
- package/src/models/scallop.ts +13 -2
- package/src/models/scallopCache.ts +55 -25
- package/src/models/scallopClient.ts +30 -29
- package/src/models/scallopUtils.ts +42 -10
- package/src/queries/borrowIncentiveQuery.ts +12 -10
- package/src/queries/coreQuery.ts +33 -16
- package/src/queries/loyaltyProgramQuery.ts +2 -2
- package/src/queries/portfolioQuery.ts +2 -2
- package/src/queries/priceQuery.ts +1 -1
- package/src/queries/referralQuery.ts +1 -1
- package/src/queries/sCoinQuery.ts +1 -1
- package/src/queries/spoolQuery.ts +4 -2
- package/src/queries/vescaQuery.ts +8 -3
- package/src/utils/index.ts +1 -0
- package/src/utils/tokenBucket.ts +63 -0
package/dist/models/scallop.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { ScallopParams } from '../types/';
|
|
|
8
8
|
import { ScallopIndexer } from './scallopIndexer';
|
|
9
9
|
import { ScallopCache } from './scallopCache';
|
|
10
10
|
import { QueryClientConfig } from '@tanstack/query-core';
|
|
11
|
+
import { TokenBucket } from 'src/utils';
|
|
11
12
|
/**
|
|
12
13
|
* @argument params - The parameters for the Scallop instance.
|
|
13
14
|
* @argument cacheOptions - The cache options for the QueryClient.
|
|
@@ -30,7 +31,7 @@ export declare class Scallop {
|
|
|
30
31
|
suiKit: SuiKit;
|
|
31
32
|
cache: ScallopCache;
|
|
32
33
|
private _address;
|
|
33
|
-
constructor(params: ScallopParams, cacheOptions?: QueryClientConfig);
|
|
34
|
+
constructor(params: ScallopParams, cacheOptions?: QueryClientConfig, tokenBucket?: TokenBucket);
|
|
34
35
|
/**
|
|
35
36
|
* Get a scallop address instance that already has read addresses.
|
|
36
37
|
*
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { QueryClient, QueryClientConfig } from '@tanstack/query-core';
|
|
2
2
|
import { SuiTxArg } from '@scallop-io/sui-kit';
|
|
3
3
|
import { SuiKit } from '@scallop-io/sui-kit';
|
|
4
|
-
import type { SuiObjectResponse, SuiObjectDataOptions, SuiObjectData,
|
|
4
|
+
import type { SuiObjectResponse, SuiObjectDataOptions, SuiObjectData, GetOwnedObjectsParams, DevInspectResults, GetDynamicFieldsParams, DynamicFieldPage, GetDynamicFieldObjectParams, GetBalanceParams } from '@mysten/sui.js/client';
|
|
5
|
+
import { TokenBucket } from 'src/utils';
|
|
5
6
|
type QueryInspectTxnParams = {
|
|
6
7
|
queryTarget: string;
|
|
7
8
|
args: SuiTxArg[];
|
|
@@ -22,8 +23,10 @@ type QueryInspectTxnParams = {
|
|
|
22
23
|
export declare class ScallopCache {
|
|
23
24
|
readonly queryClient: QueryClient;
|
|
24
25
|
readonly _suiKit?: SuiKit;
|
|
25
|
-
|
|
26
|
+
private tokenBucket;
|
|
27
|
+
constructor(cacheOptions?: QueryClientConfig, suiKit?: SuiKit, tokenBucket?: TokenBucket);
|
|
26
28
|
private get suiKit();
|
|
29
|
+
private get client();
|
|
27
30
|
/**
|
|
28
31
|
* @description Invalidate cache based on the refetchType parameter
|
|
29
32
|
* @param refetchType Determines the type of queries to be refetched. Defaults to `active`.
|
|
@@ -38,21 +41,21 @@ export declare class ScallopCache {
|
|
|
38
41
|
* @description Cache protocol config call for 60 seconds.
|
|
39
42
|
* @returns Promise<ProtocolConfig>
|
|
40
43
|
*/
|
|
41
|
-
getProtocolConfig(): Promise<import("@mysten/sui.js/client").ProtocolConfig>;
|
|
44
|
+
getProtocolConfig(): Promise<import("@mysten/sui.js/client").ProtocolConfig | null>;
|
|
42
45
|
/**
|
|
43
46
|
* @description Provides cache for inspectTxn of the SuiKit.
|
|
44
47
|
* @param QueryInspectTxnParams
|
|
45
48
|
* @param txBlock
|
|
46
49
|
* @returns Promise<DevInspectResults>
|
|
47
50
|
*/
|
|
48
|
-
queryInspectTxn({ queryTarget, args, typeArgs, }: QueryInspectTxnParams): Promise<DevInspectResults>;
|
|
51
|
+
queryInspectTxn({ queryTarget, args, typeArgs, }: QueryInspectTxnParams): Promise<DevInspectResults | null>;
|
|
49
52
|
/**
|
|
50
53
|
* @description Provides cache for getObject of the SuiKit.
|
|
51
54
|
* @param objectId
|
|
52
55
|
* @param QueryObjectParams
|
|
53
56
|
* @returns Promise<SuiObjectResponse>
|
|
54
57
|
*/
|
|
55
|
-
queryGetObject(objectId: string, options?: SuiObjectDataOptions): Promise<SuiObjectResponse>;
|
|
58
|
+
queryGetObject(objectId: string, options?: SuiObjectDataOptions): Promise<SuiObjectResponse | null>;
|
|
56
59
|
/**
|
|
57
60
|
* @description Provides cache for getObjects of the SuiKit.
|
|
58
61
|
* @param objectIds
|
|
@@ -64,9 +67,9 @@ export declare class ScallopCache {
|
|
|
64
67
|
* @param input
|
|
65
68
|
* @returns Promise<PaginatedObjectsResponse>
|
|
66
69
|
*/
|
|
67
|
-
queryGetOwnedObjects(input: GetOwnedObjectsParams): Promise<PaginatedObjectsResponse>;
|
|
68
|
-
queryGetDynamicFields(input: GetDynamicFieldsParams): Promise<DynamicFieldPage>;
|
|
69
|
-
queryGetDynamicFieldObject(input: GetDynamicFieldObjectParams): Promise<SuiObjectResponse>;
|
|
70
|
+
queryGetOwnedObjects(input: GetOwnedObjectsParams): Promise<import("@mysten/sui.js/client").PaginatedObjectsResponse | null>;
|
|
71
|
+
queryGetDynamicFields(input: GetDynamicFieldsParams): Promise<DynamicFieldPage | null>;
|
|
72
|
+
queryGetDynamicFieldObject(input: GetDynamicFieldObjectParams): Promise<SuiObjectResponse | null>;
|
|
70
73
|
queryGetAllCoinBalances(owner: string): Promise<{
|
|
71
74
|
[k: string]: string;
|
|
72
75
|
}>;
|
|
@@ -3,11 +3,11 @@ import { ScallopAddress } from './scallopAddress';
|
|
|
3
3
|
import { ScallopUtils } from './scallopUtils';
|
|
4
4
|
import { ScallopBuilder } from './scallopBuilder';
|
|
5
5
|
import { ScallopQuery } from './scallopQuery';
|
|
6
|
+
import { ScallopCache } from './scallopCache';
|
|
6
7
|
import type { SuiTransactionBlockResponse } from '@mysten/sui.js/client';
|
|
7
8
|
import type { TransactionObjectArgument } from '@mysten/sui.js/transactions';
|
|
8
9
|
import type { SuiObjectArg } from '@scallop-io/sui-kit';
|
|
9
10
|
import type { ScallopClientFnReturnType, ScallopInstanceParams, ScallopClientParams, SupportPoolCoins, SupportCollateralCoins, SupportAssetCoins, SupportStakeCoins, SupportStakeMarketCoins, SupportBorrowIncentiveCoins, ScallopTxBlock } from '../types';
|
|
10
|
-
import { ScallopCache } from './scallopCache';
|
|
11
11
|
/**
|
|
12
12
|
* @description
|
|
13
13
|
* It provides contract interaction operations for general users.
|
|
@@ -64,7 +64,7 @@ export declare class ScallopClient {
|
|
|
64
64
|
* @param obligationId - The obligation id.
|
|
65
65
|
* @return Obligation data.
|
|
66
66
|
*/
|
|
67
|
-
queryObligation(obligationId: string): Promise<import("../types").ObligationQueryInterface>;
|
|
67
|
+
queryObligation(obligationId: string): Promise<import("../types").ObligationQueryInterface | undefined>;
|
|
68
68
|
/**
|
|
69
69
|
* Query all stake accounts data.
|
|
70
70
|
*
|
|
@@ -118,7 +118,7 @@ export declare class ScallopQuery {
|
|
|
118
118
|
* @param obligationId - The obligation id.
|
|
119
119
|
* @return Obligation data.
|
|
120
120
|
*/
|
|
121
|
-
queryObligation(obligationId: string): Promise<import("../types").ObligationQueryInterface>;
|
|
121
|
+
queryObligation(obligationId: string): Promise<import("../types").ObligationQueryInterface | undefined>;
|
|
122
122
|
/**
|
|
123
123
|
* Get all asset coin amounts.
|
|
124
124
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SuiAddressArg } from '@scallop-io/sui-kit';
|
|
2
1
|
import { ScallopAddress } from './scallopAddress';
|
|
3
2
|
import type { ScallopUtilsParams, ScallopInstanceParams, SupportCoins, SupportAssetCoins, SupportMarketCoins, SupportStakeMarketCoins, SupportBorrowIncentiveCoins, CoinWrappedType, SupportSCoin } from '../types';
|
|
3
|
+
import type { SuiAddressArg, SuiTxArg, SuiTxBlock } from '@scallop-io/sui-kit';
|
|
4
4
|
/**
|
|
5
5
|
* @description
|
|
6
6
|
* Integrates some helper functions frequently used in interactions with the Scallop contract.
|
|
@@ -148,6 +148,14 @@ export declare class ScallopUtils {
|
|
|
148
148
|
version: string;
|
|
149
149
|
balance: string;
|
|
150
150
|
}[]>;
|
|
151
|
+
/**
|
|
152
|
+
* Merge coins with type `coinType` to dest
|
|
153
|
+
* @param txBlock
|
|
154
|
+
* @param dest
|
|
155
|
+
* @param coinType
|
|
156
|
+
* @param sender
|
|
157
|
+
*/
|
|
158
|
+
mergeSimilarCoins(txBlock: SuiTxBlock, dest: SuiTxArg, coinType: string, sender: string): Promise<void>;
|
|
151
159
|
/**
|
|
152
160
|
* Get all asset coin names in the obligation record by obligation id.
|
|
153
161
|
*
|
|
@@ -113,7 +113,7 @@ export declare const getObligationLocked: (query: ScallopQuery, obligationId: st
|
|
|
113
113
|
* @param obligationId - The obligation id.
|
|
114
114
|
* @return Obligation data.
|
|
115
115
|
*/
|
|
116
|
-
export declare const queryObligation: (query: ScallopQuery, obligationId: SuiAddressArg) => Promise<ObligationQueryInterface>;
|
|
116
|
+
export declare const queryObligation: (query: ScallopQuery, obligationId: SuiAddressArg) => Promise<ObligationQueryInterface | undefined>;
|
|
117
117
|
/**
|
|
118
118
|
* Query all owned coin amount.
|
|
119
119
|
*
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare class TokenBucket {
|
|
2
|
+
private tokensPerInterval;
|
|
3
|
+
private interval;
|
|
4
|
+
private tokens;
|
|
5
|
+
private lastRefill;
|
|
6
|
+
constructor(tokensPerInterval: number, intervalInMs: number);
|
|
7
|
+
refill(): void;
|
|
8
|
+
removeTokens(count: number): boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const callWithRateLimit: <T>(tokenBucket: TokenBucket, fn: () => Promise<T>, retryDelayInMs?: number, maxRetries?: number) => Promise<T | null>;
|
|
11
|
+
export { TokenBucket, callWithRateLimit };
|
package/package.json
CHANGED
|
@@ -47,18 +47,12 @@ const generateLoyaltyProgramQuickMethod: GenerateLoyaltyProgramQuickMethod = ({
|
|
|
47
47
|
const rewardCoin = txBlock.claimLoyaltyRevenue(veScaKey);
|
|
48
48
|
|
|
49
49
|
// get existing sca coin to merge with
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
txBlock.mergeCoins(rewardCoin, existingScaCoin);
|
|
57
|
-
} catch (e) {
|
|
58
|
-
// ignore
|
|
59
|
-
} finally {
|
|
60
|
-
toTransferObject.push(rewardCoin);
|
|
61
|
-
}
|
|
50
|
+
await builder.utils.mergeSimilarCoins(
|
|
51
|
+
txBlock,
|
|
52
|
+
rewardCoin,
|
|
53
|
+
coinIds.sca,
|
|
54
|
+
requireSender(txBlock)
|
|
55
|
+
);
|
|
62
56
|
|
|
63
57
|
if (toTransferObject.length > 0) {
|
|
64
58
|
txBlock.transferObjects(toTransferObject, sender);
|
|
@@ -90,15 +90,15 @@ const stakeHelper = async (
|
|
|
90
90
|
builder: ScallopBuilder,
|
|
91
91
|
txBlock: SuiTxBlockWithSpoolNormalMethods,
|
|
92
92
|
stakeAccount: SuiAddressArg,
|
|
93
|
-
coinType: string,
|
|
94
93
|
coinName: SupportStakeMarketCoins,
|
|
95
94
|
amount: number,
|
|
96
95
|
sender: string,
|
|
97
96
|
isSCoin: boolean = false
|
|
98
97
|
) => {
|
|
99
98
|
try {
|
|
100
|
-
const
|
|
101
|
-
|
|
99
|
+
const { takeCoin, leftCoin, totalAmount } = isSCoin
|
|
100
|
+
? await builder.selectSCoin(txBlock, coinName, amount, sender)
|
|
101
|
+
: await builder.selectMarketCoin(txBlock, coinName, amount, sender);
|
|
102
102
|
if (isSCoin) {
|
|
103
103
|
const marketCoin = txBlock.burnSCoin(coinName, takeCoin);
|
|
104
104
|
txBlock.stake(stakeAccount, marketCoin, coinName);
|
|
@@ -106,9 +106,9 @@ const stakeHelper = async (
|
|
|
106
106
|
txBlock.stake(stakeAccount, takeCoin, coinName);
|
|
107
107
|
}
|
|
108
108
|
txBlock.transferObjects([leftCoin], sender);
|
|
109
|
-
return
|
|
109
|
+
return totalAmount;
|
|
110
110
|
} catch (e) {
|
|
111
|
-
return
|
|
111
|
+
return 0;
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
114
|
|
|
@@ -213,28 +213,24 @@ const generateSpoolQuickMethod: GenerateSpoolQuickMethod = ({
|
|
|
213
213
|
stakeAccountId
|
|
214
214
|
);
|
|
215
215
|
|
|
216
|
-
const marketCoinType =
|
|
217
|
-
builder.utils.parseMarketCoinType(stakeMarketCoinName);
|
|
218
|
-
const sCoinType = builder.utils.parseSCoinType(stakeMarketCoinName);
|
|
219
216
|
if (typeof amountOrMarketCoin === 'number') {
|
|
220
217
|
// try stake market coin
|
|
221
|
-
const
|
|
218
|
+
const stakedMarketCoinAmount = await stakeHelper(
|
|
222
219
|
builder,
|
|
223
220
|
txBlock,
|
|
224
221
|
stakeAccountIds[0],
|
|
225
|
-
marketCoinType,
|
|
226
222
|
stakeMarketCoinName,
|
|
227
223
|
amountOrMarketCoin,
|
|
228
224
|
sender
|
|
229
225
|
);
|
|
230
226
|
|
|
227
|
+
amountOrMarketCoin -= stakedMarketCoinAmount;
|
|
231
228
|
// no market coin, try sCoin
|
|
232
|
-
if (
|
|
229
|
+
if (amountOrMarketCoin > 0) {
|
|
233
230
|
await stakeHelper(
|
|
234
231
|
builder,
|
|
235
232
|
txBlock,
|
|
236
233
|
stakeAccountIds[0],
|
|
237
|
-
sCoinType,
|
|
238
234
|
stakeMarketCoinName,
|
|
239
235
|
amountOrMarketCoin,
|
|
240
236
|
sender,
|
|
@@ -280,7 +276,7 @@ const generateSpoolQuickMethod: GenerateSpoolQuickMethod = ({
|
|
|
280
276
|
}
|
|
281
277
|
|
|
282
278
|
amount -= amountToUnstake;
|
|
283
|
-
if (amount
|
|
279
|
+
if (amount <= 0) break;
|
|
284
280
|
}
|
|
285
281
|
|
|
286
282
|
if (toTransfer.length > 0) {
|
|
@@ -289,38 +285,6 @@ const generateSpoolQuickMethod: GenerateSpoolQuickMethod = ({
|
|
|
289
285
|
if (toTransfer.length > 1) {
|
|
290
286
|
txBlock.mergeCoins(mergedCoin, toTransfer.slice(1));
|
|
291
287
|
}
|
|
292
|
-
|
|
293
|
-
if (returnSCoin) {
|
|
294
|
-
// check for existing sCoins
|
|
295
|
-
try {
|
|
296
|
-
const existingCoins = await builder.utils.selectCoins(
|
|
297
|
-
Number.MAX_SAFE_INTEGER,
|
|
298
|
-
builder.utils.parseSCoinType(stakeMarketCoinName),
|
|
299
|
-
requireSender(txBlock)
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
if (existingCoins.length > 0) {
|
|
303
|
-
txBlock.mergeCoins(mergedCoin, existingCoins);
|
|
304
|
-
}
|
|
305
|
-
} catch (e) {
|
|
306
|
-
// ignore
|
|
307
|
-
}
|
|
308
|
-
} else {
|
|
309
|
-
// check for existing market coins
|
|
310
|
-
try {
|
|
311
|
-
const existingCoins = await builder.utils.selectCoins(
|
|
312
|
-
Number.MAX_SAFE_INTEGER,
|
|
313
|
-
builder.utils.parseMarketCoinType(stakeMarketCoinName),
|
|
314
|
-
requireSender(txBlock)
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
if (existingCoins.length > 0) {
|
|
318
|
-
txBlock.mergeCoins(mergedCoin, existingCoins);
|
|
319
|
-
}
|
|
320
|
-
} catch (e) {
|
|
321
|
-
// ignore
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
288
|
return mergedCoin;
|
|
325
289
|
}
|
|
326
290
|
},
|
package/src/models/scallop.ts
CHANGED
|
@@ -10,6 +10,11 @@ import { ScallopIndexer } from './scallopIndexer';
|
|
|
10
10
|
import { ScallopCache } from './scallopCache';
|
|
11
11
|
import { QueryClientConfig } from '@tanstack/query-core';
|
|
12
12
|
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
13
|
+
import { TokenBucket } from 'src/utils';
|
|
14
|
+
import {
|
|
15
|
+
DEFAULT_INTERVAL_IN_MS,
|
|
16
|
+
DEFAULT_TOKENS_PER_INTERVAL,
|
|
17
|
+
} from 'src/constants/tokenBucket';
|
|
13
18
|
|
|
14
19
|
/**
|
|
15
20
|
* @argument params - The parameters for the Scallop instance.
|
|
@@ -35,12 +40,18 @@ export class Scallop {
|
|
|
35
40
|
|
|
36
41
|
private _address: ScallopAddress;
|
|
37
42
|
|
|
38
|
-
public constructor(
|
|
43
|
+
public constructor(
|
|
44
|
+
params: ScallopParams,
|
|
45
|
+
cacheOptions?: QueryClientConfig,
|
|
46
|
+
tokenBucket?: TokenBucket
|
|
47
|
+
) {
|
|
39
48
|
this.params = params;
|
|
40
49
|
this.suiKit = new SuiKit(params);
|
|
41
50
|
this.cache = new ScallopCache(
|
|
42
51
|
cacheOptions ?? DEFAULT_CACHE_OPTIONS,
|
|
43
|
-
this.suiKit
|
|
52
|
+
this.suiKit,
|
|
53
|
+
tokenBucket ??
|
|
54
|
+
new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS)
|
|
44
55
|
);
|
|
45
56
|
this._address = new ScallopAddress(
|
|
46
57
|
{
|
|
@@ -10,15 +10,20 @@ import type {
|
|
|
10
10
|
SuiObjectResponse,
|
|
11
11
|
SuiObjectDataOptions,
|
|
12
12
|
SuiObjectData,
|
|
13
|
-
PaginatedObjectsResponse,
|
|
14
13
|
GetOwnedObjectsParams,
|
|
15
14
|
DevInspectResults,
|
|
16
15
|
GetDynamicFieldsParams,
|
|
17
16
|
DynamicFieldPage,
|
|
18
17
|
GetDynamicFieldObjectParams,
|
|
19
18
|
GetBalanceParams,
|
|
19
|
+
SuiClient,
|
|
20
20
|
} from '@mysten/sui.js/client';
|
|
21
21
|
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
22
|
+
import { callWithRateLimit, TokenBucket } from 'src/utils';
|
|
23
|
+
import {
|
|
24
|
+
DEFAULT_INTERVAL_IN_MS,
|
|
25
|
+
DEFAULT_TOKENS_PER_INTERVAL,
|
|
26
|
+
} from 'src/constants/tokenBucket';
|
|
22
27
|
|
|
23
28
|
type QueryInspectTxnParams = {
|
|
24
29
|
queryTarget: string;
|
|
@@ -42,10 +47,18 @@ type QueryInspectTxnParams = {
|
|
|
42
47
|
export class ScallopCache {
|
|
43
48
|
public readonly queryClient: QueryClient;
|
|
44
49
|
public readonly _suiKit?: SuiKit;
|
|
50
|
+
private tokenBucket: TokenBucket;
|
|
45
51
|
|
|
46
|
-
public constructor(
|
|
52
|
+
public constructor(
|
|
53
|
+
cacheOptions?: QueryClientConfig,
|
|
54
|
+
suiKit?: SuiKit,
|
|
55
|
+
tokenBucket?: TokenBucket
|
|
56
|
+
) {
|
|
47
57
|
this.queryClient = new QueryClient(cacheOptions ?? DEFAULT_CACHE_OPTIONS);
|
|
48
58
|
this._suiKit = suiKit;
|
|
59
|
+
this.tokenBucket =
|
|
60
|
+
tokenBucket ??
|
|
61
|
+
new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS);
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
private get suiKit(): SuiKit {
|
|
@@ -55,6 +68,10 @@ export class ScallopCache {
|
|
|
55
68
|
return this._suiKit;
|
|
56
69
|
}
|
|
57
70
|
|
|
71
|
+
private get client(): SuiClient {
|
|
72
|
+
return this.suiKit.client();
|
|
73
|
+
}
|
|
74
|
+
|
|
58
75
|
/**
|
|
59
76
|
* @description Invalidate cache based on the refetchType parameter
|
|
60
77
|
* @param refetchType Determines the type of queries to be refetched. Defaults to `active`.
|
|
@@ -80,7 +97,9 @@ export class ScallopCache {
|
|
|
80
97
|
return await this.queryClient.fetchQuery({
|
|
81
98
|
queryKey: ['getProtocolConfig'],
|
|
82
99
|
queryFn: async () => {
|
|
83
|
-
return await this.
|
|
100
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
101
|
+
this.client.getProtocolConfig()
|
|
102
|
+
);
|
|
84
103
|
},
|
|
85
104
|
staleTime: 30000,
|
|
86
105
|
});
|
|
@@ -96,14 +115,14 @@ export class ScallopCache {
|
|
|
96
115
|
queryTarget,
|
|
97
116
|
args,
|
|
98
117
|
typeArgs,
|
|
99
|
-
}: QueryInspectTxnParams): Promise<DevInspectResults> {
|
|
118
|
+
}: QueryInspectTxnParams): Promise<DevInspectResults | null> {
|
|
100
119
|
const txBlock = new SuiTxBlock();
|
|
101
120
|
|
|
102
121
|
// resolve all the object args to prevent duplicate getNormalizedMoveFunction calls
|
|
103
122
|
const resolvedArgs = await Promise.all(
|
|
104
123
|
args.map(async (arg) => {
|
|
105
124
|
if (typeof arg === 'string') {
|
|
106
|
-
return (await this.queryGetObject(arg, { showContent: true }))
|
|
125
|
+
return (await this.queryGetObject(arg, { showContent: true }))?.data;
|
|
107
126
|
}
|
|
108
127
|
return arg;
|
|
109
128
|
})
|
|
@@ -112,9 +131,9 @@ export class ScallopCache {
|
|
|
112
131
|
|
|
113
132
|
// build the txBlock to prevent duplicate getProtocolConfig calls
|
|
114
133
|
const txBytes = await txBlock.txBlock.build({
|
|
115
|
-
client: this.
|
|
134
|
+
client: this.client,
|
|
116
135
|
onlyTransactionKind: true,
|
|
117
|
-
protocolConfig: await this.getProtocolConfig(),
|
|
136
|
+
protocolConfig: (await this.getProtocolConfig()) ?? undefined,
|
|
118
137
|
});
|
|
119
138
|
|
|
120
139
|
const query = await this.queryClient.fetchQuery({
|
|
@@ -127,7 +146,9 @@ export class ScallopCache {
|
|
|
127
146
|
JSON.stringify(typeArgs),
|
|
128
147
|
],
|
|
129
148
|
queryFn: async () => {
|
|
130
|
-
return await this.
|
|
149
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
150
|
+
this.suiKit.inspectTxn(txBytes)
|
|
151
|
+
);
|
|
131
152
|
},
|
|
132
153
|
});
|
|
133
154
|
return query;
|
|
@@ -142,7 +163,7 @@ export class ScallopCache {
|
|
|
142
163
|
public async queryGetObject(
|
|
143
164
|
objectId: string,
|
|
144
165
|
options?: SuiObjectDataOptions
|
|
145
|
-
): Promise<SuiObjectResponse> {
|
|
166
|
+
): Promise<SuiObjectResponse | null> {
|
|
146
167
|
const queryKey = ['getObject', objectId, this.suiKit.currentAddress()];
|
|
147
168
|
if (options) {
|
|
148
169
|
queryKey.push(JSON.stringify(options));
|
|
@@ -150,10 +171,12 @@ export class ScallopCache {
|
|
|
150
171
|
return this.queryClient.fetchQuery({
|
|
151
172
|
queryKey,
|
|
152
173
|
queryFn: async () => {
|
|
153
|
-
return await this.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
174
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
175
|
+
this.client.getObject({
|
|
176
|
+
id: objectId,
|
|
177
|
+
options,
|
|
178
|
+
})
|
|
179
|
+
);
|
|
157
180
|
},
|
|
158
181
|
});
|
|
159
182
|
}
|
|
@@ -179,7 +202,9 @@ export class ScallopCache {
|
|
|
179
202
|
return this.queryClient.fetchQuery({
|
|
180
203
|
queryKey: queryKey,
|
|
181
204
|
queryFn: async () => {
|
|
182
|
-
return await this.
|
|
205
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
206
|
+
this.suiKit.getObjects(objectIds, options)
|
|
207
|
+
);
|
|
183
208
|
},
|
|
184
209
|
});
|
|
185
210
|
}
|
|
@@ -189,9 +214,7 @@ export class ScallopCache {
|
|
|
189
214
|
* @param input
|
|
190
215
|
* @returns Promise<PaginatedObjectsResponse>
|
|
191
216
|
*/
|
|
192
|
-
public async queryGetOwnedObjects(
|
|
193
|
-
input: GetOwnedObjectsParams
|
|
194
|
-
): Promise<PaginatedObjectsResponse> {
|
|
217
|
+
public async queryGetOwnedObjects(input: GetOwnedObjectsParams) {
|
|
195
218
|
const queryKey = ['getOwnedObjects', input.owner];
|
|
196
219
|
if (input.cursor) {
|
|
197
220
|
queryKey.push(JSON.stringify(input.cursor));
|
|
@@ -209,14 +232,16 @@ export class ScallopCache {
|
|
|
209
232
|
return this.queryClient.fetchQuery({
|
|
210
233
|
queryKey,
|
|
211
234
|
queryFn: async () => {
|
|
212
|
-
return await this.
|
|
235
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
236
|
+
this.client.getOwnedObjects(input)
|
|
237
|
+
);
|
|
213
238
|
},
|
|
214
239
|
});
|
|
215
240
|
}
|
|
216
241
|
|
|
217
242
|
public async queryGetDynamicFields(
|
|
218
243
|
input: GetDynamicFieldsParams
|
|
219
|
-
): Promise<DynamicFieldPage> {
|
|
244
|
+
): Promise<DynamicFieldPage | null> {
|
|
220
245
|
const queryKey = ['getDynamicFields', input.parentId];
|
|
221
246
|
if (input.cursor) {
|
|
222
247
|
queryKey.push(JSON.stringify(input.cursor));
|
|
@@ -228,14 +253,16 @@ export class ScallopCache {
|
|
|
228
253
|
return this.queryClient.fetchQuery({
|
|
229
254
|
queryKey,
|
|
230
255
|
queryFn: async () => {
|
|
231
|
-
return await this.
|
|
256
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
257
|
+
this.client.getDynamicFields(input)
|
|
258
|
+
);
|
|
232
259
|
},
|
|
233
260
|
});
|
|
234
261
|
}
|
|
235
262
|
|
|
236
263
|
public async queryGetDynamicFieldObject(
|
|
237
264
|
input: GetDynamicFieldObjectParams
|
|
238
|
-
): Promise<SuiObjectResponse> {
|
|
265
|
+
): Promise<SuiObjectResponse | null> {
|
|
239
266
|
const queryKey = [
|
|
240
267
|
'getDynamicFieldObject',
|
|
241
268
|
input.parentId,
|
|
@@ -245,7 +272,9 @@ export class ScallopCache {
|
|
|
245
272
|
return this.queryClient.fetchQuery({
|
|
246
273
|
queryKey,
|
|
247
274
|
queryFn: async () => {
|
|
248
|
-
return await this.
|
|
275
|
+
return await callWithRateLimit(this.tokenBucket, () =>
|
|
276
|
+
this.client.getDynamicFieldObject(input)
|
|
277
|
+
);
|
|
249
278
|
},
|
|
250
279
|
});
|
|
251
280
|
}
|
|
@@ -257,9 +286,10 @@ export class ScallopCache {
|
|
|
257
286
|
return this.queryClient.fetchQuery({
|
|
258
287
|
queryKey,
|
|
259
288
|
queryFn: async () => {
|
|
260
|
-
const allBalances = await this.
|
|
261
|
-
.client()
|
|
262
|
-
|
|
289
|
+
const allBalances = await callWithRateLimit(this.tokenBucket, () =>
|
|
290
|
+
this.client.getAllBalances({ owner })
|
|
291
|
+
);
|
|
292
|
+
if (!allBalances) return {};
|
|
263
293
|
const balances = allBalances.reduce(
|
|
264
294
|
(acc, coinBalance) => {
|
|
265
295
|
if (coinBalance.totalBalance !== '0') {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeSuiAddress } from '@mysten/sui.js/utils';
|
|
2
2
|
import { SuiKit } from '@scallop-io/sui-kit';
|
|
3
|
+
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
3
4
|
import {
|
|
4
5
|
ADDRESSES_ID,
|
|
5
6
|
SUPPORT_BORROW_INCENTIVE_POOLS,
|
|
@@ -11,6 +12,8 @@ import { ScallopAddress } from './scallopAddress';
|
|
|
11
12
|
import { ScallopUtils } from './scallopUtils';
|
|
12
13
|
import { ScallopBuilder } from './scallopBuilder';
|
|
13
14
|
import { ScallopQuery } from './scallopQuery';
|
|
15
|
+
import { ScallopCache } from './scallopCache';
|
|
16
|
+
import { requireSender } from 'src/utils';
|
|
14
17
|
import type { SuiTransactionBlockResponse } from '@mysten/sui.js/client';
|
|
15
18
|
import type { TransactionObjectArgument } from '@mysten/sui.js/transactions';
|
|
16
19
|
import type { SuiObjectArg } from '@scallop-io/sui-kit';
|
|
@@ -27,8 +30,6 @@ import type {
|
|
|
27
30
|
ScallopTxBlock,
|
|
28
31
|
SupportSCoin,
|
|
29
32
|
} from '../types';
|
|
30
|
-
import { ScallopCache } from './scallopCache';
|
|
31
|
-
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* @description
|
|
@@ -747,6 +748,17 @@ export class ScallopClient {
|
|
|
747
748
|
stakeMarketCoinName,
|
|
748
749
|
stakeAccountId
|
|
749
750
|
);
|
|
751
|
+
|
|
752
|
+
if (sCoin) {
|
|
753
|
+
// merge to existing sCoins if exist
|
|
754
|
+
await this.utils.mergeSimilarCoins(
|
|
755
|
+
txBlock,
|
|
756
|
+
sCoin,
|
|
757
|
+
this.utils.parseSCoinType(stakeMarketCoinName),
|
|
758
|
+
requireSender(txBlock)
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
750
762
|
txBlock.transferObjects([sCoin], sender);
|
|
751
763
|
|
|
752
764
|
if (sign) {
|
|
@@ -800,6 +812,13 @@ export class ScallopClient {
|
|
|
800
812
|
this.utils.parseCoinName<SupportStakeCoins>(stakeMarketCoinName);
|
|
801
813
|
if (stakeMarketCoin) {
|
|
802
814
|
const coin = txBlock.withdraw(stakeMarketCoin, stakeCoinName);
|
|
815
|
+
await this.utils.mergeSimilarCoins(
|
|
816
|
+
txBlock,
|
|
817
|
+
coin,
|
|
818
|
+
this.utils.parseCoinType(this.utils.parseCoinName(stakeCoinName)),
|
|
819
|
+
requireSender(txBlock)
|
|
820
|
+
);
|
|
821
|
+
|
|
803
822
|
txBlock.transferObjects([coin], sender);
|
|
804
823
|
} else {
|
|
805
824
|
throw new Error(`No stake found for ${stakeMarketCoinName}`);
|
|
@@ -991,12 +1010,10 @@ export class ScallopClient {
|
|
|
991
1010
|
this.walletAddress
|
|
992
1011
|
); // throw error no coins found
|
|
993
1012
|
|
|
994
|
-
|
|
1013
|
+
toDestroyMarketCoin = marketCoins[0];
|
|
995
1014
|
if (marketCoins.length > 1) {
|
|
996
|
-
txBlock.mergeCoins(
|
|
1015
|
+
txBlock.mergeCoins(toDestroyMarketCoin, marketCoins.slice(1));
|
|
997
1016
|
}
|
|
998
|
-
|
|
999
|
-
toDestroyMarketCoin = mergedMarketCoin;
|
|
1000
1017
|
} catch (e: any) {
|
|
1001
1018
|
// Ignore
|
|
1002
1019
|
const errMsg = e.toString() as String;
|
|
@@ -1012,29 +1029,15 @@ export class ScallopClient {
|
|
|
1012
1029
|
toDestroyMarketCoin
|
|
1013
1030
|
);
|
|
1014
1031
|
|
|
1015
|
-
// check if current sCoin
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
const mergedSCoin = existSCoins[0];
|
|
1023
|
-
if (existSCoins.length > 1) {
|
|
1024
|
-
txBlock.mergeCoins(mergedSCoin, existSCoins.slice(1));
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// merge existing sCoin to new sCoin
|
|
1028
|
-
txBlock.mergeCoins(sCoin, [mergedSCoin]);
|
|
1029
|
-
} catch (e: any) {
|
|
1030
|
-
// ignore
|
|
1031
|
-
const errMsg = e.toString() as String;
|
|
1032
|
-
if (!errMsg.includes('No valid coins found for the transaction'))
|
|
1033
|
-
throw e;
|
|
1034
|
-
}
|
|
1032
|
+
// check if current sCoin
|
|
1033
|
+
await this.utils.mergeSimilarCoins(
|
|
1034
|
+
txBlock,
|
|
1035
|
+
sCoin,
|
|
1036
|
+
this.utils.parseSCoinType(sCoinName as SupportSCoin),
|
|
1037
|
+
requireSender(txBlock)
|
|
1038
|
+
);
|
|
1035
1039
|
sCoins.push(sCoin);
|
|
1036
1040
|
}
|
|
1037
|
-
|
|
1038
1041
|
// check for staked market coin in spool
|
|
1039
1042
|
if (SUPPORT_SPOOLS.includes(sCoinName as SupportStakeMarketCoins)) {
|
|
1040
1043
|
try {
|
|
@@ -1047,8 +1050,6 @@ export class ScallopClient {
|
|
|
1047
1050
|
}
|
|
1048
1051
|
} catch (e: any) {
|
|
1049
1052
|
// ignore
|
|
1050
|
-
const errMsg = e.toString();
|
|
1051
|
-
if (!errMsg.includes('No stake account found')) throw e;
|
|
1052
1053
|
}
|
|
1053
1054
|
}
|
|
1054
1055
|
|