@d8x/perpetuals-sdk 0.0.45 → 0.1.0

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 (40) hide show
  1. package/README.md +12 -0
  2. package/abi/MockTokenSwap.json +186 -0
  3. package/config/defaultConfig.json +36 -10
  4. package/config/mockSwap.json +4 -0
  5. package/config/oldConfig.json +2 -1
  6. package/config/priceFeedConfig.json +18 -0
  7. package/dist/accountTrade.d.ts +1 -0
  8. package/dist/accountTrade.js +31 -7
  9. package/dist/d8XMath.d.ts +6 -0
  10. package/dist/d8XMath.js +19 -1
  11. package/dist/liquidatorTool.d.ts +6 -4
  12. package/dist/liquidatorTool.js +13 -7
  13. package/dist/marketData.d.ts +6 -11
  14. package/dist/marketData.js +59 -41
  15. package/dist/nodeSDKTypes.d.ts +33 -2
  16. package/dist/nodeSDKTypes.js +3 -18
  17. package/dist/orderReferrerTool.d.ts +17 -7
  18. package/dist/orderReferrerTool.js +42 -13
  19. package/dist/perpetualDataHandler.d.ts +46 -6
  20. package/dist/perpetualDataHandler.js +143 -16
  21. package/dist/perpetualEventHandler.d.ts +0 -3
  22. package/dist/perpetualEventHandler.js +0 -3
  23. package/dist/priceFeeds.d.ts +115 -0
  24. package/dist/priceFeeds.js +373 -0
  25. package/dist/triangulator.d.ts +27 -0
  26. package/dist/triangulator.js +107 -0
  27. package/dist/version.d.ts +1 -1
  28. package/dist/version.js +1 -1
  29. package/package.json +1 -1
  30. package/src/accountTrade.ts +31 -8
  31. package/src/d8XMath.ts +18 -0
  32. package/src/liquidatorTool.ts +28 -8
  33. package/src/marketData.ts +66 -41
  34. package/src/nodeSDKTypes.ts +30 -3
  35. package/src/orderReferrerTool.ts +55 -13
  36. package/src/perpetualDataHandler.ts +154 -21
  37. package/src/perpetualEventHandler.ts +0 -3
  38. package/src/priceFeeds.ts +371 -0
  39. package/src/triangulator.ts +105 -0
  40. package/src/version.ts +1 -1
@@ -8,17 +8,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const ethers_1 = require("ethers");
13
16
  const nodeSDKTypes_1 = require("./nodeSDKTypes");
14
17
  const utils_1 = require("./utils");
15
18
  const d8XMath_1 = require("./d8XMath");
19
+ const priceFeeds_1 = __importDefault(require("./priceFeeds"));
16
20
  /**
17
21
  * Parent class for MarketData and WriteAccessHandler that handles
18
22
  * common data and chain operations.
19
23
  */
