@scallop-io/sui-scallop-sdk 2.0.0-alpha.6 → 2.0.0-alpha.7

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.
@@ -43,15 +43,9 @@ import {
43
43
  getUserPortfolio,
44
44
  getPriceUpdatePolicies,
45
45
  getAssetOracles,
46
+ getOnDemandAggObjectIds,
46
47
  } from '../queries';
47
48
  import {
48
- // string,
49
- // string,
50
- // string,
51
- // string,
52
- // string,
53
- // string,
54
- // string,
55
49
  ScallopQueryParams,
56
50
  StakePools,
57
51
  StakeRewardPools,
@@ -61,6 +55,7 @@ import {
61
55
  MarketPools,
62
56
  MarketCollaterals,
63
57
  xOracleRules,
58
+ SupportOracleType,
64
59
  } from '../types';
65
60
  import { ScallopAddress } from './scallopAddress';
66
61
  import { ScallopUtils } from './scallopUtils';
@@ -911,12 +906,21 @@ export class ScallopQuery {
911
906
  return [...this.constants.whitelist.lending].reduce(
912
907
  (acc, pool) => {
913
908
  acc[pool] = {
914
- primary: primary?.[pool] ?? [],
915
- secondary: secondary?.[pool] ?? [],
909
+ primary: (primary?.[pool] ?? []) as SupportOracleType[],
910
+ secondary: (secondary?.[pool] ?? []) as SupportOracleType[],
916
911
  };
917
912
  return acc;
918
913
  },
919
914
  {} as Record<string, xOracleRules>
920
915
  );
921
916
  }
917
+
918
+ /**
919
+ * Get switchboard on-demand aggregator object id based on coinType
920
+ * @param coinType
921
+ * @returns
922
+ */
923
+ public async getSwitchboardOnDemandAggregatorObjectIds(coinName: string[]) {
924
+ return await getOnDemandAggObjectIds(this, coinName);
925
+ }
922
926
  }
