@scallop-io/sui-scallop-sdk 0.46.36 → 0.46.38

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 (45) hide show
  1. package/dist/builders/loyaltyProgramBuilder.d.ts +12 -0
  2. package/dist/builders/referralBuilder.d.ts +1 -1
  3. package/dist/constants/testAddress.d.ts +2 -0
  4. package/dist/index.js +684 -172
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +674 -162
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/models/scallopQuery.d.ts +10 -3
  9. package/dist/models/scallopUtils.d.ts +1 -1
  10. package/dist/queries/index.d.ts +1 -0
  11. package/dist/queries/loyaltyProgramQuery.d.ts +10 -0
  12. package/dist/queries/vescaQuery.d.ts +8 -6
  13. package/dist/types/address.d.ts +6 -0
  14. package/dist/types/builder/index.d.ts +3 -1
  15. package/dist/types/builder/loyaltyProgram.d.ts +23 -0
  16. package/dist/types/builder/vesca.d.ts +16 -0
  17. package/dist/types/query/index.d.ts +1 -0
  18. package/dist/types/query/loyaltyProgram.d.ts +5 -0
  19. package/dist/types/query/vesca.d.ts +18 -0
  20. package/dist/utils/builder.d.ts +6 -5
  21. package/package.json +7 -6
  22. package/src/builders/index.ts +6 -1
  23. package/src/builders/loyaltyProgramBuilder.ts +115 -0
  24. package/src/builders/referralBuilder.ts +1 -1
  25. package/src/builders/vescaBuilder.ts +5 -1
  26. package/src/constants/testAddress.ts +383 -0
  27. package/src/models/scallopAddress.ts +12 -2
  28. package/src/models/scallopCache.ts +0 -1
  29. package/src/models/scallopQuery.ts +28 -16
  30. package/src/models/scallopUtils.ts +3 -3
  31. package/src/queries/borrowIncentiveQuery.ts +9 -8
  32. package/src/queries/coreQuery.ts +70 -66
  33. package/src/queries/index.ts +1 -0
  34. package/src/queries/loyaltyProgramQuery.ts +77 -0
  35. package/src/queries/portfolioQuery.ts +36 -28
  36. package/src/queries/vescaQuery.ts +70 -15
  37. package/src/types/address.ts +6 -0
  38. package/src/types/builder/index.ts +3 -0
  39. package/src/types/builder/loyaltyProgram.ts +35 -0
  40. package/src/types/builder/vesca.ts +16 -0
  41. package/src/types/query/index.ts +1 -0
  42. package/src/types/query/loyaltyProgram.ts +5 -0
  43. package/src/types/query/vesca.ts +21 -0
  44. package/src/utils/builder.ts +69 -53
  45. package/src/utils/query.ts +6 -5
@@ -50,18 +50,6 @@ export const queryMarket = async (
50
50
  query: ScallopQuery,
51
51
  indexer: boolean = false
52
52
  ) => {
53
- const packageId = query.address.get('core.packages.query.id');
54
- const marketId = query.address.get('core.market');
55
- const queryTarget = `${packageId}::market_query::market_data`;
56
- const args = [marketId];
57
-
58
- // const txBlock = new SuiKitTxBlock();
59
- // txBlock.moveCall(queryTarget, args);
60
- const queryResult = await query.cache.queryInspectTxn(
61
- { queryTarget, args }
62
- // txBlock
63
- );
64
- const marketData = queryResult.events[0].parsedJson as MarketQueryInterface;
65
53
  const coinPrices = await query.utils.getCoinPrices();
66
54
 
67
55
  const pools: MarketPools = {};
@@ -86,6 +74,14 @@ export const queryMarket = async (
86
74
  };
87
75
  }
88
76
 
