@scallop-io/sui-scallop-sdk 1.5.3 → 2.0.0-alpha.2

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 (60) hide show
  1. package/dist/index.d.mts +451 -602
  2. package/dist/index.d.ts +451 -602
  3. package/dist/index.js +29 -60
  4. package/dist/index.mjs +6 -6
  5. package/package.json +1 -1
  6. package/src/builders/loyaltyProgramBuilder.ts +5 -3
  7. package/src/builders/oracle.ts +10 -24
  8. package/src/builders/referralBuilder.ts +5 -9
  9. package/src/builders/sCoinBuilder.ts +9 -8
  10. package/src/builders/spoolBuilder.ts +4 -6
  11. package/src/constants/common.ts +114 -126
  12. package/src/constants/index.ts +0 -5
  13. package/src/constants/pyth.ts +25 -34
  14. package/src/constants/queryKeys.ts +2 -0
  15. package/src/models/index.ts +1 -0
  16. package/src/models/scallop.ts +23 -19
  17. package/src/models/scallopAddress.ts +7 -4
  18. package/src/models/scallopBuilder.ts +36 -41
  19. package/src/models/scallopCache.ts +1 -1
  20. package/src/models/scallopClient.ts +93 -94
  21. package/src/models/scallopConstants.ts +342 -0
  22. package/src/models/scallopIndexer.ts +11 -24
  23. package/src/models/scallopQuery.ts +70 -77
  24. package/src/models/scallopUtils.ts +122 -249
  25. package/src/queries/borrowIncentiveQuery.ts +21 -56
  26. package/src/queries/borrowLimitQuery.ts +3 -6
  27. package/src/queries/coreQuery.ts +94 -112
  28. package/src/queries/flashloanFeeQuery.ts +86 -0
  29. package/src/queries/isolatedAssetQuery.ts +12 -11
  30. package/src/queries/poolAddressesQuery.ts +187 -112
  31. package/src/queries/portfolioQuery.ts +65 -67
  32. package/src/queries/priceQuery.ts +16 -22
  33. package/src/queries/sCoinQuery.ts +15 -16
  34. package/src/queries/spoolQuery.ts +49 -59
  35. package/src/queries/supplyLimitQuery.ts +2 -6
  36. package/src/queries/xOracleQuery.ts +4 -15
  37. package/src/types/address.ts +12 -18
  38. package/src/types/builder/borrowIncentive.ts +2 -3
  39. package/src/types/builder/core.ts +20 -27
  40. package/src/types/builder/index.ts +1 -2
  41. package/src/types/builder/referral.ts +4 -8
  42. package/src/types/builder/sCoin.ts +4 -8
  43. package/src/types/builder/spool.ts +7 -10
  44. package/src/types/constant/common.ts +43 -49
  45. package/src/types/constant/enum.ts +15 -27
  46. package/src/types/constant/xOracle.ts +3 -5
  47. package/src/types/model.ts +49 -28
  48. package/src/types/query/borrowIncentive.ts +7 -24
  49. package/src/types/query/core.ts +8 -18
  50. package/src/types/query/portfolio.ts +8 -17
  51. package/src/types/query/spool.ts +5 -11
  52. package/src/types/utils.ts +1 -21
  53. package/src/utils/core.ts +1 -1
  54. package/src/utils/query.ts +13 -20
  55. package/src/utils/util.ts +6 -84
  56. package/src/constants/coinGecko.ts +0 -34
  57. package/src/constants/enum.ts +0 -268
  58. package/src/constants/flashloan.ts +0 -18
  59. package/src/constants/poolAddress.ts +0 -898
  60. package/src/models/scallopPrice.ts +0 -0
