@gearbox-protocol/sdk 8.2.0 → 8.3.0-next.1

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.
@@ -26,6 +26,7 @@ var import_base = require("../base/index.js");
26
26
  var import_constants = require("../constants/index.js");
27
27
  var import_utils = require("../utils/index.js");
28
28
  var import_viem = require("../utils/viem/index.js");
29
+ var import_MarketConfiguratorContract = require("./MarketConfiguratorContract.js");
29
30
  var import_MarketSuite = require("./MarketSuite.js");
30
31
  class MarketRegister extends import_base.SDKConstruct {
31
32
  #logger;
@@ -34,6 +35,10 @@ class MarketRegister extends import_base.SDKConstruct {
34
35
  */
35
36
  #markets = new import_utils.AddressMap(void 0, "markets");
36
37
  #marketFilter;
38
+ #marketConfigurators = new import_utils.AddressMap(
39
+ void 0,
40
+ "marketConfigurators"
41
+ );
37
42
  constructor(sdk) {
38
43
  super(sdk);
39
44
  this.#logger = (0, import_utils.childLogger)("MarketRegister", sdk.logger);
@@ -46,11 +51,7 @@ class MarketRegister extends import_base.SDKConstruct {
46
51
  new import_MarketSuite.MarketSuite(this.sdk, data)
47
52
  );
48
53
  }
49
- this.#marketFilter = {
50
- configurators: this.marketConfigurators.map((c) => c.address),
51
- pools: [],
52
- underlying: import_constants.ADDRESS_0X0
53
- };
54
+ this.#setMarketFilter(this.marketConfigurators.map((c) => c.address));
54
55
  }
55
56
  async loadMarkets(marketConfigurators, ignoreUpdateablePrices) {
56
57
  if (!marketConfigurators.length) {
@@ -61,35 +62,43 @@ class MarketRegister extends import_base.SDKConstruct {
61
62
  }
62
63
  await this.#loadMarkets(marketConfigurators, [], ignoreUpdateablePrices);
63
64
  }
65
+ #setMarketFilter(configurators, pools = []) {
66
+ for (const c of configurators) {
67
+ this.#marketConfigurators.upsert(
68
+ c,
69
+ new import_MarketConfiguratorContract.MarketConfiguratorContract(this.sdk, c)
70
+ );
71
+ }
72
+ this.#marketFilter = {
73
+ configurators,
74
+ pools,
75
+ underlying: import_constants.ADDRESS_0X0
76
+ };
77
+ }
64
78
  get marketFilter() {
79
+ if (!this.#marketFilter) {
80
+ throw new Error(
81
+ "market filter is not set, check if market register was properly attached or hydrated"
82
+ );
83
+ }
65
84
  return this.#marketFilter;
66
85
  }
67
86
  async syncState(skipPriceUpdate) {
68
- const dirtyPools = [];
69
- const nonDirtyOracles = [];
70
- for (const m of this.markets) {
71
- if (m.dirty) {
72
- dirtyPools.push(m.pool);
73
- } else {
74
- nonDirtyOracles.push(m.priceOracle.address);
75
- }
76
- }
77
- if (dirtyPools.length) {
78
- this.#logger?.debug(`need to reload ${dirtyPools.length} markets`);
87
+ const dirty = this.markets.some((m) => m.dirty) || this.marketConfigurators.some((c) => c.dirty);
88
+ if (dirty) {
89
+ this.#logger?.debug(
90
+ "some markets or market configurators are dirty, reloading everything"
91
+ );
79
92
  await this.#loadMarkets(
80
- Array.from(new Set(dirtyPools.map((p) => p.marketConfigurator.address))),
81
- dirtyPools.map((p) => p.pool.address)
93
+ [...this.marketFilter.configurators],
94
+ [...this.marketFilter.pools]
82
95
  );
83
- } else if (!skipPriceUpdate && nonDirtyOracles.length) {
84
- await this.updatePrices(nonDirtyOracles);
96
+ } else if (!skipPriceUpdate) {
97
+ await this.updatePrices();
85
98
  }
