@scallop-io/sui-scallop-sdk 0.46.53 → 0.46.55
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 +1982 -1888
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1933 -1839
- 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 +8 -18
- package/src/builders/spoolBuilder.ts +1 -33
- 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 +28 -13
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TransactionBlock } from '@mysten/sui.js/transactions';
|
|
2
|
-
import {
|
|
2
|
+
import { SuiTxBlock as SuiKitTxBlock } from '@scallop-io/sui-kit';
|
|
3
3
|
import { coinIds } from 'src/constants';
|
|
4
4
|
import { ScallopBuilder } from 'src/models';
|
|
5
5
|
import {
|
|
@@ -43,26 +43,16 @@ const generateLoyaltyProgramQuickMethod: GenerateLoyaltyProgramQuickMethod = ({
|
|
|
43
43
|
if (!veScaKey) throw new Error(`No veScaKey found for user ${sender}`);
|
|
44
44
|
|
|
45
45
|
// claim the pending reward
|
|
46
|
-
const toTransferObject: SuiObjectArg[] = [];
|
|
47
46
|
const rewardCoin = txBlock.claimLoyaltyRevenue(veScaKey);
|
|
48
47
|
|
|
49
48
|
// get existing sca coin to merge with
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} catch (e) {
|
|
58
|
-
// ignore
|
|
59
|
-
} finally {
|
|
60
|
-
toTransferObject.push(rewardCoin);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (toTransferObject.length > 0) {
|
|
64
|
-
txBlock.transferObjects(toTransferObject, sender);
|
|
65
|
-
}
|
|
49
|
+
await builder.utils.mergeSimilarCoins(
|
|
50
|
+
txBlock,
|
|
51
|
+
rewardCoin,
|
|
52
|
+
coinIds.sca,
|
|
53
|
+
requireSender(txBlock)
|
|
54
|
+
);
|
|
55
|
+
txBlock.transferObjects([rewardCoin], sender);
|
|
66
56
|
},
|
|
67
57
|
};
|
|
68
58
|
};
|
|
@@ -276,7 +276,7 @@ const generateSpoolQuickMethod: GenerateSpoolQuickMethod = ({
|
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
amount -= amountToUnstake;
|
|
279
|
-
if (amount
|
|
279
|
+
if (amount <= 0) break;
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
if (toTransfer.length > 0) {
|
|
@@ -285,38 +285,6 @@ const generateSpoolQuickMethod: GenerateSpoolQuickMethod = ({
|
|
|
285
285
|
if (toTransfer.length > 1) {
|
|
286
286
|
txBlock.mergeCoins(mergedCoin, toTransfer.slice(1));
|
|
287
287
|
}
|
|
288
|
-
|
|
289
|
-
if (returnSCoin) {
|
|
290
|
-
// check for existing sCoins
|
|
291
|
-
try {
|
|
292
|
-
const existingCoins = await builder.utils.selectCoins(
|
|
293
|
-
Number.MAX_SAFE_INTEGER,
|
|
294
|
-
builder.utils.parseSCoinType(stakeMarketCoinName),
|
|
295
|
-
requireSender(txBlock)
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
if (existingCoins.length > 0) {
|
|
299
|
-
txBlock.mergeCoins(mergedCoin, existingCoins);
|
|
300
|
-
}
|
|
301
|
-
} catch (e) {
|
|
302
|
-
// ignore
|
|
303
|
-
}
|
|
304
|
-
} else {
|
|
305
|
-
// check for existing market coins
|
|
306
|
-
try {
|
|
307
|
-
const existingCoins = await builder.utils.selectCoins(
|
|
308
|
-
Number.MAX_SAFE_INTEGER,
|
|
309
|
-
builder.utils.parseMarketCoinType(stakeMarketCoinName),
|
|
310
|
-
requireSender(txBlock)
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
if (existingCoins.length > 0) {
|
|
314
|
-
txBlock.mergeCoins(mergedCoin, existingCoins);
|
|
315
|
-
}
|
|
316
|
-
} catch (e) {
|
|
317
|
-
// ignore
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
288
|
return mergedCoin;
|
|
321
289
|
}
|
|
322
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}`);
|
|
@@ -1010,17 +1029,13 @@ export class ScallopClient {
|
|
|
1010
1029
|
toDestroyMarketCoin
|
|
1011
1030
|
);
|
|
1012
1031
|
|
|
1013
|
-
// check if current sCoin
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
txBlock.mergeCoins(sCoin, existSCoins);
|
|
1021
|
-
} catch (e: any) {
|
|
1022
|
-
// ignore
|
|
1023
|
-
}
|
|
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
|
+
);
|
|
1024
1039
|
sCoins.push(sCoin);
|
|
1025
1040
|
}
|
|
1026
1041
|
// check for staked market coin in spool
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SUI_TYPE_ARG, normalizeStructTag } from '@mysten/sui.js/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { SuiKit } from '@scallop-io/sui-kit';
|
|
3
3
|
import { SuiPriceServiceConnection } from '@pythnetwork/pyth-sui-js';
|
|
4
4
|
import { ScallopAddress } from './scallopAddress';
|
|
5
5
|
import { ScallopQuery } from './scallopQuery';
|
|
@@ -26,6 +26,9 @@ import {
|
|
|
26
26
|
parseAssetSymbol,
|
|
27
27
|
findClosestUnlockRound,
|
|
28
28
|
} from '../utils';
|
|
29
|
+
import { PYTH_ENDPOINTS } from 'src/constants/pyth';
|
|
30
|
+
import { ScallopCache } from './scallopCache';
|
|
31
|
+
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
29
32
|
import type {
|
|
30
33
|
ScallopUtilsParams,
|
|
31
34
|
ScallopInstanceParams,
|
|
@@ -39,9 +42,7 @@ import type {
|
|
|
39
42
|
CoinWrappedType,
|
|
40
43
|
SupportSCoin,
|
|
41
44
|
} from '../types';
|
|
42
|
-
import {
|
|
43
|
-
import { ScallopCache } from './scallopCache';
|
|
44
|
-
import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
|
|
45
|
+
import type { SuiAddressArg, SuiTxArg, SuiTxBlock } from '@scallop-io/sui-kit';
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* @description
|
|
@@ -396,6 +397,35 @@ export class ScallopUtils {
|
|
|
396
397
|
return coins;
|
|
397
398
|
}
|
|
398
399
|
|
|
400
|
+
/**
|
|
401
|
+
* Merge coins with type `coinType` to dest
|
|
402
|
+
* @param txBlock
|
|
403
|
+
* @param dest
|
|
404
|
+
* @param coinType
|
|
405
|
+
* @param sender
|
|
406
|
+
*/
|
|
407
|
+
public async mergeSimilarCoins(
|
|
408
|
+
txBlock: SuiTxBlock,
|
|
409
|
+
dest: SuiTxArg,
|
|
410
|
+
coinType: string,
|
|
411
|
+
sender: string
|
|
412
|
+
): Promise<void> {
|
|
413
|
+
// merge to existing coins if exist
|
|
414
|
+
try {
|
|
415
|
+
const existingSCoin = await this.selectCoins(
|
|
416
|
+
Number.MAX_SAFE_INTEGER,
|
|
417
|
+
coinType,
|
|
418
|
+
sender
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
if (existingSCoin.length > 0) {
|
|
422
|
+
txBlock.mergeCoins(dest, existingSCoin);
|
|
423
|
+
}
|
|
424
|
+
} catch (e) {
|
|
425
|
+
// ignore
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
399
429
|
/**
|
|
400
430
|
* Get all asset coin names in the obligation record by obligation id.
|
|
401
431
|
*
|
|
@@ -408,12 +438,14 @@ export class ScallopUtils {
|
|
|
408
438
|
*/
|
|
409
439
|
public async getObligationCoinNames(obligationId: SuiAddressArg) {
|
|
410
440
|
const obligation = await queryObligation(this._query, obligationId);
|
|
411
|
-
const collateralCoinTypes =
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
441
|
+
const collateralCoinTypes =
|
|
442
|
+
obligation?.collaterals.map((collateral) => {
|
|
443
|
+
return `0x${collateral.type.name}`;
|
|
444
|
+
}) ?? [];
|
|
445
|
+
const debtCoinTypes =
|
|
446
|
+
obligation?.debts.map((debt) => {
|
|
447
|
+
return `0x${debt.type.name}`;
|
|
448
|
+
}) ?? [];
|
|
417
449
|
const obligationCoinTypes = [
|
|
418
450
|
...new Set([...collateralCoinTypes, ...debtCoinTypes]),
|
|
419
451
|
];
|