77
+ const packageId = query.address.get('core.packages.query.id');
78
+ const marketId = query.address.get('core.market');
79
+ const queryTarget = `${packageId}::market_query::market_data`;
80
+ const args = [marketId];
81
+
82
+ const queryResult = await query.cache.queryInspectTxn({ queryTarget, args });
83
+ const marketData = queryResult.events[0].parsedJson as MarketQueryInterface;
84
+
89
85
  for (const pool of marketData.pools) {
90
86
  const coinType = normalizeStructTag(pool.type.name);
91
87
  const poolCoinName =
@@ -236,19 +232,21 @@ export const getMarketPools = async (
236
232
  return marketPools;
237
233
  }
238
234
 
239
- for (const poolCoinName of poolCoinNames) {
240
- const marketPool = await getMarketPool(
241
- query,
242
- poolCoinName,
243
- indexer,
244
- marketObjectResponse.data,
245
- coinPrices?.[poolCoinName]
246
- );
235
+ Promise.allSettled(
236
+ poolCoinNames.map(async (poolCoinName) => {
237
+ const marketPool = await getMarketPool(
238
+ query,
239
+ poolCoinName,
240
+ indexer,
241
+ marketObjectResponse.data,
242
+ coinPrices?.[poolCoinName]
243
+ );
247
244
 
248
- if (marketPool) {
249
- marketPools[poolCoinName] = marketPool;
250
- }
251
- }
245
+ if (marketPool) {
246
+ marketPools[poolCoinName] = marketPool;
247
+ }
248
+ })
249
+ );
252
250
 
253
251
  return marketPools;
254
252
  };
