@gearbox-protocol/sdk 7.7.0 → 7.9.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.
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var CachedStateSubscriber_exports = {};
20
+ __export(CachedStateSubscriber_exports, {
21
+ CachedStateSubscriber: () => CachedStateSubscriber
22
+ });
23
+ module.exports = __toCommonJS(CachedStateSubscriber_exports);
24
+ var import_sdk = require("../sdk/index.js");
25
+ class CachedStateSubscriber {
26
+ #stateURL;
27
+ #etag;
28
+ #currentBlock;
29
+ #sdk;
30
+ constructor(sdk, stateURL) {
31
+ this.#stateURL = stateURL;
32
+ this.#sdk = sdk;
33
+ }
34
+ /**
35
+ * Subscribe to sdk state changes
36
+ * @param opts - Options
37
+ * @returns Unsubscribe function
38
+ */
39
+ subscribe(opts) {
40
+ const intervalMs = opts?.pollInterval ?? 10 * 60 * 1e3;
41
+ const interval = setInterval(async () => {
42
+ const newBlock = await this.#poll();
43
+ if (newBlock && opts?.onChange) {
44
+ opts.onChange(newBlock);
45
+ }
46
+ }, intervalMs);
47
+ return () => clearInterval(interval);
48
+ }
49
+ async #poll() {
50
+ try {
51
+ const head = await fetch(this.#stateURL, { method: "HEAD" });
52
+ const etag = head.headers.get("ETag");
53
+ if (!etag || etag === this.#etag) {
54
+ return;
55
+ }
56
+ const response = await fetch(this.#stateURL);
57
+ const txt = await response.text();
58
+ const state = (0, import_sdk.json_parse)(txt);
59
+ if (state.currentBlock === this.#currentBlock) {
60
+ return;
61
+ }
62
+ this.#etag = etag;
63
+ this.#currentBlock = state.currentBlock;
64
+ this.#logger?.debug(`rehydrating state at block ${state.currentBlock}`);
65
+ this.#sdk.rehydrate(state);
66
+ return state.currentBlock;
67
+ } catch (e) {
68
+ this.#logger?.error(e, "error while polling cached state");
69
+ }
70
+ }
71
+ get #logger() {
72
+ return this.#sdk.logger;
73
+ }
74
+ }
75
+ // Annotate the CommonJS export names for ESM import in node:
76
+ 0 && (module.exports = {
77
+ CachedStateSubscriber
78
+ });
@@ -17,6 +17,7 @@ var dev_exports = {};
17
17
  module.exports = __toCommonJS(dev_exports);
18
18
  __reExport(dev_exports, require("./AccountOpener.js"), module.exports);
19
19
  __reExport(dev_exports, require("./AccountsCounterPlugin.js"), module.exports);
20
+ __reExport(dev_exports, require("./CachedStateSubscriber.js"), module.exports);
20
21
  __reExport(dev_exports, require("./calcLiquidatableLTs.js"), module.exports);
21
22
  __reExport(dev_exports, require("./create2.js"), module.exports);
22
23
  __reExport(dev_exports, require("./createAnvilClient.js"), module.exports);
