@scallop-io/sui-scallop-sdk 1.4.1 → 1.4.2-rc.1

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 (80) hide show
  1. package/dist/constants/common.d.ts +1 -1
  2. package/dist/constants/poolAddress.d.ts +16 -4
  3. package/dist/constants/queryKeys.d.ts +2 -2
  4. package/dist/constants/tokenBucket.d.ts +2 -2
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +1270 -588
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +1225 -544
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/models/scallopBuilder.d.ts +2 -1
  11. package/dist/models/scallopCache.d.ts +2 -0
  12. package/dist/models/scallopQuery.d.ts +38 -20
  13. package/dist/models/scallopUtils.d.ts +4 -2
  14. package/dist/queries/borrowIncentiveQuery.d.ts +12 -0
  15. package/dist/queries/coreQuery.d.ts +18 -19
  16. package/dist/queries/index.d.ts +2 -0
  17. package/dist/queries/isolatedAssetQuery.d.ts +2 -2
  18. package/dist/queries/objectsQuery.d.ts +3 -0
  19. package/dist/queries/poolAddressesQuery.d.ts +18 -0
  20. package/dist/queries/spoolQuery.d.ts +6 -2
  21. package/dist/test.d.ts +1 -0
  22. package/dist/types/builder/borrowIncentive.d.ts +5 -5
  23. package/dist/types/builder/core.d.ts +20 -16
  24. package/dist/types/builder/loyaltyProgram.d.ts +1 -1
  25. package/dist/types/builder/referral.d.ts +4 -4
  26. package/dist/types/builder/sCoin.d.ts +2 -2
  27. package/dist/types/builder/spool.d.ts +4 -4
  28. package/dist/types/builder/vesca.d.ts +6 -6
  29. package/dist/types/query/core.d.ts +22 -5
  30. package/dist/types/query/spool.d.ts +20 -0
  31. package/dist/types/utils.d.ts +7 -2
  32. package/dist/utils/core.d.ts +2 -0
  33. package/dist/utils/index.d.ts +2 -0
  34. package/dist/utils/query.d.ts +1 -1
  35. package/dist/utils/util.d.ts +1 -0
  36. package/package.json +7 -7
  37. package/src/builders/borrowIncentiveBuilder.ts +28 -15
  38. package/src/builders/coreBuilder.ts +76 -49
  39. package/src/builders/loyaltyProgramBuilder.ts +4 -3
  40. package/src/builders/referralBuilder.ts +23 -10
  41. package/src/builders/sCoinBuilder.ts +8 -6
  42. package/src/builders/spoolBuilder.ts +21 -14
  43. package/src/builders/vescaBuilder.ts +23 -13
  44. package/src/constants/common.ts +1 -12
  45. package/src/constants/poolAddress.ts +336 -10
  46. package/src/constants/queryKeys.ts +9 -5
  47. package/src/constants/testAddress.ts +42 -0
  48. package/src/constants/tokenBucket.ts +2 -2
  49. package/src/index.ts +1 -0
  50. package/src/models/scallopBuilder.ts +59 -2
  51. package/src/models/scallopCache.ts +171 -19
  52. package/src/models/scallopClient.ts +16 -10
  53. package/src/models/scallopQuery.ts +36 -28
  54. package/src/models/scallopUtils.ts +11 -4
  55. package/src/queries/borrowIncentiveQuery.ts +6 -8
  56. package/src/queries/borrowLimitQuery.ts +1 -0
  57. package/src/queries/coreQuery.ts +408 -258
  58. package/src/queries/index.ts +2 -0
  59. package/src/queries/isolatedAssetQuery.ts +37 -31
  60. package/src/queries/objectsQuery.ts +20 -0
  61. package/src/queries/poolAddressesQuery.ts +146 -0
  62. package/src/queries/portfolioQuery.ts +31 -13
  63. package/src/queries/priceQuery.ts +3 -1
  64. package/src/queries/spoolQuery.ts +189 -122
  65. package/src/test.ts +17 -0
  66. package/src/types/builder/borrowIncentive.ts +8 -5
  67. package/src/types/builder/core.ts +23 -17
  68. package/src/types/builder/loyaltyProgram.ts +1 -1
  69. package/src/types/builder/referral.ts +6 -4
  70. package/src/types/builder/sCoin.ts +2 -2
  71. package/src/types/builder/spool.ts +4 -4
  72. package/src/types/builder/vesca.ts +9 -6
  73. package/src/types/query/core.ts +21 -5
  74. package/src/types/query/spool.ts +21 -0
  75. package/src/types/utils.ts +8 -3
  76. package/src/utils/core.ts +18 -0
  77. package/src/utils/index.ts +2 -0
  78. package/src/utils/query.ts +21 -5
  79. package/src/utils/tokenBucket.ts +9 -29
  80. package/src/utils/util.ts +8 -0
@@ -3,16 +3,21 @@ import {
3
3
  SUPPORT_POOLS,
4
4
  PROTOCOL_OBJECT_ID,
5
5
  SUPPORT_COLLATERALS,
6
- BORROW_FEE_PROTOCOL_ID,
7
6
  FlashLoanFeeObjectMap,
7
+ POOL_ADDRESSES,
8
8
  } from '../constants';
9
9
  import {
10
10
  parseOriginMarketPoolData,
11
11
  calculateMarketPoolData,
12
12
  parseOriginMarketCollateralData,
13
13
  calculateMarketCollateralData,
14
+ parseObjectAs,
14
15
  } from '../utils';
15
- import type { SuiObjectResponse, SuiObjectData } from '@mysten/sui/client';
16
+ import type {
17
+ SuiObjectResponse,
18
+ SuiObjectData,
19
+ SuiParsedData,
20
+ } from '@mysten/sui/client';
16
21
  import type { SuiObjectArg } from '@scallop-io/sui-kit';
17
22
  import type { ScallopAddress, ScallopCache, ScallopQuery } from '../models';
18
23
  import {
@@ -28,22 +33,28 @@ import {
28
33
  ObligationQueryInterface,
29
34
  Obligation,
30
35
  InterestModel,
31
- BorrowIndex,
32
36
  BalanceSheet,
33
37
  RiskModel,
34
38
  CollateralStat,
35
39
  SupportMarketCoins,
36
40
  OptionalKeys,
37
41
  CoinPrices,
42
+ OriginMarketPoolData,
43
+ BorrowFee,
44
+ BorrowDynamic,
45
+ OriginMarketCollateralData,
38
46
  } from '../types';
39
47
  import BigNumber from 'bignumber.js';
40
48
  import { getSupplyLimit } from './supplyLimitQuery';
41
49
  import { isIsolatedAsset } from './isolatedAssetQuery';
42
50
  import { getBorrowLimit } from './borrowLimitQuery';
51
+ import { queryMultipleObjects } from './objectsQuery';
43
52
 
44
53
  /**
45
54
  * Query market data.
46
55
  *
56
+ * @deprecated Use query market pools
57
+ *
47
58
  * @description
48
59
  * Use inspectTxn call to obtain the data provided in the scallop contract query module.
49
60
  *
@@ -126,6 +137,9 @@ export const queryMarket = async (
126
137
  highKink: pool.highKink,
127
138
  midKink: pool.midKink,
128
139
  minBorrowAmount: pool.minBorrowAmount,
140
+ isIsolated: await isIsolatedAsset(query.utils, poolCoinName),
141
+ supplyLimit: (await getSupplyLimit(query.utils, poolCoinName)) ?? '0',
142
+ borrowLimit: (await getBorrowLimit(query.utils, poolCoinName)) ?? '0',
129
143
  });
130
144
 
131
145
  const calculatedMarketPoolData = calculateMarketPoolData(
@@ -133,19 +147,6 @@ export const queryMarket = async (
133
147
  parsedMarketPoolData
134
148
  );
135
149
 
136
- const coinDecimal = query.utils.getCoinDecimal(poolCoinName);
137
- const maxSupplyCoin = BigNumber(
138
- (await getSupplyLimit(query.utils, poolCoinName)) ?? '0'
139
- )
140
- .shiftedBy(-coinDecimal)
141
- .toNumber();
142
-
143
- const maxBorrowCoin = BigNumber(
144
- (await getBorrowLimit(query.utils, poolCoinName)) ?? '0'
145
- )
146
- .shiftedBy(-coinDecimal)
147
- .toNumber();
148
-
149
150
  pools[poolCoinName] = {
150
151
  coinName: poolCoinName,
151
152
  symbol: query.utils.parseSymbol(poolCoinName),
@@ -155,7 +156,6 @@ export const queryMarket = async (
155
156
  query.utils.parseMarketCoinName(poolCoinName)
156
157
  ),
157
158
  coinWrappedType: query.utils.getCoinWrappedType(poolCoinName),
158
- coinDecimal,
159
159
  coinPrice: coinPrice,
160
160
  highKink: parsedMarketPoolData.highKink,
161
161
  midKink: parsedMarketPoolData.midKink,
@@ -164,10 +164,6 @@ export const queryMarket = async (
164
164
  borrowFee: parsedMarketPoolData.borrowFee,
165
165
  marketCoinSupplyAmount: parsedMarketPoolData.marketCoinSupplyAmount,
166
166
  minBorrowAmount: parsedMarketPoolData.minBorrowAmount,
167
- isIsolated: await isIsolatedAsset(query.utils, poolCoinName),
168
- // isIsolated: false,
169
- maxSupplyCoin,
170
- maxBorrowCoin,
171
167
  ...calculatedMarketPoolData,
172
168
  };
173
169
  }
@@ -188,10 +184,11 @@ export const queryMarket = async (
188
184
  collateralFactor: collateral.collateralFactor,
189
185
  liquidationFactor: collateral.liquidationFactor,
190
186
  liquidationDiscount: collateral.liquidationDiscount,
191
- liquidationPanelty: collateral.liquidationPanelty,
187
+ liquidationPenalty: collateral.liquidationPanelty,
192
188
  liquidationReserveFactor: collateral.liquidationReserveFactor,
193
189
  maxCollateralAmount: collateral.maxCollateralAmount,
194
190
  totalCollateralAmount: collateral.totalCollateralAmount,
191
+ isIsolated: await isIsolatedAsset(query.utils, collateralCoinName),
195
192
  });
196
193
 
197
194
  const calculatedMarketCollateralData = calculateMarketCollateralData(
@@ -205,15 +202,14 @@ export const queryMarket = async (
205
202
  coinType: coinType,
206
203
  marketCoinType: query.utils.parseMarketCoinType(collateralCoinName),
207
204
  coinWrappedType: query.utils.getCoinWrappedType(collateralCoinName),
208
- coinDecimal: query.utils.getCoinDecimal(collateralCoinName),
209
205
  coinPrice: coinPrice,
210
206
  collateralFactor: parsedMarketCollateralData.collateralFactor,
211
207
  liquidationFactor: parsedMarketCollateralData.liquidationFactor,
212
208
  liquidationDiscount: parsedMarketCollateralData.liquidationDiscount,
213
- liquidationPanelty: parsedMarketCollateralData.liquidationPanelty,
209
+ liquidationPenalty: parsedMarketCollateralData.liquidationPenalty,
214
210
  liquidationReserveFactor:
215
211
  parsedMarketCollateralData.liquidationReserveFactor,
216
- isIsolated: await isIsolatedAsset(query.utils, collateralCoinName),
212
+
217
213
  ...calculatedMarketCollateralData,
218
214
  };
219
215
  }
@@ -225,6 +221,135 @@ export const queryMarket = async (
225
221
  } as Market;
226
222
  };
227
223
 
224
+ const queryRequiredMarketObjects = async (
225
+ query: ScallopQuery,
226
+ poolCoinNames: SupportPoolCoins[]
227
+ ) => {
228
+ // Prepare all tasks for querying each object type
229
+ const tasks = poolCoinNames.map((t) => ({
230
+ poolCoinName: t,
231
+ balanceSheet: POOL_ADDRESSES[t]?.lendingPoolAddress,
232
+ collateralStat: POOL_ADDRESSES[t]?.collateralPoolAddress,
233
+ borrowDynamic: POOL_ADDRESSES[t]?.borrowDynamic,
234
+ interestModel: POOL_ADDRESSES[t]?.interestModel,
235
+ riskModel: POOL_ADDRESSES[t]?.riskModel,
236
+ borrowFeeKey: POOL_ADDRESSES[t]?.borrowFeeKey,
237
+ supplyLimitKey: POOL_ADDRESSES[t]?.supplyLimitKey,
238
+ borrowLimitKey: POOL_ADDRESSES[t]?.borrowLimitKey,
239
+ isolatedAssetKey: POOL_ADDRESSES[t]?.isolatedAssetKey,
240
+ }));
241
+
242
+ // Query all objects for each key in parallel
243
+ const [
244
+ balanceSheetObjects,
245
+ collateralStatObjects,
246
+ borrowDynamicObjects,
247
+ interestModelObjects,
248
+ riskModelObjects,
249
+ borrowFeeObjects,
250
+ supplyLimitObjects,
251
+ borrowLimitObjects,
252
+ isolatedAssetObjects,
253
+ ] = await Promise.all([
254
+ queryMultipleObjects(
255
+ query.cache,
256
+ tasks.map((task) => task.balanceSheet).filter((t): t is string => !!t)
257
+ ),
258
+ queryMultipleObjects(
259
+ query.cache,
260
+ tasks.map((task) => task.collateralStat).filter((t): t is string => !!t)
261
+ ),
262
+ queryMultipleObjects(
263
+ query.cache,
264
+ tasks.map((task) => task.borrowDynamic).filter((t): t is string => !!t)
265
+ ),
266
+ queryMultipleObjects(
267
+ query.cache,
268
+ tasks.map((task) => task.interestModel).filter((t): t is string => !!t)
269
+ ),
270
+ queryMultipleObjects(
271
+ query.cache,
272
+ tasks.map((task) => task.riskModel).filter((t): t is string => !!t)
273
+ ),
274
+ queryMultipleObjects(
275
+ query.cache,
276
+ tasks.map((task) => task.borrowFeeKey).filter((t): t is string => !!t)
277
+ ),
278
+ queryMultipleObjects(
279
+ query.cache,
280
+ tasks.map((task) => task.supplyLimitKey).filter((t): t is string => !!t)
281
+ ),
282
+ queryMultipleObjects(
283
+ query.cache,
284
+ tasks.map((task) => task.borrowLimitKey).filter((t): t is string => !!t)
285
+ ),
286
+ queryMultipleObjects(
287
+ query.cache,
288
+ tasks.map((task) => task.isolatedAssetKey).filter((t): t is string => !!t)
289
+ ),
290
+ ]);
291
+
292
+ // Map the results back to poolCoinNames
293
+ const mapObjects = (
294
+ tasks: { poolCoinName: string; [key: string]: string | undefined }[],
295
+ fetchedObjects: SuiObjectData[]
296
+ ) => {
297
+ const resultMap: Record<string, SuiObjectData> = {};
298
+ let fetchedIndex = 0;
299
+
300
+ for (const task of tasks) {
301
+ const key = task[Object.keys(task)[1]]; // current object key being queried
302
+ if (key) {
303
+ resultMap[task.poolCoinName] = fetchedObjects[fetchedIndex];
304
+ fetchedIndex++;
305
+ }
306
+ }
307
+ return resultMap;
308
+ };
309
+
310
+ const balanceSheetMap = mapObjects(tasks, balanceSheetObjects);
311
+ const collateralStatMap = mapObjects(tasks, collateralStatObjects);
312
+ const borrowDynamicMap = mapObjects(tasks, borrowDynamicObjects);
313
+ const interestModelMap = mapObjects(tasks, interestModelObjects);
314
+ const riskModelMap = mapObjects(tasks, riskModelObjects);
315
+ const borrowFeeMap = mapObjects(tasks, borrowFeeObjects);
316
+ const supplyLimitMap = mapObjects(tasks, supplyLimitObjects);
317
+ const borrowLimitMap = mapObjects(tasks, borrowLimitObjects);
318
+ const isolatedAssetMap = mapObjects(tasks, isolatedAssetObjects);
319
+
320
+ // Construct the final requiredObjects result
321
+ return poolCoinNames.reduce(
322
+ (acc, name) => {
323
+ acc[name] = {
324
+ balanceSheet: balanceSheetMap[name],
325
+ collateralStat: collateralStatMap[name],
326
+ borrowDynamic: borrowDynamicMap[name],
327
+ interestModel: interestModelMap[name],
328
+ riskModel: riskModelMap[name],
329
+ borrowFeeKey: borrowFeeMap[name],
330
+ supplyLimitKey: supplyLimitMap[name],
331
+ borrowLimitKey: borrowLimitMap[name],
332
+ isolatedAssetKey: isolatedAssetMap[name],
333
+ };
334
+ return acc;
335
+ },
336
+ {} as Record<
337
+ SupportPoolCoins,
338
+ {
339
+ balanceSheet: SuiObjectData;
340
+ collateralStat?: SuiObjectData;
341
+ riskModel?: SuiObjectData;
342
+ borrowDynamic: SuiObjectData;
343
+ interestModel: SuiObjectData;
344
+ borrowFeeKey: SuiObjectData;
345
+ supplyLimitKey: SuiObjectData;
346
+ borrowLimitKey: SuiObjectData;
347
+ isolatedAssetKey: SuiObjectData;
348
+ }
349
+ >
350
+ );
351
+ };
352
+
228
353
  /**
229
354
  * Get coin market pools data.
230
355
  *
@@ -239,53 +364,172 @@ export const queryMarket = async (
239
364
  */
240
365
  export const getMarketPools = async (
241
366
  query: ScallopQuery,
242
- poolCoinNames: SupportPoolCoins[] = [...SUPPORT_POOLS],
367
+ poolCoinNames: SupportPoolCoins[],
243
368
  indexer: boolean = false,
244
369
  coinPrices?: CoinPrices
245
- ) => {
246
- const marketId = query.address.get('core.market');
247
- const marketObjectResponse = await query.cache.queryGetObject(marketId, {
248
- showContent: true,
249
- });
370
+ ): Promise<{
371
+ pools: MarketPools;
372
+ collaterals: MarketCollaterals;
373
+ }> => {
250
374
  coinPrices = coinPrices ?? (await query.utils.getCoinPrices());
251
375
 
252
- const marketPools: MarketPools = {};
376
+ const pools: MarketPools = {};
377
+ const collaterals: MarketCollaterals = {};
253
378
 
254
379
  if (indexer) {
255
- const marketPoolsIndexer = await query.indexer.getMarketPools();
256
-
257
- const updateMarketPool = (marketPool: MarketPool) => {
258
- if (!poolCoinNames.includes(marketPool.coinName)) return;
259
- marketPool.coinPrice =
260
- coinPrices[marketPool.coinName] ?? marketPool.coinPrice;
261
- marketPool.coinWrappedType = query.utils.getCoinWrappedType(
262
- marketPool.coinName
263
- );
264
- marketPools[marketPool.coinName] = marketPool;
380
+ // const marketPoolsIndexer = await query.indexer.getMarketPools();
381
+
382
+ // const updateMarketPool = (marketPool: MarketPool) => {
383
+ // if (!poolCoinNames.includes(marketPool.coinName)) return;
384
+ // marketPool.coinPrice =
385
+ // coinPrices[marketPool.coinName] ?? marketPool.coinPrice;
386
+ // marketPool.coinWrappedType = query.utils.getCoinWrappedType(
387
+ // marketPool.coinName
388
+ // );
389
+ // pools[marketPool.coinName] = marketPool;
390
+ // };
391
+
392
+ // Object.values(marketPoolsIndexer).forEach(updateMarketPool);
393
+
394
+ // return pools;
395
+ const marketIndexer = await query.indexer.getMarket();
396
+
397
+ const updatePools = (item: MarketPool) => {
398
+ item.coinPrice = coinPrices[item.coinName] ?? item.coinPrice;
399
+ item.coinWrappedType = query.utils.getCoinWrappedType(item.coinName);
400
+ pools[item.coinName] = item;
401
+ };
402
+
403
+ const updateCollaterals = (item: MarketCollateral) => {
404
+ item.coinPrice = coinPrices[item.coinName] ?? item.coinPrice;
405
+ item.coinWrappedType = query.utils.getCoinWrappedType(item.coinName);
406
+ collaterals[item.coinName] = item;
265
407
  };
266
408
 
267
- Object.values(marketPoolsIndexer).forEach(updateMarketPool);
409
+ Object.values(marketIndexer.pools).forEach(updatePools);
410
+ Object.values(marketIndexer.collaterals).forEach(updateCollaterals);
268
411
 
269
- return marketPools;
412
+ return {
413
+ pools,
414
+ collaterals,
415
+ };
270
416
  }
271
417
 
418
+ const requiredObjects = await queryRequiredMarketObjects(
419
+ query,
420
+ poolCoinNames
421
+ );
422
+
272
423
  await Promise.allSettled(
273
424
  poolCoinNames.map(async (poolCoinName) => {
274
- const marketPool = await getMarketPool(
275
- query,
276
- poolCoinName,
277
- indexer,
278
- marketObjectResponse?.data,
279
- coinPrices?.[poolCoinName]
280
- );
281
-
282
- if (marketPool) {
283
- marketPools[poolCoinName] = marketPool;
425
+ try {
426
+ const result = await getMarketPool(
427
+ query,
428
+ poolCoinName,
429
+ indexer,
430
+ coinPrices?.[poolCoinName] ?? 0,
431
+ requiredObjects[poolCoinName]
432
+ );
433
+ if (result?.marketPool) {
434
+ pools[poolCoinName] = result?.marketPool;
435
+ }
436
+ if (result?.collateral) {
437
+ collaterals[poolCoinName as SupportCollateralCoins] =
438
+ result.collateral;
439
+ }
440
+ } catch (e) {
441
+ console.error(e);
284
442
  }
285
443
  })
286
444
  );
287
445
 
288
- return marketPools;
446
+ return {
447
+ pools,
448
+ collaterals,
449
+ };
450
+ };
451
+
452
+ const parseMarketPoolObjects = ({
453
+ balanceSheet,
454
+ borrowDynamic,
455
+ collateralStat,
456
+ interestModel,
457
+ riskModel,
458
+ borrowFeeKey,
459
+ supplyLimitKey,
460
+ borrowLimitKey,
461
+ isolatedAssetKey,
462
+ }: {
463
+ balanceSheet: SuiObjectData;
464
+ borrowDynamic: SuiObjectData;
465
+ collateralStat?: SuiObjectData;
466
+ interestModel: SuiObjectData;
467
+ riskModel?: SuiObjectData;
468
+ borrowFeeKey: SuiObjectData;
469
+ supplyLimitKey?: SuiObjectData;
470
+ borrowLimitKey?: SuiObjectData;
471
+ isolatedAssetKey: SuiObjectData;
472
+ }): OriginMarketPoolData & {
473
+ parsedOriginMarketCollateral?: OriginMarketCollateralData;
474
+ } => {
475
+ const _balanceSheet = parseObjectAs<BalanceSheet>(balanceSheet);
476
+ const _interestModel = parseObjectAs<InterestModel>(interestModel);
477
+ const _borrowDynamic = parseObjectAs<BorrowDynamic>(borrowDynamic);
478
+ const _borrowFee = parseObjectAs<BorrowFee>(borrowFeeKey);
479
+ const _supplyLimit = supplyLimitKey
480
+ ? parseObjectAs<string>(supplyLimitKey)
481
+ : '0';
482
+ const _borrowLimit = borrowLimitKey
483
+ ? parseObjectAs<string>(borrowLimitKey)
484
+ : '0';
485
+ const _riskModel = riskModel
486
+ ? parseObjectAs<RiskModel>(riskModel)
487
+ : undefined;
488
+ const _collateralStat = collateralStat
489
+ ? parseObjectAs<CollateralStat>(collateralStat)
490
+ : undefined;
491
+
492
+ const parsedOriginMarketCollateral =
493
+ _riskModel && _collateralStat
494
+ ? {
495
+ type: _interestModel.type.fields,
496
+ isIsolated: !!isolatedAssetKey,
497
+ collateralFactor: _riskModel.collateral_factor.fields,
498
+ liquidationFactor: _riskModel.liquidation_factor.fields,
499
+ liquidationPenalty: _riskModel.liquidation_penalty.fields,
500
+ liquidationDiscount: _riskModel.liquidation_discount.fields,
501
+ liquidationReserveFactor:
502
+ _riskModel.liquidation_revenue_factor.fields,
503
+ maxCollateralAmount: _riskModel.max_collateral_amount,
504
+ totalCollateralAmount: _collateralStat.amount,
505
+ }
506
+ : undefined;
507
+
508
+ return {
509
+ type: _interestModel.type.fields,
510
+ maxBorrowRate: _interestModel.max_borrow_rate.fields,
511
+ interestRate: _borrowDynamic.interest_rate.fields,
512
+ interestRateScale: _borrowDynamic.interest_rate_scale,
513
+ borrowIndex: _borrowDynamic.borrow_index,
514
+ lastUpdated: _borrowDynamic.last_updated,
515
+ cash: _balanceSheet.cash,
516
+ debt: _balanceSheet.debt,
517
+ marketCoinSupply: _balanceSheet.market_coin_supply,
518
+ reserve: _balanceSheet.revenue,
519
+ reserveFactor: _interestModel.revenue_factor.fields,
520
+ borrowWeight: _interestModel.borrow_weight.fields,
521
+ borrowFeeRate: _borrowFee,
522
+ baseBorrowRatePerSec: _interestModel.base_borrow_rate_per_sec.fields,
523
+ borrowRateOnHighKink: _interestModel.borrow_rate_on_high_kink.fields,
524
+ borrowRateOnMidKink: _interestModel.borrow_rate_on_mid_kink.fields,
525
+ highKink: _interestModel.high_kink.fields,
526
+ midKink: _interestModel.mid_kink.fields,
527
+ minBorrowAmount: _interestModel.min_borrow_amount,
528
+ isIsolated: !!isolatedAssetKey,
529
+ supplyLimit: _supplyLimit,
530
+ borrowLimit: _borrowLimit,
531
+ parsedOriginMarketCollateral,
532
+ };
289
533
  };
290
534
 
291
535
  /**
@@ -302,9 +546,19 @@ export const getMarketPool = async (
302
546
  query: ScallopQuery,
303
547
  poolCoinName: SupportPoolCoins,
304
548
  indexer: boolean = false,
305
- marketObject?: SuiObjectData | null,
306
- coinPrice?: number
307
- ): Promise<MarketPool | undefined> => {
549
+ coinPrice: number,
550
+ requiredObjects?: {
551
+ balanceSheet: SuiObjectData;
552
+ borrowDynamic: SuiObjectData;
553
+ interestModel: SuiObjectData;
554
+ borrowFeeKey: SuiObjectData;
555
+ supplyLimitKey: SuiObjectData;
556
+ borrowLimitKey: SuiObjectData;
557
+ isolatedAssetKey: SuiObjectData;
558
+ }
559
+ ): Promise<
560
+ { marketPool: MarketPool; collateral?: MarketCollateral } | undefined
561
+ > => {
308
562
  coinPrice = coinPrice ?? (await query.utils.getCoinPrices())?.[poolCoinName];
309
563
 
310
564
  if (indexer) {
@@ -317,202 +571,83 @@ export const getMarketPool = async (
317
571
  marketPoolIndexer.coinName
318
572
  );
319
573
 
320
- return marketPoolIndexer;
321
- }
322
-
323
- const marketId = query.address.get('core.market');
324
- marketObject =
325
- marketObject ||
326
- (
327
- await query.cache.queryGetObject(marketId, {
328
- showContent: true,
329
- })
330
- )?.data;
331
-
332
- if (!(marketObject && marketObject.content?.dataType === 'moveObject'))
333
- throw new Error(`Failed to fetch marketObject`);
334
-
335
- const fields = marketObject.content.fields as any;
336
- const coinType = query.utils.parseCoinType(poolCoinName);
337
- // Get balance sheet.
338
- const balanceSheetParentId =
339
- fields.vault.fields.balance_sheets.fields.table.fields.id.id;
340
- const balanceSheetDynamicFieldObjectResponse =
341
- await query.cache.queryGetDynamicFieldObject({
342
- parentId: balanceSheetParentId,
343
- name: {
344
- type: '0x1::type_name::TypeName',
345
- value: {
346
- name: coinType.substring(2),
347
- },
348
- },
349
- });
350
-
351
- const balanceSheetDynamicFieldObject =
352
- balanceSheetDynamicFieldObjectResponse?.data;
353
-
354
- if (
355
- !(
356
- balanceSheetDynamicFieldObject &&
357
- balanceSheetDynamicFieldObject.content &&
358
- 'fields' in balanceSheetDynamicFieldObject.content
359
- )
360
- )
361
- throw new Error(
362
- `Failed to fetch balanceSheetDynamicFieldObject for ${poolCoinName}: ${balanceSheetDynamicFieldObjectResponse?.error?.code.toString()}`
363
- );
364
- const balanceSheet: BalanceSheet = (
365
- balanceSheetDynamicFieldObject.content.fields as any
366
- ).value.fields;
367
-
368
- // Get borrow index.
369
- const borrowIndexParentId = fields.borrow_dynamics.fields.table.fields.id.id;
370
- const borrowIndexDynamicFieldObjectResponse =
371
- await query.cache.queryGetDynamicFieldObject({
372
- parentId: borrowIndexParentId,
373
- name: {
374
- type: '0x1::type_name::TypeName',
375
- value: {
376
- name: coinType.substring(2),
377
- },
378
- },
379
- });
380
-
381
- const borrowIndexDynamicFieldObject =
382
- borrowIndexDynamicFieldObjectResponse?.data;
383
- if (
384
- !(
385
- borrowIndexDynamicFieldObject &&
386
- borrowIndexDynamicFieldObject.content &&
387
- 'fields' in borrowIndexDynamicFieldObject.content
388
- )
389
- )
390
- throw new Error(
391
- `Failed to fetch borrowIndexDynamicFieldObject for ${poolCoinName}`
392
- );
393
- const borrowIndex: BorrowIndex = (
394
- borrowIndexDynamicFieldObject.content.fields as any
395
- ).value.fields;
396
-
397
- // Get interest models.
398
- const interestModelParentId =
399
- fields.interest_models.fields.table.fields.id.id;
400
- const interestModelDynamicFieldObjectResponse =
401
- await query.cache.queryGetDynamicFieldObject({
402
- parentId: interestModelParentId,
403
- name: {
404
- type: '0x1::type_name::TypeName',
405
- value: {
406
- name: coinType.substring(2),
407
- },
408
- },
409
- });
410
-
411
- const interestModelDynamicFieldObject =
412
- interestModelDynamicFieldObjectResponse?.data;
413
- if (
414
- !(
415
- interestModelDynamicFieldObject &&
416
- interestModelDynamicFieldObject.content &&
417
- 'fields' in interestModelDynamicFieldObject.content
418
- )
419
- )
420
- throw new Error(
421
- `Failed to fetch interestModelDynamicFieldObject for ${poolCoinName}: ${interestModelDynamicFieldObject}`
422
- );
423
- const interestModel: InterestModel = (
424
- interestModelDynamicFieldObject.content.fields as any
425
- ).value.fields;
426
-
427
- // Get borrow fee.
428
- const getBorrowFee = async () => {
429
- const borrowFeeDynamicFieldObjectResponse =
430
- await query.cache.queryGetDynamicFieldObject({
431
- parentId: marketId,
432
- name: {
433
- type: `${BORROW_FEE_PROTOCOL_ID}::market_dynamic_keys::BorrowFeeKey`,
434
- value: {
435
- type: {
436
- name: coinType.substring(2),
437
- },
438
- },
439
- },
440
- });
574
+ let marketCollateralIndexer: MarketCollateral | undefined = undefined;
575
+ if (SUPPORT_COLLATERALS.includes(poolCoinName as SupportCollateralCoins)) {
576
+ marketCollateralIndexer = await query.indexer.getMarketCollateral(
577
+ poolCoinName as SupportCollateralCoins
578
+ );
579
+ marketCollateralIndexer.coinPrice =
580
+ coinPrice ?? marketCollateralIndexer.coinPrice;
581
+ marketCollateralIndexer.coinWrappedType = query.utils.getCoinWrappedType(
582
+ marketCollateralIndexer.coinName
583
+ );
584
+ }
441
585
 
442
- const borrowFeeDynamicFieldObject =
443
- borrowFeeDynamicFieldObjectResponse?.data;
444
- if (
445
- !(
446
- borrowFeeDynamicFieldObject &&
447
- borrowFeeDynamicFieldObject.content &&
448
- 'fields' in borrowFeeDynamicFieldObject.content
449
- )
450
- )
451
- return { value: '0' };
452
- return (borrowFeeDynamicFieldObject.content.fields as any).value.fields;
453
- };
586
+ return {
587
+ marketPool: marketPoolIndexer,
588
+ collateral: marketCollateralIndexer,
589
+ };
590
+ }
454
591
 
455
- const parsedMarketPoolData = parseOriginMarketPoolData({
456
- type: interestModel.type.fields,
457
- maxBorrowRate: interestModel.max_borrow_rate.fields,
458
- interestRate: borrowIndex.interest_rate.fields,
459
- interestRateScale: borrowIndex.interest_rate_scale,
460
- borrowIndex: borrowIndex.borrow_index,
461
- lastUpdated: borrowIndex.last_updated,
462
- cash: balanceSheet.cash,
463
- debt: balanceSheet.debt,
464
- marketCoinSupply: balanceSheet.market_coin_supply,
465
- reserve: balanceSheet.revenue,
466
- reserveFactor: interestModel.revenue_factor.fields,
467
- borrowWeight: interestModel.borrow_weight.fields,
468
- borrowFeeRate: await getBorrowFee(),
469
- baseBorrowRatePerSec: interestModel.base_borrow_rate_per_sec.fields,
470
- borrowRateOnHighKink: interestModel.borrow_rate_on_high_kink.fields,
471
- borrowRateOnMidKink: interestModel.borrow_rate_on_mid_kink.fields,
472
- highKink: interestModel.high_kink.fields,
473
- midKink: interestModel.mid_kink.fields,
474
- minBorrowAmount: interestModel.min_borrow_amount,
475
- });
592
+ requiredObjects ??= (await queryRequiredMarketObjects(query, [poolCoinName]))[
593
+ poolCoinName
594
+ ];
476
595
 
596
+ const parsedMarketPoolObjects = parseMarketPoolObjects(requiredObjects);
597
+ const parsedMarketPoolData = parseOriginMarketPoolData(
598
+ parsedMarketPoolObjects
599
+ );
477
600
  const calculatedMarketPoolData = calculateMarketPoolData(
478
601
  query.utils,
479
602
  parsedMarketPoolData
480
603
  );
481
-
482
- const coinDecimal = query.utils.getCoinDecimal(poolCoinName);
483
- const maxSupplyCoin = BigNumber(
484
- (await getSupplyLimit(query.utils, poolCoinName)) ?? '0'
485
- )
486
- .shiftedBy(-coinDecimal)
487
- .toNumber();
488
- const maxBorrowCoin = BigNumber(
489
- (await getBorrowLimit(query.utils, poolCoinName)) ?? '0'
490
- )
491
- .shiftedBy(-coinDecimal)
492
- .toNumber();
493
-
494
- return {
495
- coinName: poolCoinName,
604
+ const parsedMarketCollateralData =
605
+ parsedMarketPoolObjects.parsedOriginMarketCollateral
606
+ ? parseOriginMarketCollateralData(
607
+ parsedMarketPoolObjects.parsedOriginMarketCollateral
608
+ )
609
+ : undefined;
610
+
611
+ const basePoolData = <T extends SupportPoolCoins = SupportPoolCoins>() => ({
612
+ coinName: poolCoinName as T,
496
613
  symbol: query.utils.parseSymbol(poolCoinName),
497
- coinType: query.utils.parseCoinType(poolCoinName),
498
614
  marketCoinType: query.utils.parseMarketCoinType(poolCoinName),
499
- sCoinType: query.utils.parseSCoinType(
500
- query.utils.parseMarketCoinName(poolCoinName)
501
- ),
502
- coinWrappedType: query.utils.getCoinWrappedType(poolCoinName),
503
- coinDecimal,
504
- coinPrice: coinPrice ?? 0,
505
- highKink: parsedMarketPoolData.highKink,
506
- midKink: parsedMarketPoolData.midKink,
507
- reserveFactor: parsedMarketPoolData.reserveFactor,
508
- borrowWeight: parsedMarketPoolData.borrowWeight,
509
- borrowFee: parsedMarketPoolData.borrowFee,
510
- marketCoinSupplyAmount: parsedMarketPoolData.marketCoinSupplyAmount,
511
- minBorrowAmount: parsedMarketPoolData.minBorrowAmount,
512
- maxSupplyCoin,
513
- maxBorrowCoin,
514
- isIsolated: await isIsolatedAsset(query.utils, poolCoinName),
515
- ...calculatedMarketPoolData,
615
+ coinType: query.utils.parseCoinType(poolCoinName),
616
+ });
617
+ return {
618
+ marketPool: {
619
+ ...basePoolData(),
620
+ sCoinType: query.utils.parseSCoinType(
621
+ query.utils.parseMarketCoinName(poolCoinName)
622
+ ),
623
+ coinWrappedType: query.utils.getCoinWrappedType(poolCoinName),
624
+ coinPrice: coinPrice ?? 0,
625
+ highKink: parsedMarketPoolData.highKink,
626
+ midKink: parsedMarketPoolData.midKink,
627
+ reserveFactor: parsedMarketPoolData.reserveFactor,
628
+ borrowWeight: parsedMarketPoolData.borrowWeight,
629
+ borrowFee: parsedMarketPoolData.borrowFee,
630
+ marketCoinSupplyAmount: parsedMarketPoolData.marketCoinSupplyAmount,
631
+ minBorrowAmount: parsedMarketPoolData.minBorrowAmount,
632
+ ...calculatedMarketPoolData,
633
+ },
634
+ collateral: parsedMarketCollateralData
635
+ ? {
636
+ ...basePoolData<SupportCollateralCoins>(),
637
+ coinWrappedType: query.utils.getCoinWrappedType(poolCoinName),
638
+ coinPrice: coinPrice,
639
+ collateralFactor: parsedMarketCollateralData.collateralFactor,
640
+ liquidationFactor: parsedMarketCollateralData.liquidationFactor,
641
+ liquidationDiscount: parsedMarketCollateralData.liquidationDiscount,
642
+ liquidationPenalty: parsedMarketCollateralData.liquidationPenalty,
643
+ liquidationReserveFactor:
644
+ parsedMarketCollateralData.liquidationReserveFactor,
645
+ ...calculateMarketCollateralData(
646
+ query.utils,
647
+ parsedMarketCollateralData
648
+ ),
649
+ }
650
+ : undefined,
516
651
  };
517
652
  };
518
653
 
@@ -691,10 +826,11 @@ export const getMarketCollateral = async (
691
826
  collateralFactor: riskModel.collateral_factor.fields,
692
827
  liquidationFactor: riskModel.liquidation_factor.fields,
693
828
  liquidationDiscount: riskModel.liquidation_discount.fields,
694
- liquidationPanelty: riskModel.liquidation_penalty.fields,
829
+ liquidationPenalty: riskModel.liquidation_penalty.fields,
695
830
  liquidationReserveFactor: riskModel.liquidation_revenue_factor.fields,
696
831
  maxCollateralAmount: riskModel.max_collateral_amount,
697
832
  totalCollateralAmount: collateralStat.amount,
833
+ isIsolated: await isIsolatedAsset(query.utils, collateralCoinName),
698
834
  });
699
835
 
700
836
  const calculatedMarketCollateralData = calculateMarketCollateralData(
@@ -708,15 +844,13 @@ export const getMarketCollateral = async (
708
844
  coinType: query.utils.parseCoinType(collateralCoinName),
709
845
  marketCoinType: query.utils.parseMarketCoinType(collateralCoinName),
710
846
  coinWrappedType: query.utils.getCoinWrappedType(collateralCoinName),
711
- coinDecimal: query.utils.getCoinDecimal(collateralCoinName),
712
847
  coinPrice: coinPrice ?? 0,
713
848
  collateralFactor: parsedMarketCollateralData.collateralFactor,
714
849
  liquidationFactor: parsedMarketCollateralData.liquidationFactor,
715
850
  liquidationDiscount: parsedMarketCollateralData.liquidationDiscount,
716
- liquidationPanelty: parsedMarketCollateralData.liquidationPanelty,
851
+ liquidationPenalty: parsedMarketCollateralData.liquidationPenalty,
717
852
  liquidationReserveFactor:
718
853
  parsedMarketCollateralData.liquidationReserveFactor,
719
- isIsolated: await isIsolatedAsset(query.utils, collateralCoinName),
720
854
  ...calculatedMarketCollateralData,
721
855
  };
722
856
  };
@@ -772,14 +906,32 @@ export const getObligations = async (
772
906
  const keyObjects = keyObjectsResponse.filter((ref) => !!ref.data);
773
907
 
774
908
  const obligations: Obligation[] = [];
909
+ // fetch all obligations with multi get objects
910
+ const obligationsObjects = await queryMultipleObjects(
911
+ address.cache,
912
+ keyObjects
913
+ .map((ref) => ref.data?.content)
914
+ .filter(
915
+ (content): content is SuiParsedData & { dataType: 'moveObject' } =>
916
+ content?.dataType === 'moveObject'
917
+ )
918
+ .map((content) => (content.fields as any).ownership.fields.of),
919
+ {
920
+ showContent: true,
921
+ }
922
+ );
923
+
775
924
  await Promise.allSettled(
776
- keyObjects.map(async ({ data }) => {
925
+ keyObjects.map(async ({ data }, idx) => {
777
926
  const keyId = data?.objectId;
778
927
  const content = data?.content;
779
928
  if (keyId && content && 'fields' in content) {
780
929
  const fields = content.fields as any;
781
930
  const obligationId = String(fields.ownership.fields.of);
782
- const locked = await getObligationLocked(address.cache, obligationId);
931
+ const locked = await getObligationLocked(
932
+ address.cache,
933
+ obligationsObjects[idx]
934
+ );
783
935
  obligations.push({ id: obligationId, keyId, locked });
784
936
  }
785
937
  })
@@ -799,7 +951,7 @@ export const getObligationLocked = async (
799
951
  cache: ScallopCache,
800
952
  obligation: string | SuiObjectData
801
953
  ) => {
802
- const obligationObjectResponse =
954
+ const obligationObjectData =
803
955
  typeof obligation === 'string'
804
956
  ? (
805
957
  await cache.queryGetObject(obligation, {
@@ -809,13 +961,11 @@ export const getObligationLocked = async (
809
961
  : obligation;
810
962
  let obligationLocked = false;
811
963
  if (
812
- obligationObjectResponse &&
813
- obligationObjectResponse?.content?.dataType === 'moveObject' &&
814
- 'lock_key' in obligationObjectResponse.content.fields
964
+ obligationObjectData &&
965
+ obligationObjectData?.content?.dataType === 'moveObject' &&
966
+ 'lock_key' in obligationObjectData.content.fields
815
967
  ) {
816
- obligationLocked = Boolean(
817
- obligationObjectResponse.content.fields.lock_key
818
- );
968
+ obligationLocked = Boolean(obligationObjectData.content.fields.lock_key);
819
969
  }
820
970
 
821
971
  return obligationLocked;