86
99
  }
87
100
  async #loadMarkets(configurators, pools, ignoreUpdateablePrices) {
88
- this.#marketFilter = {
89
- configurators,
90
- pools,
91
- underlying: import_constants.ADDRESS_0X0
92
- };
101
+ this.#setMarketFilter(configurators, pools);
93
102
  const [marketCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
94
103
  import_constants.AP_MARKET_COMPRESSOR,
95
104
  import_constants.VERSION_RANGE_310
@@ -118,7 +127,7 @@ class MarketRegister extends import_base.SDKConstruct {
118
127
  abi: import_compressors.iMarketCompressorAbi,
119
128
  address: marketCompressorAddress,
120
129
  functionName: "getMarkets",
121
- args: [this.#marketFilter]
130
+ args: [this.marketFilter]
122
131
  }
123
132
  ],
124
133
  blockNumber: this.sdk.currentBlock,
@@ -131,7 +140,7 @@ class MarketRegister extends import_base.SDKConstruct {
131
140
  abi: import_compressors.iMarketCompressorAbi,
132
141
  address: marketCompressorAddress,
133
142
  functionName: "getMarkets",
134
- args: [this.#marketFilter],
143
+ args: [this.marketFilter],
135
144
  blockNumber: this.sdk.currentBlock,
136
145
  // @ts-expect-error
137
146
  gas: this.sdk.gasLimit
@@ -179,7 +188,11 @@ class MarketRegister extends import_base.SDKConstruct {
179
188
  }
180
189
  }
181
190
  get watchAddresses() {
182
- return new Set(this.markets.flatMap((m) => Array.from(m.watchAddresses)));
191
+ return /* @__PURE__ */ new Set([
192
+ ...this.markets.flatMap((m) => Array.from(m.watchAddresses)),
193
+ // this is needed to handle edge case of market configurator without markets, to detect CreateMarket event
194
+ ...this.marketFilter.configurators
195
+ ]);
183
196
  }
184
197
  get state() {
185
198
  return this.markets.map((market) => market.state);
@@ -196,11 +209,7 @@ class MarketRegister extends import_base.SDKConstruct {
196
209
  return this.markets.flatMap((market) => market.creditManagers);
197
210
  }
198
211
  get marketConfigurators() {
199
- const result = /* @__PURE__ */ new Set();
200
- for (const m of this.markets) {
201
- result.add(m.configurator);
202
- }
203
- return Array.from(result);
212
+ return this.#marketConfigurators.values();
204
213
  }
205
214
  findCreditManager(creditManager) {
206
215
  const addr = creditManager.toLowerCase();
@@ -39,16 +39,13 @@ class MarketSuite extends import_base.SDKConstruct {
39
39
  constructor(sdk, marketData) {
40
40
  super(sdk);
41
41
  this.state = marketData;
42
- let configurator = sdk.contracts.get(
43
- marketData.configurator
44
- );
45
- if (!configurator) {
46
- configurator = new import_MarketConfiguratorContract.MarketConfiguratorContract(
47
- sdk,
48
- marketData.configurator
42
+ const mc = sdk.contracts.mustGet(marketData.configurator);
43
+ if (!(mc instanceof import_MarketConfiguratorContract.MarketConfiguratorContract)) {
44
+ throw new Error(
45
+ `Market configurator ${marketData.configurator} is not a market configurator`
49
46
  );
50
47
  }
51
- this.configurator = configurator;
48
+ this.configurator = mc;
52
49
  this.acl = marketData.acl;
53
50
  for (const t of marketData.tokens) {
54
51
  sdk.tokensMeta.upsert(t.addr, t);
@@ -98,6 +98,31 @@ class PriceFeedRegister extends import_base.SDKConstruct {
98
98
  this.#latestUpdate = latestUpdate;
99
99
  return result;
100
100
  }
101
+ /**
102
+ * Similar to generatePriceFeedsUpdateTxs, but will generate necessary price update transactions for external price feeds
103
+ * This does not add feeds to this register, so they won't be implicitly included in future generatePriceFeedsUpdateTxs calls
104
+ * @param feeds
105
+ * @param block
106
+ * @returns
107
+ */
108
+ async generateExternalPriceFeedsUpdateTxs(feeds, block) {
109
+ const [priceFeedCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
110
+ import_constants.AP_PRICE_FEED_COMPRESSOR,
111
+ import_constants.VERSION_RANGE_310
112
+ );
113
+ const blockParam = block ?? { blockNumber: this.sdk.currentBlock };
114
+ const result = await this.provider.publicClient.readContract({
115
+ address: priceFeedCompressorAddress,
116
+ abi: import_compressors.iPriceFeedCompressorAbi,
117
+ functionName: "loadPriceFeedTree",
118
+ args: [feeds],
119
+ ...blockParam,
120
+ // @ts-expect-error
121
+ gas: this.sdk.gasLimit
122
+ });
123
+ const feedContracts = result.map((data) => this.create(data));
124
+ return this.generatePriceFeedsUpdateTxs(feedContracts);
125
+ }
101
126
  has(address) {
102
127
  return this.#feeds.has(address);
103
128
  }
@@ -204,6 +204,12 @@ class RouterV300Contract extends import_AbstractRouterContract.AbstractRouterCon
204
204
  leftover,
205
205
  connectors
206
206
  });
207
+ const force = ca.tokens.some(
208
+ (b) => b.token.toLowerCase() === import_sdk_gov_legacy.tokenDataByNetwork.Mainnet.stkcvxRLUSDUSDC.toLowerCase() && b.balance > 10n
209
+ );
210
+ if (force) {
211
+ this.logger?.warn("applying stkcvxRLUSDUSDC workaround");
212
+ }
207
213
  let results = [];
208
214
  for (const po of pathOptions) {
209
215
  const { result: result2 } = await this.contract.simulate.findBestClosePath(
@@ -215,7 +221,7 @@ class RouterV300Contract extends import_AbstractRouterContract.AbstractRouterCon
215
221
  BigInt(slippage),
216
222
  po,
217
223
  BigInt(LOOPS_PER_TX),
218
- false
224
+ force
219
225
  ],
220
226
  {
221
227
  gas: GAS_PER_BLOCK
@@ -7,6 +7,7 @@ import {
7
7
  } from "../constants/index.js";
8
8
  import { AddressMap, childLogger } from "../utils/index.js";
9
9
  import { simulateWithPriceUpdates } from "../utils/viem/index.js";
10
+ import { MarketConfiguratorContract } from "./MarketConfiguratorContract.js";
10
11
  import { MarketSuite } from "./MarketSuite.js";
11
12
  class MarketRegister extends SDKConstruct {
12
13
  #logger;
@@ -15,6 +16,10 @@ class MarketRegister extends SDKConstruct {
15
16
  */
16
17
  #markets = new AddressMap(void 0, "markets");
17
18
  #marketFilter;
19
+ #marketConfigurators = new AddressMap(
20
+ void 0,
21
+ "marketConfigurators"
22
+ );
18
23
  constructor(sdk) {
19
24
  super(sdk);
20
25
  this.#logger = childLogger("MarketRegister", sdk.logger);
@@ -27,11 +32,7 @@ class MarketRegister extends SDKConstruct {
27
32
  new MarketSuite(this.sdk, data)
28
33
  );
29
34
  }
30
- this.#marketFilter = {
31
- configurators: this.marketConfigurators.map((c) => c.address),
32
- pools: [],
33
- underlying: ADDRESS_0X0
34
- };
35
+ this.#setMarketFilter(this.marketConfigurators.map((c) => c.address));
35
36
  }
36
37
  async loadMarkets(marketConfigurators, ignoreUpdateablePrices) {
37
38
  if (!marketConfigurators.length) {
@@ -42,35 +43,43 @@ class MarketRegister extends SDKConstruct {
42
43
  }
43
44
  await this.#loadMarkets(marketConfigurators, [], ignoreUpdateablePrices);
44
45
  }
46
+ #setMarketFilter(configurators, pools = []) {
47
+ for (const c of configurators) {
48
+ this.#marketConfigurators.upsert(
49
+ c,
50
+ new MarketConfiguratorContract(this.sdk, c)
51
+ );
52
+ }
53
+ this.#marketFilter = {
54
+ configurators,
55
+ pools,
56
+ underlying: ADDRESS_0X0
57
+ };
58
+ }
45
59
  get marketFilter() {
60
+ if (!this.#marketFilter) {
61
+ throw new Error(
62
+ "market filter is not set, check if market register was properly attached or hydrated"
63
+ );
64
+ }
46
65
  return this.#marketFilter;
47
66
  }
48
67
  async syncState(skipPriceUpdate) {
49
- const dirtyPools = [];
50
- const nonDirtyOracles = [];
51
- for (const m of this.markets) {
52
- if (m.dirty) {
53
- dirtyPools.push(m.pool);
54
- } else {
55
- nonDirtyOracles.push(m.priceOracle.address);
56
- }
57
- }
58
- if (dirtyPools.length) {
59
- this.#logger?.debug(`need to reload ${dirtyPools.length} markets`);
68
+ const dirty = this.markets.some((m) => m.dirty) || this.marketConfigurators.some((c) => c.dirty);
69
+ if (dirty) {
70
+ this.#logger?.debug(
71
+ "some markets or market configurators are dirty, reloading everything"
72
+ );
60
73
  await this.#loadMarkets(
61
- Array.from(new Set(dirtyPools.map((p) => p.marketConfigurator.address))),
62
- dirtyPools.map((p) => p.pool.address)
74
+ [...this.marketFilter.configurators],
75
+ [...this.marketFilter.pools]
63
76
  );
64
- } else if (!skipPriceUpdate && nonDirtyOracles.length) {
65
- await this.updatePrices(nonDirtyOracles);
77
+ } else if (!skipPriceUpdate) {
78
+ await this.updatePrices();
66
79
  }
67
80
  }
68
81
  async #loadMarkets(configurators, pools, ignoreUpdateablePrices) {
69
- this.#marketFilter = {
70
- configurators,
71
- pools,
72
- underlying: ADDRESS_0X0
73
- };
82
+ this.#setMarketFilter(configurators, pools);
74
83
  const [marketCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
75
84
  AP_MARKET_COMPRESSOR,
76
85
  VERSION_RANGE_310
@@ -99,7 +108,7 @@ class MarketRegister extends SDKConstruct {
99
108
  abi: iMarketCompressorAbi,
100
109
  address: marketCompressorAddress,
101
110
  functionName: "getMarkets",
102
- args: [this.#marketFilter]
111
+ args: [this.marketFilter]
103
112
  }
104
113
  ],
105
114
  blockNumber: this.sdk.currentBlock,
@@ -112,7 +121,7 @@ class MarketRegister extends SDKConstruct {
112
121
  abi: iMarketCompressorAbi,
113
122
  address: marketCompressorAddress,
114
123
  functionName: "getMarkets",
115
- args: [this.#marketFilter],
124
+ args: [this.marketFilter],
116
125
  blockNumber: this.sdk.currentBlock,
117
126
  // @ts-expect-error
118
127
  gas: this.sdk.gasLimit
@@ -160,7 +169,11 @@ class MarketRegister extends SDKConstruct {
160
169
  }
161
170
  }
162
171
  get watchAddresses() {
163
- return new Set(this.markets.flatMap((m) => Array.from(m.watchAddresses)));
172
+ return /* @__PURE__ */ new Set([
173
+ ...this.markets.flatMap((m) => Array.from(m.watchAddresses)),
174
+ // this is needed to handle edge case of market configurator without markets, to detect CreateMarket event
175
+ ...this.marketFilter.configurators
176
+ ]);
164
177
  }
165
178
  get state() {
166
179
  return this.markets.map((market) => market.state);
@@ -177,11 +190,7 @@ class MarketRegister extends SDKConstruct {
177
190
  return this.markets.flatMap((market) => market.creditManagers);
178
191
  }
179
192
  get marketConfigurators() {
180
- const result = /* @__PURE__ */ new Set();
181
- for (const m of this.markets) {
182
- result.add(m.configurator);
183
- }
184
- return Array.from(result);
193
+ return this.#marketConfigurators.values();
185
194
  }
186
195
  findCreditManager(creditManager) {
187
196
  const addr = creditManager.toLowerCase();
@@ -16,16 +16,13 @@ class MarketSuite extends SDKConstruct {
16
16
  constructor(sdk, marketData) {
17
17
  super(sdk);
18
18
  this.state = marketData;
19
- let configurator = sdk.contracts.get(
20
- marketData.configurator
21
- );
22
- if (!configurator) {
23
- configurator = new MarketConfiguratorContract(
24
- sdk,
25
- marketData.configurator
19
+ const mc = sdk.contracts.mustGet(marketData.configurator);
20
+ if (!(mc instanceof MarketConfiguratorContract)) {
21
+ throw new Error(
22
+ `Market configurator ${marketData.configurator} is not a market configurator`
26
23
  );
27
24
  }
28
- this.configurator = configurator;
25
+ this.configurator = mc;
29
26
  this.acl = marketData.acl;
30
27
  for (const t of marketData.tokens) {
31
28
  sdk.tokensMeta.upsert(t.addr, t);
@@ -81,6 +81,31 @@ class PriceFeedRegister extends SDKConstruct {
81
81
  this.#latestUpdate = latestUpdate;
82
82
  return result;
83
83
  }
84
+ /**
85
+ * Similar to generatePriceFeedsUpdateTxs, but will generate necessary price update transactions for external price feeds
86
+ * This does not add feeds to this register, so they won't be implicitly included in future generatePriceFeedsUpdateTxs calls
87
+ * @param feeds
88
+ * @param block
89
+ * @returns
90
+ */
91
+ async generateExternalPriceFeedsUpdateTxs(feeds, block) {
92
+ const [priceFeedCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
93
+ AP_PRICE_FEED_COMPRESSOR,
94
+ VERSION_RANGE_310
95
+ );
96
+ const blockParam = block ?? { blockNumber: this.sdk.currentBlock };
97
+ const result = await this.provider.publicClient.readContract({
98
+ address: priceFeedCompressorAddress,
99
+ abi: iPriceFeedCompressorAbi,
100
+ functionName: "loadPriceFeedTree",
101
+ args: [feeds],
102
+ ...blockParam,
103
+ // @ts-expect-error
104
+ gas: this.sdk.gasLimit
105
+ });
106
+ const feedContracts = result.map((data) => this.create(data));
107
+ return this.generatePriceFeedsUpdateTxs(feedContracts);
108
+ }
84
109
  has(address) {
85
110
  return this.#feeds.has(address);
86
111
  }
@@ -2,7 +2,7 @@ import { encodeFunctionData, getContract } from "viem";
2
2
  import { iRouterV300Abi, iSwapperV300Abi } from "../../abi/routerV300.js";
3
3
  import { iCreditFacadeV300MulticallAbi } from "../../abi/v300.js";
4
4
  import { PERCENTAGE_FACTOR } from "../constants/index.js";
5
- import { getConnectors } from "../sdk-gov-legacy/index.js";
5
+ import { getConnectors, tokenDataByNetwork } from "../sdk-gov-legacy/index.js";
6
6
  import { AbstractRouterContract } from "./AbstractRouterContract.js";
7
7
  import { assetsMap, balancesMap, compareRouterResults } from "./helpers.js";
8
8
  import { PathOptionFactory } from "./PathOptionFactory.js";
@@ -181,6 +181,12 @@ class RouterV300Contract extends AbstractRouterContract {
181
181
  leftover,
182
182
  connectors
183
183
  });
184
+ const force = ca.tokens.some(
185
+ (b) => b.token.toLowerCase() === tokenDataByNetwork.Mainnet.stkcvxRLUSDUSDC.toLowerCase() && b.balance > 10n
186
+ );
187
+ if (force) {
188
+ this.logger?.warn("applying stkcvxRLUSDUSDC workaround");
189
+ }
184
190
  let results = [];
185
191
  for (const po of pathOptions) {
186
192
  const { result: result2 } = await this.contract.simulate.findBestClosePath(
@@ -192,7 +198,7 @@ class RouterV300Contract extends AbstractRouterContract {
192
198
  BigInt(slippage),
193
199
  po,
194
200
  BigInt(LOOPS_PER_TX),
195
- false
201
+ force
196
202
  ],
197
203
  {
198
204
  gas: GAS_PER_BLOCK
@@ -1,11 +1,11 @@
1
1
  import type { Address } from "viem";
2
- import type { MarketData } from "../base/index.js";
2
+ import type { MarketData, MarketFilter } from "../base/index.js";
3
3
  import { SDKConstruct } from "../base/index.js";
4
4
  import type { GearboxSDK } from "../GearboxSDK.js";
5
5
  import type { MarketStateHuman } from "../types/index.js";
6
6
  import { AddressMap } from "../utils/index.js";
7
7
  import type { CreditSuite } from "./credit/index.js";
8
- import type { MarketConfiguratorContract } from "./MarketConfiguratorContract.js";
8
+ import { MarketConfiguratorContract } from "./MarketConfiguratorContract.js";
9
9
  import { MarketSuite } from "./MarketSuite.js";
10
10
  import type { PoolSuite } from "./pool/index.js";
11
11
  export declare class MarketRegister extends SDKConstruct {
@@ -13,11 +13,7 @@ export declare class MarketRegister extends SDKConstruct {
13
13
  constructor(sdk: GearboxSDK);
14
14
  hydrate(state: MarketData[]): void;
15
15
  loadMarkets(marketConfigurators: Address[], ignoreUpdateablePrices?: boolean): Promise<void>;
16
- get marketFilter(): {
17
- configurators: readonly `0x${string}`[];
18
- pools: readonly `0x${string}`[];
19
- underlying: `0x${string}`;
20
- } | undefined;
16
+ get marketFilter(): MarketFilter;
21
17
  syncState(skipPriceUpdate?: boolean): Promise<void>;
22
18
  /**
23
19
  * Loads new prices and price feeds for given oracles from PriceFeedCompressor, defaults to all oracles
@@ -1,4 +1,4 @@
1
- import type { Address } from "viem";
1
+ import type { Address, BlockTag } from "viem";
2
2
  import type { PriceFeedTreeNode } from "../../base/index.js";
3
3
  import { SDKConstruct } from "../../base/index.js";
4
4
  import type { GearboxSDK } from "../../GearboxSDK.js";
@@ -40,6 +40,18 @@ export declare class PriceFeedRegister extends SDKConstruct implements IHooks<Pr
40
40
  * @returns
41
41
  */
42
42
  generatePriceFeedsUpdateTxs(priceFeeds?: IPriceFeedContract[], logContext?: Record<string, any>): Promise<UpdatePriceFeedsResult>;
43
+ /**
44
+ * Similar to generatePriceFeedsUpdateTxs, but will generate necessary price update transactions for external price feeds
45
+ * This does not add feeds to this register, so they won't be implicitly included in future generatePriceFeedsUpdateTxs calls
46
+ * @param feeds
47
+ * @param block
48
+ * @returns
49
+ */
50
+ generateExternalPriceFeedsUpdateTxs(feeds: Address[], block?: {
51
+ blockNumber: bigint;
52
+ } | {
53
+ blockTag: BlockTag;
54
+ }): Promise<UpdatePriceFeedsResult>;
43
55
  has(address: Address): boolean;
44
56
  mustGet(address: Address): IPriceFeedContract;
45
57
  getOrCreate(data: PriceFeedTreeNode): IPriceFeedContract;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "8.2.0",
3
+ "version": "8.3.0-next.1",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "main": "./dist/cjs/sdk/index.js",