20
24
  class PerpetualDataHandler {
21
25
  constructor(config) {
26
+ this.PRICE_UPDATE_FEE_GWEI = 1;
22
27
  this.proxyContract = null;
23
28
  // limit order book
24
29
  this.lobFactoryContract = null;
@@ -35,6 +40,7 @@ class PerpetualDataHandler {
35
40
  this.lobFactoryABI = require(config.limitOrderBookFactoryABILocation);
36
41
  this.lobABI = require(config.limitOrderBookABILocation);
37
42
  this.symbolList = new Map(Object.entries(require(config.symbolListLocation)));
43
+ this.priceFeedGetter = new priceFeeds_1.default(this, config.priceFeedConfigNetwork);
38
44
  }
39
45
  initContractsAndData(signerOrProvider) {
40
46
  return __awaiter(this, void 0, void 0, function* () {
@@ -69,6 +75,7 @@ class PerpetualDataHandler {
69
75
  throw Error("proxy or limit order book not defined");
70
76
  }
71
77
  this.nestedPerpetualIDs = yield PerpetualDataHandler.getNestedPerpetualIds(proxyContract);
78
+ let requiredPairs = new Set();
72
79
  for (let j = 0; j < this.nestedPerpetualIDs.length; j++) {
73
80
  let pool = yield proxyContract.getLiquidityPool(j + 1);
74
81
  let poolMarginTokenAddr = pool.marginTokenAddress;
@@ -87,8 +94,17 @@ class PerpetualDataHandler {
87
94
  let quote = (0, utils_1.contractSymbolToSymbol)(perp.S2QuoteCCY, this.symbolList);
88
95
  let base3 = (0, utils_1.contractSymbolToSymbol)(perp.S3BaseCCY, this.symbolList);
89
96
  let quote3 = (0, utils_1.contractSymbolToSymbol)(perp.S3QuoteCCY, this.symbolList);
90
- currentSymbols.push(base + "-" + quote);
91
- currentSymbolsS3.push(base3 + "-" + quote3);
97
+ let sym = base + "-" + quote;
98
+ let sym3 = base3 + "-" + quote3;
99
+ requiredPairs.add(sym);
100
+ if (sym3 != "-") {
101
+ requiredPairs.add(sym3);
102
+ }
103
+ else {
104
+ sym3 = "";
105
+ }
106
+ currentSymbols.push(sym);
107
+ currentSymbolsS3.push(sym3);
92
108
  initRate.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fInitialMarginRate));
93
109
  mgnRate.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fMaintenanceMarginRate));
94
110
  lotSizes.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fLotSizeBC));
@@ -129,6 +145,9 @@ class PerpetualDataHandler {
129
145
  let currentSymbols3 = currentSymbols.map((x) => x + "-" + poolCCY);
130
146
  // push into map
131
147
  for (let k = 0; k < perpetualIDs.length; k++) {
148
+ // add price IDs
149
+ let idsB32, isPyth;
150
+ [idsB32, isPyth] = yield proxyContract.getPriceInfo(perpetualIDs[k]);
132
151
  this.symbolToPerpStaticInfo.set(currentSymbols3[k], {
133
152
  id: perpetualIDs[k],
134
153
  limitOrderBookAddr: currentLimitOrderBookAddr[k],
@@ -138,11 +157,16 @@ class PerpetualDataHandler {
138
157
  S2Symbol: currentSymbols[k],
139
158
  S3Symbol: currentSymbolsS3[k],
140
159
  lotSizeBC: lotSizes[k],
160
+ priceIds: idsB32,
141
161
  });
142
162
  }
143
163
  // push margin token address into map
144
164
  this.symbolToTokenAddrMap.set(poolCCY, poolMarginTokenAddr);
145
165
  }
166
+ // pre-calculate all triangulation paths so we can easily get from
167
+ // the prices of price-feeds to the index price required, e.g.
168
+ // BTC-USDC : BTC-USD / USDC-USD
169
+ this.priceFeedGetter.initializeTriangulations(requiredPairs);
146
170
  });
147
171
  }