@@ -0,0 +1,342 @@
1
+ import axios, { AxiosInstance } from 'axios';
2
+ import { queryKeys } from 'src/constants';
3
+ import {
4
+ PoolAddress,
5
+ ScallopConstantsInstanceParams,
6
+ ScallopConstantsParams,
7
+ Whitelist,
8
+ } from 'src/types';
9
+ import { ScallopCache } from './scallopCache';
10
+ import { QueryKey } from '@tanstack/query-core';
11
+ import { newSuiKit } from './suiKit';
12
+ import { ScallopAddress } from './scallopAddress';
13
+ import { parseStructTag } from '@scallop-io/sui-kit';
14
+
15
+ /**
16
+ * @description
17
+ * It provides methods to construct constants for Scallop SDK instances.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const scallopConstants = new ScallopConstants();
22
+ * await scallopConstants.init();
23
+ * ```
24
+ */
25
+ export class ScallopConstants {
26
+ private readonly _requestClient: AxiosInstance;
27
+ public address: ScallopAddress;
28
+ public cache: ScallopCache;
29
+
30
+ private _poolAddresses: Record<string, PoolAddress | undefined> = {};
31
+ private _whitelist: Whitelist = {
32
+ lending: new Set(),
33
+ borrowing: new Set(),
34
+ collateral: new Set(),
35
+ packages: new Set(),
36
+ scoin: new Set(),
37
+ spool: new Set(),
38
+ borrowIncentiveRewards: new Set(),
39
+ suiBridge: new Set(),
40
+ wormhole: new Set(),
41
+ oracles: new Set(),
42
+ pythEndpoints: new Set(),
43
+ deprecated: new Set(),
44
+ };
45
+
46
+ private _coinDecimals: Record<string, number | undefined> = {};
47
+ private _coinNameToCoinTypeMap: Record<string, string | undefined> = {};
48
+ private _coinNameToOldMarketCoinTypeMap: Record<string, string | undefined> =
49
+ {};
50
+ private _scoinRawNameToSCoinNameMap: Record<string, string | undefined> = {};
51
+ private _scoinTypeToSCoinNameMap: Record<string, string | undefined> = {};
52
+ private _wormholeCoinTypeToCoinNameMap: Record<string, string | undefined> =
53
+ {};
54
+ private _voloCoinTypeToCoinNameMap: Record<string, string | undefined> = {};
55
+ private _suiBridgeCoinTypeToCoinNameMap: Record<string, string | undefined> =
56
+ {};
57
+ private _coinTypes: Record<string, string | undefined> = {};
58
+ private _sCoinTypes: Record<string, string | undefined> = {};
59
+ private _coinTypeToCoinNameMap: Record<string, string | undefined> = {};
60
+
61
+ constructor(
62
+ public readonly params: ScallopConstantsParams,
63
+ instance?: ScallopConstantsInstanceParams
64
+ ) {
65
+ this.params = params;
66
+ this._requestClient = axios.create({
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ Accept: 'application/json',
70
+ },
71
+ timeout: 8000,
72
+ });
73
+
74
+ this.cache =
75
+ instance?.address?.cache ??
76
+ instance?.cache ??
77
+ new ScallopCache(this.params, {
78
+ suiKit: newSuiKit(this.params),
79
+ });
80
+
81
+ this.address =
82
+ instance?.address ??
83
+ new ScallopAddress(this.params, {
84
+ cache: this.cache,
85
+ });
86
+
87
+ if (params.forcePoolAddressInterface) {
88
+ this._poolAddresses = params.forcePoolAddressInterface;
89
+ }
90
+
91
+ if (params.forceWhitelistInterface) {
92
+ this._whitelist = params.forceWhitelistInterface;
93
+ }
94
+ }
95
+
96
+ get isAddressInitialized() {
97
+ return !this.isEmptyObject(this.address.getAllAddresses());
98
+ }
99
+
100
+ get isInitialized() {
101
+ return (
102
+ !!this._poolAddresses && !!this._whitelist && this.isAddressInitialized
103
+ );
104
+ }
105
+
106
+ get queryClient() {
107
+ return this.cache.queryClient;
108
+ }
109
+
110
+ get poolAddresses() {
111
+ return this._poolAddresses;
112
+ }
113
+
114
+ get whitelist() {
115
+ return this._whitelist;
116
+ }
117
+
118
+ parseToOldMarketCoin(coinType: string) {
119
+ return `${this.protocolObjectId}::reserve::MarketCoin<${coinType}>`;
120
+ }
121
+
122
+ get protocolObjectId() {
123
+ return (
124
+ (this.address.get('core.object') as string | undefined) ??
125
+ ('0xefe8b36d5b2e43728cc323298626b83177803521d195cfb11e15b910e892fddf' as const)
126
+ );
127
+ }
128
+
129
+ get coinDecimals() {
130
+ if (this.isEmptyObject(this._coinDecimals)) {
131
+ this._coinDecimals = Object.fromEntries([
132
+ ...Object.entries(this.poolAddresses)
133
+ .filter(([_, value]) => !!value)
134
+ .map(([key, value]) => [key, value!.decimals]),
135
+ ...Object.entries(this.poolAddresses)
136
+ .filter(([_, value]) => !!value?.sCoinName)
137
+ .map(([_, value]) => [value!.sCoinName, value!.decimals]),
138
+ ]);
139
+ }
140
+ return this._coinDecimals;
141
+ }
142
+
143
+ get coinTypes() {
144
+ if (this.isEmptyObject(this._coinTypes))
145
+ this._coinTypes = Object.fromEntries([
146
+ ...Object.entries(this.poolAddresses)
147
+ .filter(([_, value]) => !!value)
148
+ .map(([key, value]) => [key, value?.coinType]),
149
+ ...Object.entries(this.poolAddresses)
150
+ .filter(([_, value]) => !!value && value.sCoinName && value.sCoinType)
151
+ .map(([_, value]) => [value!.sCoinName, value!.sCoinType]),
152
+ ]);
153
+ return this._coinTypes;
154
+ }
155
+
156
+ get wormholeCoinTypeToCoinName() {
157
+ if (this.isEmptyObject(this._wormholeCoinTypeToCoinNameMap))
158
+ this._wormholeCoinTypeToCoinNameMap = Object.fromEntries(
159
+ Object.entries(this.poolAddresses)
160
+ .filter(([key, value]) => !!value && this.whitelist.wormhole.has(key))
161
+ .map(([_, value]) => [value!.coinType, value!.coinName])
162
+ );
163
+ return this._wormholeCoinTypeToCoinNameMap;
164
+ }
165
+
166
+ get coinNameToCoinTypeMap() {
167
+ if (this.isEmptyObject(this._coinNameToCoinTypeMap))
168
+ this._coinNameToCoinTypeMap = Object.fromEntries(
169
+ Object.entries(this.poolAddresses)
170
+ .filter(([_, value]) => !!value)
171
+ .map(([_, value]) => [value!.coinName, value!.coinType])
172
+ );
173
+ return this._coinNameToCoinTypeMap;
174
+ }
175
+
176
+ get coinTypeToCoinNameMap() {
177
+ if (this.isEmptyObject(this._coinTypeToCoinNameMap))
178
+ this._coinTypeToCoinNameMap = Object.fromEntries(
179
+ Object.entries(this.coinNameToCoinTypeMap).map(([key, val]) => [
180
+ val,
181
+ key,
182
+ ])
183
+ );
184
+ return this._coinTypeToCoinNameMap;
185
+ }
186
+
187
+ get coinNameToOldMarketCoinTypeMap() {
188
+ if (this.isEmptyObject(this._coinNameToOldMarketCoinTypeMap))
189
+ this._coinNameToOldMarketCoinTypeMap = Object.fromEntries(
190
+ Object.entries(this.poolAddresses)
191
+ .filter(([_, value]) => !!value && value.spool)
192
+ .map(([_, value]) => [
193
+ value!.coinName,
194
+ this.parseToOldMarketCoin(value!.coinType),
195
+ ])
196
+ );
197
+ return this._coinNameToOldMarketCoinTypeMap;
198
+ }
199
+
200
+ get sCoinRawNameToScoinNameMap() {
201
+ if (this.isEmptyObject(this._scoinRawNameToSCoinNameMap))
202
+ this._scoinRawNameToSCoinNameMap = Object.fromEntries(
203
+ Object.entries(this.poolAddresses)
204
+ .filter(([_, value]) => !!value && value.sCoinType && value.sCoinName)
205
+ .map(([_, value]) => {
206
+ const scoinRawName = parseStructTag(value!.sCoinType!).name;
207
+ return [scoinRawName, value!.sCoinName!];
208
+ })
209
+ );
210
+
211
+ return this._scoinRawNameToSCoinNameMap;
212
+ }
213
+
214
+ get sCoinTypeToSCoinNameMap() {
215
+ if (this.isEmptyObject(this._scoinTypeToSCoinNameMap))
216
+ this._scoinTypeToSCoinNameMap = Object.fromEntries(
217
+ Object.entries(this.poolAddresses)
218
+ .filter(([_, value]) => !!value && value.sCoinType && value.sCoinName)
219
+ .map(([_, value]) => [value!.sCoinType!, value!.sCoinName!])
220
+ );
221
+
222
+ return this._scoinTypeToSCoinNameMap;
223
+ }
224
+
225
+ get voloCoinTypeToCoinNameMap() {
226
+ if (this.isEmptyObject(this._voloCoinTypeToCoinNameMap))
227
+ this._voloCoinTypeToCoinNameMap = {
228
+ [this.poolAddresses['vsui']!.coinType]: 'vsui',
229
+ };
230
+ return this._voloCoinTypeToCoinNameMap;
231
+ }
232
+
233
+ get suiBridgeCoinTypeToCoinNameMap() {
234
+ if (this.isEmptyObject(this._suiBridgeCoinTypeToCoinNameMap))
235
+ this._suiBridgeCoinTypeToCoinNameMap = Object.fromEntries(
236
+ Object.entries(this.poolAddresses)
237
+ .filter(
238
+ ([_, value]) =>
239
+ !!value && this.whitelist.suiBridge.has(value.coinName)
240
+ )
241
+ .map(([_, value]) => [value!.coinType, value!.coinName])
242
+ );
243
+ return this._suiBridgeCoinTypeToCoinNameMap;
244
+ }
245
+
246
+ get sCoinTypes() {
247
+ if (this.isEmptyObject(this._sCoinTypes))
248
+ this._sCoinTypes = Object.fromEntries(
249
+ Object.entries(this.poolAddresses)
250
+ .filter(([_, value]) => !!value && value.sCoinName && value.sCoinType)
251
+ .map(([_, value]) => [value!.sCoinName, value!.sCoinType!])
252
+ );
253
+
254
+ return this._sCoinTypes;
255
+ }
256
+
257
+ get supportedBorrowIncentiveRewards() {
258
+ return new Set([
259
+ ...Object.values(this.poolAddresses)
260
+ .filter((t) => !!t)
261
+ .map((t) => t?.coinName),
262
+ ]);
263
+ }
264
+
265
+ private isEmptyObject(obj: Record<string, unknown>) {
266
+ return Object.keys(obj).length === 0;
267
+ }
268
+
269
+ private async readApi<T>({
270
+ url,
271
+ queryKey,
272
+ }: {
273
+ url: string;
274
+ queryKey: QueryKey;
275
+ }) {
276
+ const resp = await this.queryClient.fetchQuery({
277
+ queryKey,
278
+ queryFn: async () => {
279
+ return await this._requestClient.get(url);
280
+ },
281
+ });
282
+
283
+ if (resp.status === 200) {
284
+ return resp.data as T;
285
+ } else {
286
+ throw Error(
287
+ `Error: ${resp.status}; Failed to read ${url} ${resp.statusText}`
288
+ );
289
+ }
290
+ }
291
+
292
+ async readWhiteList() {
293
+ const response = await this.readApi<Record<keyof Whitelist, string[]>>({
294
+ url:
295
+ this.params.whitelistApiUrl ?? 'https://sui.apis.scallop.io/whitelist',
296
+ queryKey: queryKeys.api.getWhiteList(),
297
+ });
298
+
299
+ return Object.fromEntries(
300
+ Object.entries(response).map(([key, value]) => [key, new Set(value)])
301
+ ) as Whitelist;
302
+ }
303
+
304
+ async readPoolAddresses() {
305
+ return await this.readApi<Record<string, PoolAddress>>({
306
+ url:
307
+ this.params.poolAddressesApiUrl ??
308
+ `https://sui.apis.scallop.io/poolAddresses`,
309
+ queryKey: queryKeys.api.getPoolAddresses(),
310
+ });
311
+ }
312
+
313
+ async init(params?: Partial<ScallopConstantsParams>) {
314
+ if (!this.isAddressInitialized) {
315
+ await this.address.read();
316
+ }
317
+
318
+ if (params?.forcePoolAddressInterface) {
319
+ this._poolAddresses = params?.forcePoolAddressInterface;
320
+ }
321
+
322
+ if (params?.forceWhitelistInterface) {
323
+ this._whitelist = params?.forceWhitelistInterface;
324
+ }
325
+
326
+ if (this.isInitialized) return;
327
+
328
+ const [whitelistResponse, poolAddressesResponse] = await Promise.all([
329
+ this.readWhiteList(),
330
+ this.readPoolAddresses(),
331
+ ]);
332
+ if (!this.params.forceWhitelistInterface) {
333
+ this._whitelist = whitelistResponse;
334
+ }
335
+ if (!this.params.forcePoolAddressInterface)
336
+ this._poolAddresses = Object.fromEntries(
337
+ Object.entries(poolAddressesResponse).filter(([key]) =>
338
+ Object.values(this.whitelist).some((set) => set.has(key))
339
+ )
340
+ );
341
+ }
342
+ }
@@ -10,16 +10,10 @@ import type {
10
10
  Spool,
11
11
  BorrowIncentivePools,
12
12
  BorrowIncentivePool,
13
- SupportPoolCoins,
14
- SupportCollateralCoins,
15
- SupportStakeMarketCoins,
16
- SupportBorrowIncentiveCoins,
17
13
  TotalValueLocked,
18
- ScallopQueryParams,
19
- ScallopParams,
20
14
  BorrowIncentivePoolPoints,
21
- SupportBorrowIncentiveRewardCoins,
22
15
  ScallopIndexerInstanceParams,
16
+ ScallopIndexerParams,
23
17
  } from '../types';
