@gearbox-protocol/sdk 9.0.4 → 9.1.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.
@@ -0,0 +1,195 @@
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 RevolverTransport_exports = {};
20
+ __export(RevolverTransport_exports, {
21
+ NoAvailableTransportsError: () => NoAvailableTransportsError,
22
+ RevolverTransport: () => RevolverTransport
23
+ });
24
+ module.exports = __toCommonJS(RevolverTransport_exports);
25
+ var import_viem = require("viem");
26
+ var import_providers = require("./providers.js");
27
+ class NoAvailableTransportsError extends import_viem.BaseError {
28
+ constructor() {
29
+ super("no available transports");
30
+ }
31
+ }
32
+ class RevolverTransport {
33
+ #transports;
34
+ #index = 0;
35
+ #config;
36
+ overrides;
37
+ /**
38
+ * Create a new RevolverTransport
39
+ * RevolverTransport usues several RPC providers and rotates between them when requests fail
40
+ * Failed transport goes into temporary cooldown, after which it can be tried again
41
+ * When all transports are on cooldown, the transport will throw a NoAvailableTransportsError
42
+ * @param config
43
+ * @returns
44
+ */
45
+ static create(config) {
46
+ const transport = new RevolverTransport({
47
+ ...config
48
+ });
49
+ return (...args) => {
50
+ transport.overrides = args[0];
51
+ return transport;
52
+ };
53
+ }
54
+ constructor(config) {
55
+ this.#config = { ...config };
56
+ const rpcUrls = /* @__PURE__ */ new Map();
57
+ const cooldowns = /* @__PURE__ */ new Map();
58
+ for (const { provider, keys, cooldown } of config.providers) {
59
+ for (const key of keys) {
60
+ const url = (0, import_providers.getProviderUrl)(provider, config.network, key, "http");
61
+ if (url) {
62
+ rpcUrls.set(url, provider);
63
+ if (cooldown) {
64
+ cooldowns.set(url, cooldown);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ this.#transports = Array.from(rpcUrls.entries()).map(
70
+ ([url, provider], i) => ({
71
+ provider,
72
+ transport: (0, import_viem.http)(url, {
73
+ retryCount: config.retryCount,
74
+ retryDelay: config.retryDelay,
75
+ timeout: config.timeout,
76
+ batch: false,
77
+ key: `${provider}-${i}`,
78
+ name: `${provider}-${i}`,
79
+ onFetchRequest: this.#config.onRequest ? (...args) => this.#config.onRequest?.(`${provider}-${i}`, ...args) : void 0,
80
+ onFetchResponse: this.#config.onResponse ? (...args) => this.#config.onResponse?.(`${provider}-${i}`, ...args) : void 0
81
+ }),
82
+ cooldown: cooldowns.get(url) ?? 0
83
+ })
84
+ );
85
+ if (this.#transports.length === 0) {
86
+ throw new NoAvailableTransportsError();
87
+ }
88
+ }
89
+ get value() {
90
+ return {
91
+ rotate: (reason) => this.rotate(reason),
92
+ currentTransportName: this.currentTransportName
93
+ };
94
+ }
95
+ request = async (r) => {
96
+ if (this.#transports.length === 1) {
97
+ return this.#transport({ ...this.overrides }).request(r);
98
+ }
99
+ do {
100
+ try {
101
+ const resp = await this.#transport({ ...this.overrides }).request(r);
102
+ return resp;
103
+ } catch (e) {
104
+ if (e instanceof import_viem.RpcError || e instanceof import_viem.HttpRequestError) {
105
+ await this.rotate(e);
106
+ } else {
107
+ throw e;
108
+ }
109
+ }
110
+ } while (this.#hasAvailableTransports);
111
+ throw new NoAvailableTransportsError();
112
+ };
113
+ get config() {
114
+ return {
115
+ key: "revolver",
116
+ name: "revolver",
117
+ type: "revolver",
118
+ request: this.request,
119
+ retryCount: this.#config.retryCount,
120
+ methods: void 0,
121
+ retryDelay: this.#config.retryDelay,
122
+ timeout: this.#config.timeout
123
+ };
124
+ }
125
+ /**
126
+ * Manually rotate the transport
127
+ * @param reason
128
+ * @returns true if rotation was successful
129
+ */
130
+ async rotate(reason) {
131
+ if (this.#transports.length === 1) {
132
+ return true;
133
+ }
134
+ this.#logger?.debug(
135
+ {
136
+ reason,
137
+ current: this.currentTransportName,
138
+ index: this.#index,
139
+ total: this.#transports.length
140
+ },
141
+ "rotating transport"
142
+ );
143
+ const oldTransportName = this.currentTransportName;
144
+ const now = Date.now();
145
+ this.#transports[this.#index].cooldown = now + (this.#config.cooldown ?? 6e4);
146
+ for (let i = 0; i < this.#transports.length - 1; i++) {
147
+ this.#index = (this.#index + 1) % this.#transports.length;
148
+ if (this.#transports[this.#index].cooldown < now) {
149
+ this.#logger?.info(
150
+ {
151
+ current: this.currentTransportName,
152
+ index: this.#index,
153
+ total: this.#transports.length
154
+ },
155
+ "switched to next transport"
156
+ );
157
+ await this.#config.onRotateSuccess?.(
158
+ oldTransportName,
159
+ this.currentTransportName,
160
+ reason
161
+ );
162
+ return true;
163
+ } else {
164
+ this.#logger?.warn(
165
+ {
166
+ current: this.currentTransportName,
167
+ index: this.#index,
168
+ total: this.#transports.length
169
+ },
170
+ "transport is still on cooldown"
171
+ );
172
+ }
173
+ }
174
+ await this.#config.onRotateFailed?.(reason);
175
+ return false;
176
+ }
177
+ get currentTransportName() {
178
+ return this.#transport({}).config.name;
179
+ }
180
+ get #logger() {
181
+ return this.#config.logger;
182
+ }
183
+ get #transport() {
184
+ return this.#transports[this.#index].transport;
185
+ }
186
+ get #hasAvailableTransports() {
187
+ const now = Date.now();
188
+ return this.#transports.some((t) => t.cooldown < now);
189
+ }
190
+ }
191
+ // Annotate the CommonJS export names for ESM import in node:
192
+ 0 && (module.exports = {
193
+ NoAvailableTransportsError,
194
+ RevolverTransport
195
+ });
@@ -21,11 +21,12 @@ __reExport(dev_exports, require("./calcLiquidatableLTs.js"), module.exports);
21
21
  __reExport(dev_exports, require("./claimFromFaucet.js"), module.exports);