148
172
  /**
@@ -179,6 +203,55 @@ class PerpetualDataHandler {
179
203
  symbol4BToLongSymbol(sym) {
180
204
  return (0, utils_1.symbol4BToLongSymbol)(sym, this.symbolList);
181
205
  }
206
+ /**
207
+ * Get PriceFeedSubmission data required for blockchain queries that involve price data, and the corresponding
208
+ * triangulated prices for the indices S2 and S3
209
+ * @param symbol pool symbol of the form "ETH-USD-MATIC"
210
+ * @returns PriceFeedSubmission and prices for S2 and S3. [S2price, 0] if S3 not defined.
211
+ */
212
+ fetchPriceSubmissionInfoForPerpetual(symbol) {
213
+ return __awaiter(this, void 0, void 0, function* () {
214
+ // fetch prices from required price-feeds (REST)
215
+ return yield this.priceFeedGetter.fetchFeedPriceInfoAndIndicesForPerpetual(symbol);
216
+ });
217
+ }
218
+ /**
219
+ * Get the symbols required as indices for the given perpetual
220
+ * @param symbol of the form ETH-USD-MATIC, specifying the perpetual
221
+ * @returns name of underlying index prices, e.g. ["MATIC-USD", ""]
222
+ */
223
+ getIndexSymbols(symbol) {
224
+ // get index
225
+ let staticInfo = this.symbolToPerpStaticInfo.get(symbol);
226
+ if (staticInfo == undefined) {
227
+ throw new Error(`No static info for perpetual with symbol ${symbol}`);
228
+ }
229
+ return [staticInfo.S2Symbol, staticInfo.S3Symbol];
230
+ }
231
+ /**
232
+ * Get the latest prices for a given perpetual from the offchain oracle
233
+ * networks
234
+ * @param symbol perpetual symbol of the form BTC-USD-MATIC
235
+ * @returns array of price feed updates that can be submitted to the smart contract
236
+ * and corresponding price information
237
+ */
238
+ fetchLatestFeedPriceInfo(symbol) {
239
+ return __awaiter(this, void 0, void 0, function* () {
240
+ return yield this.priceFeedGetter.fetchLatestFeedPriceInfoForPerpetual(symbol);
241
+ });
242
+ }
243
+ /**
244
+ * Get list of required pyth price source IDs for given perpetual
245
+ * @param symbol perpetual symbol, e.g., BTC-USD-MATIC
246
+ * @returns list of required pyth price sources for this perpetual
247
+ */
248
+ getPriceIds(symbol) {
249
+ let perpInfo = this.symbolToPerpStaticInfo.get(symbol);
250
+ if (perpInfo == undefined) {
251
+ throw Error(`Perpetual with symbol ${symbol} not found. Check symbol or use createProxyInstance().`);
252
+ }
253
+ return perpInfo.priceIds;
254
+ }
182
255
  static _getSymbolFromPoolId(poolId, staticInfos) {
183
256
  let idx = poolId - 1;
184
257
  return staticInfos[idx].poolMarginSymbol;
@@ -252,26 +325,29 @@ class PerpetualDataHandler {
252
325
  return mgn;
253
326
  });
254
327
  }