@@ -28,6 +29,7 @@ __reExport(dev_exports, require("./migrateFaucet.js"), module.exports);
28
29
  0 && (module.exports = {
29
30
  ...require("./AccountOpener.js"),
30
31
  ...require("./AccountsCounterPlugin.js"),
32
+ ...require("./CachedStateSubscriber.js"),
31
33
  ...require("./calcLiquidatableLTs.js"),
32
34
  ...require("./create2.js"),
33
35
  ...require("./createAnvilClient.js"),
@@ -210,15 +210,22 @@ class GearboxSDK {
210
210
  return this;
211
211
  }
212
212
  #hydrate(options, state) {
213
- const { logger: _logger, redstone, ...opts } = options;
213
+ const { logger: _logger, ...opts } = options;
214
214
  if (state.version !== STATE_VERSION) {
215
215
  throw new Error(
216
216
  `hydrated state version is ${state.version}, but expected ${STATE_VERSION}`
217
217
  );
218
218
  }
219
+ const re = this.#attachConfig ? "re" : "";
220
+ this.logger?.info(
221
+ {
222
+ networkType: this.provider.networkType
223
+ },
224
+ `${re}hydrating sdk state`
225
+ );
219
226
  this.#currentBlock = state.currentBlock;
220
227
  this.#timestamp = state.timestamp;
221
- this.#priceFeeds = new import_pricefeeds.PriceFeedRegister(this, { redstone });
228
+ this.#priceFeeds = new import_pricefeeds.PriceFeedRegister(this, { redstone: opts.redstone });
222
229
  this.#addressProvider = (0, import_core.hydrateAddressProvider)(this, state.addressProvider);
223
230
  this.logger?.debug(
224
231
  `address provider version: ${this.#addressProvider.version}`
@@ -242,6 +249,7 @@ class GearboxSDK {
242
249
  plugin.hydrate(pluginState);
243
250
  }
244
251
  }
252
+ this.logger?.info(`${re}hydrated sdk state`);
245
253
  return this;
246
254
  }
247
255
  /**
@@ -254,6 +262,19 @@ class GearboxSDK {
254
262
  }
255
263
  await this.#attach(this.#attachConfig);
256
264
  }
265
+ /**
266
+ * Rehydrate existing SDK from new state without re-creating instance
267
+ */
268
+ rehydrate(state) {
269
+ if (!this.#attachConfig) {
270
+ throw new Error("cannot rehydrate, attach config is not set");
271
+ }
272
+ const opts = {
273
+ ignoreUpdateablePrices: this.#attachConfig.ignoreUpdateablePrices,
274
+ redstone: this.#attachConfig.redstone
275
+ };
276
+ this.#hydrate(opts, state);
277
+ }
257
278
  /**
258
279
  * Converts contract call into some human-friendly string
259
280
  * This method is safe and should not throw
@@ -59,9 +59,6 @@ class MarketSuite extends import_base.SDKConstruct {
59
59
  this.creditManagers.push(new import_credit.CreditSuite(sdk, marketData, i));
60
60
  }
61
61
  this.priceOracle = (0, import_oracle.getOrCreatePriceOracle)(sdk, marketData.priceOracle);
62
- sdk.logger?.debug(
63
- `oracle ${this.labelAddress(this.priceOracle.address)} has ${this.priceOracle.mainPriceFeeds.size} main and ${this.priceOracle.reservePriceFeeds.size} reserve price feeds`
64
- );
65
62
  }
66
63
  get dirty() {
67
64
  return this.configurator.dirty || this.pool.dirty || this.priceOracle.dirty || this.creditManagers.some((cm) => cm.dirty);
@@ -28,16 +28,20 @@ var import_PriceOracleV310Contract = require("./PriceOracleV310Contract.js");
28
28
  function getOrCreatePriceOracle(sdk, data) {
29
29
  const { version, addr } = data.baseParams;
30
30
  const existing = sdk.contracts.get(addr);
31
+ let result;
31
32
  if (existing) {
32
- return tryExtendExistingOracle(existing, data);
33
+ result = tryExtendExistingOracle(existing, data);
34
+ } else if ((0, import_constants.isV300)(version)) {
35
+ result = new import_PriceOracleV300Contract.PriceOracleV300Contract(sdk, data);
36
+ } else if ((0, import_constants.isV310)(version)) {
37
+ result = new import_PriceOracleV310Contract.PriceOracleV310Contract(sdk, data);
38
+ } else {
39
+ throw new Error(`Unsupported oracle version ${version}`);
33
40
  }
34
- if ((0, import_constants.isV300)(version)) {
35
- return new import_PriceOracleV300Contract.PriceOracleV300Contract(sdk, data);
36
- }
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
+ sdk.logger?.debug(
42
+ `oracle ${addr} v${version} was ${existing ? "extended" : "created"} with ${result.mainPriceFeeds.size} main and ${result.reservePriceFeeds.size} reserve price feeds`
43
+ );
44
+ return result;
41
45
  }
42
46
  function tryExtendExistingOracle(existing, data) {
43
47
  const { version, addr } = data.baseParams;
@@ -0,0 +1,54 @@
1
+ import { json_parse } from "../sdk/index.js";
2
+ class CachedStateSubscriber {
3
+ #stateURL;
4
+ #etag;
5
+ #currentBlock;
6
+ #sdk;
7
+ constructor(sdk, stateURL) {
8
+ this.#stateURL = stateURL;
9
+ this.#sdk = sdk;
10
+ }
11
+ /**
12
+ * Subscribe to sdk state changes
13
+ * @param opts - Options
14
+ * @returns Unsubscribe function
15
+ */
16
+ subscribe(opts) {
17
+ const intervalMs = opts?.pollInterval ?? 10 * 60 * 1e3;
18
+ const interval = setInterval(async () => {
19
+ const newBlock = await this.#poll();
20
+ if (newBlock && opts?.onChange) {
21
+ opts.onChange(newBlock);
22
+ }
23
+ }, intervalMs);
24
+ return () => clearInterval(interval);
25
+ }
26
+ async #poll() {
27
+ try {
28
+ const head = await fetch(this.#stateURL, { method: "HEAD" });
29
+ const etag = head.headers.get("ETag");
30
+ if (!etag || etag === this.#etag) {
31
+ return;
32
+ }
33
+ const response = await fetch(this.#stateURL);
34
+ const txt = await response.text();
35
+ const state = json_parse(txt);
36
+ if (state.currentBlock === this.#currentBlock) {
37
+ return;
38
+ }
39
+ this.#etag = etag;
40
+ this.#currentBlock = state.currentBlock;
41
+ this.#logger?.debug(`rehydrating state at block ${state.currentBlock}`);
42
+ this.#sdk.rehydrate(state);
43
+ return state.currentBlock;
44
+ } catch (e) {
45
+ this.#logger?.error(e, "error while polling cached state");
46
+ }
47
+ }
48
+ get #logger() {
49
+ return this.#sdk.logger;
50
+ }
51
+ }
52
+ export {
53
+ CachedStateSubscriber
54
+ };
@@ -1,5 +1,6 @@
1
1
  export * from "./AccountOpener.js";
