@scallop-io/sui-scallop-sdk 0.46.40 → 0.46.42

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 (61) hide show
  1. package/dist/builders/loyaltyProgramBuilder.d.ts +1 -1
  2. package/dist/builders/sCoinBuilder.d.ts +4 -0
  3. package/dist/constants/common.d.ts +3 -1
  4. package/dist/constants/enum.d.ts +12 -10
  5. package/dist/index.js +660 -97
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +658 -92
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/models/scallopBuilder.d.ts +16 -1
  10. package/dist/models/scallopClient.d.ts +5 -0
  11. package/dist/models/scallopQuery.d.ts +21 -2
  12. package/dist/models/scallopUtils.d.ts +32 -2
  13. package/dist/queries/portfolioQuery.d.ts +1 -1
  14. package/dist/queries/sCoinQuery.d.ts +27 -0
  15. package/dist/test.d.ts +1 -0
  16. package/dist/types/address.d.ts +8 -1
  17. package/dist/types/builder/core.d.ts +12 -4
  18. package/dist/types/builder/index.d.ts +6 -1
  19. package/dist/types/builder/sCoin.d.ts +37 -0
  20. package/dist/types/builder/spool.d.ts +2 -1
  21. package/dist/types/constant/common.d.ts +3 -2
  22. package/dist/types/constant/enum.d.ts +13 -1
  23. package/dist/types/query/core.d.ts +2 -1
  24. package/dist/types/query/index.d.ts +1 -0
  25. package/dist/types/query/portfolio.d.ts +1 -0
  26. package/dist/types/query/sCoin.d.ts +1 -0
  27. package/package.json +3 -3
  28. package/src/builders/coreBuilder.ts +72 -17
  29. package/src/builders/index.ts +5 -1
  30. package/src/builders/loyaltyProgramBuilder.ts +1 -1
  31. package/src/builders/referralBuilder.ts +1 -1
  32. package/src/builders/sCoinBuilder.ts +119 -0
  33. package/src/builders/spoolBuilder.ts +1 -1
  34. package/src/builders/vescaBuilder.ts +3 -3
  35. package/src/constants/common.ts +19 -5
  36. package/src/constants/enum.ts +98 -20
  37. package/src/constants/testAddress.ts +115 -21
  38. package/src/models/scallopAddress.ts +44 -3
  39. package/src/models/scallopBuilder.ts +43 -7
  40. package/src/models/scallopCache.ts +32 -4
  41. package/src/models/scallopClient.ts +121 -0
  42. package/src/models/scallopQuery.ts +46 -0
  43. package/src/models/scallopUtils.ts +56 -2
  44. package/src/queries/coreQuery.ts +10 -4
  45. package/src/queries/portfolioQuery.ts +26 -4
  46. package/src/queries/sCoinQuery.ts +94 -0
  47. package/src/queries/vescaQuery.ts +0 -1
  48. package/src/test.ts +19 -0
  49. package/src/types/address.ts +13 -0
  50. package/src/types/builder/core.ts +19 -4
  51. package/src/types/builder/index.ts +11 -3
  52. package/src/types/builder/sCoin.ts +61 -0
  53. package/src/types/builder/spool.ts +2 -0
  54. package/src/types/constant/common.ts +4 -1
  55. package/src/types/constant/enum.ts +17 -0
  56. package/src/types/query/core.ts +3 -0
  57. package/src/types/query/index.ts +1 -0
  58. package/src/types/query/portfolio.ts +1 -0
  59. package/src/types/query/sCoin.ts +1 -0
  60. package/src/utils/builder.ts +1 -1
  61. package/src/utils/util.ts +13 -17
@@ -14,6 +14,7 @@ import type {
14
14
  ScallopTxBlock,
15
15
  SupportMarketCoins,
16
16
  SupportAssetCoins,
17
+ SupportSCoin,
17
18
  } from '../types';
18
19
  import { ScallopCache } from './scallopCache';
19
20
  import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