255
- static _queryPerpetualPrice(symbol, tradeAmount, symbolToPerpStaticInfo, _proxyContract) {
328
+ static _queryPerpetualPrice(symbol, tradeAmount, symbolToPerpStaticInfo, _proxyContract, indexPrices) {
256
329
  return __awaiter(this, void 0, void 0, function* () {
257
330
  let perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
258
- let fPrice = yield _proxyContract.queryPerpetualPrice(perpId, (0, d8XMath_1.floatToABK64x64)(tradeAmount));
331
+ let fIndexPrices = indexPrices.map((x) => (0, d8XMath_1.floatToABK64x64)(x == undefined || Number.isNaN(x) ? 0 : x));
332
+ let fPrice = yield _proxyContract.queryPerpetualPrice(perpId, (0, d8XMath_1.floatToABK64x64)(tradeAmount), fIndexPrices);
259
333
  return (0, d8XMath_1.ABK64x64ToFloat)(fPrice);
260
334
  });
261
335
  }
262
- static _queryPerpetualMarkPrice(symbol, symbolToPerpStaticInfo, _proxyContract) {
336
+ static _queryPerpetualMarkPrice(symbol, symbolToPerpStaticInfo, _proxyContract, indexPrices) {
263
337
  return __awaiter(this, void 0, void 0, function* () {
264
338
  let perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
265
- let ammState = yield _proxyContract.getAMMState(perpId);
339
+ let [S2, S3] = indexPrices.map((x) => (0, d8XMath_1.floatToABK64x64)(x == undefined || Number.isNaN(x) ? 0 : x));
340
+ let ammState = yield _proxyContract.getAMMState(perpId, [S2, S3]);
266
341
  return (0, d8XMath_1.ABK64x64ToFloat)(ammState[6].mul(nodeSDKTypes_1.ONE_64x64.add(ammState[8])).div(nodeSDKTypes_1.ONE_64x64));
267
342
  });
268
343
  }
269
- static _queryPerpetualState(symbol, symbolToPerpStaticInfo, _proxyContract) {
344
+ static _queryPerpetualState(symbol, symbolToPerpStaticInfo, _proxyContract, indexPrices) {
270
345
  var _a, _b;
271
346
  return __awaiter(this, void 0, void 0, function* () {
272
347
  let perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
273
348
  let ccy = symbol.split("-");
274
- let ammState = yield _proxyContract.getAMMState(perpId);
349
+ let [S2, S3] = [indexPrices[0], indexPrices[1]];
350
+ let ammState = yield _proxyContract.getAMMState(perpId, [S2, S3].map((x) => (0, d8XMath_1.floatToABK64x64)(x == undefined || Number.isNaN(x) ? 0 : x)));
275
351
  let markPrice = (0, d8XMath_1.ABK64x64ToFloat)(ammState[6].mul(nodeSDKTypes_1.ONE_64x64.add(ammState[8])).div(nodeSDKTypes_1.ONE_64x64));
276
352
  let state = {
277
353
  id: perpId,
@@ -285,6 +361,7 @@ class PerpetualDataHandler {
285
361
  currentFundingRateBps: (0, d8XMath_1.ABK64x64ToFloat)(ammState[14]) * 1e4,
286
362
  openInterestBC: (0, d8XMath_1.ABK64x64ToFloat)(ammState[11]),
287
363
  maxPositionBC: (0, d8XMath_1.ABK64x64ToFloat)(ammState[12]),
364
+ isMarketClosed: indexPrices[2] || indexPrices[3],
288
365
  };
289
366
  if (((_a = symbolToPerpStaticInfo.get(symbol)) === null || _a === void 0 ? void 0 : _a.collateralCurrencyType) == nodeSDKTypes_1.CollaterlCCY.BASE) {
290
367
  state.collToQuoteIndexPrice = state.indexPrice;
@@ -569,18 +646,37 @@ class PerpetualDataHandler {
569
646
  }
570
647
  /**
571
648
  * Read config file into NodeSDKConfig interface
572
- * @param fileLocation json-file with required variables for config
649
+ * @param configNameOrfileLocation json-file with required variables for config, or name of a default known config
573
650
  * @returns NodeSDKConfig
574
651
  */
575
- static readSDKConfig(fileLocation) {
576
- if (fileLocation == nodeSDKTypes_1.DEFAULT_CONFIG_MAINNET_NAME) {
577
- fileLocation = nodeSDKTypes_1.DEFAULT_CONFIG_MAINNET;
652
+ static readSDKConfig(configNameOrFileLocation, version) {
653
+ let config;
654
+ if (/\.json$/.test(configNameOrFileLocation)) {
655
+ // file path
656
+ let configFile = require(configNameOrFileLocation);
657
+ config = configFile;
658
+ }
659
+ else {
660
+ // name
661
+ let configFile = require(nodeSDKTypes_1.DEFAULT_CONFIG);
662
+ configFile = configFile.filter((c) => c.name == configNameOrFileLocation);
663
+ if (configFile.length == 0) {
664
+ throw Error(`Config name ${configNameOrFileLocation} not found.`);
665
+ }
666
+ else if (configFile.length > 1) {
667
+ // TODO: pick one with highest version, unless version is given
668
+ throw Error(`Config name ${configNameOrFileLocation} not unique.`);
669
+ }
670
+ for (let configItem of configFile) {
671
+ if (configItem.name == configNameOrFileLocation) {
672
+ config = configItem;
673
+ break;
674
+ }
675
+ }
578
676
  }
579
- else if (fileLocation == nodeSDKTypes_1.DEFAULT_CONFIG_TESTNET_NAME) {
580
- fileLocation = nodeSDKTypes_1.DEFAULT_CONFIG_TESTNET;
677
+ if (config == undefined) {
678
+ throw Error(`Config file ${configNameOrFileLocation} not found.`);
581
679
  }
582
- let configFile = require(fileLocation);
583
- let config = configFile;
584
680
  return config;
585
681
  }
586
682
  /**
@@ -593,5 +689,36 @@ class PerpetualDataHandler {
593
689
  const FormatTypes = ethers_1.ethers.utils.FormatTypes;
594
690
  return contract.interface.getFunction(functionName).format(FormatTypes.full);
595
691
  }
692
+ /**
693
+ * Gets the pool index (in exchangeInfo) corresponding to a given symbol.
694
+ * @param symbol Symbol of the form ETH-USD-MATIC
695
+ * @returns Pool index
696
+ */
697
+ getPoolIndexFromSymbol(symbol) {
698
+ let pools = this.poolStaticInfos;
699
+ let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
700
+ let k = 0;
701
+ while (k < pools.length) {
702
+ if (pools[k].poolId == poolId) {
703
+ // pool found
704
+ return k;
705
+ }
706
+ k++;
707
+ }
708
+ return -1;
709
+ }
710
+ getMarginTokenFromSymbol(symbol) {
711
+ let pools = this.poolStaticInfos;
712
+ let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
713
+ let k = 0;
714
+ while (k < pools.length) {
715
+ if (pools[k].poolId == poolId) {
716
+ // pool found
717
+ return pools[k].poolMarginTokenAddr;
718
+ }
719
+ k++;
720
+ }
721
+ return undefined;
722
+ }
596
723
  }
597
724
  exports.default = PerpetualDataHandler;
@@ -8,9 +8,6 @@ import { ExchangeInfo, MarginAccount, OrderStruct, PerpetualState, SmartContract
8
8
  * ordersInPerpetual: Map<number, OrderStruct> all open orders for the given trader
9
9
  * positionInPerpetual: Map<number, MarginAccount> all open positions for the given trader
10
10
  *
11
- * TODO:
12
- * - update functions for midprice & index & collateral prices without event
13
- * - testing
14
11
  *
15
12
  * Get data:
16
13
  * - getPerpetualData(perp id (string) or symbol) : PerpetualState. This is a reference!
@@ -19,9 +19,6 @@ const nodeSDKTypes_1 = require("./nodeSDKTypes");
19
19
  * ordersInPerpetual: Map<number, OrderStruct> all open orders for the given trader
20
20
  * positionInPerpetual: Map<number, MarginAccount> all open positions for the given trader
21
21
  *
22
- * TODO:
23
- * - update functions for midprice & index & collateral prices without event
24
- * - testing
25
22
  *
26
23
  * Get data:
27
24
  * - getPerpetualData(perp id (string) or symbol) : PerpetualState. This is a reference!
@@ -0,0 +1,115 @@
1
+ import PerpetualDataHandler from "./perpetualDataHandler";
2
+ import { PriceFeedConfig, PriceFeedSubmission, PriceFeedFormat } from "./nodeSDKTypes";
3
+ /**
4
+ * This class communicates with the REST API that provides price-data that is
5
+ * to be submitted to the smart contracts for certain functions such as
6
+ * trader liquidations, trade executions, change of trader margin amount.
7
+ */
8
+ export default class PriceFeeds {
9
+ private config;
10
+ private feedEndpoints;
11
+ private feedInfo;
12
+ private dataHandler;
13
+ private triangulations;
14
+ private THRESHOLD_MARKET_CLOSED_SEC;
15
+ constructor(dataHandler: PerpetualDataHandler, priceFeedConfigNetwork: string);
16
+ /**
17
+ * Pre-processing of triangulations for symbols, given the price feeds
18
+ * @param symbols set of symbols we want to triangulate from price feeds
19
+ */
20
+ initializeTriangulations(symbols: Set<string>): void;
21
+ /**
22
+ * Get required information to be able to submit a blockchain transaction with price-update
23
+ * such as trade execution, liquidation
24
+ * @param symbol symbol of perpetual, e.g., BTC-USD-MATIC
25
+ * @returns PriceFeedSubmission, index prices, market closed information
26
+ */
27
+ fetchFeedPriceInfoAndIndicesForPerpetual(symbol: string): Promise<{
28
+ submission: PriceFeedSubmission;
29
+ pxS2S3: [number, number];
30
+ mktClosed: [boolean, boolean];
31
+ }>;
32
+ /**
33
+ * Get all prices/isMarketClosed for the provided symbols via
34
+ * "latest_price_feeds" and triangulation. Triangulation must be defined in config, unless
35
+ * it is a direct price feed.
36
+ * @returns map of feed-price symbol to price/isMarketClosed
37
+ */
38
+ fetchPrices(symbols: string[]): Promise<Map<string, [number, boolean]>>;
39
+ /**
40
+ * Get index prices and market closed information for the given perpetual
41
+ * @param symbol perpetual symbol such as ETH-USD-MATIC
42
+ * @returns
43
+ */
44
+ fetchPricesForPerpetual(symbol: string): Promise<{
45
+ idxPrices: number[];
46
+ mktClosed: boolean[];
47
+ }>;
48
+ /**
49
+ * Fetch the provided feed prices and bool whether market is closed or open
50
+ * - requires the feeds to be defined in priceFeedConfig.json
51
+ * - if undefined, all feeds are queried
52
+ * @param symbols array of feed-price symbols (e.g., [btc-usd, eth-usd]) or undefined
53
+ * @returns mapping symbol-> [price, isMarketClosed]
54
+ */
55
+ fetchFeedPrices(symbols?: string[]): Promise<Map<string, [number, boolean]>>;
56
+ /**
57
+ * Get all configured feed prices via "latest_price_feeds"
58
+ * @returns map of feed-price symbol to price/isMarketClosed
59
+ */
60
+ fetchAllFeedPrices(): Promise<Map<string, [number, boolean]>>;
61
+ /**
62
+ * Get the latest prices for a given perpetual from the offchain oracle
63
+ * networks
64
+ * @param symbol perpetual symbol of the form BTC-USD-MATIC
65
+ * @returns array of price feed updates that can be submitted to the smart contract
66
+ * and corresponding price information
67
+ */
68
+ fetchLatestFeedPriceInfoForPerpetual(symbol: string): Promise<PriceFeedSubmission>;
69
+ /**
70
+ * Extract pair-prices from underlying price feeds via triangulation
71
+ * The function either needs a direct price feed or a defined triangulation to succesfully
72
+ * return a triangulated price
73
+ * @param symbols array of pairs for which we want prices, e.g., [BTC-USDC, ETH-USD]
74
+ * @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
75
+ * @returns array of prices with same order as symbols
76
+ */
77
+ calculateTriangulatedPricesFromFeedInfo(symbols: string[], feeds: PriceFeedSubmission): [number[], boolean[]];
78
+ /**
79
+ * Extract pair-prices from underlying price feeds via triangulation
80
+ * The function either needs a direct price feed or a defined triangulation to succesfully
81
+ * return a triangulated price
82
+ * @param symbols array of pairs for which we want prices, e.g., [BTC-USDC, ETH-USD]
83
+ * @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
84
+ * @returns array of prices with same order as symbols
85
+ */
86
+ triangulatePricesFromFeedPrices(symbols: string[], feedPriceMap: Map<string, [number, boolean]>): [number[], boolean[]];
87
+ /**
88
+ * Queries the REST endpoint and returns parsed VAA price data
89
+ * @param query query price-info from endpoint
90
+ * @returns vaa and price info
91
+ */
92
+ private fetchVAAQuery;
93
+ /**
94
+ * Queries the REST endpoint and returns parsed price data
95
+ * @param query query price-info from endpoint
96
+ * @returns vaa and price info
97
+ */
98
+ fetchPriceQuery(query: string): Promise<[string[], PriceFeedFormat[]]>;
99
+ /**
100
+ * Searches for configuration for given network
101
+ * @param configs pricefeed configuration from json
102
+ * @param network e.g. testnet
103
+ * @returns selected configuration
104
+ */
105
+ static _selectConfig(configs: PriceFeedConfig[], network: string): PriceFeedConfig;
106
+ /**
107
+ * Wraps configuration into convenient data-structure
108
+ * @param config configuration for the selected network
109
+ * @returns feedInfo-map and endPoints-array
110
+ */
111
+ static _constructFeedInfo(config: PriceFeedConfig): [Map<string, {
112
+ symbol: string;
113
+ endpointId: number;
114
+ }>, string[]];
115
+ }