24
18
  import { ScallopCache } from './scallopCache';
25
19
  import { queryKeys } from 'src/constants';
@@ -38,17 +32,17 @@ import { queryKeys } from 'src/constants';
38
32
  */
39
33
  export class ScallopIndexer {
40
34
  private readonly cache: ScallopCache;
41
- public readonly params: ScallopQueryParams;
35
+ public readonly params: ScallopIndexerParams;
42
36
  private readonly _requestClient: AxiosInstance;
43
37
 
44
38
  public constructor(
45
- params: ScallopParams = {},
39
+ params: ScallopIndexerParams,
46
40
  instance?: ScallopIndexerInstanceParams
47
41
  ) {
48
42
  this.params = params;
49
43
  this.cache = instance?.cache ?? new ScallopCache(this.params);
50
44
  this._requestClient = axios.create({
51
- baseURL: SDK_API_BASE_URL,
45
+ baseURL: params.indexerApiUrl ?? SDK_API_BASE_URL,
52
46
  headers: {
53
47
  'Content-Type': 'application/json',
54
48
  Accept: 'application/json',
@@ -107,9 +101,7 @@ export class ScallopIndexer {
107
101
  *
108
102
  * @return Market pool data.
109
103
  */
110
- public async getMarketPool(
111
- poolCoinName: SupportPoolCoins
112
- ): Promise<MarketPool> {
104
+ public async getMarketPool(poolCoinName: string): Promise<MarketPool> {
113
105
  return (await this.getMarketPools())[poolCoinName] as MarketPool;
114
106
  }
115
107
 
@@ -128,7 +120,7 @@ export class ScallopIndexer {
128
120
  * @return Market collateral data.
129
121
  */
130
122
  public async getMarketCollateral(
131
- collateralCoinName: SupportCollateralCoins
123
+ collateralCoinName: string
132
124
  ): Promise<MarketCollateral> {
133
125
  return (await this.getMarketCollaterals())[
134
126
  collateralCoinName
@@ -165,9 +157,7 @@ export class ScallopIndexer {
165
157
  *
166
158
  * @return Spool data.
167
159
  */
168
- public async getSpool(
169
- marketCoinName: SupportStakeMarketCoins
170
- ): Promise<Spool> {
160
+ public async getSpool(marketCoinName: string): Promise<Spool> {
171
161
  return (await this.getSpools())[marketCoinName] as Spool;
172
162
  }
173
163
 
@@ -199,10 +189,7 @@ export class ScallopIndexer {
199
189
  prev[curr.coinName] = curr;
200
190
  return prev;
201
191
  },
202
- {} as Record<
203
- SupportBorrowIncentiveRewardCoins,
204
- BorrowIncentivePoolPoints
205
- >
192
+ {} as Record<string, BorrowIncentivePoolPoints>
206
193
  );
207
194
  }
208
195
  borrowIncentivePools[borrowIncentivePool.coinName] =
@@ -222,7 +209,7 @@ export class ScallopIndexer {
222
209
  * @return Borrow incentive pool data.
223
210
  */
224
211
  public async getBorrowIncentivePool(
225
- borrowIncentiveCoinName: SupportBorrowIncentiveCoins
212
+ borrowIncentiveCoinName: string
226
213
  ): Promise<BorrowIncentivePool> {
227
214
  return (await this.getBorrowIncentivePools())[
228
215
  borrowIncentiveCoinName
@@ -266,7 +253,7 @@ export class ScallopIndexer {
266
253
  *
267
254
  * @return price data.
268
255
  */
269
- public async getCoinPrice(poolCoinName: SupportPoolCoins): Promise<number> {
256
+ public async getCoinPrice(poolCoinName: string): Promise<number> {
270
257
  return (await this.getMarketPool(poolCoinName))?.coinPrice ?? 0;
271
258
  }
272
259
 
@@ -274,7 +261,7 @@ export class ScallopIndexer {
274
261
  const marketPools = await this.getMarketPools();
275
262
  return Object.entries(marketPools).reduce(
276
263
  (prev, [coinName, market]) => {
277
- prev[coinName] = market.coinPrice;
264
+ if (market) prev[coinName] = market.coinPrice;
278
265
  return prev;
279
266
  },
280
267
  {} as Record<string, number>