22
22
  __reExport(dev_exports, require("./create2.js"), module.exports);
23
23
  __reExport(dev_exports, require("./createAnvilClient.js"), module.exports);
24
- __reExport(dev_exports, require("./createTransport.js"), module.exports);
25
24
  __reExport(dev_exports, require("./detectChain.js"), module.exports);
26
25
  __reExport(dev_exports, require("./EthCallSpy.js"), module.exports);
27
26
  __reExport(dev_exports, require("./ltUtils.js"), module.exports);
28
27
  __reExport(dev_exports, require("./migrateFaucet.js"), module.exports);
28
+ __reExport(dev_exports, require("./providers.js"), module.exports);
29
+ __reExport(dev_exports, require("./RevolverTransport.js"), module.exports);
29
30
  __reExport(dev_exports, require("./types.js"), module.exports);
30
31
  // Annotate the CommonJS export names for ESM import in node:
31
32
  0 && (module.exports = {
@@ -35,10 +36,11 @@ __reExport(dev_exports, require("./types.js"), module.exports);
35
36
  ...require("./claimFromFaucet.js"),
36
37
  ...require("./create2.js"),
37
38
  ...require("./createAnvilClient.js"),
38
- ...require("./createTransport.js"),
39
39
  ...require("./detectChain.js"),
40
40
  ...require("./EthCallSpy.js"),
41
41
  ...require("./ltUtils.js"),
42
42
  ...require("./migrateFaucet.js"),
43
+ ...require("./providers.js"),
44
+ ...require("./RevolverTransport.js"),
43
45
  ...require("./types.js")
44
46
  });