2
2
  export * from "./AccountsCounterPlugin.js";
3
+ export * from "./CachedStateSubscriber.js";
3
4
  export * from "./calcLiquidatableLTs.js";
4
5
  export * from "./create2.js";
5
6
  export * from "./createAnvilClient.js";
@@ -208,15 +208,22 @@ class GearboxSDK {
208
208
  return this;
209
209
  }
210
210
  #hydrate(options, state) {
211
- const { logger: _logger, redstone, ...opts } = options;
211
+ const { logger: _logger, ...opts } = options;
212
212
  if (state.version !== STATE_VERSION) {
213
213
  throw new Error(
214
214
  `hydrated state version is ${state.version}, but expected ${STATE_VERSION}`
215
215
  );
216
216
  }
217
+ const re = this.#attachConfig ? "re" : "";
218
+ this.logger?.info(
219
+ {
220
+ networkType: this.provider.networkType
221
+ },
222
+ `${re}hydrating sdk state`
223
+ );
217
224
  this.#currentBlock = state.currentBlock;
218
225
  this.#timestamp = state.timestamp;
219
- this.#priceFeeds = new PriceFeedRegister(this, { redstone });
226
+ this.#priceFeeds = new PriceFeedRegister(this, { redstone: opts.redstone });
220
227
  this.#addressProvider = hydrateAddressProvider(this, state.addressProvider);
221
228
  this.logger?.debug(
222
229
  `address provider version: ${this.#addressProvider.version}`
@@ -240,6 +247,7 @@ class GearboxSDK {
240
247
  plugin.hydrate(pluginState);
241
248
  }
242
249
  }
250
+ this.logger?.info(`${re}hydrated sdk state`);
243
251
  return this;
244
252
  }
