@gearbox-protocol/sdk 18.2.0-next.15 → 18.2.0-next.16

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.
@@ -4,11 +4,13 @@ const require_onchain_constants_address_provider = require("../../../onchain/con
4
4
  const require_model_opportunities_schema = require("../../../model/opportunities.schema.js");
5
5
  const require_abi_compressors_priceFeedCompressor = require("../../../abi/compressors/priceFeedCompressor.js");
6
6
  require("../../../onchain/index.js");
7
+ const require_offchain_errors_OffchainStatusError = require("../../../offchain/errors/OffchainStatusError.js");
7
8
  const require_offchain_AbstractOffchainNamespace = require("../../../offchain/AbstractOffchainNamespace.js");
8
9
  require("../../deployment/addresses.js");
9
10
  const require_permissionless_bindings_address_provider = require("../../bindings/address-provider.js");
10
11
  const require_permissionless_utils_price_update_get_prices = require("../../utils/price-update/get-prices.js");
11
12
  const require_permissionless_api_oracles_enrich = require("./enrich.js");
13
+ const require_permissionless_api_oracles_onchain_feed = require("./onchain-feed.js");
12
14
  const require_permissionless_api_oracles_schemas = require("./schemas.js");
13
15
  const require_permissionless_api_oracles_stress_run = require("./stress/run.js");
14
16
  const require_permissionless_api_oracles_score_run = require("./score/run.js");
@@ -28,6 +30,10 @@ function slotKey(oracle, token, reserve) {
28
30
  function describe(e) {
29
31
  return e instanceof Error ? e.message : String(e);
30
32
  }
33
+ /** The backend answered that it has no such feed. */
34
+ function isNotFound(e) {
35
+ return e instanceof require_offchain_errors_OffchainStatusError.OffchainStatusError && e.status === 404;
36
+ }
31
37
  /**
32
38
  * The price feeds of one chain: the PriceFeedStore as the backend has indexed
33
39
  * it, and the prices behind it.
@@ -139,25 +145,65 @@ var PermissionlessOracles = class extends require_offchain_AbstractOffchainNames
139
145
  * oracle holds for the slot, read off the chain here — see
140
146
  * {@link PermissionlessPriceFeedMarket.marketStalenessPeriod}.
141
147
  *
142
- * @throws When the store does not carry the feed. A private draft is not
143
- * here — it lives in whichever app wrote it.
148
+ * A feed the store does not carry is read off the chain instead, through
149
+ * the PriceFeedCompressor, and answered with `inStore: false`: its type,
150
+ * version and description are the chain's, while what only the store knows
151
+ * — who deployed it, its staleness period, the assets it may price and the
152
+ * markets it fills — is answered as unknown or empty.
153
+ *
154
+ * @throws When neither the store nor the chain knows the feed. A private
155
+ * draft is not here — it lives in whichever app wrote it.
144
156
  **/
145
157
  async feed({ chainId, address }) {
146
158
  const feed = address.toLowerCase();
147
- const indexed = await this.getData({
148
- path: `/pfs/${chainId}/price-feed/${address}`,
149
- schema: require_permissionless_api_oracles_schemas.priceFeedDetailsSchema
150
- });
159
+ let indexed;
160
+ try {
161
+ indexed = await this.getData({
162
+ path: `/pfs/${chainId}/price-feed/${address}`,
163
+ schema: require_permissionless_api_oracles_schemas.priceFeedDetailsSchema
164
+ });
165
+ } catch (e) {
166
+ const node = isNotFound(e) ? await this.#onchainNode(chainId, feed) : void 0;
167
+ if (!node) throw e;
168
+ return {
169
+ chainId,
170
+ priceFeed: require_permissionless_api_oracles_onchain_feed.onchainPriceFeed(node),
171
+ assets: [],
172
+ markets: [],
173
+ inStore: false
174
+ };
175
+ }
151
176
  const periods = await this.#stalenessPeriods(chainId, feed, indexed.markets);
152
177
  return {
153
178
  ...indexed,
154
179
  markets: indexed.markets.map((market) => ({
155
180
  ...market,
156
181
  marketStalenessPeriod: periods.get(slotKey(market.priceOracle, market.token, market.reserve)) ?? null
157
- }))
182
+ })),
183
+ inStore: true
158
184
  };
159
185
  }