@@ -475,11 +473,12 @@ export const getMarketCollaterals = async (
475
473
  ) => {
476
474
  collateralCoinNames = collateralCoinNames || [...SUPPORT_COLLATERALS];
477
475
  const marketId = query.address.get('core.market');
478
- const marketObjectResponse = await query.cache.queryGetObject(marketId, {
479
- showContent: true,
480
- });
481
- const coinPrices = await query.utils.getCoinPrices(collateralCoinNames ?? []);
482
-
476
+ const [marketObjectResponse, coinPrices] = await Promise.all([
477
+ query.cache.queryGetObject(marketId, {
478
+ showContent: true,
479
+ }),
480
+ query.utils.getCoinPrices(collateralCoinNames ?? []),
481
+ ]);
483
482
  const marketCollaterals: MarketCollaterals = {};
484
483
 
485
484
  if (indexer) {
@@ -496,19 +495,21 @@ export const getMarketCollaterals = async (
496
495
  return marketCollaterals;
497
496
  }
498
497
 
499
- for (const collateralCoinName of collateralCoinNames) {
500
- const marketCollateral = await getMarketCollateral(
501
- query,
502
- collateralCoinName,
503
- indexer,
504
- marketObjectResponse.data,
505
- coinPrices?.[collateralCoinName]
506
- );
498
+ await Promise.allSettled(
499
+ collateralCoinNames.map(async (collateralCoinName) => {
500
+ const marketCollateral = await getMarketCollateral(
501
+ query,
502
+ collateralCoinName,
503
+ indexer,
504
+ marketObjectResponse.data,
505
+ coinPrices?.[collateralCoinName]
506
+ );
507
507
 
508
- if (marketCollateral) {
509
- marketCollaterals[collateralCoinName] = marketCollateral;
510
- }
511
- }
508
+ if (marketCollateral) {
509
+ marketCollaterals[collateralCoinName] = marketCollateral;
510
+ }
511
+ })
512
+ );
512
513
 
513
514
  return marketCollaterals;
514
515
  };
@@ -530,6 +531,22 @@ export const getMarketCollateral = async (
530
531
  marketObject?: SuiObjectData | null,
531
532
  coinPrice?: number
532
533
  ) => {
534
+ if (indexer) {
535
+ const marketCollateralIndexer =
536
+ await query.indexer.getMarketCollateral(collateralCoinName);
537
+ marketCollateralIndexer.coinPrice =
538
+ coinPrice || marketCollateralIndexer.coinPrice;
539
+ marketCollateralIndexer.coinWrappedType = query.utils.getCoinWrappedType(
540
+ marketCollateralIndexer.coinName
541
+ );
542
+
543
+ return marketCollateralIndexer;
544
+ }
545
+
546
+ let marketCollateral: MarketCollateral | undefined;
547
+ let riskModel: RiskModel | undefined;
548
+ let collateralStat: CollateralStat | undefined;
549
+
533
550
  const marketId = query.address.get('core.market');
534
551
  marketObject =
535
552
  marketObject ||
@@ -545,22 +562,6 @@ export const getMarketCollateral = async (
545
562
  collateralCoinName
546
563
  ];
547
564
 
548
- let marketCollateral: MarketCollateral | undefined;
549
- let riskModel: RiskModel | undefined;
550
- let collateralStat: CollateralStat | undefined;
551
-
552
- if (indexer) {
553
- const marketCollateralIndexer =
554
- await query.indexer.getMarketCollateral(collateralCoinName);
555
- marketCollateralIndexer.coinPrice =
556
- coinPrice || marketCollateralIndexer.coinPrice;
557
- marketCollateralIndexer.coinWrappedType = query.utils.getCoinWrappedType(
558
- marketCollateralIndexer.coinName
559
- );
560
-
561
- return marketCollateralIndexer;
562
- }
563
-
564
565
  if (marketObject) {
565
566
  if (marketObject.content && 'fields' in marketObject.content) {
566
567
  const fields = marketObject.content.fields as any;
@@ -698,15 +699,18 @@ export const getObligations = async (
698
699
  const keyObjects = await query.cache.queryGetObjects(keyObjectIds);
699
700
 
700
701
  const obligations: Obligation[] = [];
701
- for (const keyObject of keyObjects) {
702
- const keyId = keyObject.objectId;
703
- if (keyObject.content && 'fields' in keyObject.content) {
704
- const fields = keyObject.content.fields as any;
705
- const obligationId = String(fields.ownership.fields.of);
706
- const locked = await getObligationLocked(query, obligationId);
707
- obligations.push({ id: obligationId, keyId, locked });
708
- }
709
- }
702
+ await Promise.allSettled(
703
+ keyObjects.map(async (keyObject) => {
704
+ const keyId = keyObject.objectId;
705
+ if (keyObject.content && 'fields' in keyObject.content) {
706
+ const fields = keyObject.content.fields as any;
707
+ const obligationId = String(fields.ownership.fields.of);
708
+ const locked = await getObligationLocked(query, obligationId);
709
+ obligations.push({ id: obligationId, keyId, locked });
710
+ }
711
+ })
712
+ );
713
+
710
714
  return obligations;
711
715
  };
712
716
 
@@ -5,3 +5,4 @@ export * from './priceQuery';
5
5
  export * from './portfolioQuery';
6
6
  export * from './vescaQuery';
7
7
  export * from './referralQuery';
8
+ export * from './loyaltyProgramQuery';
@@ -0,0 +1,77 @@
1
+ import { SuiObjectData } from '@mysten/sui.js/src/client';
2
+ import BigNumber from 'bignumber.js';
3
+ import { ScallopQuery } from 'src/models';
4
+ import { LoyaltyProgramInfo } from 'src/types';
5
+ import { z as zod } from 'zod';
6
+
7
+ const rewardPoolFieldsZod = zod
8
+ .object({
9
+ balance: zod.string(),
10
+ enable_claim: zod.boolean(),
11
+ })
12
+ .transform((value) => ({
13
+ totalPoolReward: BigNumber(value.balance).shiftedBy(-9).toNumber(),
14
+ isClaimEnabled: value.enable_claim,
15
+ }));
16
+
17
+ const userRewardFieldsZod = zod
18
+ .object({
19
+ value: zod.string(),
20
+ })
21
+ .transform((value) => BigNumber(value.value).shiftedBy(-9).toNumber());
22
+
23
+ type RewardPoolFields = zod.infer<typeof rewardPoolFieldsZod>;
24
+ type UserRewardFields = zod.infer<typeof userRewardFieldsZod>;
25
+
26
+ /**
27
+ * Get user's loyalty program information and pending rewards if exists
28
+ * @param query
29
+ * @param veScaKey
30
+ * @returns
31
+ */
32
+ export const getLoyaltyProgramInformations = async (
33
+ query: ScallopQuery,
34
+ veScaKey?: string | SuiObjectData
35
+ ): Promise<LoyaltyProgramInfo | null> => {
36
+ const rewardPool = query.address.get('loyaltyProgram.rewardPool');
37
+
38
+ // get fields from rewardPool object
39
+ const rewardPoolObject = await query.cache.queryGetObject(rewardPool, {
40
+ showContent: true,
41
+ });
42
+
43
+ if (rewardPoolObject.data?.content?.dataType !== 'moveObject') return null;
44
+ const rewardPoolFields = rewardPoolObject.data.content.fields;
45
+ const { isClaimEnabled, totalPoolReward } = rewardPoolFieldsZod.parse(
46
+ rewardPoolFields
47
+ ) as RewardPoolFields;
48
+
49
+ const result: LoyaltyProgramInfo = {
50
+ pendingReward: 0,
51
+ totalPoolReward,
52
+ isClaimEnabled,
53
+ };
54
+
55
+ // query the user pending reward if exist
56
+ veScaKey = veScaKey || (await query.getVeScas())[0]?.keyObject;
57
+ if (!veScaKey) return result;
58
+
59
+ const userRewardTableId = query.address.get(
60
+ 'loyaltyProgram.userRewardTableId'
61
+ );
62
+
63
+ const userRewardObject = await query.cache.queryGetDynamicFieldObject({
64
+ parentId: userRewardTableId,
65
+ name: {
66
+ type: '0x2::object::ID',
67
+ value: typeof veScaKey === 'string' ? veScaKey : veScaKey.objectId,
68
+ },
69
+ });
70
+
71
+ if (userRewardObject.data?.content?.dataType !== 'moveObject') return result;
72
+ const userRewardFields = userRewardObject.data.content.fields;
73
+ result.pendingReward = userRewardFieldsZod.parse(
74
+ userRewardFields
75
+ ) as UserRewardFields;
76
+ return result;
77
+ };
@@ -49,36 +49,44 @@ export const getLendings = async (
49
49
  (SUPPORT_SPOOLS as readonly SupportMarketCoins[]).includes(marketCoinName)
50
50
  ) as SupportStakeMarketCoins[];
51
51
 
52
- const marketPools = await query.getMarketPools(poolCoinNames, indexer);
53
- const spools = await query.getSpools(stakeMarketCoinNames, indexer);
54
- const coinAmounts = await query.getCoinAmounts(poolCoinNames, ownerAddress);
55
- const marketCoinAmounts = await query.getMarketCoinAmounts(
56
- marketCoinNames,
57
- ownerAddress
58
- );
59
- const allStakeAccounts = await query.getAllStakeAccounts(ownerAddress);
60
- const coinPrices = await query.utils.getCoinPrices(poolCoinNames);
52
+ const [
53
+ marketPools,
54
+ spools,
55
+ coinAmounts,
56
+ marketCoinAmounts,
57
+ allStakeAccounts,
58
+ coinPrices,
59
+ ] = await Promise.all([
60
+ query.getMarketPools(poolCoinNames, indexer),
61
+ query.getSpools(stakeMarketCoinNames, indexer),
62
+ query.getCoinAmounts(poolCoinNames, ownerAddress),
63
+ query.getMarketCoinAmounts(marketCoinNames, ownerAddress),
64
+ query.getAllStakeAccounts(ownerAddress),
65
+ query.utils.getCoinPrices(poolCoinNames),
66
+ ]);
61
67
 
62
68
  const lendings: Lendings = {};
63
- for (const poolCoinName of poolCoinNames) {
64
- const stakeMarketCoinName = stakeMarketCoinNames.find(
65
- (marketCoinName) =>
66
- marketCoinName === query.utils.parseMarketCoinName(poolCoinName)
67
- );
68
- const marketCoinName = query.utils.parseMarketCoinName(poolCoinName);
69
- lendings[poolCoinName] = await getLending(
70
- query,
71
- poolCoinName,
72
- ownerAddress,
73
- indexer,
74
- marketPools?.[poolCoinName],
75
- stakeMarketCoinName ? spools[stakeMarketCoinName] : undefined,
76
- stakeMarketCoinName ? allStakeAccounts[stakeMarketCoinName] : undefined,
77
- coinAmounts?.[poolCoinName],
78
- marketCoinAmounts?.[marketCoinName],
79
- coinPrices?.[poolCoinName] ?? 0
80
- );
81
- }
69
+ await Promise.allSettled(
70
+ poolCoinNames.map(async (poolCoinName) => {
71
+ const stakeMarketCoinName = stakeMarketCoinNames.find(
72
+ (marketCoinName) =>
73
+ marketCoinName === query.utils.parseMarketCoinName(poolCoinName)
74
+ );
75
+ const marketCoinName = query.utils.parseMarketCoinName(poolCoinName);
76
+ lendings[poolCoinName] = await getLending(
77
+ query,
78
+ poolCoinName,
79
+ ownerAddress,
80
+ indexer,
81
+ marketPools?.[poolCoinName],
82
+ stakeMarketCoinName ? spools[stakeMarketCoinName] : undefined,
83
+ stakeMarketCoinName ? allStakeAccounts[stakeMarketCoinName] : undefined,
84
+ coinAmounts?.[poolCoinName],
85
+ marketCoinAmounts?.[marketCoinName],
86
+ coinPrices?.[poolCoinName] ?? 0
87
+ );
88
+ })
89
+ );
82
90
 
83
91
  return lendings;
84
92
  };
@@ -1,5 +1,5 @@
1
1
  import BigNumber from 'bignumber.js';
2
- import { Vesca } from '../types';
2
+ import { VeScaTreasuryFields, VeScaTreasuryInfo, Vesca } from '../types';
3
3
  import {
4
4
  type SuiObjectResponse,
5
5
  type SuiObjectData,
@@ -9,6 +9,7 @@ import type { ScallopQuery } from '../models';
9
9
  import { MAX_LOCK_DURATION } from 'src/constants';
10
10
  import { SUI_CLOCK_OBJECT_ID, SuiTxBlock } from '@scallop-io/sui-kit';
11
11
  import { bcs } from '@mysten/sui.js/bcs';
12
+ import { z as zod } from 'zod';
12
13
  /**
13
14
  * Query all owned veSca key.
14
15
  *
@@ -63,11 +64,10 @@ export const getVescaKeys = async (
63
64
  */
64
65
  export const getVeScas = async (query: ScallopQuery, ownerAddress?: string) => {
65
66
  const keyObjectDatas = await getVescaKeys(query, ownerAddress);
66
- const keyObjectId: string[] = keyObjectDatas.map((data) => data.objectId);
67
67
 
68
- const veScas: (Vesca | undefined)[] = Array(keyObjectId.length).fill(null);
69
- const tasks = keyObjectId.map(async (keyId, idx) => {
70
- const veSca = await getVeSca(query, keyId);
68
+ const veScas: Vesca[] = Array(keyObjectDatas.length).fill(null);
69
+ const tasks = keyObjectDatas.map(async (veScaKey, idx) => {
70
+ const veSca = await getVeSca(query, veScaKey);
71
71
  if (veSca) {
72
72
  veScas[idx] = veSca;
73
73
  }
@@ -79,22 +79,33 @@ export const getVeScas = async (query: ScallopQuery, ownerAddress?: string) => {
79
79
  .sort((a, b) => b!.currentVeScaBalance - a!.currentVeScaBalance);
80
80
  };
81
81
 
82
+ const SuiObjectRefZod = zod.object({
83
+ objectId: zod.string(),
84
+ digest: zod.string(),
85
+ version: zod.string(),
86
+ });
87
+
88
+ type SuiObjectRefType = zod.infer<typeof SuiObjectRefZod>;
82
89
  /**
83
90
  * Get veSca data.
84
91
  *
85
92
  * @param query - The Scallop query instance.
86
- * @param veScaKeyId - The vesca key id.
93
+ * @param veScaKey - The vesca key id.
87
94
  * @param ownerAddress - The owner address.
88
95
  * @returns Vesca data.
89
96
  */
90
97
  export const getVeSca = async (
91
98
  query: ScallopQuery,
92
- veScaKeyId?: string,
99
+ veScaKey?: string | SuiObjectData,
93
100
  ownerAddress?: string
94
101
  ) => {
95
102
  const tableId = query.address.get(`vesca.tableId`);
96
- veScaKeyId =
97
- veScaKeyId || (await getVescaKeys(query, ownerAddress))[0].objectId;
103
+ veScaKey = veScaKey || (await getVescaKeys(query, ownerAddress))[0];
104
+
105
+ if (!veScaKey) return undefined;
106
+ if (typeof veScaKey === 'object') {
107
+ veScaKey = SuiObjectRefZod.parse(veScaKey) as SuiObjectRefType;
108
+ }
98
109
 
99
110
  let vesca: Vesca | undefined = undefined;
100
111
 
@@ -103,7 +114,7 @@ export const getVeSca = async (
103
114
  parentId: tableId,
104
115
  name: {
105
116
  type: '0x2::object::ID',
106
- value: veScaKeyId,
117
+ value: typeof veScaKey === 'string' ? veScaKey : veScaKey.objectId,
107
118
  },
108
119
  });
109
120
  const veScaDynamicFieldObject = veScaDynamicFieldObjectResponse.data;
@@ -131,7 +142,9 @@ export const getVeSca = async (
131
142
 
132
143
  vesca = {
133
144
  id: veScaDynamicFieldObject.objectId,
134
- keyId: veScaKeyId,
145
+ keyId: typeof veScaKey === 'string' ? veScaKey : veScaKey.objectId,
146
+ keyObject: typeof veScaKey === 'string' ? undefined : veScaKey,
147
+ object: SuiObjectRefZod.parse(veScaDynamicFieldObjectResponse.data),
135
148
  lockedScaAmount,
136
149
  lockedScaCoin,
137
150
  currentVeScaBalance,
@@ -145,12 +158,13 @@ export const getVeSca = async (
145
158
  /**
146
159
  * Get current total veSca treasury amount.
147
160
  */
148
- export const getTotalVeScaTreasuryAmount = async (
149
- query: ScallopQuery
161
+ const getTotalVeScaTreasuryAmount = async (
162
+ query: ScallopQuery,
163
+ veScaTreasury: SuiObjectData
150
164
  ): Promise<string> => {
151
165
  const veScaPkgId = query.address.get('vesca.id');
152
166
  const veScaConfig = query.address.get('vesca.config');
153
- const veScaTreasury = query.address.get('vesca.treasury');
167
+ veScaTreasury = veScaTreasury ?? query.address.get('vesca.treasury');
154
168
 
155
169
  // refresh query
156
170
  const refreshQueryTarget = `${veScaPkgId}::treasury::refresh`;
@@ -201,7 +215,6 @@ export const getTotalVeScaTreasuryAmount = async (
201
215
  queryFn: async () => {
202
216
  return await query.suiKit.inspectTxn(txBytes);
203
217
  },
204
- staleTime: 8000,
205
218
  });
206
219
 
207
220
  const results = res.results;
@@ -213,3 +226,45 @@ export const getTotalVeScaTreasuryAmount = async (
213
226
 
214
227
  return '0';
215
228
  };
229
+
230
+ /**
231
+ * Get veSCA treasury informations
232
+ * @param query
233
+ * @returns VeScaTreasuryInfo
234
+ */
235
+ export const getVeScaTreasuryInfo = async (
236
+ query: ScallopQuery
237
+ ): Promise<VeScaTreasuryInfo | null> => {
238
+ const veScaTreasuryId = query.address.get('vesca.treasury');
239
+ const veScaTreasury = await query.cache.queryGetObject(veScaTreasuryId, {
240
+ showContent: true,
241
+ });
242
+
243
+ if (!veScaTreasury || veScaTreasury.data?.content?.dataType !== 'moveObject')
244
+ return null;
245
+
246
+ const treasuryFields = veScaTreasury.data.content
247
+ .fields as VeScaTreasuryFields;
248
+
249
+ console.log(treasuryFields);
250
+ const totalLockedSca = BigNumber(
251
+ treasuryFields.unlock_schedule.fields.locked_sca_amount
252
+ )
253
+ .shiftedBy(-9)
254
+ .toNumber();
255
+ const totalVeSca = BigNumber(
256
+ (await getTotalVeScaTreasuryAmount(query, veScaTreasury.data)) ?? 0
257
+ )
258
+ .shiftedBy(-9)
259
+ .toNumber();
260
+ const averageLockingPeriod =
261
+ totalLockedSca > 0 ? (totalVeSca / totalLockedSca) * 4 : 0; // in years
262
+
263
+ const averageLockingPeriodUnit = 'year';
264
+ return {
265
+ totalLockedSca,
266
+ totalVeSca,
267
+ averageLockingPeriod,
268
+ averageLockingPeriodUnit,
269
+ };
270
+ };
@@ -115,6 +115,12 @@ export interface AddressesInterface {
115
115
  tiersTableId: string;
116
116
  authorizedWitnessList: string;
117
117
  };
118
+ loyaltyProgram: {
119
+ id: string;
120
+ object: string;
121
+ rewardPool: string;
122
+ userRewardTableId: string;
123
+ };
118
124
  }
119
125
 
120
126
  type AddressPathsProps<T> = T extends string
@@ -3,14 +3,17 @@ import type { SpoolTxBlock } from './spool';
3
3
  import type { BorrowIncentiveTxBlock } from './borrowIncentive';
4
4
  import type { VeScaTxBlock } from './vesca';
5
5
  import type { ReferralTxBlock } from './referral';
6
+ import { LoyaltyProgramTxBlock } from './loyaltyProgram';
6
7
 
7
8
  export type * from './core';
8
9
  export type * from './spool';
9
10
  export type * from './borrowIncentive';
10
11
  export type * from './vesca';
12
+ export type * from './loyaltyProgram';
11
13
 
12
14
  export type ScallopTxBlock = CoreTxBlock &
13
15
  SpoolTxBlock &
14
16
  ReferralTxBlock &
17
+ LoyaltyProgramTxBlock &
15
18
  BorrowIncentiveTxBlock &
16
19
  VeScaTxBlock;
@@ -0,0 +1,35 @@
1
+ import {
2
+ SuiObjectArg,
3
+ SuiTxBlock as SuiKitTxBlock,
4
+ TransactionResult,
5
+ } from '@scallop-io/sui-kit';
6
+ import { type ScallopBuilder } from 'src/models';
7
+
8
+ export type LoyaltyProgramIds = {
9
+ loyaltyProgramPkgId: string;
10
+ rewardPool: string;
11
+ userRewardTableId: string;
12
+ };
13
+
14
+ export type LoyaltyProgramNormalMethods = {
15
+ claimLoyaltyRevenue: (veScaKey: SuiObjectArg) => TransactionResult;
16
+ };
17
+
18
+ export type LoyaltyProgramQuickMethods = {
19
+ claimLoyaltyRevenueQuick: (veScaKey?: SuiObjectArg) => Promise<void>;
20
+ };
21
+
22
+ export type SuiTxBlockWithLoyaltyProgramNormalMethods = SuiKitTxBlock &
23
+ LoyaltyProgramNormalMethods;
24
+ export type LoyaltyProgramTxBlock = SuiTxBlockWithLoyaltyProgramNormalMethods &
25
+ LoyaltyProgramQuickMethods;
26
+
27
+ export type GenerateLoyaltyProgramNormalMethod = (params: {
28
+ builder: ScallopBuilder;
29
+ txBlock: SuiKitTxBlock;
30
+ }) => LoyaltyProgramNormalMethods;
31
+
32
+ export type GenerateLoyaltyProgramQuickMethod = (params: {
33
+ builder: ScallopBuilder;
34
+ txBlock: SuiTxBlockWithLoyaltyProgramNormalMethods;
35
+ }) => LoyaltyProgramQuickMethods;
@@ -33,6 +33,22 @@ export type VeScaNormalMethods = {
33
33
  };
34
34
 
35
35
  export type VeScaQuickMethods = {
36
+ /**
37
+ * Quick methods to automate
38
+ * lock initial SCA, extend lock period, lock more SCA, renew expired VeSCA, and redeem SCA
39
+ *
40
+ * **Flow:**
41
+ * - If only `amountOrCoin` is provided, it will lock the amount of existing not expired veSCA
42
+ * - If only `lockPeriodInDays` is provided, it will extend the lock period of existing not expired veSCA
43
+ *
44
+ * **Note:**
45
+ * - If one or both flow above is used on a expired veSCA, it will claim the unlocked SCA
46
+ * and renew the veSCA first, and then flow continues
47
+ * - If users has no veSCA yet, they need to provide both `amountOrCoin` and `lockPeriodInDays` for initial lock
48
+ * @param amountOrCoin
49
+ * @param lockPeriodInDays
50
+ * @param autoCheck
51
+ */
36
52
  lockScaQuick(
37
53
  amountOrCoin?: SuiObjectArg | number,
38
54
  lockPeriodInDays?: number,
@@ -3,3 +3,4 @@ export type * from './spool';
3
3
  export type * from './borrowIncentive';
4
4
  export type * from './portfolio';
5
5
  export type * from './vesca';
6
+ export type * from './loyaltyProgram';
@@ -0,0 +1,5 @@
1
+ export type LoyaltyProgramInfo = {
2
+ pendingReward: number;
3
+ totalPoolReward: number;
4
+ isClaimEnabled: boolean;
5
+ };
@@ -1,8 +1,29 @@
1
+ import type { SuiObjectRef } from '@mysten/sui.js/client';
2
+
1
3
  export type Vesca = {
2
4
  id: string;
3
5
  keyId: string;
6
+ keyObject?: SuiObjectRef;
7
+ object?: SuiObjectRef;
4
8
  lockedScaAmount: string;
5
9
  lockedScaCoin: number;
6
10
  currentVeScaBalance: number;
7
11
  unlockAt: number;
8
12
  };
13
+
14
+ export type VeScaTreasuryFields = {
15
+ total_ve_sca_amount: string;
16
+ sca_balance: string;
17
+ unlock_schedule: {
18
+ fields: {
19
+ locked_sca_amount: string;
20
+ };
21
+ };
22
+ };
23
+
24
+ export type VeScaTreasuryInfo = {
25
+ totalLockedSca: number;
26
+ totalVeSca: number;
27
+ averageLockingPeriod: number;
28
+ averageLockingPeriodUnit: string;
29
+ };