@@ -16,43 +16,13 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var createTransport_exports = {};
20
- __export(createTransport_exports, {
21
- createTransport: () => createTransport,
19
+ var providers_exports = {};
20
+ __export(providers_exports, {
22
21
  getAlchemyUrl: () => getAlchemyUrl,
23
22
  getDrpcUrl: () => getDrpcUrl,
24
23
  getProviderUrl: () => getProviderUrl
25
24
  });
26
- module.exports = __toCommonJS(createTransport_exports);
27
- var import_viem = require("viem");
28
- var import_sdk = require("../sdk/index.js");
29
- function createTransport(config) {
30
- const { rpcProviders = [], protocol, network, ...rest } = config;
31
- const rpcUrls = /* @__PURE__ */ new Map();
32
- for (const { provider, keys } of rpcProviders) {
33
- for (const key of keys) {
34
- const url = getProviderUrl(provider, network, key, protocol);
35
- if (url) {
36
- rpcUrls.set(url, provider);
37
- }
38
- }
39
- }
40
- const transports = Array.from(rpcUrls.entries()).map(
41
- ([url, provider], index) => protocol === "http" ? (0, import_viem.http)(url, {
42
- ...rest,
43
- key: `${provider}-${index}`,
44
- name: `${provider}-${index}`
45
- }) : (0, import_viem.webSocket)(url, {
46
- ...rest,
47
- key: `${provider}-${index}`,
48
- name: `${provider}-${index}`
49
- })
50
- );
51
- if (transports.length === 0) {
52
- throw new Error("no fitting rpc urls found");
53
- }
54
- return transports.length > 1 ? (0, import_viem.fallback)(transports) : transports[0];
55
- }
25
+ module.exports = __toCommonJS(providers_exports);
56
26
  function getProviderUrl(provider, network, apiKey, protocol) {
57
27
  switch (provider) {
58
28
  case "alchemy":
@@ -68,7 +38,7 @@ function getProviderUrl(provider, network, apiKey, protocol) {
68
38
  }
69
39
  }
70
40
  function getAlchemyUrl(network, apiKey, protocol) {
71
- const { alchemyDomain } = (0, import_sdk.getChain)(network);
41
+ const alchemyDomain = ALCHEMY_DOMAINS[network];
72
42
  if (!alchemyDomain) {
73
43
  return void 0;
74
44
  }
@@ -87,9 +57,24 @@ const DRPC_NETS = {
87
57
  Monad: "monad-testnet",
88
58
  Hemi: "hemi",
89
59
  Lisk: "lisk",
90
- // TODO: no drpc
91
- MegaETH: "",
92
- Etherlink: ""
60
+ MegaETH: null,
61
+ Etherlink: null
62
+ };
63
+ const ALCHEMY_DOMAINS = {
64
+ Mainnet: "eth-mainnet",
65
+ Arbitrum: "arb-mainnet",
66
+ Optimism: "opt-mainnet",
67
+ Base: "base-mainnet",
68
+ Sonic: "sonic-mainnet",
69
+ Monad: "monad-testnet",
70
+ Berachain: "berachain-mainnet",
71
+ Avalanche: "avax-mainnet",
72
+ BNB: "bnb-mainnet",
73
+ WorldChain: "worldchain-mainnet",
74
+ MegaETH: null,
75
+ Etherlink: null,
76
+ Hemi: null,
77
+ Lisk: null
93
78
  };
94
79
  function getDrpcUrl(network, apiKey, protocol) {
95
80
  const net = DRPC_NETS[network];
@@ -97,7 +82,6 @@ function getDrpcUrl(network, apiKey, protocol) {
97
82
  }
98
83
  // Annotate the CommonJS export names for ESM import in node:
99
84
  0 && (module.exports = {
100
- createTransport,
101
85
  getAlchemyUrl,
102
86
  getDrpcUrl,
103
87
  getProviderUrl
@@ -81,7 +81,6 @@ const chains = {
81
81
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
82
82
  symbol: "USDC"
83
83
  },
84
- alchemyDomain: "eth-mainnet",
85
84
  firstBlock: 18433056n
86
85
  // AddressProvderV3 0x9ea7b04Da02a5373317D745c1571c84aaD03321D
87
86
  },
@@ -99,7 +98,6 @@ const chains = {
99
98
  address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
100
99
  symbol: "USDC"
101
100
  },
102
- alchemyDomain: "arb-mainnet",
103
101
  firstBlock: 184650310n
104
102
  },
105
103
  "arbitrum-one-rpc"
@@ -116,7 +114,6 @@ const chains = {
116
114
  address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
117
115
  symbol: "USDC"
118
116
  },
119
- alchemyDomain: "opt-mainnet",
120
117
  firstBlock: 118410666n
121
118
  },
122
119
  "optimism-rpc"
@@ -130,8 +127,7 @@ const chains = {
130
127
  wellKnownToken: {
131
128
  address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
132
129
  symbol: "USDC"
133
- },
134
- alchemyDomain: "base-mainnet"
130
+ }
135
131
  },
136
132
  "base-rpc"
137
133
  ),
@@ -154,7 +150,6 @@ const chains = {
154
150
  address: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894",
155
151
  symbol: "USDC"
156
152
  },
157
- alchemyDomain: "sonic-mainnet",
158
153
  firstBlock: 9779380n
159
154
  }),