@@ -496,7 +496,7 @@ const parseMarketPoolObjects = ({
496
496
  collateralStat?: SuiObjectData;
497
497
  interestModel: SuiObjectData;
498
498
  riskModel?: SuiObjectData;
499
- borrowFeeKey: SuiObjectData;
499
+ borrowFeeKey?: SuiObjectData;
500
500
  supplyLimitKey?: SuiObjectData;
501
501
  borrowLimitKey?: SuiObjectData;
502
502
  isolatedAssetKey: SuiObjectData;
@@ -506,7 +506,9 @@ const parseMarketPoolObjects = ({
506
506
  const _balanceSheet = parseObjectAs<BalanceSheet>(balanceSheet);
507
507
  const _interestModel = parseObjectAs<InterestModel>(interestModel);
508
508
  const _borrowDynamic = parseObjectAs<BorrowDynamic>(borrowDynamic);
509
- const _borrowFee = parseObjectAs<BorrowFee>(borrowFeeKey);
509
+ const _borrowFee = borrowFeeKey
510
+ ? parseObjectAs<BorrowFee>(borrowFeeKey)
511
+ : { value: '0' };
510
512
  const _supplyLimit = supplyLimitKey
511
513
  ? parseObjectAs<string>(supplyLimitKey)
512
514
  : '0';
@@ -12,4 +12,5 @@ export * from './vescaQuery';
12
12
  export * from './borrowLimitQuery';
13
13
  export * from './poolAddressesQuery';
14
14
  export * from './objectsQuery';
15
+ export * from './switchboardQuery';
15
16
  export * from './xOracleQuery';
@@ -254,7 +254,6 @@ export const getPoolAddresses = async (
254
254
  )?.decimals ?? 0;
255
255
  const spoolName = spoolData ? `s${coinName}` : undefined;
256
256
 
257
- // @TODO: add query for flashloanFeeObject
258
257
  results[coinName] = {
259
258
  coinName,
260
259
  symbol,
@@ -0,0 +1,64 @@
1
+ import { ScallopQuery } from 'src/models';
2
+
3
+ export const getOnDemandAggObjectIds = async (
4
+ query: ScallopQuery,
5
+ coinNames: string[],
6
+ switchboardRegistryTableId: string = query.address.get(
7
+ 'core.oracles.switchboard.registryTableId'
8
+ )
9
+ ): Promise<string[]> => {
10
+ const missingAgg: Array<{
11
+ idx: number;
12
+ coinName: string;
13
+ }> = [];
14
+
15
+ // Check if Aggregator is already registered in Address API
16
+ const registeredAggs = coinNames.map((coinName, idx) => {
17
+ const registeredAgg = query.utils.address.get(
18
+ `core.coins.${coinName}.oracle.switchboard`
19
+ );
20
+ if (registeredAgg) {
21
+ return registeredAgg;
22
+ } else {
23
+ missingAgg.push({
24
+ idx,
25
+ coinName,
26
+ });
27
+ return null;
28
+ }
29
+ });
30
+
31
+ if (missingAgg.length === 0) return registeredAggs;
32
+
33
+ // If not, query from the registry table
34
+ const missingCoinNames = missingAgg.map((agg) => agg.coinName);
35
+ const coinTypes = missingCoinNames.map((coinName) => {
36
+ const coinType = query.utils.parseCoinType(coinName);
37
+ if (!coinType) throw new Error(`Invalid coin name: ${coinName}`);
38
+ return coinType;
39
+ });
40
+
41
+ await Promise.all(
42
+ coinTypes.map(async (coinType, idx) => {
43
+ const dfName = {
44
+ type: '0x1::type_name::TypeName',
45
+ value: {
46
+ name: coinType.slice(2),
47
+ },
48
+ };
49
+
50
+ const resp = await query.cache.queryGetDynamicFieldObject({
51
+ parentId: switchboardRegistryTableId,
52
+ name: dfName,
53
+ });
54
+
55
+ if (!resp?.data?.content || resp.data.content.dataType !== 'moveObject')
56
+ throw new Error(`No on-demand aggregator found for ${coinType}`);
57
+
58
+ const content = resp.data.content;
59
+ registeredAggs[idx] = (content.fields as any).value;
60
+ })
61
+ );
62
+
63
+ return registeredAggs;
64
+ };
@@ -1,11 +1,11 @@
1
1
  import { SuiObjectResponse } from '@mysten/sui/client';
2
2
  import { ScallopAddress, ScallopUtils } from 'src/models';
3
- import { xOracleRuleType } from 'src/types';
3
+ import { SupportOracleType, xOracleRuleType } from 'src/types';
4
4
 
5
- const PRIMARY_PRICE_UPDATE_POLICY =
6
- '0x56e48a141f20a3a6a6d3fc43e58b01fc63f756c08224870e7890c80ec9d2afee';
7
- const SECONDARY_PRICE_UPDDATE_POLICY =
8
- '0xef4d9430ae42c1b24199ac55e87ddd7262622447ee3c7de8868efe839b3d8705';
5
+ // const PRIMARY_PRICE_UPDATE_POLICY =
6
+ // '0x56e48a141f20a3a6a6d3fc43e58b01fc63f756c08224870e7890c80ec9d2afee';
7
+ // const SECONDARY_PRICE_UPDDATE_POLICY =
8
+ // '0xef4d9430ae42c1b24199ac55e87ddd7262622447ee3c7de8868efe839b3d8705';
9
9
 
10
10
  /**
11
11
  * Query the price update policy table ids. Usually the value for these table will be constant.
@@ -22,14 +22,14 @@ export const getPriceUpdatePolicies = async (
22
22
  const [primaryPriceUpdatePolicyTable, secondaryPriceUpdatePolicyTable] =
23
23
  await Promise.all([
24
24
  address.cache.queryGetDynamicFieldObject({
25
- parentId: PRIMARY_PRICE_UPDATE_POLICY,
25
+ parentId: address.get('core.oracles.primaryPriceUpdatePolicyObject'),
26
26
  name: {
27
27
  type: priceUpdatePolicyRulesKeyType,
28
28
  value: { dummy_field: false },
29
29
  },
30
30
  }),
31
31
  address.cache.queryGetDynamicFieldObject({
32
- parentId: SECONDARY_PRICE_UPDDATE_POLICY,
32
+ parentId: address.get('core.oracles.secondaryPriceUpdatePolicyObject'),
33
33
  name: {
34
34
  type: priceUpdatePolicyRulesKeyType,
35
35
  value: { dummy_field: false },
@@ -43,39 +43,47 @@ export const getPriceUpdatePolicies = async (
43
43
  };
44
44
  };
45
45
 
46
- const PRIMARY_PRICE_UPDATE_POLICY_VECSET_ID =
47
- '0xc22c9d691ee4c780de09db91d8b487d863211ebf08720772144bcf716318826c';
48
- const SECONDARY_PRICE_UPDATE_POLICY_VECSET_ID =
49
- '0x3b184ff859f5de30eeaf186898e5224925be6bb6d2baa74347ef471a8cd1c0d3';
46
+ // const PRIMARY_PRICE_UPDATE_POLICY_VECSET_ID =
47
+ // '0xc22c9d691ee4c780de09db91d8b487d863211ebf08720772144bcf716318826c';
48
+ // const SECONDARY_PRICE_UPDATE_POLICY_VECSET_ID =
49
+ // '0x3b184ff859f5de30eeaf186898e5224925be6bb6d2baa74347ef471a8cd1c0d3';
50
50
 
51
51
  export const getAssetOracles = async (
52
52
  utils: ScallopUtils,
53
53
  ruleType: xOracleRuleType
54
54
  ): Promise<Record<string, string[]> | null> => {
55
- if (ruleType === 'primary' && !PRIMARY_PRICE_UPDATE_POLICY_VECSET_ID) {
55
+ if (
56
+ ruleType === 'primary' &&
57
+ !utils.address.get('core.oracles.primaryPriceUpdatePolicyVecsetId')
58
+ ) {
56
59
  console.error('Primary price update policy vecset id is not set');
57
60
  return null;
58
61
  }
59
- if (ruleType === 'secondary' && !SECONDARY_PRICE_UPDATE_POLICY_VECSET_ID) {
62
+ if (
63
+ ruleType === 'secondary' &&
64
+ !utils.address.get('core.oracles.secondaryPriceUpdatePolicyVecsetId')
65
+ ) {
60
66
  console.error('Secondary price update policy vecset id is not set');
61
67
  return null;
62
68
  }
63
69
 
64
- const ruleTypeNameToOracleType: Record<string, string> = {
70
+ const ruleTypeNameToOracleType: Record<string, SupportOracleType> = {
65
71
  [`${utils.address.get('core.packages.pyth.object')}::rule::Rule`]: 'pyth',
66
72
  [`${utils.address.get('core.packages.supra.object')}::rule::Rule`]: 'supra',
67
73
  [`${utils.address.get('core.packages.switchboard.object')}::rule::Rule`]:
68
74
  'switchboard',
69
75
  };
70
76
 
71
- const assetPrimaryOracles = {} as Record<string, string[]>;
77
+ const assetOracles = {} as Record<string, SupportOracleType[]>;
72
78
  let cursor = null;
73
79
  do {
74
80
  const response = await utils.cache.queryGetDynamicFields({
75
81
  parentId:
76
82
  ruleType === 'primary'
77
- ? PRIMARY_PRICE_UPDATE_POLICY_VECSET_ID
78
- : SECONDARY_PRICE_UPDATE_POLICY_VECSET_ID,
83
+ ? utils.address.get('core.oracles.primaryPriceUpdatePolicyVecsetId')
84
+ : utils.address.get(
85
+ 'core.oracles.secondaryPriceUpdatePolicyVecsetId'
86
+ ),
79
87
  cursor,
80
88
  limit: 10,
81
89
  });
@@ -97,8 +105,8 @@ export const getAssetOracles = async (
97
105
 
98
106
  const assetName = utils.parseCoinNameFromType(`0x${typeName}`);
99
107
  if (!assetName) throw new Error(`Invalid asset name: ${assetName}`);
100
- if (!assetPrimaryOracles[assetName]) {
101
- assetPrimaryOracles[assetName] = [];
108
+ if (!assetOracles[assetName]) {
109
+ assetOracles[assetName] = [];
102
110
  }
103
111
 
104
112
  const value = fields.value as {
@@ -109,7 +117,7 @@ export const getAssetOracles = async (
109
117
  };
110
118
 
111
119
  value.fields.contents.forEach((content) => {
112
- assetPrimaryOracles[assetName].push(
120
+ assetOracles[assetName].push(
113
121
  ruleTypeNameToOracleType[`0x${content.fields.name}`]
114
122
  );
115
123
  });
@@ -117,5 +125,5 @@ export const getAssetOracles = async (
117
125
  if (!hasNextPage) break;
118
126
  } while (cursor);
119
127
 
120
- return assetPrimaryOracles;
128
+ return assetOracles;
121
129
  };
@@ -1,5 +1,4 @@
1
- const _SUPPORT_ORACLES = ['supra', 'switchboard', 'pyth'] as const;
2
- type SupportOracleType = (typeof _SUPPORT_ORACLES)[number];
1
+ import { _SUPPORT_ORACLES, SupportOracleType } from './constant/xOracle';
3
2
 
4
3
  export interface AddressesInterface {
5
4
  core: {
@@ -46,6 +45,8 @@ export interface AddressesInterface {
46
45
  ? {
47
46
  registry: string;
48
47
  registryCap: string;
48
+ registryTableId: string;
49
+ state: string;
49
50
  }
50
51
  : K extends (typeof _SUPPORT_ORACLES)[2]
51
52
  ? {
@@ -56,7 +57,14 @@ export interface AddressesInterface {
56
57
  wormholeState: string;
57
58
  }
58
59
  : never;
59
- } & { xOracle: string; xOracleCap: string };
60
+ } & {
61
+ xOracle: string;
62
+ xOracleCap: string;
63
+ primaryPriceUpdatePolicyObject: string;
64
+ secondaryPriceUpdatePolicyObject: string;
65
+ primaryPriceUpdatePolicyVecsetId: string;
66
+ secondaryPriceUpdatePolicyVecsetId: string;
67
+ };
60
68
  packages: Partial<
61
69
  Record<
62
70
  string,
@@ -1,6 +1,9 @@
1
+ export const _SUPPORT_ORACLES = ['supra', 'switchboard', 'pyth'] as const;
2
+ export type SupportOracleType = (typeof _SUPPORT_ORACLES)[number];
3
+
1
4
  export type xOracleRules = {
2
- primary: string[];
3
- secondary: string[];
5
+ primary: SupportOracleType[];
6
+ secondary: SupportOracleType[];
4
7
  };
5
8
  export type xOracleRuleType = keyof xOracleRules;
6
9