245
253
  /**
@@ -252,6 +260,19 @@ class GearboxSDK {
252
260
  }
253
261
  await this.#attach(this.#attachConfig);
254
262
  }
263
+ /**
264
+ * Rehydrate existing SDK from new state without re-creating instance
265
+ */
266
+ rehydrate(state) {
267
+ if (!this.#attachConfig) {
268
+ throw new Error("cannot rehydrate, attach config is not set");
269
+ }
270
+ const opts = {
271
+ ignoreUpdateablePrices: this.#attachConfig.ignoreUpdateablePrices,
272
+ redstone: this.#attachConfig.redstone
273
+ };
274
+ this.#hydrate(opts, state);
275
+ }
255
276
  /**
256
277
  * Converts contract call into some human-friendly string
257
278
  * This method is safe and should not throw
@@ -36,9 +36,6 @@ class MarketSuite extends SDKConstruct {
36
36
  this.creditManagers.push(new CreditSuite(sdk, marketData, i));
37
37
  }
38
38
  this.priceOracle = getOrCreatePriceOracle(sdk, marketData.priceOracle);
39
- sdk.logger?.debug(
40
- `oracle ${this.labelAddress(this.priceOracle.address)} has ${this.priceOracle.mainPriceFeeds.size} main and ${this.priceOracle.reservePriceFeeds.size} reserve price feeds`
41
- );
42
39
  }
43
40
  get dirty() {
44
41
  return this.configurator.dirty || this.pool.dirty || this.priceOracle.dirty || this.creditManagers.some((cm) => cm.dirty);
@@ -5,16 +5,20 @@ import { PriceOracleV310Contract } from "./PriceOracleV310Contract.js";
5
5
  function getOrCreatePriceOracle(sdk, data) {
6
6
  const { version, addr } = data.baseParams;
7
7
  const existing = sdk.contracts.get(addr);
8
+ let result;
8
9
  if (existing) {
9
- return tryExtendExistingOracle(existing, data);
10
+ result = tryExtendExistingOracle(existing, data);
11
+ } else if (isV300(version)) {
12
+ result = new PriceOracleV300Contract(sdk, data);
13
+ } else if (isV310(version)) {
14
+ result = new PriceOracleV310Contract(sdk, data);
15
+ } else {
16
+ throw new Error(`Unsupported oracle version ${version}`);
10
17
  }
11
- if (isV300(version)) {
12
- return new PriceOracleV300Contract(sdk, data);
13
- }
14
- if (isV310(version)) {
15
- return new PriceOracleV310Contract(sdk, data);
16
- }
17
- throw new Error(`Unsupported oracle version ${version}`);
18
+ sdk.logger?.debug(
19
+ `oracle ${addr} v${version} was ${existing ? "extended" : "created"} with ${result.mainPriceFeeds.size} main and ${result.reservePriceFeeds.size} reserve price feeds`
20
+ );
21
+ return result;
18
22
  }
19
23
  function tryExtendExistingOracle(existing, data) {
20
24
  const { version, addr } = data.baseParams;
@@ -0,0 +1,21 @@
1
+ import type { GearboxSDK, PluginsMap } from "../sdk/index.js";
2
+ export interface CachedStateSubscriberOptions {
3
+ /**
4
+ * Polling interval in milliseconds
5
+ */
6
+ pollInterval?: number;
7
+ /**
8
+ * Callback to be called when state changes
9
+ */
10
+ onChange?: (blockNumber: bigint) => void;
11
+ }
12
+ export declare class CachedStateSubscriber<const Plugins extends PluginsMap = {}> {
13
+ #private;
14
+ constructor(sdk: GearboxSDK<Plugins>, stateURL: string);
15
+ /**
16
+ * Subscribe to sdk state changes
17
+ * @param opts - Options
18
+ * @returns Unsubscribe function
19
+ */
20
+ subscribe(opts?: CachedStateSubscriberOptions): () => void;
21
+ }
@@ -1,5 +1,6 @@
1
1
  export * from "./AccountOpener.js";
2
2
  export * from "./AccountsCounterPlugin.js";
3
+ export * from "./CachedStateSubscriber.js";
3
4
  export * from "./calcLiquidatableLTs.js";
4
5
  export * from "./create2.js";
5
6
  export * from "./createAnvilClient.js";
@@ -92,6 +92,10 @@ export declare class GearboxSDK<const Plugins extends PluginsMap = {}> {
92
92
  * Be mindful of block number, for example
93
93
  */
94
94
  reattach(): Promise<void>;
95
+ /**
96
+ * Rehydrate existing SDK from new state without re-creating instance
97
+ */
98
+ rehydrate(state: GearboxState<Plugins>): void;
95
99
  /**
96
100
  * Converts contract call into some human-friendly string
97
101
  * This method is safe and should not throw
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "7.7.0",
3
+ "version": "7.9.0",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "main": "./dist/cjs/sdk/index.js",