160
155
  "sonic-rpc"
@@ -180,9 +175,8 @@ const chains = {
180
175
  wellKnownToken: {
181
176
  address: "0xf817257fed379853cDe0fa4F97AB987181B1E5Ea",
182
177
  symbol: "USDC"
183
- },
178
+ }
184
179
  // TODO: has no block explorer API
185
- alchemyDomain: "monad-testnet"
186
180
  }),
187
181
  Berachain: withPublicNode(
188
182
  {
@@ -200,8 +194,7 @@ const chains = {
200
194
  wellKnownToken: {
201
195
  address: "0x549943e04f40284185054145c6e4e9568c1d3241",
202
196
  symbol: "USDC.e"
203
- },
204
- alchemyDomain: "berachain-mainnet"
197
+ }
205
198
  },
206
199
  "berachain-rpc"
207
200
  ),
@@ -214,8 +207,7 @@ const chains = {
214
207
  wellKnownToken: {
215
208
  address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
216
209
  symbol: "USDC"
217
- },
218
- alchemyDomain: "avax-mainnet"
210
+ }
219
211
  },
220
212
  "avalanche-c-chain-rpc"
221
213
  ),
@@ -233,7 +225,6 @@ const chains = {
233
225
  address: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
234
226
  symbol: "USDC"
235
227
  },
236
- alchemyDomain: "bnb-mainnet",
237
228
  firstBlock: 48761804n
238
229
  },
239
230
  "bsc-rpc"
@@ -246,8 +237,7 @@ const chains = {
246
237
  wellKnownToken: {
247
238
  address: "0x79a02482a880bce3f13e09da970dc34db4cd24d1",
248
239
  symbol: "USDC"
249
- },
250
- alchemyDomain: "worldchain-mainnet"
240
+ }
251
241
  // TODO: has no block explorer API
252
242
  }),
253
243
  Etherlink: (0, import_viem.defineChain)({
@@ -0,0 +1,177 @@
1
+ import {
2
+ BaseError,
3
+ HttpRequestError,
4
+ http,
5
+ RpcError
6
+ } from "viem";
7
+ import {
8
+ getProviderUrl
9
+ } from "./providers.js";
10
+ class NoAvailableTransportsError extends BaseError {
11
+ constructor() {
12
+ super("no available transports");
13
+ }
14
+ }
15
+ class RevolverTransport {
16
+ #transports;
17
+ #index = 0;
18
+ #config;
19
+ overrides;
20
+ /**
21
+ * Create a new RevolverTransport
22
+ * RevolverTransport usues several RPC providers and rotates between them when requests fail
23
+ * Failed transport goes into temporary cooldown, after which it can be tried again
24
+ * When all transports are on cooldown, the transport will throw a NoAvailableTransportsError
25
+ * @param config
26
+ * @returns
27
+ */
28
+ static create(config) {
29
+ const transport = new RevolverTransport({
30
+ ...config
31
+ });
32
+ return (...args) => {
33
+ transport.overrides = args[0];
34
+ return transport;
35
+ };
36
+ }
37
+ constructor(config) {
38
+ this.#config = { ...config };
39
+ const rpcUrls = /* @__PURE__ */ new Map();
40
+ const cooldowns = /* @__PURE__ */ new Map();
41
+ for (const { provider, keys, cooldown } of config.providers) {
42
+ for (const key of keys) {
43
+ const url = getProviderUrl(provider, config.network, key, "http");
44
+ if (url) {
45
+ rpcUrls.set(url, provider);
46
+ if (cooldown) {
47
+ cooldowns.set(url, cooldown);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ this.#transports = Array.from(rpcUrls.entries()).map(
53
+ ([url, provider], i) => ({
54
+ provider,
55
+ transport: http(url, {
56
+ retryCount: config.retryCount,
57
+ retryDelay: config.retryDelay,
58
+ timeout: config.timeout,
59
+ batch: false,
60
+ key: `${provider}-${i}`,
61
+ name: `${provider}-${i}`,
62
+ onFetchRequest: this.#config.onRequest ? (...args) => this.#config.onRequest?.(`${provider}-${i}`, ...args) : void 0,
63
+ onFetchResponse: this.#config.onResponse ? (...args) => this.#config.onResponse?.(`${provider}-${i}`, ...args) : void 0
64
+ }),
65
+ cooldown: cooldowns.get(url) ?? 0
66
+ })
67
+ );
68
+ if (this.#transports.length === 0) {
69
+ throw new NoAvailableTransportsError();
70
+ }
71
+ }
72
+ get value() {
73
+ return {
74
+ rotate: (reason) => this.rotate(reason),
75
+ currentTransportName: this.currentTransportName
76
+ };
77
+ }
78
+ request = async (r) => {
79
+ if (this.#transports.length === 1) {
80
+ return this.#transport({ ...this.overrides }).request(r);
81
+ }
82
+ do {
83
+ try {
84
+ const resp = await this.#transport({ ...this.overrides }).request(r);
85
+ return resp;
86
+ } catch (e) {
87
+ if (e instanceof RpcError || e instanceof HttpRequestError) {
88
+ await this.rotate(e);
89
+ } else {
90
+ throw e;
91
+ }
92
+ }
93
+ } while (this.#hasAvailableTransports);
94
+ throw new NoAvailableTransportsError();
95
+ };
96
+ get config() {
97
+ return {
98
+ key: "revolver",
99
+ name: "revolver",
100
+ type: "revolver",
101
+ request: this.request,
102
+ retryCount: this.#config.retryCount,
103
+ methods: void 0,
104
+ retryDelay: this.#config.retryDelay,
105
+ timeout: this.#config.timeout
106
+ };
107
+ }
108
+ /**
109
+ * Manually rotate the transport
110
+ * @param reason
111
+ * @returns true if rotation was successful
112
+ */
113
+ async rotate(reason) {
114
+ if (this.#transports.length === 1) {
115
+ return true;
116
+ }
117
+ this.#logger?.debug(
118
+ {
119
+ reason,
120
+ current: this.currentTransportName,
121
+ index: this.#index,
122
+ total: this.#transports.length
123
+ },
124
+ "rotating transport"
125
+ );
126
+ const oldTransportName = this.currentTransportName;
127
+ const now = Date.now();
128
+ this.#transports[this.#index].cooldown = now + (this.#config.cooldown ?? 6e4);
129
+ for (let i = 0; i < this.#transports.length - 1; i++) {
130
+ this.#index = (this.#index + 1) % this.#transports.length;
131
+ if (this.#transports[this.#index].cooldown < now) {
132
+ this.#logger?.info(
133
+ {
134
+ current: this.currentTransportName,
135
+ index: this.#index,
136
+ total: this.#transports.length
137
+ },
138
+ "switched to next transport"
139
+ );
140
+ await this.#config.onRotateSuccess?.(
141
+ oldTransportName,
142
+ this.currentTransportName,
143
+ reason
144
+ );
145
+ return true;
146
+ } else {
147
+ this.#logger?.warn(
148
+ {
149
+ current: this.currentTransportName,
150
+ index: this.#index,
151
+ total: this.#transports.length
152
+ },
153
+ "transport is still on cooldown"
154
+ );
155
+ }
156
+ }
157
+ await this.#config.onRotateFailed?.(reason);
158
+ return false;
159
+ }
160
+ get currentTransportName() {
161
+ return this.#transport({}).config.name;
162
+ }
163
+ get #logger() {
164
+ return this.#config.logger;
165
+ }
166
+ get #transport() {
167
+ return this.#transports[this.#index].transport;
168
+ }
169
+ get #hasAvailableTransports() {
170
+ const now = Date.now();
171
+ return this.#transports.some((t) => t.cooldown < now);
172
+ }
173
+ }
174
+ export {
175
+ NoAvailableTransportsError,
176
+ RevolverTransport
177
+ };
@@ -4,9 +4,10 @@ export * from "./calcLiquidatableLTs.js";
4
4
  export * from "./claimFromFaucet.js";
5
5
  export * from "./create2.js";
6
6
  export * from "./createAnvilClient.js";
7
- export * from "./createTransport.js";
8
7
  export * from "./detectChain.js";
9
8
  export * from "./EthCallSpy.js";
10
9
  export * from "./ltUtils.js";
11
10
  export * from "./migrateFaucet.js";
11
+ export * from "./providers.js";
12
+ export * from "./RevolverTransport.js";
12
13
  export * from "./types.js";
@@ -1,32 +1,3 @@
1
- import { fallback, http, webSocket } from "viem";
2
- import { getChain } from "../sdk/index.js";
3
- function createTransport(config) {
4
- const { rpcProviders = [], protocol, network, ...rest } = config;
5
- const rpcUrls = /* @__PURE__ */ new Map();
6
- for (const { provider, keys } of rpcProviders) {
7
- for (const key of keys) {
8
- const url = getProviderUrl(provider, network, key, protocol);
9
- if (url) {
10
- rpcUrls.set(url, provider);
11
- }
12
- }
13
- }
14
- const transports = Array.from(rpcUrls.entries()).map(
15
- ([url, provider], index) => protocol === "http" ? http(url, {
16
- ...rest,
17
- key: `${provider}-${index}`,
18
- name: `${provider}-${index}`
19
- }) : webSocket(url, {
20
- ...rest,
21
- key: `${provider}-${index}`,
22
- name: `${provider}-${index}`
23
- })
24
- );
25
- if (transports.length === 0) {
26
- throw new Error("no fitting rpc urls found");
27
- }
28
- return transports.length > 1 ? fallback(transports) : transports[0];
29
- }
30
1
  function getProviderUrl(provider, network, apiKey, protocol) {
31
2
  switch (provider) {
32
3
  case "alchemy":
@@ -42,7 +13,7 @@ function getProviderUrl(provider, network, apiKey, protocol) {
42
13
  }
43
14
  }
44
15
  function getAlchemyUrl(network, apiKey, protocol) {
45
- const { alchemyDomain } = getChain(network);
16
+ const alchemyDomain = ALCHEMY_DOMAINS[network];
46
17
  if (!alchemyDomain) {
47
18
  return void 0;
48
19
  }
@@ -61,16 +32,30 @@ const DRPC_NETS = {
61
32
  Monad: "monad-testnet",
62
33
  Hemi: "hemi",
63
34
  Lisk: "lisk",
64
- // TODO: no drpc
65
- MegaETH: "",
66
- Etherlink: ""
35
+ MegaETH: null,
36
+ Etherlink: null
37
+ };
38
+ const ALCHEMY_DOMAINS = {
39
+ Mainnet: "eth-mainnet",
40
+ Arbitrum: "arb-mainnet",
41
+ Optimism: "opt-mainnet",
42
+ Base: "base-mainnet",
43
+ Sonic: "sonic-mainnet",
44
+ Monad: "monad-testnet",
45
+ Berachain: "berachain-mainnet",
46
+ Avalanche: "avax-mainnet",
47
+ BNB: "bnb-mainnet",
48
+ WorldChain: "worldchain-mainnet",
49
+ MegaETH: null,
50
+ Etherlink: null,
51
+ Hemi: null,
52
+ Lisk: null
67
53
  };
68
54
  function getDrpcUrl(network, apiKey, protocol) {
69
55
  const net = DRPC_NETS[network];
70
56
  return net ? `${protocol}s://lb.drpc.org/${net}/${apiKey}` : void 0;
71
57
  }
72
58
  export {
73
- createTransport,
74
59
  getAlchemyUrl,
75
60
  getDrpcUrl,
76
61
  getProviderUrl
@@ -65,7 +65,6 @@ const chains = {
65
65
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
66
66
  symbol: "USDC"
67
67
  },
68
- alchemyDomain: "eth-mainnet",
69
68
  firstBlock: 18433056n
70
69
  // AddressProvderV3 0x9ea7b04Da02a5373317D745c1571c84aaD03321D
71
70
  },
@@ -83,7 +82,6 @@ const chains = {
83
82
  address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
84
83
  symbol: "USDC"
85
84
  },
86
- alchemyDomain: "arb-mainnet",
87
85
  firstBlock: 184650310n
88
86
  },
89
87
  "arbitrum-one-rpc"
@@ -100,7 +98,6 @@ const chains = {
100
98
  address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
101
99
  symbol: "USDC"
102
100
  },
103
- alchemyDomain: "opt-mainnet",
104
101
  firstBlock: 118410666n
105
102
  },
106
103
  "optimism-rpc"
@@ -114,8 +111,7 @@ const chains = {
114
111
  wellKnownToken: {
115
112
  address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
116
113
  symbol: "USDC"
117
- },
118
- alchemyDomain: "base-mainnet"
114
+ }
119
115
  },