@@ -124,7 +125,7 @@ export class ScallopBuilder {
124
125
  sender: string
125
126
  ) {
126
127
  const coinType = this.utils.parseCoinType(assetCoinName);
127
- const coins = await this.utils.selectCoinIds(amount, coinType, sender);
128
+ const coins = await this.utils.selectCoins(amount, coinType, sender);
128
129
  const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(coins, amount);
129
130
  return { takeCoin, leftCoin };
130
131
  }
@@ -145,13 +146,48 @@ export class ScallopBuilder {
145
146
  sender: string
146
147
  ) {
147
148
  const marketCoinType = this.utils.parseMarketCoinType(marketCoinName);
148
- const coins = await this.utils.selectCoinIds(
149
- amount,
150
- marketCoinType,
151
- sender
149
+ const coins = await this.utils.selectCoins(amount, marketCoinType, sender);
150
+ const totalAmount = coins.reduce((prev, coin) => {
151
+ prev += Number(coin.balance);
152
+ return prev;
153
+ }, 0);
154
+ const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(
155
+ coins,
156
+ Math.min(amount, totalAmount)
152
157
  );
153
- const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(coins, amount);
154
- return { takeCoin, leftCoin };
158
+ return { takeCoin, leftCoin, totalAmount };
159
+ }
160
+
161
+ /**
162
+ * Specifying the sender's amount of sCoins to get coins args from transaction result.
163
+ *
164
+ * @param txBlock - Scallop txBlock or txBlock created by SuiKit .
165
+ * @param marketCoinName - Specific support sCoin name.
166
+ * @param amount - Amount of coins to be selected.
167
+ * @param sender - Sender address.
168
+ * @return Take coin and left coin.
169
+ */
170
+ public async selectSCoin(
171
+ txBlock: ScallopTxBlock | SuiKitTxBlock,
172
+ sCoinName: SupportSCoin,
173
+ amount: number,
174
+ sender: string
175
+ ) {
176
+ const sCoinType = this.utils.parseSCoinType(sCoinName);
177
+ const coins = await this.utils.selectCoins(amount, sCoinType, sender);
178
+ const totalAmount = coins.reduce((prev, coin) => {
179
+ prev += Number(coin.balance);
180
+ return prev;
181
+ }, 0);
182
+ const [takeCoin, leftCoin] = txBlock.takeAmountFromCoins(
183
+ coins,
184
+ Math.min(totalAmount, amount)
185
+ );
186
+ return {
187
+ takeCoin,
188
+ leftCoin,
189
+ totalAmount,
190
+ };
155
191
  }
156
192
 
157
193
  /**
@@ -1,5 +1,10 @@
1
1
  import { QueryClient, QueryClientConfig } from '@tanstack/query-core';
2
- import { SuiTxArg, SuiTxBlock, normalizeStructTag } from '@scallop-io/sui-kit';
2
+ import {
3
+ SuiTxArg,
4
+ SuiTxBlock,
5
+ normalizeStructTag,
6
+ normalizeSuiAddress,
7
+ } from '@scallop-io/sui-kit';
3
8
  import { SuiKit } from '@scallop-io/sui-kit';
4
9
  import type {
5
10
  SuiObjectResponse,
@@ -162,6 +167,7 @@ export class ScallopCache {
162
167
  objectIds: string[],
163
168
  options?: SuiObjectDataOptions
164
169
  ): Promise<SuiObjectData[]> {
170
+ if (objectIds.length === 0) return [];
165
171
  const queryKey = [
166
172
  'getObjects',
167
173
  JSON.stringify(objectIds),
@@ -171,7 +177,7 @@ export class ScallopCache {
171
177
  queryKey.push(JSON.stringify(options));
172
178
  }
173
179
  return this.queryClient.fetchQuery({
174
- queryKey,
180
+ queryKey: queryKey,
175
181
  queryFn: async () => {
176
182
  return await this.suiKit.getObjects(objectIds, options);
177
183
  },
@@ -254,7 +260,7 @@ export class ScallopCache {
254
260
  const allBalances = await this.suiKit
255
261
  .client()
256
262
  .getAllBalances({ owner });
257
- return allBalances.reduce(
263
+ const balances = allBalances.reduce(
258
264
  (acc, coinBalance) => {
259
265
  if (coinBalance.totalBalance !== '0') {
260
266
  acc[normalizeStructTag(coinBalance.coinType)] =
@@ -264,12 +270,34 @@ export class ScallopCache {
264
270
  },
265
271
  {} as { [k: string]: string }
266
272
  );
273
+
274
+ // Set query data for each coin balance
275
+ for (const coinType in balances) {
276
+ const coinBalanceQueryKey = [
277
+ 'getCoinBalance',
278
+ normalizeSuiAddress(owner),
279
+ normalizeStructTag(coinType),
280
+ ];
281
+ this.queryClient.setQueryData(
282
+ coinBalanceQueryKey,
283
+ balances[coinType]
284
+ );
285
+ }
286
+
287
+ return balances;
267
288
  },
289
+ staleTime: 5000,
268
290
  });
269
291
  }
270
292
 
271
293
  public async queryGetCoinBalance(input: GetBalanceParams): Promise<string> {
272
- const queryKey = ['getCoinBalance', input.owner, input.coinType];
294
+ if (!input.coinType) return '0';
295
+
296
+ const queryKey = [
297
+ 'getCoinBalance',
298
+ normalizeSuiAddress(input.owner),
299
+ normalizeStructTag(input.coinType),
300
+ ];
273
301
  return this.queryClient.fetchQuery({
274
302
  queryKey,
275
303
  queryFn: async () => {
@@ -4,6 +4,8 @@ import {
4
4
  ADDRESSES_ID,
5
5
  SUPPORT_BORROW_INCENTIVE_POOLS,
6
6
  SUPPORT_BORROW_INCENTIVE_REWARDS,
7
+ SUPPORT_SCOIN,
8
+ SUPPORT_SPOOLS,
7
9
  } from '../constants';
8
10
  import { ScallopAddress } from './scallopAddress';
9
11
  import { ScallopUtils } from './scallopUtils';
@@ -23,6 +25,7 @@ import type {
23
25
  SupportStakeMarketCoins,
24
26
  SupportBorrowIncentiveCoins,
25
27
  ScallopTxBlock,
28
+ SupportSCoin,
26
29
  } from '../types';
27
30
  import { ScallopCache } from './scallopCache';
28
31
  import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
@@ -959,6 +962,124 @@ export class ScallopClient {
959
962
  }
960
963
  }
961
964
 
965
+ /* ==================== Migrate market coin to sCoin method ==================== */
966
+ /**
967
+ * Function to migrate all market coin in user wallet into sCoin
968
+ * @returns Transaction response
969
+ */
970
+ public async migrateAllMarketCoin<S extends boolean>(
971
+ sign: S = true as S
972
+ ): Promise<ScallopClientFnReturnType<S>> {
973
+ const txBlock = this.builder.createTxBlock();
974
+ txBlock.setSender(this.walletAddress);
975
+
976
+ const toTransfer: SuiObjectArg[] = [];
977
+ await Promise.all(
978
+ SUPPORT_SCOIN.map(async (sCoinName) => {
979
+ /**
980
+ * First check marketCoin inside mini wallet
981
+ * Then check stakedMarketCoin inside spool
982
+ */
983
+ let toDestroyMarketCoin: SuiObjectArg | undefined;
984
+
985
+ // check market coin in mini wallet
986
+ try {
987
+ const marketCoins = await this.utils.selectCoins(
988
+ Number.MAX_SAFE_INTEGER,
989
+ this.utils.parseMarketCoinType(sCoinName as SupportSCoin),
990
+ this.walletAddress
991
+ ); // throw error no coins found
992
+
993
+ const mergedMarketCoin = marketCoins[0];
994
+ if (marketCoins.length > 1) {
995
+ txBlock.mergeCoins(mergedMarketCoin, marketCoins.slice(1));
996
+ }
997
+
998
+ toDestroyMarketCoin = mergedMarketCoin;
999
+ } catch (e: any) {
1000
+ // Ignore
1001
+ const errMsg = e.toString() as String;
1002
+ if (!errMsg.includes('No valid coins found for the transaction'))
1003
+ throw e;
1004
+ }
1005
+
1006
+ // check for staked market coin in spool
1007
+ if (SUPPORT_SPOOLS.includes(sCoinName as SupportStakeMarketCoins)) {
1008
+ try {
1009
+ const stakedMarketCoins = await txBlock.unstakeQuick(
1010
+ Number.MAX_SAFE_INTEGER,
1011
+ sCoinName as SupportStakeMarketCoins
1012
+ );
1013
+ if (stakedMarketCoins.length > 0) {
1014
+ const mergedStakedMarketCoin = stakedMarketCoins[0];
1015
+ if (stakedMarketCoins.length > 1) {
1016
+ txBlock.mergeCoins(
1017
+ mergedStakedMarketCoin,
1018
+ stakedMarketCoins.slice(1)
1019
+ );
1020
+ }
1021
+ // merge with takeMarketCoin
1022
+ if (toDestroyMarketCoin) {
1023
+ txBlock.mergeCoins(toDestroyMarketCoin, [
1024
+ mergedStakedMarketCoin,
1025
+ ]);
1026
+ } else {
1027
+ toDestroyMarketCoin = mergedStakedMarketCoin;
1028
+ }
1029
+ }
1030
+ } catch (e: any) {
1031
+ // ignore
1032
+ const errMsg = e.toString();
1033
+ if (!errMsg.includes('No stake account found')) throw e;
1034
+ }
1035
+ }
1036
+
1037
+ // if market coin found, mint sCoin
1038
+ if (toDestroyMarketCoin) {
1039
+ // mint new sCoin
1040
+ const sCoin = txBlock.mintSCoin(
1041
+ sCoinName as SupportSCoin,
1042
+ toDestroyMarketCoin
1043
+ );
1044
+
1045
+ // check if current sCoin exist
1046
+ try {
1047
+ const existSCoins = await this.utils.selectCoins(
1048
+ Number.MAX_SAFE_INTEGER,
1049
+ this.utils.parseSCoinType(sCoinName as SupportSCoin),
1050
+ this.walletAddress
1051
+ ); // throw error on no coins found
1052
+ const mergedSCoin = existSCoins[0];
1053
+ if (existSCoins.length > 1) {
1054
+ txBlock.mergeCoins(mergedSCoin, existSCoins.slice(1));
1055
+ }
1056
+
1057
+ // merge existing sCoin to new sCoin
1058
+ txBlock.mergeCoins(sCoin, [mergedSCoin]);
1059
+ } catch (e: any) {
1060
+ // ignore
1061
+ const errMsg = e.toString() as String;
1062
+ if (!errMsg.includes('No valid coins found for the transaction'))
1063
+ throw e;
1064
+ }
1065
+ toTransfer.push(sCoin);
1066
+ }
1067
+ })
1068
+ );
1069
+
1070
+ if (toTransfer.length > 0) {
1071
+ txBlock.transferObjects(toTransfer, this.walletAddress);
1072
+ }
1073
+
1074
+ if (sign) {
1075
+ return (await this.suiKit.signAndSendTxn(
1076
+ txBlock
1077
+ )) as ScallopClientFnReturnType<S>;
1078
+ } else {
1079
+ return txBlock.txBlock as ScallopClientFnReturnType<S>;
1080
+ }
1081
+ }
1082
+
962
1083
  /* ==================== Other Method ==================== */
963
1084
 
964
1085
  /**
@@ -45,6 +45,7 @@ import {
45
45
  StakePools,
46
46
  StakeRewardPools,
47
47
  SupportBorrowIncentiveCoins,
48
+ SupportSCoin,
48
49
  } from '../types';
49
50
  import { ScallopAddress } from './scallopAddress';
50
51
  import { ScallopUtils } from './scallopUtils';
@@ -52,6 +53,11 @@ import { ScallopIndexer } from './scallopIndexer';
52
53
  import { ScallopCache } from './scallopCache';
53
54
  import { DEFAULT_CACHE_OPTIONS } from 'src/constants/cache';
54
55
  import { SuiObjectData } from '@mysten/sui.js/src/client';
56
+ import {
57
+ getSCoinAmount,
58
+ getSCoinAmounts,
59
+ getSCoinTotalSupply,
60
+ } from 'src/queries/sCoinQuery';
55
61
 
56
62
  /**
57
63
  * @description
@@ -596,6 +602,46 @@ export class ScallopQuery {
596
602
  }
597
603
 
598
604
  /**
605
+ * Get total supply of sCoin
606
+ * @param sCoinName - Supported sCoin name
607
+ * @returns Total Supply
608
+ */
609
+ public async getSCoinTotalSupply(sCoinName: SupportSCoin) {
610
+ return await getSCoinTotalSupply(this, sCoinName);
611
+ }
612
+
613
+ /**
614
+ * Get all sCoin amounts.
615
+ *
616
+ * @param sCoinNames - Specific an array of support sCoin name.
617
+ * @param ownerAddress - The owner address.
618
+ * @return All market sCoin amounts.
619
+ */
620
+ public async getSCoinAmounts(
621
+ sCoinNames?: SupportSCoin[],
622
+ ownerAddress?: string
623
+ ) {
624
+ return await getSCoinAmounts(this, sCoinNames, ownerAddress);
625
+ }
626
+
627
+ /**
628
+ * Get sCoin amount.
629
+ *
630
+ * @param coinNames - Specific support sCoin name.
631
+ * @param ownerAddress - The owner address.
632
+ * @return sCoin amount.
633
+ */
634
+ public async getSCoinAmount(
635
+ sCoinName: SupportSCoin | SupportMarketCoins,
636
+ ownerAddress?: string
637
+ ) {
638
+ const parsedSCoinName = this.utils.parseSCoinName(sCoinName);
639
+ return parsedSCoinName
640
+ ? await getSCoinAmount(this, parsedSCoinName, ownerAddress)
641
+ : 0;
642
+ }
643
+
644
+ /*
599
645
  * Get flashloan fee for specified assets
600
646
  */
601
647
  public async getFlashLoanFees(
@@ -16,6 +16,8 @@ import {
16
16
  coinIds,
17
17
  UNLOCK_ROUND_DURATION,
18
18
  MAX_LOCK_DURATION,
19
+ SUPPORT_SCOIN,
20
+ sCoinIds,
19
21
  } from '../constants';
20
22
  import { queryObligation } from '../queries';
21
23
  import {
@@ -35,6 +37,7 @@ import type {
35
37
  CoinPrices,
36
38
  PriceMap,
37
39
  CoinWrappedType,
40
+ SupportSCoin,
38
41
  } from '../types';
39
42
  import { PYTH_ENDPOINTS } from 'src/constants/pyth';
40
43
  import { ScallopCache } from './scallopCache';
@@ -170,6 +173,57 @@ export class ScallopUtils {
170
173
  }
171
174
  }
172
175
 
176
+ /**
177
+ * Convert coin name to sCoin name.
178
+ *
179
+ * @param coinName - Specific support coin name.
180
+ * @return sCoin name.
181
+ */
182
+ public parseSCoinName<T extends SupportSCoin>(
183
+ coinName: SupportCoins | SupportMarketCoins
184
+ ) {
185
+ // need more check because sbtc, ssol and sapt has no sCoin type
186
+ if (
187
+ isMarketCoin(coinName) &&
188
+ SUPPORT_SCOIN.includes(coinName as SupportSCoin)
189
+ ) {
190
+ return coinName as T;
191
+ } else {
192
+ const marketCoinName = `s${coinName}`;
193
+ if (SUPPORT_SCOIN.includes(marketCoinName as SupportSCoin)) {
194
+ return marketCoinName as T;
195
+ }
196
+ return undefined;
197
+ }
198
+ }
199
+ /**
200
+ * Convert sCoin name into sCoin type
201
+ * @param sCoinName
202
+ * @returns sCoin type
203
+ */
204
+ public parseSCoinType(sCoinName: SupportSCoin) {
205
+ return sCoinIds[sCoinName];
206
+ }
207
+
208
+ /**
209
+ * Convert sCoin name into its underlying coin type
210
+ * @param sCoinName
211
+ * @returns coin type
212
+ */
213
+ public parseUnderlyingSCoinType(sCoinName: SupportSCoin) {
214
+ const coinName = this.parseCoinName(sCoinName);
215
+ return this.parseCoinType(coinName);
216
+ }
217
+
218
+ /**
219
+ * Get sCoin treasury id from sCoin name
220
+ * @param sCoinName
221
+ * @returns sCoin treasury id
222
+ */
223
+ public getSCoinTreasury(sCoinName: SupportSCoin) {
224
+ return this._address.get(`scoin.coins.${sCoinName}.treasury`);
225
+ }
226
+
173
227
  /**
174
228
  * Convert coin name to market coin type.
175
229
  *
@@ -328,7 +382,7 @@ export class ScallopUtils {
328
382
  * @param coinType - The coin type, default is 0x2::SUI::SUI.
329
383
  * @return The selected transaction coin arguments.
330
384
  */
331
- public async selectCoinIds(
385
+ public async selectCoins(
332
386
  amount: number,
333
387
  coinType: string = SUI_TYPE_ARG,
334
388
  ownerAddress?: string
@@ -339,7 +393,7 @@ export class ScallopUtils {
339
393
  amount,
340
394
  coinType
341
395
  );
342
- return coins.map((c) => c.objectId);
396
+ return coins;
343
397
  }
344
398
 
345
399
  /**
@@ -4,6 +4,7 @@ import {
4
4
  PROTOCOL_OBJECT_ID,
5
5
  SUPPORT_COLLATERALS,
6
6
  BORROW_FEE_PROTOCOL_ID,
7
+ USE_TEST_ADDRESS,
7
8
  FlashLoanFeeObjectMap,
8
9
  } from '../constants';
9
10
  import {
@@ -405,7 +406,12 @@ export const getMarketPool = async (
405
406
  }
406
407
  }
407
408
 
408
- if (balanceSheet && borrowIndex && interestModel && borrowFeeRate) {
409
+ if (
410
+ balanceSheet &&
411
+ borrowIndex &&
412
+ interestModel &&
413
+ (USE_TEST_ADDRESS || borrowFeeRate)
414
+ ) {
409
415
  const parsedMarketPoolData = parseOriginMarketPoolData({
410
416
  type: interestModel.type.fields,
411
417
  maxBorrowRate: interestModel.max_borrow_rate.fields,
@@ -419,7 +425,7 @@ export const getMarketPool = async (
419
425
  reserve: balanceSheet.revenue,
420
426
  reserveFactor: interestModel.revenue_factor.fields,
421
427
  borrowWeight: interestModel.borrow_weight.fields,
422
- borrowFeeRate: borrowFeeRate,
428
+ borrowFeeRate: borrowFeeRate || { value: '0' },
423
429
  baseBorrowRatePerSec: interestModel.base_borrow_rate_per_sec.fields,
424
430
  borrowRateOnHighKink: interestModel.borrow_rate_on_high_kink.fields,
425
431
  borrowRateOnMidKink: interestModel.borrow_rate_on_mid_kink.fields,
@@ -475,10 +481,10 @@ export const getMarketCollaterals = async (
475
481
  collateralCoinNames = collateralCoinNames || [...SUPPORT_COLLATERALS];
476
482
  const marketId = query.address.get('core.market');
477
483
  const [marketObjectResponse, coinPrices] = await Promise.all([
478
- query.cache.queryGetObject(marketId, {
484
+ await query.cache.queryGetObject(marketId, {
479
485
  showContent: true,
480
486
  }),
481
- query.utils.getCoinPrices(collateralCoinNames ?? []),
487
+ await query.utils.getCoinPrices(collateralCoinNames ?? []),
482
488
  ]);
483
489
  const marketCollaterals: MarketCollaterals = {};
484
490
 
@@ -24,6 +24,7 @@ import type {
24
24
  TotalValueLocked,
25
25
  SupportBorrowIncentiveCoins,
26
26
  ObligationBorrowIcentiveReward,
27
+ SupportBorrowIncentiveRewardCoins,
27
28
  } from '../types';
28
29
 
29
30
  /**
@@ -118,7 +119,8 @@ export const getLending = async (
118
119
  stakeAccounts?: StakeAccount[],
119
120
  coinAmount?: number,
120
121
  marketCoinAmount?: number,
121
- coinPrice?: number
122
+ coinPrice?: number,
123
+ sCoinAmount?: number
122
124
  ) => {
123
125
  const marketCoinName = query.utils.parseMarketCoinName(poolCoinName);
124
126
  marketPool = marketPool || (await query.getMarketPool(poolCoinName, indexer));
@@ -140,6 +142,8 @@ export const getLending = async (
140
142
  marketCoinAmount =
141
143
  marketCoinAmount ||
142
144
  (await query.getMarketCoinAmount(marketCoinName, ownerAddress));
145
+ sCoinAmount =
146
+ sCoinAmount || (await query.getSCoinAmount(marketCoinName, ownerAddress));
143
147
  coinPrice =
144
148
  coinPrice ||
145
149
  (await query.utils.getCoinPrices([poolCoinName]))?.[poolCoinName];
@@ -206,9 +210,9 @@ export const getLending = async (
206
210
  }
207
211
 
208
212
  // Handle supplied coin
209
- const suppliedAmount = BigNumber(marketCoinAmount).multipliedBy(
210
- marketPool?.conversionRate ?? 1
211
- );
213
+ const suppliedAmount = BigNumber(marketCoinAmount)
214
+ .plus(BigNumber(sCoinAmount))
215
+ .multipliedBy(marketPool?.conversionRate ?? 1);
212
216
  const suppliedCoin = suppliedAmount.shiftedBy(-1 * coinDecimal);
213
217
  const suppliedValue = suppliedCoin.multipliedBy(coinPrice ?? 0);
214
218
 
@@ -351,6 +355,7 @@ export const getObligationAccount = async (
351
355
  let totalBorrowCapacityValue = BigNumber(0);
352
356
  let totalRequiredCollateralValue = BigNumber(0);
353
357
  let totalBorrowedPools = 0;
358
+ let totalRewardedPools = 0;
354
359
  let totalBorrowedValue = BigNumber(0);
355
360
  let totalBorrowedValueWithWeight = BigNumber(0);
356
361
 
@@ -555,6 +560,22 @@ export const getObligationAccount = async (
555
560
  }
556
561
  }
557
562
 
563
+ if (
564
+ Object.keys(borrowIncentivePool.points).some((coinName: any) => {
565
+ const rewardApr =
566
+ borrowIncentivePool.points[
567
+ coinName as SupportBorrowIncentiveRewardCoins
568
+ ]?.rewardApr;
569
+ return (
570
+ rewardApr !== Infinity &&
571
+ typeof rewardApr == 'number' &&
572
+ rewardApr > 0
573
+ );
574
+ }) &&
575
+ borrowIncentiveAccount.debtAmount > 0
576
+ ) {
577
+ totalRewardedPools++;
578
+ }
558
579
  borrowIncentives[coinName] = {
559
580
  coinName: borrowIncentivePool.coinName,
560
581
  coinType: borrowIncentivePool.coinType,
@@ -612,6 +633,7 @@ export const getObligationAccount = async (
612
633
  totalRiskLevel: riskLevel.toNumber(),
613
634
  totalDepositedPools,
614
635
  totalBorrowedPools,
636
+ totalRewardedPools,
615
637
  collaterals,
616
638
  debts,
617
639
  borrowIncentives,
@@ -0,0 +1,94 @@
1
+ import { bcs } from '@mysten/sui.js/bcs';
2
+ import assert from 'assert';
3
+ import BigNumber from 'bignumber.js';
4
+ import { SUPPORT_SCOIN } from 'src/constants';
5
+ import { ScallopQuery } from 'src/models';
6
+ import { OptionalKeys, SupportSCoin, sCoinBalance } from 'src/types';
7
+
8
+ /**
9
+ * Get total supply of sCoin
10
+ * @param query
11
+ * @param sCoinName
12
+ * @returns `number`
13
+ */
14
+ export const getSCoinTotalSupply = async (
15
+ query: ScallopQuery,
16
+ sCoinName: SupportSCoin
17
+ ): Promise<sCoinBalance> => {
18
+ const sCoinPkgId = query.address.get('scoin.id');
19
+ // get treasury
20
+ const args = [query.utils.getSCoinTreasury(sCoinName)];
21
+ const typeArgs = [
22
+ query.utils.parseSCoinType(sCoinName),
23
+ query.utils.parseUnderlyingSCoinType(sCoinName),
24
+ ];
25
+ const queryTarget = `${sCoinPkgId}::s_coin_converter::total_supply`;
26
+ const queryResults = await query.cache.queryInspectTxn({
27
+ queryTarget,
28
+ args,
29
+ typeArgs,
30
+ });
31
+ const results = queryResults.results;
32
+ if (results && results[0].returnValues) {
33
+ const value = Uint8Array.from(results[0].returnValues[0][0]);
34
+ const type = results[0].returnValues[0][1]; // should be u64
35
+ assert(type === 'u64', 'Result type is not u64');
36
+
37
+ return BigNumber(bcs.de(type, value))
38
+ .shiftedBy(
39
+ query.utils.getCoinDecimal(query.utils.parseCoinName(sCoinName))
40
+ )
41
+ .toNumber();
42
+ }
43
+
44
+ return 0;
45
+ };
46
+
47
+ /**
48
+ * Query all owned sCoin amount.
49
+ *
50
+ * @param query - The Scallop query instance.
51
+ * @param sCoinNames - Specific an array of support sCoin name.
52
+ * @param ownerAddress - The owner address.
53
+ * @return All owned sCoins amount.
54
+ */
55
+ export const getSCoinAmounts = async (
56
+ query: ScallopQuery,
57
+ sCoinNames?: SupportSCoin[],
58
+ ownerAddress?: string
59
+ ) => {
60
+ sCoinNames = sCoinNames || [...SUPPORT_SCOIN];
61
+ const owner = ownerAddress || query.suiKit.currentAddress();
62
+ const sCoins = {} as OptionalKeys<Record<SupportSCoin, number>>;
63
+
64
+ await Promise.allSettled(
65
+ sCoinNames.map(async (sCoinName) => {
66
+ const sCoin = await getSCoinAmount(query, sCoinName, owner);
67
+ sCoins[sCoinName] = sCoin;
68
+ })
69
+ );
70
+
71
+ return sCoins;
72
+ };
73
+
74
+ /**
75
+ * Query owned sCoin amount.
76
+ *
77
+ * @param query - The Scallop query instance.
78
+ * @param sCoinNames - Specific support sCoin name.
79
+ * @param ownerAddress - The owner address.
80
+ * @return Owned sCoin amount.
81
+ */
82
+ export const getSCoinAmount = async (
83
+ query: ScallopQuery,
84
+ sCoinName: SupportSCoin,
85
+ ownerAddress?: string
86
+ ) => {
87
+ const owner = ownerAddress || query.suiKit.currentAddress();
88
+ const sCoinType = query.utils.parseSCoinType(sCoinName);
89
+ const amount = await query.cache.queryGetCoinBalance({
90
+ owner,
91
+ coinType: sCoinType,
92
+ });
93
+ return BigNumber(amount).toNumber();
94
+ };
@@ -244,7 +244,6 @@ export const getVeScaTreasuryInfo = async (
244
244
  const treasuryFields = veScaTreasury.data.content
245
245
  .fields as VeScaTreasuryFields;
246
246
 
247
- console.log(treasuryFields);
248
247
  const totalLockedSca = BigNumber(
249
248
  treasuryFields.unlock_schedule.fields.locked_sca_amount
250
249
  )
package/src/test.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { Scallop } from './models';
2
+ import * as dotenv from 'dotenv';
3
+ dotenv.config();
4
+ const scallop = new Scallop({
5
+ secretKey: process.env.SECRET_KEY as string,
6
+ });
7
+
8
+ const main = async () => {
9
+ const query = await scallop.createScallopQuery();
10
+
11
+ const res = await query.getVeScas(
12
+ '0xd1a70cfe7332e994a950b9c570e93def4b6d2ec53b34ff5c0cc9946226a7cf3d'
13
+ );
14
+ console.dir(res, { depth: null });
15
+ };
16
+ main()
17
+ .then()
18
+ .catch(console.error)
19
+ .finally(() => process.exit(0));