160
186
  /**
187
+ * One feed as the PriceFeedCompressor reads it, or nothing when the chain
188
+ * cannot be read or the compressor does not know the feed.
189
+ *
190
+ * Failures are warnings and not errors: this only ever stands in for a
191
+ * store that did not have the feed, and the caller reports that miss
192
+ * rather than whatever kept the chain from answering in its place.
193
+ */
194
+ async #onchainNode(chainId, feed) {
195
+ try {
196
+ const client = this.#chains.client(chainId);
197
+ const compressor = await new require_permissionless_bindings_address_provider.AddressProviderContract("0xF7f0a609BfAb9a0A98786951ef10e5FE26cC1E38", client).getLatestVersionAddress(require_onchain_constants_address_provider.AP_PRICE_FEED_COMPRESSOR);
198
+ if (compressor === viem.zeroAddress) return;
199
+ const { nodes } = await require_permissionless_api_oracles_stress_run.readFeedTrees(client, compressor, [feed]);
200
+ return nodes.get(feed);
201
+ } catch (e) {
202
+ this.logger?.warn(`could not read price feed ${feed} off chain ${chainId}: ${describe(e)}`);
203
+ return;
204
+ }
205
+ }
206
+ /**
161
207
  * Staleness period each market's own oracle holds for the feed's slots,
162
208
  * keyed by {@link slotKey}.
163
209
  *
@@ -0,0 +1,25 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let viem = require("viem");
3
+ //#region src/permissionless/api/oracles/onchain-feed.ts
4
+ /**
5
+ * What the store would say about a feed, from what the chain says instead.
6
+ *
7
+ * Two fields are the store's alone and are answered as unknown rather than
8
+ * guessed: who deployed it is a store row, so it is the zero address, and the
9
+ * staleness period is a store setting a feed that was never added does not
10
+ * have, so it is 0. The compressor reports `PRICE_FEED::EXTERNAL` for a
11
+ * contract it cannot otherwise place; an empty type is the same thing said
12
+ * less clearly.
13
+ */
14
+ function onchainPriceFeed(node) {
15
+ return {
16
+ address: (0, viem.getAddress)(node.address),
17
+ contractType: node.contractType.trim() || "PRICE_FEED::EXTERNAL",
18
+ version: node.version,
19
+ deployedBy: viem.zeroAddress,
20
+ stalenessPeriod: 0,
21
+ name: node.description.trim()
22
+ };
23
+ }
24
+ //#endregion
25
+ exports.onchainPriceFeed = onchainPriceFeed;
@@ -137,10 +137,21 @@ var InstanceOwnerTransactions = class {
137
137
  const batch = await this.#batchContext(chainId);
138
138
  const pfCompressor = await this.#priceFeedCompressor(batch.client);
139
139
  const known = await batch.store.getKnownPriceFeeds();
140
+ const isKnown = new Set(known.map(lower));
140
141
  const feeds = await require_permissionless_api_transactions_lp_price_feeds.getFeedsToUpdate(batch.client, pfCompressor, known);
142
+ const addTxs = [];
143
+ const added = [];
141
144
  const configureTxs = [];
142
- for (const feed of feeds) configureTxs.push(...await require_permissionless_api_transactions_lp_price_feeds.updateBounds(batch.client, feed));
143
- const txs = [batch.store.configurePriceFeeds(configureTxs.map((tx) => ({
145
+ for (const feed of feeds) {
146
+ const boundTxs = await require_permissionless_api_transactions_lp_price_feeds.updateBounds(batch.client, feed.address);
147
+ if (boundTxs.length === 0) continue;
148
+ if (!isKnown.has(feed.address)) {
149
+ addTxs.push(batch.store.addPriceFeedTx(feed.address, 0, feed.description));
150
+ added.push(feed.address);
151
+ }
152
+ configureTxs.push(...boundTxs);
153
+ }
154
+ const txs = [...addTxs, batch.store.configurePriceFeeds(configureTxs.map((tx) => ({
144
155
  target: tx.to,
145
156
  callData: tx.callData
146
157
  })))];
@@ -149,7 +160,7 @@ var InstanceOwnerTransactions = class {
149
160
  author: owner,
150
161
  name: "update-bounds",
151
162
  txs,
152
- touchedFeeds: []
163
+ touchedFeeds: added
153
164
  });
154
165
  }
155
166
  /**
@@ -52,9 +52,12 @@ async function updateBounds(client, address) {
52
52
  /**
53
53
  * Of the whole feed tree behind `feeds`, the ones that are LP feeds: the
54
54
  * probe keeps whatever answers `getLPExchangeRate`.
55
+ *
56
+ * The trees reach past `feeds` themselves, so an LP feed read inside one of
57
+ * them is among the results whether or not it is one of `feeds`.
55
58
  **/
56
59
  async function getFeedsToUpdate(client, pfCompressor, feeds) {
57
- const updateableFeeds = /* @__PURE__ */ new Set();
60
+ const updateableFeeds = /* @__PURE__ */ new Map();
58
61
  const { data } = await client.call({
59
62
  to: pfCompressor,
60
63
  data: (0, viem.encodeFunctionData)({
@@ -69,8 +72,8 @@ async function getFeedsToUpdate(client, pfCompressor, feeds) {
69
72
  functionName: "loadPriceFeedTree",
70
73
  data: data ?? "0x"
71
74
  });
72
- for (const tree of trees) updateableFeeds.add(tree.baseParams.addr.toLowerCase());
73
- const candidates = Array.from(updateableFeeds);
75
+ for (const tree of trees) updateableFeeds.set(tree.baseParams.addr.toLowerCase(), tree.description);
76
+ const candidates = Array.from(updateableFeeds.keys());
74
77
  const { results } = await require_onchain_utils_viem_simulateMulticall.simulateMulticall(client, {
75
78
  contracts: candidates.map((feed) => ({
76
79
  address: feed,
@@ -79,7 +82,10 @@ async function getFeedsToUpdate(client, pfCompressor, feeds) {
79
82
  })),
80
83
  allowFailure: true
81
84
  });
82
- return candidates.filter((_, index) => results[index]?.status === "success");
85
+ return candidates.filter((_, index) => results[index]?.status === "success").map((address) => ({
86
+ address,
87
+ description: updateableFeeds.get(address) ?? ""
88
+ }));
83
89
  }
84
90
  //#endregion
85
91
  exports.getFeedsToUpdate = getFeedsToUpdate;
@@ -3,15 +3,17 @@ import { AP_PRICE_FEED_COMPRESSOR } from "../../../onchain/constants/address-pro
3
3
  import { priceFeedDataSchema } from "../../../model/opportunities.schema.js";
4
4
  import { priceFeedCompressorAbi } from "../../../abi/compressors/priceFeedCompressor.js";
5
5
  import "../../../onchain/index.js";
6
+ import { OffchainStatusError } from "../../../offchain/errors/OffchainStatusError.js";
6
7
  import { AbstractOffchainNamespace } from "../../../offchain/AbstractOffchainNamespace.js";
7
8
  import "../../deployment/addresses.js";
8
9
  import { AddressProviderContract } from "../../bindings/address-provider.js";
9
10
  import { getFeedDecimals, getLatestPrices, getPrices } from "../../utils/price-update/get-prices.js";
10
11
  import { byCentrality, feedKey, pricesByFeed, toCap, totalQuotas } from "./enrich.js";
12
+ import { onchainPriceFeed } from "./onchain-feed.js";
11
13
  import { assetDetailsSchema, assetSummariesSchema, marketSlotsSchema, priceFeedDetailsSchema, priceFeedStoresSchema } from "./schemas.js";
12
- import { runStressTest } from "./stress/run.js";
14
+ import { readFeedTrees, runStressTest } from "./stress/run.js";
13
15
  import { runAssetScores, runFeedPairScore } from "./score/run.js";
14
- import { erc20Abi } from "viem";
16
+ import { erc20Abi, zeroAddress } from "viem";
15
17
  //#region src/permissionless/api/oracles/PermissionlessOracles.ts
16
18
  const GET_PRICES_GAS_LIMIT_BY_CHAIN_ID = { 143: 100000000n };
17
19
  const GET_PRICES_CHUNK_SIZE = 200;
@@ -27,6 +29,10 @@ function slotKey(oracle, token, reserve) {
27
29
  function describe(e) {
28
30
  return e instanceof Error ? e.message : String(e);
29
31
  }
32
+ /** The backend answered that it has no such feed. */
33
+ function isNotFound(e) {
34
+ return e instanceof OffchainStatusError && e.status === 404;
35
+ }
30
36
  /**
31
37
  * The price feeds of one chain: the PriceFeedStore as the backend has indexed
32
38
  * it, and the prices behind it.
@@ -138,25 +144,65 @@ var PermissionlessOracles = class extends AbstractOffchainNamespace {
138
144
  * oracle holds for the slot, read off the chain here — see
139
145
  * {@link PermissionlessPriceFeedMarket.marketStalenessPeriod}.
140
146
  *
141
- * @throws When the store does not carry the feed. A private draft is not
142
- * here — it lives in whichever app wrote it.
147
+ * A feed the store does not carry is read off the chain instead, through
148
+ * the PriceFeedCompressor, and answered with `inStore: false`: its type,
149
+ * version and description are the chain's, while what only the store knows
150
+ * — who deployed it, its staleness period, the assets it may price and the
151
+ * markets it fills — is answered as unknown or empty.
152
+ *
153
+ * @throws When neither the store nor the chain knows the feed. A private
154
+ * draft is not here — it lives in whichever app wrote it.
143
155
  **/
144
156
  async feed({ chainId, address }) {
145
157
  const feed = address.toLowerCase();
146
- const indexed = await this.getData({
147
- path: `/pfs/${chainId}/price-feed/${address}`,
148
- schema: priceFeedDetailsSchema
149
- });
158
+ let indexed;
159
+ try {
160
+ indexed = await this.getData({
161
+ path: `/pfs/${chainId}/price-feed/${address}`,
162
+ schema: priceFeedDetailsSchema
163
+ });
164
+ } catch (e) {
165
+ const node = isNotFound(e) ? await this.#onchainNode(chainId, feed) : void 0;
166
+ if (!node) throw e;
167
+ return {
168
+ chainId,
169
+ priceFeed: onchainPriceFeed(node),
170
+ assets: [],
171
+ markets: [],
172
+ inStore: false
173
+ };
174
+ }
150
175
  const periods = await this.#stalenessPeriods(chainId, feed, indexed.markets);
151
176
  return {
152
177
  ...indexed,
153
178
  markets: indexed.markets.map((market) => ({
154
179
  ...market,
155
180
  marketStalenessPeriod: periods.get(slotKey(market.priceOracle, market.token, market.reserve)) ?? null
156
- }))
181
+ })),
182
+ inStore: true
157
183
  };
158
184
  }
159
185
  /**
186
+ * One feed as the PriceFeedCompressor reads it, or nothing when the chain
187
+ * cannot be read or the compressor does not know the feed.
188
+ *
189
+ * Failures are warnings and not errors: this only ever stands in for a
190
+ * store that did not have the feed, and the caller reports that miss
191
+ * rather than whatever kept the chain from answering in its place.
192
+ */
193
+ async #onchainNode(chainId, feed) {
194
+ try {
195
+ const client = this.#chains.client(chainId);
196
+ const compressor = await new AddressProviderContract("0xF7f0a609BfAb9a0A98786951ef10e5FE26cC1E38", client).getLatestVersionAddress(AP_PRICE_FEED_COMPRESSOR);
197
+ if (compressor === zeroAddress) return;
198
+ const { nodes } = await readFeedTrees(client, compressor, [feed]);
199
+ return nodes.get(feed);
200
+ } catch (e) {
201
+ this.logger?.warn(`could not read price feed ${feed} off chain ${chainId}: ${describe(e)}`);
202
+ return;
203
+ }
204
+ }
205
+ /**
160
206
  * Staleness period each market's own oracle holds for the feed's slots,
161
207
  * keyed by {@link slotKey}.
162
208
  *
@@ -0,0 +1,24 @@
1
+ import { getAddress, zeroAddress } from "viem";
2
+ //#region src/permissionless/api/oracles/onchain-feed.ts
3
+ /**
4
+ * What the store would say about a feed, from what the chain says instead.
5
+ *
6
+ * Two fields are the store's alone and are answered as unknown rather than
7
+ * guessed: who deployed it is a store row, so it is the zero address, and the
8
+ * staleness period is a store setting a feed that was never added does not
9
+ * have, so it is 0. The compressor reports `PRICE_FEED::EXTERNAL` for a
10
+ * contract it cannot otherwise place; an empty type is the same thing said
11
+ * less clearly.
12
+ */
13
+ function onchainPriceFeed(node) {
14
+ return {
15
+ address: getAddress(node.address),
16
+ contractType: node.contractType.trim() || "PRICE_FEED::EXTERNAL",
17
+ version: node.version,
18
+ deployedBy: zeroAddress,
19
+ stalenessPeriod: 0,
20
+ name: node.description.trim()
21
+ };
22
+ }
23
+ //#endregion
24
+ export { onchainPriceFeed };
@@ -136,10 +136,21 @@ var InstanceOwnerTransactions = class {
136
136
  const batch = await this.#batchContext(chainId);
137
137
  const pfCompressor = await this.#priceFeedCompressor(batch.client);
138
138
  const known = await batch.store.getKnownPriceFeeds();
139
+ const isKnown = new Set(known.map(lower));
139
140
  const feeds = await getFeedsToUpdate(batch.client, pfCompressor, known);
141
+ const addTxs = [];
142
+ const added = [];
140
143
  const configureTxs = [];
141
- for (const feed of feeds) configureTxs.push(...await updateBounds(batch.client, feed));
142
- const txs = [batch.store.configurePriceFeeds(configureTxs.map((tx) => ({
144
+ for (const feed of feeds) {
145
+ const boundTxs = await updateBounds(batch.client, feed.address);
146
+ if (boundTxs.length === 0) continue;
147
+ if (!isKnown.has(feed.address)) {
148
+ addTxs.push(batch.store.addPriceFeedTx(feed.address, 0, feed.description));
149
+ added.push(feed.address);
150
+ }
151
+ configureTxs.push(...boundTxs);
152
+ }
153
+ const txs = [...addTxs, batch.store.configurePriceFeeds(configureTxs.map((tx) => ({
143
154
  target: tx.to,
144
155
  callData: tx.callData
145
156
  })))];
@@ -148,7 +159,7 @@ var InstanceOwnerTransactions = class {
148
159
  author: owner,
149
160
  name: "update-bounds",
150
161
  txs,
151
- touchedFeeds: []
162
+ touchedFeeds: added
152
163
  });
153
164
  }
154
165
  /**
@@ -51,9 +51,12 @@ async function updateBounds(client, address) {
51
51
  /**
52
52
  * Of the whole feed tree behind `feeds`, the ones that are LP feeds: the
53
53
  * probe keeps whatever answers `getLPExchangeRate`.
54
+ *
55
+ * The trees reach past `feeds` themselves, so an LP feed read inside one of
56
+ * them is among the results whether or not it is one of `feeds`.
54
57
  **/
55
58
  async function getFeedsToUpdate(client, pfCompressor, feeds) {
56
- const updateableFeeds = /* @__PURE__ */ new Set();
59
+ const updateableFeeds = /* @__PURE__ */ new Map();
57
60
  const { data } = await client.call({
58
61
  to: pfCompressor,
59
62
  data: encodeFunctionData({
@@ -68,8 +71,8 @@ async function getFeedsToUpdate(client, pfCompressor, feeds) {
68
71
  functionName: "loadPriceFeedTree",
69
72
  data: data ?? "0x"
70
73
  });
71
- for (const tree of trees) updateableFeeds.add(tree.baseParams.addr.toLowerCase());
72
- const candidates = Array.from(updateableFeeds);
74
+ for (const tree of trees) updateableFeeds.set(tree.baseParams.addr.toLowerCase(), tree.description);
75
+ const candidates = Array.from(updateableFeeds.keys());
73
76
  const { results } = await simulateMulticall(client, {
74
77
  contracts: candidates.map((feed) => ({
75
78
  address: feed,
@@ -78,7 +81,10 @@ async function getFeedsToUpdate(client, pfCompressor, feeds) {
78
81
  })),
79
82
  allowFailure: true
80
83
  });
81
- return candidates.filter((_, index) => results[index]?.status === "success");
84
+ return candidates.filter((_, index) => results[index]?.status === "success").map((address) => ({
85
+ address,
86
+ description: updateableFeeds.get(address) ?? ""
87
+ }));
82
88
  }
83
89
  //#endregion
84
90
  export { getFeedsToUpdate, updateBounds };
@@ -99,8 +99,14 @@ export declare class PermissionlessOracles extends AbstractOffchainNamespace {
99
99
  * oracle holds for the slot, read off the chain here — see
100
100
  * {@link PermissionlessPriceFeedMarket.marketStalenessPeriod}.
101
101
  *
102
- * @throws When the store does not carry the feed. A private draft is not
103
- * here — it lives in whichever app wrote it.
102
+ * A feed the store does not carry is read off the chain instead, through
103
+ * the PriceFeedCompressor, and answered with `inStore: false`: its type,
104
+ * version and description are the chain's, while what only the store knows
105
+ * — who deployed it, its staleness period, the assets it may price and the
106
+ * markets it fills — is answered as unknown or empty.
107
+ *
108
+ * @throws When neither the store nor the chain knows the feed. A private
109
+ * draft is not here — it lives in whichever app wrote it.
104
110
  **/
105
111
  feed({ chainId, address }: PriceFeedArgs): Promise<PermissionlessPriceFeedDetails>;
106
112
  /**
@@ -0,0 +1,15 @@
1
+ import { PriceFeed } from "../../core/pricefeed.js";
2
+ import { TreeNode } from "./stress/classify.js";
3
+ //#region src/permissionless/api/oracles/onchain-feed.d.ts
4
+ /**
5
+ * What the store would say about a feed, from what the chain says instead.
6
+ *
7
+ * Two fields are the store's alone and are answered as unknown rather than
8
+ * guessed: who deployed it is a store row, so it is the zero address, and the
9
+ * staleness period is a store setting a feed that was never added does not
10
+ * have, so it is 0. The compressor reports `PRICE_FEED::EXTERNAL` for a
11
+ * contract it cannot otherwise place; an empty type is the same thing said
12
+ * less clearly.
13
+ */
14
+ export declare function onchainPriceFeed(node: TreeNode): PriceFeed;
15
+ //#endregion
@@ -170,9 +170,10 @@ export interface PermissionlessMarketSlot extends PermissionlessIndexedPriceFeed
170
170
  /**
171
171
  * One feed of the store, with everywhere the store lets it be used.
172
172
  *
173
- * Feeds a tree carries but the store never added have no identity to report —
174
- * no status history, hence no name or staleness — so the read throws for them
175
- * rather than answering a half-filled row.
173
+ * Feeds a tree carries but the store never added have no identity to report
174
+ * here — no status history, hence no name or staleness — so the backend does
175
+ * not answer for them; the SDK reads them off the chain instead, see
176
+ * {@link PermissionlessPriceFeedDetails.inStore}.
176
177
  **/
177
178
  export interface PermissionlessIndexedPriceFeedDetails {
178
179
  chainId: number;
@@ -190,6 +191,14 @@ export interface PermissionlessIndexedPriceFeedDetails {
190
191
  **/
191
192
  export interface PermissionlessPriceFeedDetails extends PermissionlessIndexedPriceFeedDetails {
192
193
  markets: PermissionlessPriceFeedMarket[];
194
+ /**
195
+ * Whether the answer is the store's.
196
+ *
197
+ * `false` is a deployed feed the store never added, read off the chain
198
+ * instead: `deployedBy` is the zero address, `stalenessPeriod` is 0, and
199
+ * `assets` and `markets` are empty, because all of them are store rows.
200
+ */
201
+ inStore: boolean;
193
202
  }
194
203
  /**
195
204
  * One feed as a market slot holds it.
@@ -8,9 +8,17 @@ import { Address, PublicClient } from "viem";
8
8
  * transaction. Returns nothing when the bound still fits.
9
9
  **/
10
10
  export declare function updateBounds(client: PublicClient, address: Address): Promise<RawTx[]>;
11
+ /** An LP feed found in a feed tree, with what it calls itself on chain. */
12
+ export interface LPFeed {
13
+ address: Address;
14
+ description: string;
15
+ }
11
16
  /**
12
17
  * Of the whole feed tree behind `feeds`, the ones that are LP feeds: the
13
18
  * probe keeps whatever answers `getLPExchangeRate`.
19
+ *
20
+ * The trees reach past `feeds` themselves, so an LP feed read inside one of
21
+ * them is among the results whether or not it is one of `feeds`.
14
22
  **/
15
- export declare function getFeedsToUpdate(client: PublicClient, pfCompressor: Address, feeds: Address[]): Promise<Address[]>;
23
+ export declare function getFeedsToUpdate(client: PublicClient, pfCompressor: Address, feeds: Address[]): Promise<LPFeed[]>;
16
24
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "18.2.0-next.15",
3
+ "version": "18.2.0-next.16",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {