@gearbox-protocol/sdk 5.0.0-next.2 → 5.0.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 (28) hide show
  1. package/dist/cjs/dev/calcLiquidatableLTs.js +1 -5
  2. package/dist/cjs/sdk/base/BaseContract.js +1 -0
  3. package/dist/cjs/sdk/market/MarketSuite.js +5 -1
  4. package/dist/cjs/sdk/market/oracle/PriceOracleBaseContract.js +47 -52
  5. package/dist/cjs/sdk/market/oracle/PriceOracleV300Contract.js +3 -2
  6. package/dist/cjs/sdk/market/oracle/PriceOracleV310Contract.js +3 -2
  7. package/dist/cjs/sdk/market/oracle/createPriceOracle.js +9 -28
  8. package/dist/cjs/sdk/market/pricefeeds/AbstractLPPriceFeed.js +1 -2
  9. package/dist/cjs/sdk/market/pricefeeds/RedstonePriceFeed.js +1 -1
  10. package/dist/cjs/sdk/plugins/V300StalenessPeriodPlugin.js +5 -5
  11. package/dist/esm/dev/calcLiquidatableLTs.js +1 -5
  12. package/dist/esm/sdk/base/BaseContract.js +1 -0
  13. package/dist/esm/sdk/market/MarketSuite.js +6 -2
  14. package/dist/esm/sdk/market/oracle/PriceOracleBaseContract.js +47 -53
  15. package/dist/esm/sdk/market/oracle/PriceOracleV300Contract.js +3 -2
  16. package/dist/esm/sdk/market/oracle/PriceOracleV310Contract.js +3 -2
  17. package/dist/esm/sdk/market/oracle/createPriceOracle.js +8 -27
  18. package/dist/esm/sdk/market/pricefeeds/AbstractLPPriceFeed.js +1 -2
  19. package/dist/esm/sdk/market/pricefeeds/RedstonePriceFeed.js +2 -2
  20. package/dist/esm/sdk/plugins/V300StalenessPeriodPlugin.js +6 -6
  21. package/dist/types/sdk/market/MarketSuite.d.ts +2 -2
  22. package/dist/types/sdk/market/oracle/PriceOracleBaseContract.d.ts +684 -28
  23. package/dist/types/sdk/market/oracle/PriceOracleV300Contract.d.ts +1 -1
  24. package/dist/types/sdk/market/oracle/PriceOracleV310Contract.d.ts +2 -2
  25. package/dist/types/sdk/market/oracle/createPriceOracle.d.ts +3 -14
  26. package/dist/types/sdk/market/oracle/types.d.ts +6 -97
  27. package/dist/types/sdk/plugins/V300StalenessPeriodPlugin.d.ts +2 -3
  28. package/package.json +1 -1
@@ -30,11 +30,7 @@ async function calcLiquidatableLTs(sdk, ca, factor = 9990n, logger) {
30
30
  return balance > minBalance;
31
31
  }).map((t) => {
32
32
  const { token, balance } = t;
33
- const balanceU = market.priceOracle.convert(
34
- token,
35
- ca.underlying,
36
- balance
37
- );
33
+ const balanceU = market.priceOracle.convertToUnderlying(token, balance);
38
34
  const lt = BigInt(cm.creditManager.liquidationThresholds.mustGet(token));
39
35
  return {
40
36
  token,
@@ -75,6 +75,7 @@ class BaseContract extends import_SDKConstruct.SDKConstruct {
75
75
  this.addressLabels.set(this.#address, name);
76
76
  }
77
77
  }
78
+ // TODO: unused
78
79
  stateHuman(_ = true) {
79
80
  return {
80
81
  address: this.sdk.provider.addressLabels.get(this.address),
@@ -58,7 +58,11 @@ class MarketSuite extends import_base.SDKConstruct {
58
58
  for (let i = 0; i < marketData.creditManagers.length; i++) {
59
59
  this.creditManagers.push(new import_credit.CreditSuite(sdk, marketData, i));
60
60
  }
61
- this.priceOracle = (0, import_oracle.getOrCreatePriceOracle)(sdk, marketData.priceOracle);
61
+ this.priceOracle = (0, import_oracle.createPriceOracle)(
62
+ sdk,
63
+ marketData.priceOracle,
64
+ marketData.pool.underlying
65
+ );
62
66
  }
63
67
  get dirty() {
64
68
  return this.configurator.dirty || this.pool.dirty || this.priceOracle.dirty || this.creditManagers.some((cm) => cm.dirty);
@@ -42,6 +42,10 @@ var import_pricefeeds = require("../pricefeeds/index.js");
42
42
  var import_PriceFeedAnswerMap = __toESM(require("./PriceFeedAnswerMap.js"));
43
43
  const ZERO_PRICE_FEED = (0, import_viem.stringToHex)("PRICE_FEED::ZERO", { size: 32 });
44
44
  class PriceOracleBaseContract extends import_base.BaseContract {
45
+ /**
46
+ * Underlying token of market to which this price oracle belongs
47
+ */
48
+ underlying;
45
49
  /**
46
50
  * Mapping Token => [PriceFeed Address, stalenessPeriod]
47
51
  */
@@ -67,14 +71,12 @@ class PriceOracleBaseContract extends import_base.BaseContract {
67
71
  void 0,
68
72
  "reservePrices"
69
73
  );
70
- #priceFeedTree = new import_utils.AddressMap(
71
- void 0,
72
- "priceFeedTree"
73
- );
74
- constructor(sdk, args, data) {
74
+ #priceFeedTree = [];
75
+ constructor(sdk, args, data, underlying) {
75
76
  super(sdk, args);
77
+ this.underlying = underlying;
76
78
  const { priceFeedMap, priceFeedTree } = data;
77
- this.#loadState(priceFeedMap, priceFeedTree, true);
79
+ this.#loadState(priceFeedMap, priceFeedTree);
78
80
  }
79
81
  /**
80
82
  * Returns main and reserve price feeds for given tokens
@@ -96,7 +98,7 @@ class PriceOracleBaseContract extends import_base.BaseContract {
96
98
  */
97
99
  async updatePriceFeeds() {
98
100
  const updatables = [];
99
- for (const node of this.#priceFeedTree.values()) {
101
+ for (const node of this.#priceFeedTree) {
100
102
  if (node.updatable) {
101
103
  updatables.push(this.sdk.priceFeeds.mustGet(node.baseParams.addr));
102
104
  }
@@ -162,19 +164,30 @@ class PriceOracleBaseContract extends import_base.BaseContract {
162
164
  }
163
165
  /**
164
166
  * Returns true if oracle's price feed tree contains given price feed
165
- * This feed is not necessary connected to token, but can be a component of composite feed for some token
166
167
  * @param priceFeed
167
168
  * @returns
168
169
  */
169
170
  usesPriceFeed(priceFeed) {
170
- return this.#priceFeedTree.has(priceFeed);
171
+ return this.#priceFeedTree.some(
172
+ (node) => node.baseParams.addr.toLowerCase() === priceFeed.toLowerCase()
173
+ );
174
+ }
175
+ /**
176
+ * Tries to convert amount of token into underlying of current market
177
+ * @param token
178
+ * @param amount
179
+ * @param reserve
180
+ * @returns
181
+ */
182
+ convertToUnderlying(token, amount, reserve = false) {
183
+ return this.convert(token, this.underlying, amount, reserve);
171
184
  }
172
185
  /**
173
186
  * Tries to convert amount of from one token to another, using latest known prices
174
187
  * @param from
175
188
  * @param to
176
189
  * @param amount
177
- * @param reserve use reserve price feed instead of main
190
+ * @param reserve
178
191
  */
179
192
  convert(from, to, amount, reserve = false) {
180
193
  if (from === to) {
@@ -189,8 +202,9 @@ class PriceOracleBaseContract extends import_base.BaseContract {
189
202
  /**
190
203
  * Tries to convert amount of token to USD, using latest known prices
191
204
  * @param from
205
+ * @param to
192
206
  * @param amount
193
- * @param reserve use reserve price feed instead of main
207
+ * @param reserve
194
208
  */
195
209
  convertToUSD(from, amount, reserve = false) {
196
210
  const price = reserve ? this.reservePrice(from) : this.mainPrice(from);
@@ -201,7 +215,7 @@ class PriceOracleBaseContract extends import_base.BaseContract {
201
215
  * Tries to convert amount of USD to token, using latest known prices
202
216
  * @param to
203
217
  * @param amount
204
- * @param reserve use reserve price feed instead of main
218
+ * @param reserve
205
219
  */
206
220
  convertFromUSD(to, amount, reserve = false) {
207
221
  const price = reserve ? this.reservePrice(to) : this.mainPrice(to);
@@ -210,26 +224,23 @@ class PriceOracleBaseContract extends import_base.BaseContract {
210
224
  }
211
225
  /**
212
226
  * Loads new prices for this oracle from PriceFeedCompressor
213
- * Will (re)create price feeds if needed
227
+ * Does not update price feeds, only updates prices
214
228
  */
215
229
  async updatePrices() {
216
230
  await this.sdk.marketRegister.updatePrices([this.address]);
217
231
  }
218
- /**
219
- * Paired method to updatePrices, helps to update prices on all oracles in one multicall
220
- */
221
232
  syncStateMulticall() {
222
- let args = [this.address];
223
- if ((0, import_constants.isV300)(this.version)) {
224
- args = [
225
- args[0],
233
+ const args = [this.address];
234
+ if (this.version === 300) {
235
+ args.push(
226
236
  Array.from(
227
237
  /* @__PURE__ */ new Set([
238
+ this.underlying,
228
239
  ...this.mainPriceFeeds.keys(),
229
240
  ...this.reservePriceFeeds.keys()
230
241
  ])
231
242
  )
232
- ];
243
+ );
233
244
  }
234
245
  const [address] = this.sdk.addressProvider.mustGetLatest(
235
246
  import_constants.AP_PRICE_FEED_COMPRESSOR,
@@ -244,39 +255,25 @@ class PriceOracleBaseContract extends import_base.BaseContract {
244
255
  },
245
256
  onResult: (resp) => {
246
257
  const { priceFeedMap, priceFeedTree } = resp;
247
- this.#loadState(priceFeedMap, priceFeedTree, true);
258
+ this.#loadState(priceFeedMap, priceFeedTree);
248
259
  }
249
260
  };
250
261
  }
251
- /**
252
- * Helper function to handle situation when we have multiple different compressor data entries for same oracle
253
- * This happens in v300
254
- *
255
- * @deprecated should be unnecessary after full v310 migration (oracles will be unique)
256
- * @param data
257
- * @returns
258
- */
259
- merge(data) {
260
- const { priceFeedMap, priceFeedTree } = data;
261
- this.#loadState(priceFeedMap, priceFeedTree, false);
262
- return this;
263
- }
264
- #loadState(entries, tree, reset) {
265
- if (reset) {
266
- this.#priceFeedTree.clear();
267
- this.mainPriceFeeds.clear();
268
- this.reservePriceFeeds.clear();
269
- this.mainPrices.clear();
270
- this.reservePrices.clear();
271
- }
262
+ #loadState(entries, tree) {
263
+ this.#priceFeedTree = tree;
264
+ this.mainPriceFeeds.clear();
265
+ this.reservePriceFeeds.clear();
266
+ this.mainPrices.clear();
267
+ this.reservePrices.clear();
272
268
  for (const node of tree) {
273
- this.#priceFeedTree.upsert(node.baseParams.addr, node);
274
269
  this.sdk.priceFeeds.getOrCreate(node);
275
270
  }
276
- for (const entry of entries) {
271
+ entries.forEach((entry) => {
277
272
  const { token, priceFeed, reserve, stalenessPeriod } = entry;
278
273
  const ref = new import_pricefeeds.PriceFeedRef(this.sdk, priceFeed, stalenessPeriod);
279
- const node = this.#priceFeedTree.get(priceFeed);
274
+ const node = this.#priceFeedTree.find(
275
+ (n) => n.baseParams.addr === priceFeed
276
+ );
280
277
  const price = node?.answer?.price;
281
278
  const priceFeedType = node?.baseParams.contractType;
282
279
  if (reserve) {
@@ -293,7 +290,7 @@ class PriceOracleBaseContract extends import_base.BaseContract {
293
290
  }
294
291
  }
295
292
  this.#labelPriceFeed(priceFeed, reserve ? "Reserve" : "Main", token);
296
- }
293
+ });
297
294
  this.logger?.debug(
298
295
  `Got ${this.mainPriceFeeds.size} main and ${this.reservePriceFeeds.size} reserve price feeds`
299
296
  );
@@ -314,8 +311,6 @@ class PriceOracleBaseContract extends import_base.BaseContract {
314
311
  * Helper method to find "attachment point" of price feed (makes sense for updatable price feeds only) -
315
312
  * returns token (in v3.0 can be ticker) and main/reserve flag
316
313
  *
317
- * @deprecated Should be gone after v310 migration
318
- *
319
314
  * @param priceFeed
320
315
  * @returns
321
316
  */
@@ -332,9 +327,6 @@ class PriceOracleBaseContract extends import_base.BaseContract {
332
327
  }
333
328
  return [void 0, false];
334
329
  }
335
- /**
336
- * Returns list of addresses that should be watched for events to sync state
337
- */
338
330
  get watchAddresses() {
339
331
  return /* @__PURE__ */ new Set([this.address]);
340
332
  }
@@ -361,6 +353,9 @@ class PriceOracleBaseContract extends import_base.BaseContract {
361
353
  )
362
354
  };
363
355
  }
356
+ get priceFeedTree() {
357
+ return this.#priceFeedTree;
358
+ }
364
359
  #noAnswerWarn(priceFeed, node) {
365
360
  let label = this.labelAddress(priceFeed);
366
361
  if (!node) {
@@ -27,7 +27,7 @@ var import_sdk_gov_legacy = require("../../sdk-gov-legacy/index.js");
27
27
  var import_PriceOracleBaseContract = require("./PriceOracleBaseContract.js");
28
28
  const abi = [...import_v300.iPriceOracleV300Abi, ...import_iPausable.iPausableAbi];
29
29
  class PriceOracleV300Contract extends import_PriceOracleBaseContract.PriceOracleBaseContract {
30
- constructor(sdk, data) {
30
+ constructor(sdk, data, underlying) {
31
31
  super(
32
32
  sdk,
33
33
  {
@@ -35,7 +35,8 @@ class PriceOracleV300Contract extends import_PriceOracleBaseContract.PriceOracle
35
35
  name: "PriceOracleV3",
36
36
  abi
37
37
  },
38
- data
38
+ data,
39
+ underlying
39
40
  );
40
41
  }
41
42
  processLog(log) {
@@ -25,7 +25,7 @@ var import_v310 = require("../../../abi/v310.js");
25
25
  var import_PriceOracleBaseContract = require("./PriceOracleBaseContract.js");
26
26
  const abi = import_v310.iPriceOracleV310Abi;
27
27
  class PriceOracleV310Contract extends import_PriceOracleBaseContract.PriceOracleBaseContract {
28
- constructor(sdk, data) {
28
+ constructor(sdk, data, underlying) {
29
29
  super(
30
30
  sdk,
31
31
  {
@@ -33,7 +33,8 @@ class PriceOracleV310Contract extends import_PriceOracleBaseContract.PriceOracle
33
33
  name: "PriceOracleV3",
34
34
  abi
35
35
  },
36
- data
36
+ data,
37
+ underlying
37
38
  );
38
39
  }
39
40
  processLog(log) {
@@ -18,42 +18,23 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var createPriceOracle_exports = {};
20
20
  __export(createPriceOracle_exports, {
21
- getOrCreatePriceOracle: () => getOrCreatePriceOracle
21
+ createPriceOracle: () => createPriceOracle
22
22
  });
23
23
  module.exports = __toCommonJS(createPriceOracle_exports);
24
24
  var import_constants = require("../../constants/index.js");
25
- var import_PriceOracleBaseContract = require("./PriceOracleBaseContract.js");
26
25
  var import_PriceOracleV300Contract = require("./PriceOracleV300Contract.js");
27
26
  var import_PriceOracleV310Contract = require("./PriceOracleV310Contract.js");
28
- function getOrCreatePriceOracle(sdk, data) {
29
- const { version, addr } = data.baseParams;
30
- const existing = sdk.contracts.get(addr);
31
- if (existing) {
32
- return tryExtendExistingOracle(existing, data);
27
+ function createPriceOracle(sdk, data, underlying) {
28
+ const v = data.baseParams.version;
29
+ if ((0, import_constants.isV300)(v)) {
30
+ return new import_PriceOracleV300Contract.PriceOracleV300Contract(sdk, data, underlying);
33
31
  }
34
- if ((0, import_constants.isV300)(version)) {
35
- return new import_PriceOracleV300Contract.PriceOracleV300Contract(sdk, data);
32
+ if ((0, import_constants.isV310)(v)) {
33
+ return new import_PriceOracleV310Contract.PriceOracleV310Contract(sdk, data, underlying);
36
34
  }
37
- if ((0, import_constants.isV310)(version)) {
38
- return new import_PriceOracleV310Contract.PriceOracleV310Contract(sdk, data);
39
- }
40
- throw new Error(`Unsupported oracle version ${version}`);
41
- }
42
- function tryExtendExistingOracle(existing, data) {
43
- const { version, addr } = data.baseParams;
44
- if (!(existing instanceof import_PriceOracleBaseContract.PriceOracleBaseContract)) {
45
- throw new Error(
46
- `expected oracle contract at ${addr}, found existing ${existing.contractType}`
47
- );
48
- }
49
- if (Number(existing.version) !== Number(version)) {
50
- throw new Error(
51
- `expected oracle contract at ${addr} to have version ${version}, found ${existing.version}`
52
- );
53
- }
54
- return existing.merge(data);
35
+ throw new Error(`Unsupported oracle version ${v}`);
55
36
  }
56
37
  // Annotate the CommonJS export names for ESM import in node:
57
38
  0 && (module.exports = {
58
- getOrCreatePriceOracle
39
+ createPriceOracle
59
40
  });
@@ -22,7 +22,6 @@ __export(AbstractLPPriceFeed_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(AbstractLPPriceFeed_exports);
24
24
  var import_viem = require("viem");
25
- var import_versions = require("../../constants/versions.js");
26
25
  var import_AbstractPriceFeed = require("./AbstractPriceFeed.js");
27
26
  const LOWER_BOUND_FACTOR = 99n;
28
27
  class AbstractLPPriceFeedContract extends import_AbstractPriceFeed.AbstractPriceFeedContract {
@@ -37,7 +36,7 @@ class AbstractLPPriceFeedContract extends import_AbstractPriceFeed.AbstractPrice
37
36
  constructor(sdk, args) {
38
37
  super(sdk, { ...args, decimals: 8 });
39
38
  this.hasLowerBoundCap = true;
40
- if ((0, import_versions.isV310)(args.baseParams.version)) {
39
+ if (args.baseParams.version === 310n) {
41
40
  const decoder = (0, import_viem.decodeAbiParameters)(
42
41
  [
43
42
  { type: "address", name: "lpToken" },
@@ -40,7 +40,7 @@ class RedstonePriceFeedContract extends import_AbstractPriceFeed.AbstractPriceFe
40
40
  name: `RedstonePriceFeed`,
41
41
  abi: import_abi.redstonePriceFeedAbi
42
42
  });
43
- if ((0, import_constants.isV310)(args.baseParams.version)) {
43
+ if (args.baseParams.version === 310n) {
44
44
  const decoder = (0, import_viem.decodeAbiParameters)(
45
45
  [
46
46
  { type: "address", name: "token" },
@@ -39,12 +39,12 @@ class V300StalenessPeriodPlugin extends import_base.SDKConstruct {
39
39
  this.#logger = sdk.logger?.child?.({ name: "V300StalenessPeriodPlugin" }) ?? sdk.logger;
40
40
  }
41
41
  async attach() {
42
- await this.#syncPriceFeeds();
42
+ await this.#syncReservePriceFeeds();
43
43
  }
44
44
  async syncState() {
45
- await this.#syncPriceFeeds();
45
+ await this.#syncReservePriceFeeds();
46
46
  }
47
- async #syncPriceFeeds() {
47
+ async #syncReservePriceFeeds() {
48
48
  const oracles = this.#getOraclesMap();
49
49
  const [fromBlock, toBlock] = [this.#syncedTo + 1n, this.sdk.currentBlock];
50
50
  if (oracles.size === 0 || fromBlock > toBlock) {
@@ -67,7 +67,7 @@ class V300StalenessPeriodPlugin extends import_base.SDKConstruct {
67
67
  strict: true
68
68
  });
69
69
  this.#logger?.info(
70
- `loaded ${events.length} price feed events in range [${fromBlock}; ${toBlock}]`
70
+ `loaded ${events.length} SetReservePriceFeed events in range [${fromBlock}; ${toBlock}]`
71
71
  );
72
72
  for (const e of events) {
73
73
  const oracle = oracles.mustGet(e.address);
@@ -120,7 +120,7 @@ class V300StalenessPeriodPlugin extends import_base.SDKConstruct {
120
120
  }
121
121
  #getOraclesMap() {
122
122
  return new import_utils.AddressMap(
123
- this.sdk.marketRegister.markets.filter((m) => (0, import_constants.isV300)(m.priceOracle.version)).map((m) => [m.priceOracle.address, m.priceOracle])
123
+ this.sdk.marketRegister.markets.filter((m) => m.priceOracle.version === 300).map((m) => [m.priceOracle.address, m.priceOracle])
124
124
  );
125
125
  }
126
126
  }
@@ -7,11 +7,7 @@ async function calcLiquidatableLTs(sdk, ca, factor = 9990n, logger) {
7
7
  return balance > minBalance;
8
8
  }).map((t) => {
9
9
  const { token, balance } = t;
10
- const balanceU = market.priceOracle.convert(
11
- token,
12
- ca.underlying,
13
- balance
14
- );
10
+ const balanceU = market.priceOracle.convertToUnderlying(token, balance);
15
11
  const lt = BigInt(cm.creditManager.liquidationThresholds.mustGet(token));
16
12
  return {
17
13
  token,
@@ -57,6 +57,7 @@ class BaseContract extends SDKConstruct {
57
57
  this.addressLabels.set(this.#address, name);
58
58
  }
59
59
  }
60
+ // TODO: unused
60
61
  stateHuman(_ = true) {
61
62
  return {
62
63
  address: this.sdk.provider.addressLabels.get(this.address),
@@ -1,7 +1,7 @@
1
1
  import { SDKConstruct } from "../base/index.js";
2
2
  import { CreditSuite } from "./credit/index.js";
3
3
  import { MarketConfiguratorContract } from "./MarketConfiguratorContract.js";
4
- import { getOrCreatePriceOracle } from "./oracle/index.js";
4
+ import { createPriceOracle } from "./oracle/index.js";
5
5
  import { PoolSuite } from "./pool/index.js";
6
6
  class MarketSuite extends SDKConstruct {
7
7
  acl;
@@ -35,7 +35,11 @@ class MarketSuite extends SDKConstruct {
35
35
  for (let i = 0; i < marketData.creditManagers.length; i++) {
36
36
  this.creditManagers.push(new CreditSuite(sdk, marketData, i));
37
37
  }
38
- this.priceOracle = getOrCreatePriceOracle(sdk, marketData.priceOracle);
38
+ this.priceOracle = createPriceOracle(
39
+ sdk,
40
+ marketData.priceOracle,
41
+ marketData.pool.underlying
42
+ );
39
43
  }
40
44
  get dirty() {
41
45
  return this.configurator.dirty || this.pool.dirty || this.priceOracle.dirty || this.creditManagers.some((cm) => cm.dirty);
@@ -5,7 +5,6 @@ import { iUpdatablePriceFeedAbi } from "../../../abi/iUpdatablePriceFeed.js";
5
5
  import { BaseContract } from "../../base/index.js";
6
6
  import {
7
7
  AP_PRICE_FEED_COMPRESSOR,
8
- isV300,
9
8
  VERSION_RANGE_310
10
9
  } from "../../constants/index.js";
11
10
  import { AddressMap, formatBN } from "../../utils/index.js";
@@ -13,6 +12,10 @@ import { PriceFeedRef } from "../pricefeeds/index.js";
13
12
  import PriceFeedAnswerMap from "./PriceFeedAnswerMap.js";
14
13
  const ZERO_PRICE_FEED = stringToHex("PRICE_FEED::ZERO", { size: 32 });
15
14
  class PriceOracleBaseContract extends BaseContract {
15
+ /**
16
+ * Underlying token of market to which this price oracle belongs
17
+ */
18
+ underlying;
16
19
  /**
17
20
  * Mapping Token => [PriceFeed Address, stalenessPeriod]
18
21
  */
@@ -38,14 +41,12 @@ class PriceOracleBaseContract extends BaseContract {
38
41
  void 0,
39
42
  "reservePrices"
40
43
  );
41
- #priceFeedTree = new AddressMap(
42
- void 0,
43
- "priceFeedTree"
44
- );
45
- constructor(sdk, args, data) {
44
+ #priceFeedTree = [];
45
+ constructor(sdk, args, data, underlying) {
46
46
  super(sdk, args);
47
+ this.underlying = underlying;
47
48
  const { priceFeedMap, priceFeedTree } = data;
48
- this.#loadState(priceFeedMap, priceFeedTree, true);
49
+ this.#loadState(priceFeedMap, priceFeedTree);
49
50
  }
50
51
  /**
51
52
  * Returns main and reserve price feeds for given tokens
@@ -67,7 +68,7 @@ class PriceOracleBaseContract extends BaseContract {
67
68
  */
68
69
  async updatePriceFeeds() {
69
70
  const updatables = [];
70
- for (const node of this.#priceFeedTree.values()) {
71
+ for (const node of this.#priceFeedTree) {
71
72
  if (node.updatable) {
72
73
  updatables.push(this.sdk.priceFeeds.mustGet(node.baseParams.addr));
73
74
  }
@@ -133,19 +134,30 @@ class PriceOracleBaseContract extends BaseContract {
133
134
  }
134
135
  /**
135
136
  * Returns true if oracle's price feed tree contains given price feed
136
- * This feed is not necessary connected to token, but can be a component of composite feed for some token
137
137
  * @param priceFeed
138
138
  * @returns
139
139
  */
140
140
  usesPriceFeed(priceFeed) {
141
- return this.#priceFeedTree.has(priceFeed);
141
+ return this.#priceFeedTree.some(
142
+ (node) => node.baseParams.addr.toLowerCase() === priceFeed.toLowerCase()
143
+ );
144
+ }
145
+ /**
146
+ * Tries to convert amount of token into underlying of current market
147
+ * @param token
148
+ * @param amount
149
+ * @param reserve
150
+ * @returns
151
+ */
152
+ convertToUnderlying(token, amount, reserve = false) {
153
+ return this.convert(token, this.underlying, amount, reserve);
142
154
  }
143
155
  /**
144
156
  * Tries to convert amount of from one token to another, using latest known prices
145
157
  * @param from
146
158
  * @param to
147
159
  * @param amount
148
- * @param reserve use reserve price feed instead of main
160
+ * @param reserve
149
161
  */
150
162
  convert(from, to, amount, reserve = false) {
151
163
  if (from === to) {
@@ -160,8 +172,9 @@ class PriceOracleBaseContract extends BaseContract {
160
172
  /**
161
173
  * Tries to convert amount of token to USD, using latest known prices
162
174
  * @param from
175
+ * @param to
163
176
  * @param amount
164
- * @param reserve use reserve price feed instead of main
177
+ * @param reserve
165
178
  */
166
179
  convertToUSD(from, amount, reserve = false) {
167
180
  const price = reserve ? this.reservePrice(from) : this.mainPrice(from);
@@ -172,7 +185,7 @@ class PriceOracleBaseContract extends BaseContract {
172
185
  * Tries to convert amount of USD to token, using latest known prices
173
186
  * @param to
174
187
  * @param amount
175
- * @param reserve use reserve price feed instead of main
188
+ * @param reserve
176
189
  */
177
190
  convertFromUSD(to, amount, reserve = false) {
178
191
  const price = reserve ? this.reservePrice(to) : this.mainPrice(to);
@@ -181,26 +194,23 @@ class PriceOracleBaseContract extends BaseContract {
181
194
  }
182
195
  /**
183
196
  * Loads new prices for this oracle from PriceFeedCompressor
184
- * Will (re)create price feeds if needed
197
+ * Does not update price feeds, only updates prices
185
198
  */
186
199
  async updatePrices() {
187
200
  await this.sdk.marketRegister.updatePrices([this.address]);
188
201
  }
189
- /**
190
- * Paired method to updatePrices, helps to update prices on all oracles in one multicall
191
- */
192
202
  syncStateMulticall() {
193
- let args = [this.address];
194
- if (isV300(this.version)) {
195
- args = [
196
- args[0],
203
+ const args = [this.address];
204
+ if (this.version === 300) {
205
+ args.push(
197
206
  Array.from(
198
207
  /* @__PURE__ */ new Set([
208
+ this.underlying,
199
209
  ...this.mainPriceFeeds.keys(),
200
210
  ...this.reservePriceFeeds.keys()
201
211
  ])
202
212
  )
203
- ];
213
+ );
204
214
  }
205
215
  const [address] = this.sdk.addressProvider.mustGetLatest(
206
216
  AP_PRICE_FEED_COMPRESSOR,
@@ -215,39 +225,25 @@ class PriceOracleBaseContract extends BaseContract {
215
225
  },
216
226
  onResult: (resp) => {
217
227
  const { priceFeedMap, priceFeedTree } = resp;
218
- this.#loadState(priceFeedMap, priceFeedTree, true);
228
+ this.#loadState(priceFeedMap, priceFeedTree);
219
229
  }
220
230
  };
221
231
  }
222
- /**
223
- * Helper function to handle situation when we have multiple different compressor data entries for same oracle
224
- * This happens in v300
225
- *
226
- * @deprecated should be unnecessary after full v310 migration (oracles will be unique)
227
- * @param data
228
- * @returns
229
- */
230
- merge(data) {
231
- const { priceFeedMap, priceFeedTree } = data;
232
- this.#loadState(priceFeedMap, priceFeedTree, false);
233
- return this;
234
- }
235
- #loadState(entries, tree, reset) {
236
- if (reset) {
237
- this.#priceFeedTree.clear();
238
- this.mainPriceFeeds.clear();
239
- this.reservePriceFeeds.clear();
240
- this.mainPrices.clear();
241
- this.reservePrices.clear();
242
- }
232
+ #loadState(entries, tree) {
233
+ this.#priceFeedTree = tree;
234
+ this.mainPriceFeeds.clear();
235
+ this.reservePriceFeeds.clear();
236
+ this.mainPrices.clear();
237
+ this.reservePrices.clear();
243
238
  for (const node of tree) {
244
- this.#priceFeedTree.upsert(node.baseParams.addr, node);
245
239
  this.sdk.priceFeeds.getOrCreate(node);
246
240
  }
247
- for (const entry of entries) {
241
+ entries.forEach((entry) => {
248
242
  const { token, priceFeed, reserve, stalenessPeriod } = entry;
249
243
  const ref = new PriceFeedRef(this.sdk, priceFeed, stalenessPeriod);
250
- const node = this.#priceFeedTree.get(priceFeed);
244
+ const node = this.#priceFeedTree.find(
245
+ (n) => n.baseParams.addr === priceFeed
246
+ );
251
247
  const price = node?.answer?.price;
252
248
  const priceFeedType = node?.baseParams.contractType;
253
249
  if (reserve) {
@@ -264,7 +260,7 @@ class PriceOracleBaseContract extends BaseContract {
264
260
  }
265
261
  }
266
262
  this.#labelPriceFeed(priceFeed, reserve ? "Reserve" : "Main", token);
267
- }
263
+ });
268
264
  this.logger?.debug(
269
265
  `Got ${this.mainPriceFeeds.size} main and ${this.reservePriceFeeds.size} reserve price feeds`
270
266
  );
@@ -285,8 +281,6 @@ class PriceOracleBaseContract extends BaseContract {
285
281
  * Helper method to find "attachment point" of price feed (makes sense for updatable price feeds only) -
286
282
  * returns token (in v3.0 can be ticker) and main/reserve flag
287
283
  *
288
- * @deprecated Should be gone after v310 migration
289
- *
290
284
  * @param priceFeed
291
285
  * @returns
292
286
  */
@@ -303,9 +297,6 @@ class PriceOracleBaseContract extends BaseContract {
303
297
  }
304
298
  return [void 0, false];
305
299
  }
306
- /**
307
- * Returns list of addresses that should be watched for events to sync state
308
- */
309
300
  get watchAddresses() {
310
301
  return /* @__PURE__ */ new Set([this.address]);
311
302
  }
@@ -332,6 +323,9 @@ class PriceOracleBaseContract extends BaseContract {
332
323
  )
333
324
  };
334
325
  }
326
+ get priceFeedTree() {
327
+ return this.#priceFeedTree;
328
+ }
335
329
  #noAnswerWarn(priceFeed, node) {
336
330
  let label = this.labelAddress(priceFeed);
337
331
  if (!node) {