120
116
  "base-rpc"
121
117
  ),
@@ -138,7 +134,6 @@ const chains = {
138
134
  address: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894",
139
135
  symbol: "USDC"
140
136
  },
141
- alchemyDomain: "sonic-mainnet",
142
137
  firstBlock: 9779380n
143
138
  }),
144
139
  "sonic-rpc"
@@ -164,9 +159,8 @@ const chains = {
164
159
  wellKnownToken: {
165
160
  address: "0xf817257fed379853cDe0fa4F97AB987181B1E5Ea",
166
161
  symbol: "USDC"
167
- },
162
+ }
168
163
  // TODO: has no block explorer API
169
- alchemyDomain: "monad-testnet"
170
164
  }),
171
165
  Berachain: withPublicNode(
172
166
  {
@@ -184,8 +178,7 @@ const chains = {
184
178
  wellKnownToken: {
185
179
  address: "0x549943e04f40284185054145c6e4e9568c1d3241",
186
180
  symbol: "USDC.e"
187
- },
188
- alchemyDomain: "berachain-mainnet"
181
+ }
189
182
  },
190
183
  "berachain-rpc"
191
184
  ),
@@ -198,8 +191,7 @@ const chains = {
198
191
  wellKnownToken: {
199
192
  address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
200
193
  symbol: "USDC"
201
- },
202
- alchemyDomain: "avax-mainnet"
194
+ }
203
195
  },
204
196
  "avalanche-c-chain-rpc"
205
197
  ),
@@ -217,7 +209,6 @@ const chains = {
217
209
  address: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
218
210
  symbol: "USDC"
219
211
  },
220
- alchemyDomain: "bnb-mainnet",
221
212
  firstBlock: 48761804n
222
213
  },
223
214
  "bsc-rpc"
@@ -230,8 +221,7 @@ const chains = {
230
221
  wellKnownToken: {
231
222
  address: "0x79a02482a880bce3f13e09da970dc34db4cd24d1",
232
223
  symbol: "USDC"
233
- },
234
- alchemyDomain: "worldchain-mainnet"
224
+ }
235
225
  // TODO: has no block explorer API
236
226
  }),
237
227
  Etherlink: defineChain({
@@ -0,0 +1,77 @@
1
+ import { BaseError, type ClientConfig, type EIP1193RequestFn, type Transport, type TransportConfig } from "viem";
2
+ import type { HttpRpcClientOptions } from "viem/utils";
3
+ import type { ILogger, NetworkType } from "../sdk/index.js";
4
+ import { type ProviderConfig } from "./providers.js";
5
+ type OnRequestFn = (providerName: string, ...args: Parameters<Required<HttpRpcClientOptions>["onRequest"]>) => ReturnType<Required<HttpRpcClientOptions>["onRequest"]>;
6
+ type OnResponseFn = (providerName: string, ...args: Parameters<Required<HttpRpcClientOptions>["onResponse"]>) => ReturnType<Required<HttpRpcClientOptions>["onResponse"]>;
7
+ export interface RevolverTransportConfig {
8
+ network: NetworkType;
9
+ providers: ProviderConfig[];
10
+ logger?: ILogger;
11
+ key?: TransportConfig["key"] | undefined;
12
+ name?: TransportConfig["name"] | undefined;
13
+ pollingInterval?: ClientConfig["pollingInterval"] | undefined;
14
+ retryCount?: TransportConfig["retryCount"] | undefined;
15
+ retryDelay?: TransportConfig["retryDelay"] | undefined;
16
+ timeout?: TransportConfig["timeout"] | undefined;
17
+ /**
18
+ * Spying function that also returns provider name in additional to the request
19
+ */
20
+ onRequest?: OnRequestFn;
21
+ /**
22
+ * Spying function that also returns provider name in additional to the response
23
+ */
24
+ onResponse?: OnResponseFn;
25
+ /**
26
+ * Callback that is called when the transport is rotated
27
+ */
28
+ onRotateSuccess?: (oldTransportName: string, newTransportName: string, reason?: BaseError) => void | Promise<void>;
29
+ /**
30
+ * Callback that is called when the transport cannot be rotated
31
+ */
32
+ onRotateFailed?: (reason?: BaseError) => void | Promise<void>;
33
+ /**
34
+ * How long, in milliseconds, to wait before try this transport again
35
+ */
36
+ cooldown?: number | undefined;
37
+ }
38
+ export declare class NoAvailableTransportsError extends BaseError {
39
+ constructor();
40
+ }
41
+ export interface RevolverTransportValue {
42
+ /**
43
+ * Manually rotate the transport
44
+ * @param reason
45
+ * @returns true if rotation was successful
46
+ */
47
+ rotate: (reason?: BaseError) => Promise<boolean>;
48
+ /**
49
+ * The name of the current transport
50
+ */
51
+ currentTransportName: string;
52
+ }
53
+ export declare class RevolverTransport implements ReturnType<Transport<"revolver", RevolverTransportValue>> {
54
+ #private;
55
+ private overrides?;
56
+ /**
57
+ * Create a new RevolverTransport
58
+ * RevolverTransport usues several RPC providers and rotates between them when requests fail
59
+ * Failed transport goes into temporary cooldown, after which it can be tried again
60
+ * When all transports are on cooldown, the transport will throw a NoAvailableTransportsError
61
+ * @param config
62
+ * @returns
63
+ */
64
+ static create(config: RevolverTransportConfig): Transport<"revolver">;
65
+ constructor(config: RevolverTransportConfig);
66
+ get value(): RevolverTransportValue;
67
+ request: EIP1193RequestFn;
68
+ get config(): TransportConfig<"revolver">;
69
+ /**
70
+ * Manually rotate the transport
71
+ * @param reason
72
+ * @returns true if rotation was successful
73
+ */
74
+ rotate(reason?: BaseError): Promise<boolean>;
75
+ get currentTransportName(): string;
76
+ }
77
+ export {};
@@ -4,9 +4,10 @@ export * from "./calcLiquidatableLTs.js";
4
4
  export * from "./claimFromFaucet.js";
5
5
  export * from "./create2.js";
6
6
  export * from "./createAnvilClient.js";
7
- export * from "./createTransport.js";
8
7
  export * from "./detectChain.js";
9
8
  export * from "./EthCallSpy.js";
10
9
  export * from "./ltUtils.js";
11
10
  export * from "./migrateFaucet.js";
11
+ export * from "./providers.js";
12
+ export * from "./RevolverTransport.js";
12
13
  export * from "./types.js";
@@ -1,9 +1,10 @@
1
- import type { HttpTransportConfig, Transport, WebSocketTransportConfig } from "viem";
1
+ import type { HttpTransportConfig, WebSocketTransportConfig } from "viem";
2
2
  import type { NetworkType } from "../sdk/index.js";
3
3
  export type RpcProvider = "alchemy" | "drpc" | "custom";
4
4
  export interface ProviderConfig {
5
5
  provider: RpcProvider;
6
6
  keys: string[];
7
+ cooldown?: number;
7
8
  }
8
9
  export interface CreateTransportURLOptions {
9
10
  /**
@@ -19,13 +20,6 @@ export type CreateWSTransportConfig = {
19
20
  protocol: "ws";
20
21
  } & WebSocketTransportConfig & CreateTransportURLOptions;
21
22
  export type CreateTransportConfig = CreateHTTPTransportConfig | CreateWSTransportConfig;
22
- /**
23
- * Helper method to create viem Transport using API keys of well-known RPC providers and explicit fallback URLs
24
- * Currently only supports Alchemy
25
- * @param config
26
- * @returns
27
- */
28
- export declare function createTransport(config: CreateTransportConfig): Transport;
29
23
  export declare function getProviderUrl(provider: RpcProvider, network: NetworkType, apiKey: string, protocol: "http" | "ws"): string | undefined;
30
24
  export declare function getAlchemyUrl(network: NetworkType, apiKey: string, protocol: "http" | "ws"): string | undefined;
31
25
  export declare function getDrpcUrl(network: NetworkType, apiKey: string, protocol: "http" | "ws"): string | undefined;
@@ -18,10 +18,6 @@ export interface GearboxChain extends Chain {
18
18
  address: Address;
19
19
  symbol: string;
20
20
  };
21
- /**
22
- * Alchemy subdomain to construct provider URL
23
- */
24
- alchemyDomain?: string;
25
21
  /**
26
22
  * Block number when Gearbox address provider was deployed
27
23
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "9.0.4",
3
+ "version": "9.1.1",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "main": "./dist/cjs/sdk/index.js",
@@ -1 +0,0 @@
1
- export {};