@talismn/chain-connectors 1.1.0 → 1.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.
- package/dist/index.d.mts +14 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -18,11 +18,24 @@ export declare class ChainConnectionError extends Error {
|
|
|
18
18
|
chainId: string;
|
|
19
19
|
constructor(chainId: string, options?: ErrorOptions);
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Passed to subscription callbacks when the chain has been unreachable for a while. Not
|
|
23
|
+
* terminal: the subscription stays registered and is re-issued when a socket connects.
|
|
24
|
+
*/
|
|
21
25
|
export declare class StaleRpcError extends Error {
|
|
22
26
|
type: "STALE_RPC_ERROR";
|
|
23
27
|
chainId: string;
|
|
24
28
|
constructor(chainId: string, options?: ErrorOptions);
|
|
25
29
|
}
|
|
30
|
+
export type ChainConnectorDotOptions = {
|
|
31
|
+
/**
|
|
32
|
+
* How long a new socket may take to open before the provider gives up on the endpoint
|
|
33
|
+
* and tries the next one. Defaults to polkadot-api's 5 seconds. A slow device or
|
|
34
|
+
* network can take longer than that to connect while it is busy, as a phone app is
|
|
35
|
+
* at startup, and every endpoint then times out in turn.
|
|
36
|
+
*/
|
|
37
|
+
connectionTimeout?: number;
|
|
38
|
+
};
|
|
26
39
|
/**
|
|
27
40
|
* ChainConnector provides an interface similar to a websocket JSON-RPC provider, but with three points of difference:
|
|
28
41
|
*
|
|
@@ -39,7 +52,7 @@ export declare class StaleRpcError extends Error {
|
|
|
39
52
|
*/
|
|
40
53
|
export declare class ChainConnectorDot implements IChainConnectorDot {
|
|
41
54
|
#private;
|
|
42
|
-
constructor(chaindataChainProvider: IChaindataNetworkProvider);
|
|
55
|
+
constructor(chaindataChainProvider: IChaindataNetworkProvider, options?: ChainConnectorDotOptions);
|
|
43
56
|
send<T = any>(chainId: DotNetworkId, method: string, params: unknown[], _isCacheable?: boolean | undefined, extraOptions?: {
|
|
44
57
|
/**
|
|
45
58
|
* Set to `true` if this query is speculative, i.e. if on some chains it's expected that it will raise a wasm unreachable error of the form:
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/dot/IChainConnectorDot.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/IChainConnectorEth.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/IChainConnectorSol.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"mappings":";;;;;YAIY,wBAAwB,OAAO,cAAc;iBAExC;EACf,KAAK,aACH,SAAS,cACT,gBACA,mBACA,uBACA;IACE;MAED,QAAQ;EAEX,UACE,SAAS,cACT,yBACA,wBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EAEZ,MAAM,SAAS,eAAe;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/dot/IChainConnectorDot.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/IChainConnectorEth.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/IChainConnectorSol.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"mappings":";;;;;YAIY,wBAAwB,OAAO,cAAc;iBAExC;EACf,KAAK,aACH,SAAS,cACT,gBACA,mBACA,uBACA;IACE;MAED,QAAQ;EAEX,UACE,SAAS,cACT,yBACA,wBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EAEZ,MAAM,SAAS,eAAe;;;;qBCOnB,6BAA6B;EACxC;EACA;EAEA,YAAY,iBAAiB,UAAU;;;;;;qBAY5B,sBAAsB;EACjC;EACA;EAEA,YAAY,iBAAiB,UAAU;;YAmC7B;;;;;;;EAOV;;;;;;;;;;;;;;;;qBAiBW,6BAA6B;;EAOxC,YACE,wBAAwB,2BACxB,UAAU;EAON,KAAK,SACT,SAAS,cACT,gBACA,mBACA,oCACA;;;;;;;;;;IAUE;MAED,QAAQ;EAsDL,UACJ,SAAS,cACT,yBACA,wBACA,mBACA,UAAU,sBACV,2BACC,SAAS;;;;;;EA2FN,MAAM,SAAS,eAAY;;UA2BzB;;UA0BA;;;;;;UAgCM;UA2BA;UAgCN;UAoDA;UAeA;UAwBM;;UAYN;;UAQA;UAIA;;;;;YC/hBE;;EAEV,WAAW,OAAO,gBAAgB,mBAAmB,cAAc,gBAAgB,QAAQ;EAC3F;IACE,YAAY;MACV,OAAO;QAAU;;MACjB,QAAQ;MACR;;MACM;;;;;;;;;;;;qBAYC,iCAAiC;;EAG5C,YAAY,YAAY,WAAW,iBAAiB;EAI9C,KAAK,aAAa,WAAW,cAAc,gBAAgB,oBAAoB,QAAQ;EAIvF,UACJ,WAAW,cACX,yBACA,yBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EA8FN,SAAK;UAEH;;;;qBC1IG,iCAAiC;;EAG5C,YAAY,SAAS;EAIf,KAAK,aACT,UAAU,cACV,gBACA,mBACA,yBACC,QAAQ;EAOL,UACJ,UAAU,cACV,yBACA,yBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EA4BZ,SAAS;EAIT;;;;iBChEe;EACf,+BAA+B,cAAc,iBAAiB,QAAQ;EACtE,+BACE,cAAc,cACd,0BAA0B,YACvB,QAAQ;EACb,yBAAyB,eAAe;;;;qBCE7B,6BAA6B;;EAGxC,YAAY,mBAAmB,4BAA4B;EAIrD,6BAA6B,cAAc,eAAe,QAAQ;EAOlE,6BACJ,cAAc,cACd,0BAA0B,UACzB,QAAQ;EAOJ,uBAAuB,eAAe;;;;qBC5BlC,iCAAiC;;EAG5C,YAAY,SAAS;EAIf,gCAAgC,QAAQ;EAIxC,6BACJ,YAAY,cACZ,0BAA0B,UACzB,QAAQ;EAIX;;;;YCrBU,SAAS,IAAI;YAqHb;;EAEV,gBAAgB;;;;;;;qBAuDL,kBAAe,YACd,cAAY,gBACV,UACL,wBACR;qBAIU,YAAS,WACT,cAAY,gBACT,UACJ,wBACT;;;iBCzLc;EACf,SAAS,WAAW,iBAAiB,QAAQ;;EAE7C,eAAe,WAAW,iBAAiB,QAAQ;;;;qBCIxC,6BAA6B;;EAKxC,YAAY,mBAAmB,4BAA4B;EAWrD,aAAa,WAAW,eAAe,QAAQ;EAU/C,OAAO,WAAW,eAAe,QAAQ;;EAQ/C,uBAAuB,YAAY;;;;qBCtCxB,iCAAiC;;EAI5C,YAAY,SAAS,KAAK;EAKpB,UAAU,QAAQ;EAIlB,gBAAgB,QAAQ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -18,11 +18,24 @@ export declare class ChainConnectionError extends Error {
|
|
|
18
18
|
chainId: string;
|
|
19
19
|
constructor(chainId: string, options?: ErrorOptions);
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Passed to subscription callbacks when the chain has been unreachable for a while. Not
|
|
23
|
+
* terminal: the subscription stays registered and is re-issued when a socket connects.
|
|
24
|
+
*/
|
|
21
25
|
export declare class StaleRpcError extends Error {
|
|
22
26
|
type: "STALE_RPC_ERROR";
|
|
23
27
|
chainId: string;
|
|
24
28
|
constructor(chainId: string, options?: ErrorOptions);
|
|
25
29
|
}
|
|
30
|
+
export type ChainConnectorDotOptions = {
|
|
31
|
+
/**
|
|
32
|
+
* How long a new socket may take to open before the provider gives up on the endpoint
|
|
33
|
+
* and tries the next one. Defaults to polkadot-api's 5 seconds. A slow device or
|
|
34
|
+
* network can take longer than that to connect while it is busy, as a phone app is
|
|
35
|
+
* at startup, and every endpoint then times out in turn.
|
|
36
|
+
*/
|
|
37
|
+
connectionTimeout?: number;
|
|
38
|
+
};
|
|
26
39
|
/**
|
|
27
40
|
* ChainConnector provides an interface similar to a websocket JSON-RPC provider, but with three points of difference:
|
|
28
41
|
*
|
|
@@ -39,7 +52,7 @@ export declare class StaleRpcError extends Error {
|
|
|
39
52
|
*/
|
|
40
53
|
export declare class ChainConnectorDot implements IChainConnectorDot {
|
|
41
54
|
#private;
|
|
42
|
-
constructor(chaindataChainProvider: IChaindataNetworkProvider);
|
|
55
|
+
constructor(chaindataChainProvider: IChaindataNetworkProvider, options?: ChainConnectorDotOptions);
|
|
43
56
|
send<T = any>(chainId: DotNetworkId, method: string, params: unknown[], _isCacheable?: boolean | undefined, extraOptions?: {
|
|
44
57
|
/**
|
|
45
58
|
* Set to `true` if this query is speculative, i.e. if on some chains it's expected that it will raise a wasm unreachable error of the form:
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/dot/IChainConnectorDot.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/IChainConnectorEth.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/IChainConnectorSol.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"mappings":";;;;;YAIY,wBAAwB,OAAO,cAAc;iBAExC;EACf,KAAK,aACH,SAAS,cACT,gBACA,mBACA,uBACA;IACE;MAED,QAAQ;EAEX,UACE,SAAS,cACT,yBACA,wBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EAEZ,MAAM,SAAS,eAAe;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/dot/IChainConnectorDot.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/IChainConnectorEth.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/IChainConnectorSol.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"mappings":";;;;;YAIY,wBAAwB,OAAO,cAAc;iBAExC;EACf,KAAK,aACH,SAAS,cACT,gBACA,mBACA,uBACA;IACE;MAED,QAAQ;EAEX,UACE,SAAS,cACT,yBACA,wBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EAEZ,MAAM,SAAS,eAAe;;;;qBCOnB,6BAA6B;EACxC;EACA;EAEA,YAAY,iBAAiB,UAAU;;;;;;qBAY5B,sBAAsB;EACjC;EACA;EAEA,YAAY,iBAAiB,UAAU;;YAmC7B;;;;;;;EAOV;;;;;;;;;;;;;;;;qBAiBW,6BAA6B;;EAOxC,YACE,wBAAwB,2BACxB,UAAU;EAON,KAAK,SACT,SAAS,cACT,gBACA,mBACA,oCACA;;;;;;;;;;IAUE;MAED,QAAQ;EAsDL,UACJ,SAAS,cACT,yBACA,wBACA,mBACA,UAAU,sBACV,2BACC,SAAS;;;;;;EA2FN,MAAM,SAAS,eAAY;;UA2BzB;;UA0BA;;;;;;UAgCM;UA2BA;UAgCN;UAoDA;UAeA;UAwBM;;UAYN;;UAQA;UAIA;;;;;YC/hBE;;EAEV,WAAW,OAAO,gBAAgB,mBAAmB,cAAc,gBAAgB,QAAQ;EAC3F;IACE,YAAY;MACV,OAAO;QAAU;;MACjB,QAAQ;MACR;;MACM;;;;;;;;;;;;qBAYC,iCAAiC;;EAG5C,YAAY,YAAY,WAAW,iBAAiB;EAI9C,KAAK,aAAa,WAAW,cAAc,gBAAgB,oBAAoB,QAAQ;EAIvF,UACJ,WAAW,cACX,yBACA,yBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EA8FN,SAAK;UAEH;;;;qBC1IG,iCAAiC;;EAG5C,YAAY,SAAS;EAIf,KAAK,aACT,UAAU,cACV,gBACA,mBACA,yBACC,QAAQ;EAOL,UACJ,UAAU,cACV,yBACA,yBACA,mBACA,UAAU,sBACV,2BACC,SAAS;EA4BZ,SAAS;EAIT;;;;iBChEe;EACf,+BAA+B,cAAc,iBAAiB,QAAQ;EACtE,+BACE,cAAc,cACd,0BAA0B,YACvB,QAAQ;EACb,yBAAyB,eAAe;;;;qBCE7B,6BAA6B;;EAGxC,YAAY,mBAAmB,4BAA4B;EAIrD,6BAA6B,cAAc,eAAe,QAAQ;EAOlE,6BACJ,cAAc,cACd,0BAA0B,UACzB,QAAQ;EAOJ,uBAAuB,eAAe;;;;qBC5BlC,iCAAiC;;EAG5C,YAAY,SAAS;EAIf,gCAAgC,QAAQ;EAIxC,6BACJ,YAAY,cACZ,0BAA0B,UACzB,QAAQ;EAIX;;;;YCrBU,SAAS,IAAI;YAqHb;;EAEV,gBAAgB;;;;;;;qBAuDL,kBAAe,YACd,cAAY,gBACV,UACL,wBACR;qBAIU,YAAS,WACT,cAAY,gBACT,UACJ,wBACT;;;iBCzLc;EACf,SAAS,WAAW,iBAAiB,QAAQ;;EAE7C,eAAe,WAAW,iBAAiB,QAAQ;;;;qBCIxC,6BAA6B;;EAKxC,YAAY,mBAAmB,4BAA4B;EAWrD,aAAa,WAAW,eAAe,QAAQ;EAU/C,OAAO,WAAW,eAAe,QAAQ;;EAQ/C,uBAAuB,YAAY;;;;qBCtCxB,iCAAiC;;EAI5C,YAAY,SAAS,KAAK;EAKpB,UAAU,QAAQ;EAIlB,gBAAgB,QAAQ"}
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,12 @@ const BAD_RPC_ERRORS = {
|
|
|
42
42
|
};
|
|
43
43
|
const RESPONSE_TIMEOUT$1 = 3e4;
|
|
44
44
|
const KEEP_ALIVE_INTERVAL = 2e4;
|
|
45
|
+
/**
|
|
46
|
+
* How long a connection stays open once its last user releases it. A one-off request is
|
|
47
|
+
* often followed by more traffic to the same chain (balances read the runtime version,
|
|
48
|
+
* then subscribe to storage), which then reuses the socket instead of opening a new one.
|
|
49
|
+
*/
|
|
50
|
+
const IDLE_CLOSE_DELAY = 3e4;
|
|
45
51
|
/** in-flight requests reject with DestroyedError when a connection is torn down - expected, not worth logging */
|
|
46
52
|
const isDestroyedError = (error) => error instanceof Error && error.name === "DestroyedError";
|
|
47
53
|
const STALE_NOTIFY_TIMEOUT = 3e4;
|
|
@@ -54,6 +60,10 @@ var ChainConnectionError = class extends Error {
|
|
|
54
60
|
this.chainId = chainId;
|
|
55
61
|
}
|
|
56
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* Passed to subscription callbacks when the chain has been unreachable for a while. Not
|
|
65
|
+
* terminal: the subscription stays registered and is re-issued when a socket connects.
|
|
66
|
+
*/
|
|
57
67
|
var StaleRpcError = class extends Error {
|
|
58
68
|
type;
|
|
59
69
|
chainId;
|
|
@@ -79,10 +89,12 @@ var StaleRpcError = class extends Error {
|
|
|
79
89
|
*/
|
|
80
90
|
var ChainConnectorDot = class {
|
|
81
91
|
#chaindataChainProvider;
|
|
92
|
+
#connectionTimeout;
|
|
82
93
|
#connections = {};
|
|
83
94
|
#pendingConnections = {};
|
|
84
|
-
constructor(chaindataChainProvider) {
|
|
95
|
+
constructor(chaindataChainProvider, options) {
|
|
85
96
|
this.#chaindataChainProvider = chaindataChainProvider;
|
|
97
|
+
this.#connectionTimeout = options?.connectionTimeout;
|
|
86
98
|
}
|
|
87
99
|
async send(chainId, method, params, _isCacheable, extraOptions) {
|
|
88
100
|
const talismanSub = this.getTalismanSub();
|
|
@@ -171,8 +183,7 @@ var ChainConnectorDot = class {
|
|
|
171
183
|
subscription.cancelRequest?.();
|
|
172
184
|
subscription.stopFollow?.();
|
|
173
185
|
const current = this.#connections[chainId];
|
|
174
|
-
|
|
175
|
-
if (subscription.serverSubId !== null && current && !isLastUser) try {
|
|
186
|
+
if (subscription.serverSubId !== null && current) try {
|
|
176
187
|
current.client.request(unsubscribeMethod, [subscription.serverSubId]).catch((error) => {
|
|
177
188
|
if (!isDestroyedError(error)) log_default.warn(`Failed to unsubscribe from ${chainId}`, error);
|
|
178
189
|
});
|
|
@@ -202,7 +213,7 @@ var ChainConnectorDot = class {
|
|
|
202
213
|
for (const subscription of fresh.subscriptions) this.startSubscription(fresh, subscription);
|
|
203
214
|
} catch (error) {
|
|
204
215
|
log_default.warn(`Failed to recreate connection for ${chainId} after reset`, error);
|
|
205
|
-
for (const subscription of connection.subscriptions) subscription.callback(new
|
|
216
|
+
for (const subscription of connection.subscriptions) subscription.callback(new ChainConnectionError(chainId, { cause: error }), null);
|
|
206
217
|
}
|
|
207
218
|
}
|
|
208
219
|
/** Sends a request over a connection, throwing `Error("TIMEOUT")` if no response arrives in time */
|
|
@@ -260,6 +271,10 @@ var ChainConnectorDot = class {
|
|
|
260
271
|
});
|
|
261
272
|
connection = await this.#pendingConnections[chainId];
|
|
262
273
|
}
|
|
274
|
+
if (connection.idleTimeout) {
|
|
275
|
+
clearTimeout(connection.idleTimeout);
|
|
276
|
+
connection.idleTimeout = null;
|
|
277
|
+
}
|
|
263
278
|
const socketUserId = this.getExclusiveRandomId([...connection.users]);
|
|
264
279
|
connection.users.add(socketUserId);
|
|
265
280
|
return [socketUserId, connection];
|
|
@@ -270,7 +285,10 @@ var ChainConnectorDot = class {
|
|
|
270
285
|
const rpcs = chain.rpcs.concat();
|
|
271
286
|
if (!rpcs.length) throw new Error(`No healthy RPCs available for chain ${chainId}`);
|
|
272
287
|
let connection = null;
|
|
273
|
-
const provider = (0, _polkadot_api_ws_provider.getWsProvider)(rpcs, {
|
|
288
|
+
const provider = (0, _polkadot_api_ws_provider.getWsProvider)(rpcs, {
|
|
289
|
+
onStatusChanged: (status) => this.handleStatusChange(connection, status),
|
|
290
|
+
...this.#connectionTimeout !== void 0 && { timeout: this.#connectionTimeout }
|
|
291
|
+
});
|
|
274
292
|
connection = {
|
|
275
293
|
chainId,
|
|
276
294
|
provider,
|
|
@@ -279,7 +297,8 @@ var ChainConnectorDot = class {
|
|
|
279
297
|
subscriptions: /* @__PURE__ */ new Set(),
|
|
280
298
|
wasConnected: false,
|
|
281
299
|
keepAliveInterval: null,
|
|
282
|
-
staleTimeout: null
|
|
300
|
+
staleTimeout: null,
|
|
301
|
+
idleTimeout: null
|
|
283
302
|
};
|
|
284
303
|
return connection;
|
|
285
304
|
}
|
|
@@ -321,15 +340,21 @@ var ChainConnectorDot = class {
|
|
|
321
340
|
const connection = this.#connections[chainId];
|
|
322
341
|
if (!connection) return;
|
|
323
342
|
connection.users.delete(socketUserId);
|
|
324
|
-
if (connection.users.size > 0) return;
|
|
325
|
-
|
|
326
|
-
|
|
343
|
+
if (connection.users.size > 0 || connection.idleTimeout) return;
|
|
344
|
+
connection.idleTimeout = setTimeout(() => {
|
|
345
|
+
connection.idleTimeout = null;
|
|
346
|
+
if (connection.users.size > 0 || this.#connections[chainId] !== connection) return;
|
|
347
|
+
this.destroyConnection(connection);
|
|
348
|
+
delete this.#connections[chainId];
|
|
349
|
+
}, IDLE_CLOSE_DELAY);
|
|
327
350
|
}
|
|
328
351
|
destroyConnection(connection) {
|
|
329
352
|
if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval);
|
|
330
353
|
if (connection.staleTimeout) clearTimeout(connection.staleTimeout);
|
|
354
|
+
if (connection.idleTimeout) clearTimeout(connection.idleTimeout);
|
|
331
355
|
connection.keepAliveInterval = null;
|
|
332
356
|
connection.staleTimeout = null;
|
|
357
|
+
connection.idleTimeout = null;
|
|
333
358
|
for (const subscription of connection.subscriptions) {
|
|
334
359
|
subscription.stopFollow?.();
|
|
335
360
|
subscription.cancelRequest?.();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["packageJson.name","RESPONSE_TIMEOUT","getWsProvider","createClient","WsEvent","log","createClient","getWsProvider","throwAfter","viemChains","fromPairs","toPairs","camelCase","shouldThrow","fallback","http","createPublicClient","createWalletClient","isSolanaError","createDefaultRpcTransport","createSolanaRpcFromTransport","createSolanaRpcFromTransport","createSolanaRpcFromTransport"],"sources":["../package.json","../src/log.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/getChainFromEvmNetwork.ts","../src/eth/getTransportForEvmNetwork.ts","../src/eth/getEvmNetworkPublicClient.ts","../src/eth/getEvmNetworkWalletClient.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"sourcesContent":["","import anylogger from \"anylogger\"\n\nimport packageJson from \"../package.json\"\n\nexport default anylogger(packageJson.name)\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport {\n getWsProvider,\n type StatusChange,\n WsEvent,\n type WsJsonRpcProvider,\n} from \"@polkadot-api/ws-provider\"\nimport type { DotNetworkId, IChaindataNetworkProvider } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\n// errors that require an rpc fallback\n// https://docs.blastapi.io/blast-documentation/things-you-need-to-know/error-reference\nconst BAD_RPC_ERRORS: Record<string, string> = {\n \"-32097\": \"Rate limit exceeded\",\n \"-32098\": \"Capacity exceeded\",\n}\n\nconst RESPONSE_TIMEOUT = 30_000 // max wait for an rpc response (including connection time)\nconst KEEP_ALIVE_INTERVAL = 20_000 // periodic system_health to keep idle sockets alive (ws-provider kills quiet sockets after its 40s heartbeat)\n\n/** in-flight requests reject with DestroyedError when a connection is torn down - expected, not worth logging */\nconst isDestroyedError = (error: unknown): boolean =>\n error instanceof Error && error.name === \"DestroyedError\"\nconst STALE_NOTIFY_TIMEOUT = 30_000 // how long a chain can be disconnected before subscribers are notified\n\nexport class ChainConnectionError extends Error {\n type: \"CHAIN_CONNECTION_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`Unable to connect to chain ${chainId}`, options)\n\n this.type = \"CHAIN_CONNECTION_ERROR\"\n this.chainId = chainId\n }\n}\n\nexport class StaleRpcError extends Error {\n type: \"STALE_RPC_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`RPCs are stale/unavailable for chain ${chainId}`, options)\n\n this.type = \"STALE_RPC_ERROR\"\n this.chainId = chainId\n }\n}\n\ntype SocketUserId = number\n\ntype Subscription = {\n subscribeMethod: string\n params: unknown[]\n callback: SubscriptionCallback\n /** cancels the pending subscribe request, if any */\n cancelRequest: (() => void) | null\n /** stops routing notifications to the callback */\n stopFollow: (() => void) | null\n serverSubId: string | number | null\n unsubscribed: boolean\n}\n\ntype Connection = {\n chainId: DotNetworkId\n provider: WsJsonRpcProvider\n client: SubstrateClient\n users: Set<SocketUserId>\n subscriptions: Set<Subscription>\n wasConnected: boolean\n keepAliveInterval: ReturnType<typeof setInterval> | null\n staleTimeout: ReturnType<typeof setTimeout> | null\n}\n\n/**\n * ChainConnector provides an interface similar to a websocket JSON-RPC provider, but with three points of difference:\n *\n * 1. ChainConnector methods all accept a `chainId` instead of an array of RPCs. RPCs are then fetched internally from chaindata.\n * 2. ChainConnector creates only one socket connection per chain (via polkadot-api's ws-provider, which handles\n * endpoint rotation, reconnection and stale-socket detection) and ensures that all downstream requests to a chain\n * share that connection.\n * 3. Subscriptions return a callable `unsubscribe` method instead of an id, and are automatically re-established\n * when the provider reconnects (possibly to another endpoint).\n *\n * Additionally, when run on the clientside of a dapp where `window.talismanSub` is available, instead of spinning up new websocket\n * connections this class will forward all requests through to the wallet backend - where another instance of this class will\n * handle the websocket connections.\n */\nexport class ChainConnectorDot implements IChainConnectorDot {\n #chaindataChainProvider: IChaindataNetworkProvider\n\n #connections: Record<DotNetworkId, Connection> = {}\n #pendingConnections: Record<DotNetworkId, Promise<Connection>> = {}\n\n constructor(chaindataChainProvider: IChaindataNetworkProvider) {\n this.#chaindataChainProvider = chaindataChainProvider\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n async send<T = any>(\n chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean | undefined,\n extraOptions?: {\n /**\n * Set to `true` if this query is speculative, i.e. if on some chains it's expected that it will raise a wasm unreachable error of the form:\n *\n * 4003: Client error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\n *\n * By setting expectErrors to true, this method won't pollute the logs with errors we intend to have happen.\n * An example use case of this is when you plan to catch the wasm unreachable error on chains that don't support the query, and then fall back\n * to another query or perhaps an empty result.\n */\n expectErrors?: boolean\n }\n ): Promise<T> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n return await talismanSub.send(genesisHash, method, params)\n } catch (error) {\n log.warn(\n `Failed to make wallet-proxied send request for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n try {\n return await this.request<T>(connection, method, params)\n } catch (err) {\n const error = err as (Error & { code?: number; data?: unknown }) | null\n\n if (error?.message === \"TIMEOUT\") {\n log.error(`ChainConnector timeout`, { chainId, error })\n connection.provider.switch()\n throw new Error(\"Timeout\")\n }\n\n const badRpcError = BAD_RPC_ERRORS[error?.code?.toString() ?? \"\"]\n if (badRpcError) {\n log.error(`ChainConnector ${badRpcError}`, { error, chainId })\n connection.provider.switch()\n throw new Error(badRpcError)\n }\n\n if (!extraOptions?.expectErrors)\n log.error(\n `Failed to send ${method} on chain ${chainId}\\nparams: ${JSON.stringify(params)}`,\n {\n error,\n }\n )\n\n throw error\n } finally {\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n async subscribe(\n chainId: DotNetworkId,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000 // 30 seconds in milliseconds\n ): Promise<(unsubscribeMethod: string) => void> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n\n const subscriptionId = await talismanSub.subscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n )\n\n return (unsubscribeMethod: string) =>\n talismanSub.unsubscribe(subscriptionId, unsubscribeMethod)\n } catch (error) {\n log.warn(\n `Failed to create wallet-proxied subscription for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n const subscription: Subscription = {\n subscribeMethod,\n params,\n callback,\n cancelRequest: null,\n stopFollow: null,\n serverSubId: null,\n unsubscribed: false,\n }\n connection.subscriptions.add(subscription)\n\n // if the chain can't be reached at all, let the caller know after a while (the provider keeps retrying)\n if (timeout && !connection.wasConnected) {\n const staleWarning = setTimeout(() => {\n if (!subscription.unsubscribed && !connection.wasConnected)\n callback(new StaleRpcError(chainId), null)\n }, timeout)\n const clear = () => clearTimeout(staleWarning)\n // piggyback on the follow setup to clear the warning once anything happens\n const originalCallback = subscription.callback\n subscription.callback = (error, result) => {\n clear()\n subscription.callback = originalCallback\n originalCallback(error, result)\n }\n }\n\n this.startSubscription(connection, subscription)\n\n return (unsubscribeMethod: string) => {\n if (subscription.unsubscribed) return\n subscription.unsubscribed = true\n\n subscription.cancelRequest?.()\n subscription.stopFollow?.()\n\n // the connection may have been replaced by a reset() since we subscribed\n const current = this.#connections[chainId]\n // if we are the last user the connection is about to be destroyed: skip the\n // unsubscribe call, server-side subscriptions die with the socket anyway\n const isLastUser = !!current && current.users.size === 1 && current.users.has(socketUserId)\n if (subscription.serverSubId !== null && current && !isLastUser)\n try {\n current.client.request(unsubscribeMethod, [subscription.serverSubId]).catch((error) => {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n })\n } catch (error) {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n }\n\n current?.subscriptions.delete(subscription)\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n /**\n * Kills and recreates the connection for a chain, if any.\n * Useful after changing a network's rpcs to make sure the new list is applied for further requests.\n * Active subscriptions are automatically re-established on the new connection.\n */\n async reset(chainId: DotNetworkId) {\n log.info(\"ChainConnector reset\", chainId)\n const connection = this.#connections[chainId]\n if (!connection) return\n\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n\n // recreate a connection for the active subscriptions, if any\n if (connection.subscriptions.size) {\n try {\n const fresh = await this.createConnection(chainId)\n fresh.users = connection.users\n fresh.subscriptions = connection.subscriptions\n this.#connections[chainId] = fresh\n for (const subscription of fresh.subscriptions) this.startSubscription(fresh, subscription)\n } catch (error) {\n log.warn(`Failed to recreate connection for ${chainId} after reset`, error)\n for (const subscription of connection.subscriptions)\n subscription.callback(new StaleRpcError(chainId, { cause: error }), null)\n }\n }\n }\n\n /** Sends a request over a connection, throwing `Error(\"TIMEOUT\")` if no response arrives in time */\n private request<T>(\n connection: Connection,\n method: string,\n params: unknown[],\n timeoutMs = RESPONSE_TIMEOUT\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n cancel()\n reject(new Error(\"TIMEOUT\"))\n }, timeoutMs)\n\n const cancel = connection.client._request<T, unknown>(method, params, {\n onSuccess: (result) => {\n clearTimeout(timer)\n resolve(result)\n },\n onError: (error) => {\n clearTimeout(timer)\n reject(error)\n },\n })\n })\n }\n\n /** Issues the subscribe request and routes notifications to the subscription callback */\n private startSubscription(connection: Connection, subscription: Subscription) {\n subscription.serverSubId = null\n subscription.stopFollow = null\n\n subscription.cancelRequest = connection.client._request<string | number, unknown>(\n subscription.subscribeMethod,\n subscription.params,\n {\n onSuccess: (serverSubId, follow) => {\n subscription.cancelRequest = null\n if (subscription.unsubscribed) return\n\n subscription.serverSubId = serverSubId\n // raw-client matches notifications by the raw (not stringified) subscription id, but types it as string\n subscription.stopFollow = follow(serverSubId as string, {\n next: (result) => subscription.callback(null, result),\n error: (error) => subscription.callback(error, null),\n })\n },\n onError: (error) => {\n subscription.cancelRequest = null\n if (!subscription.unsubscribed) subscription.callback(error, null)\n },\n }\n )\n }\n\n /**\n * Get (or create) the shared connection for a chain.\n *\n * The caller must call releaseConnection with the returned SocketUserId once they are finished with it.\n */\n private async acquireConnection(chainId: DotNetworkId): Promise<[SocketUserId, Connection]> {\n // a single creation promise per chain guarantees that concurrent callers share the same connection\n let connection = this.#connections[chainId]\n if (!connection) {\n if (!this.#pendingConnections[chainId]) {\n this.#pendingConnections[chainId] = this.createConnection(chainId)\n .then((created) => {\n this.#connections[chainId] = created\n return created\n })\n .finally(() => {\n delete this.#pendingConnections[chainId]\n })\n }\n connection = await this.#pendingConnections[chainId]\n }\n\n const socketUserId = this.getExclusiveRandomId([...connection.users])\n connection.users.add(socketUserId)\n\n return [socketUserId, connection]\n }\n\n private async createConnection(chainId: DotNetworkId): Promise<Connection> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const rpcs = chain.rpcs.concat()\n if (!rpcs.length) throw new Error(`No healthy RPCs available for chain ${chainId}`)\n\n // will be assigned below - the provider config needs to reference the connection\n let connection: Connection = null as unknown as Connection\n\n const provider = getWsProvider(rpcs, {\n onStatusChanged: (status: StatusChange) => this.handleStatusChange(connection, status),\n })\n\n const client = createClient(provider)\n\n connection = {\n chainId,\n provider,\n client,\n users: new Set(),\n subscriptions: new Set(),\n wasConnected: false,\n keepAliveInterval: null,\n staleTimeout: null,\n }\n\n return connection\n }\n\n private handleStatusChange(connection: Connection, status: StatusChange) {\n // connection is still being constructed on the initial CONNECTING event\n if (!connection) return\n // ignore events from a connection that has been reset/destroyed\n if (this.#connections[connection.chainId] !== connection) return\n\n if (status.type === WsEvent.CONNECTED) {\n if (connection.staleTimeout) {\n clearTimeout(connection.staleTimeout)\n connection.staleTimeout = null\n }\n\n const isReconnect = connection.wasConnected\n connection.wasConnected = true\n\n // periodically send a request to keep the socket alive when there is no other traffic\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = setInterval(() => {\n this.request(connection, \"system_health\", [], KEEP_ALIVE_INTERVAL).catch((error) => {\n if (!isDestroyedError(error))\n log.warn(`Failed keep-alive for socket ${connection.chainId}`, error)\n })\n }, KEEP_ALIVE_INTERVAL)\n\n // server-side subscriptions died with the previous socket : re-establish them\n // (skip author_* subscriptions : resubmitting an extrinsic is not safe)\n if (isReconnect)\n for (const subscription of connection.subscriptions) {\n if (subscription.unsubscribed) continue\n if (subscription.subscribeMethod.startsWith(\"author_\")) continue\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n this.startSubscription(connection, subscription)\n }\n } else {\n if (connection.keepAliveInterval) {\n clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = null\n }\n\n // notify subscribers if the chain stays unreachable for too long\n if (!connection.staleTimeout && connection.subscriptions.size) {\n connection.staleTimeout = setTimeout(() => {\n connection.staleTimeout = null\n for (const subscription of connection.subscriptions)\n if (!subscription.unsubscribed)\n subscription.callback(new StaleRpcError(connection.chainId), null)\n }, STALE_NOTIFY_TIMEOUT)\n }\n }\n }\n\n private releaseConnection(chainId: DotNetworkId, socketUserId: SocketUserId): void {\n const connection = this.#connections[chainId]\n if (!connection) return\n\n connection.users.delete(socketUserId)\n if (connection.users.size > 0) return\n\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n }\n\n private destroyConnection(connection: Connection): void {\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n if (connection.staleTimeout) clearTimeout(connection.staleTimeout)\n connection.keepAliveInterval = null\n connection.staleTimeout = null\n\n // detach subscriptions before destroying the client so their callbacks don't receive a DestroyedError\n for (const subscription of connection.subscriptions) {\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n subscription.stopFollow = null\n subscription.cancelRequest = null\n subscription.serverSubId = null\n }\n\n try {\n connection.client.destroy()\n } catch (error) {\n log.warn(`Error occurred destroying connection ${connection.chainId}`, error)\n }\n }\n\n private async getGenesisHash(chainId: DotNetworkId): Promise<string> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const { genesisHash } = chain\n if (typeof genesisHash !== \"string\")\n throw new Error(`Chain ${chainId} has no genesisHash in store`)\n\n return genesisHash\n }\n\n /** continues to generate a random number until it finds one which is not present in the exclude list */\n private getExclusiveRandomId(exclude: number[] = []): number {\n let id = this.getRandomId()\n while (exclude.includes(id)) {\n id = this.getRandomId()\n }\n return id\n }\n /** generates a random number */\n private getRandomId(): number {\n return Math.trunc(Math.random() * 10 ** 8)\n }\n\n private getTalismanSub() {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n const talismanSub = typeof window !== \"undefined\" && (window as any).talismanSub\n\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSend: Function | undefined = talismanSub?.rpcByGenesisHashSend\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSubscribe: Function | undefined = talismanSub?.rpcByGenesisHashSubscribe\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashUnsubscribe: Function | undefined =\n talismanSub?.rpcByGenesisHashUnsubscribe\n\n if (typeof rpcByGenesisHashSend !== \"function\") return\n if (typeof rpcByGenesisHashSubscribe !== \"function\") return\n if (typeof rpcByGenesisHashUnsubscribe !== \"function\") return\n\n return {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n send: <T = any>(genesisHash: string, method: string, params: unknown[]): Promise<T> =>\n rpcByGenesisHashSend(genesisHash, method, params),\n\n subscribe: (\n genesisHash: string,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false\n ): Promise<string> =>\n rpcByGenesisHashSubscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n ),\n\n unsubscribe: (subscriptionId: string, unsubscribeMethod: string): Promise<void> =>\n rpcByGenesisHashUnsubscribe(subscriptionId, unsubscribeMethod),\n }\n }\n}\n","import type { DotNetworkId } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport { StaleRpcError } from \"./ChainConnectorDot\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst RESPONSE_TIMEOUT = 30_000\nconst FAILURES_BEFORE_FIRST_RESULT = 3\n\ntype HexString = `0x${string}`\ntype StorageChanges = { block: HexString; changes: [HexString, HexString | null][] }\n\n/** The parts of a polkadot-api `PolkadotClient` that the connector uses */\nexport type PapiClient = {\n /** `PolkadotClient` types it without `abortSignal`, but it is substrate-client's `request`, which honours it */\n _request: <Reply>(method: string, params: unknown[], abortSignal?: AbortSignal) => Promise<Reply>\n bestBlocks$: {\n subscribe: (observer: {\n next: (blocks: { hash: string }[]) => void\n error: (error: unknown) => void\n complete: () => void\n }) => { unsubscribe: () => void }\n }\n}\n\n/**\n * Runs `@talismn/balances` over a dapp's polkadot-api clients, so the dapp and its balances share one socket per chain.\n *\n * `state_subscribeStorage` is the only subscription balances uses. It is served by querying the keys at each new\n * best block and reporting the values that changed, like the node does. One query runs at a time, for the latest\n * best block. A failed query is retried at the next block, because balances treats a subscription error as final\n * and would stop updating that network. Only when the first three queries fail does the subscription report the error.\n */\nexport class ChainConnectorDotPapi implements IChainConnectorDot {\n #clientFor: (networkId: DotNetworkId) => PapiClient | undefined\n\n constructor(clientFor: (networkId: DotNetworkId) => PapiClient | undefined) {\n this.#clientFor = clientFor\n }\n\n async send<T = unknown>(networkId: DotNetworkId, method: string, params: unknown[]): Promise<T> {\n return requestWithTimeout<T>(this.getClient(networkId), method, params, new AbortController())\n }\n\n async subscribe(\n networkId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000\n ): Promise<(unsubscribeMethod: string) => void> {\n const client = this.getClient(networkId)\n if (subscribeMethod !== \"state_subscribeStorage\")\n throw new Error(`ChainConnectorDotPapi does not support ${subscribeMethod}`)\n\n const [keys] = params as [HexString[]]\n const values = new Map<HexString, HexString | null>()\n let bestBlockHash: string | undefined\n let queriedBlockHash: string | undefined\n let inFlight: AbortController | undefined\n let delivered = false\n let failures = 0\n let active = true\n let subscription: { unsubscribe: () => void } | undefined\n const staleTimer = timeout\n ? setTimeout(() => callback(new StaleRpcError(networkId), null), timeout)\n : undefined\n\n const stop = () => {\n active = false\n clearTimeout(staleTimer)\n inFlight?.abort()\n subscription?.unsubscribe()\n }\n\n const finish = (error: Error) => {\n if (!active) return\n stop()\n callback(error, null)\n }\n\n const reportChanges = (result: StorageChanges) => {\n const changes = result.changes.filter(([key, value]) => values.get(key) !== value)\n for (const [key, value] of changes) values.set(key, value)\n if (!changes.length) return\n\n delivered = true\n clearTimeout(staleTimer)\n callback(null, { block: result.block, changes })\n }\n\n const reportFailure = (error: Error) => {\n if (delivered || ++failures < FAILURES_BEFORE_FIRST_RESULT)\n return log.warn(\n `state_queryStorageAt failed on ${networkId}, retrying at the next block`,\n error\n )\n finish(error)\n }\n\n const queryBestBlock = async () => {\n if (!active || inFlight || !bestBlockHash || bestBlockHash === queriedBlockHash) return\n const blockHash = bestBlockHash\n queriedBlockHash = blockHash\n const controller = new AbortController()\n inFlight = controller\n\n try {\n const [result] = await requestWithTimeout<StorageChanges[]>(\n client,\n \"state_queryStorageAt\",\n [keys, blockHash],\n controller\n )\n if (!active) return\n if (!result) throw new Error(`Empty state_queryStorageAt response on ${networkId}`)\n reportChanges(result)\n } catch (error) {\n if (active) reportFailure(error as Error)\n } finally {\n if (inFlight === controller) inFlight = undefined\n queryBestBlock()\n }\n }\n\n try {\n subscription = client.bestBlocks$.subscribe({\n next: ([best]) => {\n bestBlockHash = best?.hash\n queryBestBlock()\n },\n error: (error) => finish(error as Error),\n complete: () =>\n finish(new Error(`polkadot-api client for ${networkId} stopped following blocks`)),\n })\n } catch (error) {\n stop()\n throw error\n }\n if (!active) subscription.unsubscribe()\n\n return stop\n }\n\n async reset() {}\n\n private getClient(networkId: DotNetworkId): PapiClient {\n const client = this.#clientFor(networkId)\n if (!client) throw new Error(`No polkadot-api client for network ${networkId}`)\n return client\n }\n}\n\n/** rejects on its own timer too, so a client that ignores the abort signal cannot hang the caller */\nconst requestWithTimeout = <T>(\n client: PapiClient,\n method: string,\n params: unknown[],\n controller: AbortController\n) =>\n new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n controller.abort()\n reject(new Error(\"Timeout\"))\n }, RESPONSE_TIMEOUT)\n try {\n client\n ._request<T>(method, params, controller.signal)\n .then(resolve, reject)\n .finally(() => clearTimeout(timer))\n } catch (error) {\n clearTimeout(timer)\n reject(error)\n }\n })\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport { getWsProvider } from \"@polkadot-api/ws-provider\"\nimport type { DotNetwork, DotNetworkId } from \"@talismn/chaindata-provider\"\nimport { throwAfter } from \"@talismn/util\"\n\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst TIMEOUT = 10_000\n\nexport class ChainConnectorDotStub implements IChainConnectorDot {\n #client: SubstrateClient\n\n constructor(network: DotNetwork) {\n this.#client = createClient(getWsProvider(network.rpcs.concat()))\n }\n\n async send<T = unknown>(\n _chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean\n ): Promise<T> {\n return await Promise.race([\n this.#client.request<T>(method, params),\n throwAfter(TIMEOUT, `Request ${method} timed out after ${TIMEOUT}ms`),\n ])\n }\n\n async subscribe(\n _chainId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout?: number | false\n ): Promise<(unsubscribeMethod: string) => void> {\n let stopFollow: (() => void) | null = null\n let unsubscribed = false\n\n const serverSubId = await Promise.race([\n new Promise<string | number>((resolve, reject) => {\n this.#client._request<string | number, unknown>(subscribeMethod, params, {\n onSuccess: (subId, follow) => {\n stopFollow = follow(subId as string, {\n next: (result) => callback(null, result),\n error: (error) => callback(error, null),\n })\n resolve(subId)\n },\n onError: reject,\n })\n }),\n throwAfter(timeout || TIMEOUT, `Subscription timed out after ${timeout || TIMEOUT}ms`),\n ])\n\n return (unsubscribeMethod: string) => {\n if (unsubscribed) return\n unsubscribed = true\n stopFollow?.()\n this.#client.request(unsubscribeMethod, [serverSubId]).catch(() => {}) // connection may already be gone\n }\n }\n\n reset(): Promise<void> {\n throw new Error(\"ChainConnectorDotStub does not implement reset\")\n }\n\n destroy() {\n this.#client.destroy()\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport { camelCase, fromPairs, toPairs } from \"lodash-es\"\nimport type { Chain, ChainContract } from \"viem\"\nimport * as viemChains from \"viem/chains\"\n\n// exclude zoraTestnet which uses Hyperliquid's chain id\nconst { zoraTestnet, ...validViemChains } = viemChains\n\n// viem chains benefit from multicall config & other viem goodies\nconst VIEM_CHAINS = Object.keys(validViemChains).reduce(\n (acc, curr) => {\n const chain = validViemChains[curr as keyof typeof validViemChains]\n acc[chain.id] = chain\n return acc\n },\n {} as Record<number, Chain>\n)\n\nconst chainsCache = new Map<string, Chain>()\n\nexport const clearChainsCache = (networkId?: EthNetworkId) => {\n if (networkId) chainsCache.delete(networkId)\n else chainsCache.clear()\n}\n\nexport const getChainFromEvmNetwork = (network: EthNetwork): Chain => {\n const { symbol, decimals } = network.nativeCurrency\n\n if (!chainsCache.has(network.id)) {\n const chainRpcs = network.rpcs ?? []\n\n const viemChain = VIEM_CHAINS[Number(network.id)] ?? {}\n\n const chain: Chain = {\n ...viemChain,\n id: Number(network.id),\n name: network.name ?? `Ethereum Chain ${network.id}`,\n rpcUrls: {\n public: { http: chainRpcs },\n default: { http: chainRpcs },\n },\n nativeCurrency: {\n symbol,\n decimals,\n name: symbol,\n },\n contracts: {\n ...viemChain.contracts,\n ...(network.contracts\n ? fromPairs(\n toPairs(network.contracts).map(([name, address]): [string, ChainContract] => [\n camelCase(name),\n { address },\n ])\n )\n : {}),\n },\n }\n\n chainsCache.set(network.id, chain)\n }\n\n return chainsCache.get(network.id) as Chain\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { fallback, http, shouldThrow } from \"viem\"\n\nexport type TransportOptions = {\n batch?:\n | boolean\n | {\n batchSize?: number | undefined\n wait?: number | undefined\n }\n}\n\n// Frontier nodes report reverts with a message viem does not recognize, which makes fallback retry every rpc\nconst FRONTIER_EXECUTION_ERROR = /VM Exception while processing transaction/\n\nconst isFinalError = (error: Error) =>\n shouldThrow(error) || FRONTIER_EXECUTION_ERROR.test(error.message)\n\nexport const getTransportForEvmNetwork = (\n evmNetwork: EthNetwork,\n options: TransportOptions = {}\n) => {\n if (!evmNetwork.rpcs?.length) throw new Error(\"No RPCs found for EVM network\")\n\n const { batch } = options\n\n return fallback(\n evmNetwork.rpcs.map((url) => http(url, { batch, retryCount: 0 })),\n { retryCount: 0, shouldThrow: isFinalError }\n )\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { createPublicClient, type PublicClient } from \"viem\"\n\nimport { clearChainsCache, getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork, type TransportOptions } from \"./getTransportForEvmNetwork\"\n\nconst MUTLICALL_BATCH_WAIT = 25\nconst MUTLICALL_BATCH_SIZE = 100\n\nconst HTTP_BATCH_WAIT = 25\nconst HTTP_BATCH_SIZE_WITH_MULTICALL = 10\nconst HTTP_BATCH_SIZE_WITHOUT_MULTICALL = 30\n\n// cache to reuse previously created public clients\nconst publicClientCache = new Map<string, PublicClient>()\n\nexport const clearPublicClientCache = (evmNetworkId?: string) => {\n clearChainsCache(evmNetworkId)\n\n if (evmNetworkId) publicClientCache.delete(evmNetworkId)\n else publicClientCache.clear()\n}\n\nexport const getEvmNetworkPublicClient = (network: EthNetwork): PublicClient => {\n const chain = getChainFromEvmNetwork(network)\n\n if (!publicClientCache.has(network.id)) {\n if (!network.rpcs.length) throw new Error(\"No RPCs found for Ethereum network\")\n\n const batch = chain.contracts?.multicall3\n ? { multicall: { wait: MUTLICALL_BATCH_WAIT, batchSize: MUTLICALL_BATCH_SIZE } }\n : undefined\n\n const transportOptions: TransportOptions = {\n batch: {\n batchSize: chain.contracts?.multicall3\n ? HTTP_BATCH_SIZE_WITH_MULTICALL\n : HTTP_BATCH_SIZE_WITHOUT_MULTICALL,\n wait: HTTP_BATCH_WAIT,\n },\n }\n\n const transport = getTransportForEvmNetwork(network, transportOptions)\n\n publicClientCache.set(\n network.id,\n createPublicClient({\n chain,\n transport,\n batch,\n })\n )\n }\n\n return publicClientCache.get(network.id) as PublicClient\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { type Account, createWalletClient, type WalletClient } from \"viem\"\n\nimport { getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork } from \"./getTransportForEvmNetwork\"\n\ntype WalletClientOptions = {\n account?: `0x${string}` | Account\n}\n\nexport const getEvmNetworkWalletClient = (\n network: EthNetwork,\n options: WalletClientOptions = {}\n): WalletClient => {\n const chain = getChainFromEvmNetwork(network)\n\n const transport = getTransportForEvmNetwork(network)\n\n return createWalletClient({ chain, transport, account: options.account })\n}\n","import type {\n EthNetworkId,\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n} from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { clearPublicClientCache, getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEth implements IChainConnectorEth {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async getPublicClientForEvmNetwork(evmNetworkId: EthNetworkId): Promise<PublicClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkPublicClient(network)\n }\n\n async getWalletClientForEvmNetwork(\n evmNetworkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkWalletClient(network, { account })\n }\n\n public clearRpcProvidersCache(evmNetworkId?: EthNetworkId) {\n clearPublicClientCache(evmNetworkId)\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEthStub implements IChainConnectorEth {\n #network: EthNetwork\n\n constructor(network: EthNetwork) {\n this.#network = network\n }\n\n async getPublicClientForEvmNetwork(): Promise<PublicClient | null> {\n return getEvmNetworkPublicClient(this.#network)\n }\n\n async getWalletClientForEvmNetwork(\n _networkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n return getEvmNetworkWalletClient(this.#network, { account })\n }\n\n clearRpcProvidersCache(): void {\n // No-op for stub\n }\n}\n","import type { Rpc, RpcTransport, SolanaRpcApi } from \"@solana/kit\"\nimport { createDefaultRpcTransport, createSolanaRpcFromTransport, isSolanaError } from \"@solana/kit\"\nimport type { SolNetworkId } from \"@talismn/chaindata-provider\"\n\nexport type SolRpc = Rpc<SolanaRpcApi>\n\n// Public Solana RPC nodes rate-limit aggressively with HTTP 429. kit's default transport is\n// single-shot, unlike the old web3.js `Connection` which retried 429 up to 5x with backoff, so a\n// single 429 would fail an otherwise-valid request (e.g. a user's transaction submission, or token\n// discovery silently returning no tokens). This wrapper restores that behaviour.\nconst MAX_429_RETRIES = 5\nconst BASE_BACKOFF_MS = 500\n\ntype HttpErrorContext = { statusCode?: number; headers?: Headers }\n\nconst getRateLimitContext = (error: unknown): HttpErrorContext | null => {\n if (!isSolanaError(error)) return null\n\n const context = error.context as HttpErrorContext\n return context.statusCode === 429 ? context : null\n}\n\n/** Returns the delay to wait before retrying, or `null` if the error is not a retryable 429. */\nconst get429RetryDelay = (error: unknown, attempt: number): number | null => {\n const context = getRateLimitContext(error)\n if (!context) return null\n\n // honour the server's Retry-After header (delta-seconds) when present\n const retryAfter = Number(context.headers?.get(\"retry-after\"))\n if (Number.isFinite(retryAfter) && retryAfter > 0) return retryAfter * 1000\n\n // otherwise exponential backoff: 500ms, 1s, 2s, 4s, 8s\n return BASE_BACKOFF_MS * 2 ** attempt\n}\n\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason)\n\n const onAbort = () => {\n clearTimeout(timeout)\n reject(signal?.reason)\n }\n const timeout = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort)\n resolve()\n }, ms)\n signal?.addEventListener(\"abort\", onAbort, { once: true })\n })\n\n/**\n * Wraps a transport so HTTP 429 responses are retried with backoff. Solana RPC requests are\n * idempotent (`sendTransaction` is keyed by signature), so replaying a rate-limited request is safe.\n */\nconst withRetryOn429 = (transport: RpcTransport): RpcTransport => {\n const wrapped = async (config: Parameters<RpcTransport>[0]) => {\n for (let attempt = 0; ; attempt++) {\n try {\n return await transport(config)\n } catch (error) {\n const delay = attempt < MAX_429_RETRIES ? get429RetryDelay(error, attempt) : null\n if (delay === null) throw error\n await sleep(delay, config.signal)\n }\n }\n }\n return wrapped as RpcTransport\n}\n\n/**\n * How long a request may wait on an RPC before moving on to the next one. The last RPC tried gets\n * no timeout, so a slow but working node still answers when every other one has failed.\n */\nconst FAILOVER_TIMEOUT_MS = 20_000\n\nconst sendWithTimeout = async <TResponse>(\n transport: RpcTransport,\n config: RpcTransportConfig,\n timeoutMs: number\n): Promise<TResponse> => {\n const controller = new AbortController()\n const onAbort = () => controller.abort(config.signal?.reason)\n config.signal?.addEventListener(\"abort\", onAbort, { once: true })\n const timeout = setTimeout(\n () => controller.abort(new Error(`RPC request timed out after ${timeoutMs}ms`)),\n timeoutMs\n )\n\n try {\n return await transport<TResponse>({ ...config, signal: controller.signal })\n } finally {\n clearTimeout(timeout)\n config.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\ntype RpcTransportConfig = Parameters<RpcTransport>[0]\n\nconst isSendTransactionPayload = (\n payload: unknown\n): payload is { method: \"sendTransaction\"; params: unknown[] } =>\n typeof payload === \"object\" &&\n payload !== null &&\n \"method\" in payload &&\n payload.method === \"sendTransaction\" &&\n \"params\" in payload &&\n Array.isArray(payload.params)\n\nconst withoutPreflight = (config: RpcTransportConfig): RpcTransportConfig => {\n if (!isSendTransactionPayload(config.payload)) return config\n\n const [transaction, sendConfig] = config.payload.params\n return {\n ...config,\n payload: {\n ...config.payload,\n params: [transaction, { ...(sendConfig as object | undefined), skipPreflight: true }],\n },\n }\n}\n\nexport type SolTransportOptions = {\n /** Called with the url of the RPC that answered, after every successful request */\n onRpcSuccess?: (url: string) => void\n}\n\n/**\n * Sends each request to one RPC at a time, starting from the one that answered last, and moves on to\n * the next when the request fails. A transport only throws for connection, timeout and HTTP errors:\n * JSON-RPC errors come back in the response body and are returned as is.\n *\n * A failed RPC other than a rate limited one may still have forwarded a transaction. Resending it is\n * safe, as the network processes a signature once, but its preflight simulation on the next RPC\n * could then fail although it landed. So after such a failure, every resend of that transaction,\n * including the retries after a rate limit, skips preflight.\n */\nconst withFailover = (urls: string[], options: SolTransportOptions): RpcTransport => {\n const transports = urls.map((url) => createDefaultRpcTransport({ url }))\n let preferred = 0\n const mayHaveBeenProcessed = new WeakSet<RpcTransportConfig>()\n\n const failover = async <TResponse>(config: RpcTransportConfig): Promise<TResponse> => {\n if (!transports.length) throw new Error(\"No RPCs found for Solana network\")\n\n const start = preferred\n let lastError: unknown\n let rateLimitError: unknown\n for (let attempt = 0; attempt < transports.length; attempt++) {\n config.signal?.throwIfAborted()\n const index = (start + attempt) % transports.length\n const transport = transports[index] as RpcTransport\n const isLastAttempt = attempt === transports.length - 1\n const request = mayHaveBeenProcessed.has(config) ? withoutPreflight(config) : config\n\n try {\n const response = isLastAttempt\n ? await transport<TResponse>(request)\n : await sendWithTimeout<TResponse>(transport, request, FAILOVER_TIMEOUT_MS)\n preferred = index\n options.onRpcSuccess?.(urls[index] as string)\n return response\n } catch (error) {\n if (config.signal?.aborted) throw error\n lastError = error\n if (!getRateLimitContext(error)) mayHaveBeenProcessed.add(config)\n else rateLimitError ??= error\n }\n }\n throw rateLimitError ?? lastError\n }\n return failover as RpcTransport\n}\n\n/**\n * Returns a transport over all of the network's RPCs, in the given order. A request fails over to\n * the next RPC on error, and the RPC that answered is tried first for the next request. When every\n * RPC fails and one of them answered HTTP 429, the whole list is retried with backoff.\n */\nexport const getSolTransport = (\n _networkId: SolNetworkId,\n rpcs: string[],\n options: SolTransportOptions = {}\n): RpcTransport => {\n return withRetryOn429(withFailover(rpcs, options))\n}\n\nexport const getSolRpc = (\n networkId: SolNetworkId,\n rpcs: string[],\n options?: SolTransportOptions\n): SolRpc => createSolanaRpcFromTransport(getSolTransport(networkId, rpcs, options))\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type {\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n SolNetworkId,\n} from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSol implements IChainConnectorSol {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n #transports = new Map<SolNetworkId, RpcTransport>()\n #rpcs = new Map<SolNetworkId, SolRpc>()\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async #getNetworkRpcs(networkId: SolNetworkId): Promise<string[]> {\n const network = await this.#chaindataProvider.getNetworkById(networkId, \"solana\")\n if (!network) throw new Error(`Network not found: ${networkId}`)\n\n return network.rpcs\n }\n\n async getTransport(networkId: SolNetworkId): Promise<RpcTransport> {\n if (!this.#transports.has(networkId))\n this.#transports.set(\n networkId,\n getSolTransport(networkId, await this.#getNetworkRpcs(networkId))\n )\n\n return this.#transports.get(networkId)!\n }\n\n async getRpc(networkId: SolNetworkId): Promise<SolRpc> {\n if (!this.#rpcs.has(networkId))\n this.#rpcs.set(networkId, createSolanaRpcFromTransport(await this.getTransport(networkId)))\n\n return this.#rpcs.get(networkId)!\n }\n\n /** Drops cached transports/rpcs so the next call re-reads the network's rpcs from chaindata */\n clearRpcProvidersCache(networkId?: SolNetworkId) {\n if (networkId) {\n this.#transports.delete(networkId)\n this.#rpcs.delete(networkId)\n } else {\n this.#transports.clear()\n this.#rpcs.clear()\n }\n }\n}\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type { SolNetwork } from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSolStub implements IChainConnectorSol {\n #transport: RpcTransport\n #rpc: SolRpc\n\n constructor(network: Pick<SolNetwork, \"id\" | \"rpcs\">) {\n this.#transport = getSolTransport(network.id, network.rpcs)\n this.#rpc = createSolanaRpcFromTransport(this.#transport)\n }\n\n async getRpc(): Promise<SolRpc> {\n return this.#rpc\n }\n\n async getTransport(): Promise<RpcTransport> {\n return this.#transport\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["packageJson.name","RESPONSE_TIMEOUT","getWsProvider","createClient","WsEvent","log","createClient","getWsProvider","throwAfter","viemChains","fromPairs","toPairs","camelCase","shouldThrow","fallback","http","createPublicClient","createWalletClient","isSolanaError","createDefaultRpcTransport","createSolanaRpcFromTransport","createSolanaRpcFromTransport","createSolanaRpcFromTransport"],"sources":["../package.json","../src/log.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/getChainFromEvmNetwork.ts","../src/eth/getTransportForEvmNetwork.ts","../src/eth/getEvmNetworkPublicClient.ts","../src/eth/getEvmNetworkWalletClient.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"sourcesContent":["","import anylogger from \"anylogger\"\n\nimport packageJson from \"../package.json\"\n\nexport default anylogger(packageJson.name)\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport {\n getWsProvider,\n type StatusChange,\n WsEvent,\n type WsJsonRpcProvider,\n} from \"@polkadot-api/ws-provider\"\nimport type { DotNetworkId, IChaindataNetworkProvider } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\n// errors that require an rpc fallback\n// https://docs.blastapi.io/blast-documentation/things-you-need-to-know/error-reference\nconst BAD_RPC_ERRORS: Record<string, string> = {\n \"-32097\": \"Rate limit exceeded\",\n \"-32098\": \"Capacity exceeded\",\n}\n\nconst RESPONSE_TIMEOUT = 30_000 // max wait for an rpc response (including connection time)\nconst KEEP_ALIVE_INTERVAL = 20_000 // periodic system_health to keep idle sockets alive (ws-provider kills quiet sockets after its 40s heartbeat)\n/**\n * How long a connection stays open once its last user releases it. A one-off request is\n * often followed by more traffic to the same chain (balances read the runtime version,\n * then subscribe to storage), which then reuses the socket instead of opening a new one.\n */\nconst IDLE_CLOSE_DELAY = 30_000\n\n/** in-flight requests reject with DestroyedError when a connection is torn down - expected, not worth logging */\nconst isDestroyedError = (error: unknown): boolean =>\n error instanceof Error && error.name === \"DestroyedError\"\nconst STALE_NOTIFY_TIMEOUT = 30_000 // how long a chain can be disconnected before subscribers are notified\n\nexport class ChainConnectionError extends Error {\n type: \"CHAIN_CONNECTION_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`Unable to connect to chain ${chainId}`, options)\n\n this.type = \"CHAIN_CONNECTION_ERROR\"\n this.chainId = chainId\n }\n}\n\n/**\n * Passed to subscription callbacks when the chain has been unreachable for a while. Not\n * terminal: the subscription stays registered and is re-issued when a socket connects.\n */\nexport class StaleRpcError extends Error {\n type: \"STALE_RPC_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`RPCs are stale/unavailable for chain ${chainId}`, options)\n\n this.type = \"STALE_RPC_ERROR\"\n this.chainId = chainId\n }\n}\n\ntype SocketUserId = number\n\ntype Subscription = {\n subscribeMethod: string\n params: unknown[]\n callback: SubscriptionCallback\n /** cancels the pending subscribe request, if any */\n cancelRequest: (() => void) | null\n /** stops routing notifications to the callback */\n stopFollow: (() => void) | null\n serverSubId: string | number | null\n unsubscribed: boolean\n}\n\ntype Connection = {\n chainId: DotNetworkId\n provider: WsJsonRpcProvider\n client: SubstrateClient\n users: Set<SocketUserId>\n subscriptions: Set<Subscription>\n wasConnected: boolean\n keepAliveInterval: ReturnType<typeof setInterval> | null\n staleTimeout: ReturnType<typeof setTimeout> | null\n /** closes the connection once it has had no users for IDLE_CLOSE_DELAY */\n idleTimeout: ReturnType<typeof setTimeout> | null\n}\n\nexport type ChainConnectorDotOptions = {\n /**\n * How long a new socket may take to open before the provider gives up on the endpoint\n * and tries the next one. Defaults to polkadot-api's 5 seconds. A slow device or\n * network can take longer than that to connect while it is busy, as a phone app is\n * at startup, and every endpoint then times out in turn.\n */\n connectionTimeout?: number\n}\n\n/**\n * ChainConnector provides an interface similar to a websocket JSON-RPC provider, but with three points of difference:\n *\n * 1. ChainConnector methods all accept a `chainId` instead of an array of RPCs. RPCs are then fetched internally from chaindata.\n * 2. ChainConnector creates only one socket connection per chain (via polkadot-api's ws-provider, which handles\n * endpoint rotation, reconnection and stale-socket detection) and ensures that all downstream requests to a chain\n * share that connection.\n * 3. Subscriptions return a callable `unsubscribe` method instead of an id, and are automatically re-established\n * when the provider reconnects (possibly to another endpoint).\n *\n * Additionally, when run on the clientside of a dapp where `window.talismanSub` is available, instead of spinning up new websocket\n * connections this class will forward all requests through to the wallet backend - where another instance of this class will\n * handle the websocket connections.\n */\nexport class ChainConnectorDot implements IChainConnectorDot {\n #chaindataChainProvider: IChaindataNetworkProvider\n #connectionTimeout: number | undefined\n\n #connections: Record<DotNetworkId, Connection> = {}\n #pendingConnections: Record<DotNetworkId, Promise<Connection>> = {}\n\n constructor(\n chaindataChainProvider: IChaindataNetworkProvider,\n options?: ChainConnectorDotOptions\n ) {\n this.#chaindataChainProvider = chaindataChainProvider\n this.#connectionTimeout = options?.connectionTimeout\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n async send<T = any>(\n chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean | undefined,\n extraOptions?: {\n /**\n * Set to `true` if this query is speculative, i.e. if on some chains it's expected that it will raise a wasm unreachable error of the form:\n *\n * 4003: Client error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\n *\n * By setting expectErrors to true, this method won't pollute the logs with errors we intend to have happen.\n * An example use case of this is when you plan to catch the wasm unreachable error on chains that don't support the query, and then fall back\n * to another query or perhaps an empty result.\n */\n expectErrors?: boolean\n }\n ): Promise<T> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n return await talismanSub.send(genesisHash, method, params)\n } catch (error) {\n log.warn(\n `Failed to make wallet-proxied send request for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n try {\n return await this.request<T>(connection, method, params)\n } catch (err) {\n const error = err as (Error & { code?: number; data?: unknown }) | null\n\n if (error?.message === \"TIMEOUT\") {\n log.error(`ChainConnector timeout`, { chainId, error })\n connection.provider.switch()\n throw new Error(\"Timeout\")\n }\n\n const badRpcError = BAD_RPC_ERRORS[error?.code?.toString() ?? \"\"]\n if (badRpcError) {\n log.error(`ChainConnector ${badRpcError}`, { error, chainId })\n connection.provider.switch()\n throw new Error(badRpcError)\n }\n\n if (!extraOptions?.expectErrors)\n log.error(\n `Failed to send ${method} on chain ${chainId}\\nparams: ${JSON.stringify(params)}`,\n {\n error,\n }\n )\n\n throw error\n } finally {\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n async subscribe(\n chainId: DotNetworkId,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000 // 30 seconds in milliseconds\n ): Promise<(unsubscribeMethod: string) => void> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n\n const subscriptionId = await talismanSub.subscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n )\n\n return (unsubscribeMethod: string) =>\n talismanSub.unsubscribe(subscriptionId, unsubscribeMethod)\n } catch (error) {\n log.warn(\n `Failed to create wallet-proxied subscription for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n const subscription: Subscription = {\n subscribeMethod,\n params,\n callback,\n cancelRequest: null,\n stopFollow: null,\n serverSubId: null,\n unsubscribed: false,\n }\n connection.subscriptions.add(subscription)\n\n // if the chain can't be reached at all, let the caller know after a while (the provider keeps retrying)\n if (timeout && !connection.wasConnected) {\n const staleWarning = setTimeout(() => {\n if (!subscription.unsubscribed && !connection.wasConnected)\n callback(new StaleRpcError(chainId), null)\n }, timeout)\n const clear = () => clearTimeout(staleWarning)\n // piggyback on the follow setup to clear the warning once anything happens\n const originalCallback = subscription.callback\n subscription.callback = (error, result) => {\n clear()\n subscription.callback = originalCallback\n originalCallback(error, result)\n }\n }\n\n this.startSubscription(connection, subscription)\n\n return (unsubscribeMethod: string) => {\n if (subscription.unsubscribed) return\n subscription.unsubscribed = true\n\n subscription.cancelRequest?.()\n subscription.stopFollow?.()\n\n // the connection may have been replaced by a reset() since we subscribed. It stays\n // open for a while after its last user leaves, so unsubscribe on the server even then\n const current = this.#connections[chainId]\n if (subscription.serverSubId !== null && current)\n try {\n current.client.request(unsubscribeMethod, [subscription.serverSubId]).catch((error) => {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n })\n } catch (error) {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n }\n\n current?.subscriptions.delete(subscription)\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n /**\n * Kills and recreates the connection for a chain, if any.\n * Useful after changing a network's rpcs to make sure the new list is applied for further requests.\n * Active subscriptions are automatically re-established on the new connection.\n */\n async reset(chainId: DotNetworkId) {\n log.info(\"ChainConnector reset\", chainId)\n const connection = this.#connections[chainId]\n if (!connection) return\n\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n\n // recreate a connection for the active subscriptions, if any\n if (connection.subscriptions.size) {\n try {\n const fresh = await this.createConnection(chainId)\n fresh.users = connection.users\n fresh.subscriptions = connection.subscriptions\n this.#connections[chainId] = fresh\n for (const subscription of fresh.subscriptions) this.startSubscription(fresh, subscription)\n } catch (error) {\n log.warn(`Failed to recreate connection for ${chainId} after reset`, error)\n // not a StaleRpcError: no connection is left to re-issue these subscriptions,\n // so subscribers must treat this one as terminal\n for (const subscription of connection.subscriptions)\n subscription.callback(new ChainConnectionError(chainId, { cause: error }), null)\n }\n }\n }\n\n /** Sends a request over a connection, throwing `Error(\"TIMEOUT\")` if no response arrives in time */\n private request<T>(\n connection: Connection,\n method: string,\n params: unknown[],\n timeoutMs = RESPONSE_TIMEOUT\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n cancel()\n reject(new Error(\"TIMEOUT\"))\n }, timeoutMs)\n\n const cancel = connection.client._request<T, unknown>(method, params, {\n onSuccess: (result) => {\n clearTimeout(timer)\n resolve(result)\n },\n onError: (error) => {\n clearTimeout(timer)\n reject(error)\n },\n })\n })\n }\n\n /** Issues the subscribe request and routes notifications to the subscription callback */\n private startSubscription(connection: Connection, subscription: Subscription) {\n subscription.serverSubId = null\n subscription.stopFollow = null\n\n subscription.cancelRequest = connection.client._request<string | number, unknown>(\n subscription.subscribeMethod,\n subscription.params,\n {\n onSuccess: (serverSubId, follow) => {\n subscription.cancelRequest = null\n if (subscription.unsubscribed) return\n\n subscription.serverSubId = serverSubId\n // raw-client matches notifications by the raw (not stringified) subscription id, but types it as string\n subscription.stopFollow = follow(serverSubId as string, {\n next: (result) => subscription.callback(null, result),\n error: (error) => subscription.callback(error, null),\n })\n },\n onError: (error) => {\n subscription.cancelRequest = null\n if (!subscription.unsubscribed) subscription.callback(error, null)\n },\n }\n )\n }\n\n /**\n * Get (or create) the shared connection for a chain.\n *\n * The caller must call releaseConnection with the returned SocketUserId once they are finished with it.\n */\n private async acquireConnection(chainId: DotNetworkId): Promise<[SocketUserId, Connection]> {\n // a single creation promise per chain guarantees that concurrent callers share the same connection\n let connection = this.#connections[chainId]\n if (!connection) {\n if (!this.#pendingConnections[chainId]) {\n this.#pendingConnections[chainId] = this.createConnection(chainId)\n .then((created) => {\n this.#connections[chainId] = created\n return created\n })\n .finally(() => {\n delete this.#pendingConnections[chainId]\n })\n }\n connection = await this.#pendingConnections[chainId]\n }\n\n if (connection.idleTimeout) {\n clearTimeout(connection.idleTimeout)\n connection.idleTimeout = null\n }\n const socketUserId = this.getExclusiveRandomId([...connection.users])\n connection.users.add(socketUserId)\n\n return [socketUserId, connection]\n }\n\n private async createConnection(chainId: DotNetworkId): Promise<Connection> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const rpcs = chain.rpcs.concat()\n if (!rpcs.length) throw new Error(`No healthy RPCs available for chain ${chainId}`)\n\n // will be assigned below - the provider config needs to reference the connection\n let connection: Connection = null as unknown as Connection\n\n const provider = getWsProvider(rpcs, {\n onStatusChanged: (status: StatusChange) => this.handleStatusChange(connection, status),\n ...(this.#connectionTimeout !== undefined && { timeout: this.#connectionTimeout }),\n })\n\n const client = createClient(provider)\n\n connection = {\n chainId,\n provider,\n client,\n users: new Set(),\n subscriptions: new Set(),\n wasConnected: false,\n keepAliveInterval: null,\n staleTimeout: null,\n idleTimeout: null,\n }\n\n return connection\n }\n\n private handleStatusChange(connection: Connection, status: StatusChange) {\n // connection is still being constructed on the initial CONNECTING event\n if (!connection) return\n // ignore events from a connection that has been reset/destroyed\n if (this.#connections[connection.chainId] !== connection) return\n\n if (status.type === WsEvent.CONNECTED) {\n if (connection.staleTimeout) {\n clearTimeout(connection.staleTimeout)\n connection.staleTimeout = null\n }\n\n const isReconnect = connection.wasConnected\n connection.wasConnected = true\n\n // periodically send a request to keep the socket alive when there is no other traffic\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = setInterval(() => {\n this.request(connection, \"system_health\", [], KEEP_ALIVE_INTERVAL).catch((error) => {\n if (!isDestroyedError(error))\n log.warn(`Failed keep-alive for socket ${connection.chainId}`, error)\n })\n }, KEEP_ALIVE_INTERVAL)\n\n // server-side subscriptions died with the previous socket : re-establish them\n // (skip author_* subscriptions : resubmitting an extrinsic is not safe)\n if (isReconnect)\n for (const subscription of connection.subscriptions) {\n if (subscription.unsubscribed) continue\n if (subscription.subscribeMethod.startsWith(\"author_\")) continue\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n this.startSubscription(connection, subscription)\n }\n } else {\n if (connection.keepAliveInterval) {\n clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = null\n }\n\n // notify subscribers if the chain stays unreachable for too long\n if (!connection.staleTimeout && connection.subscriptions.size) {\n connection.staleTimeout = setTimeout(() => {\n connection.staleTimeout = null\n for (const subscription of connection.subscriptions)\n if (!subscription.unsubscribed)\n subscription.callback(new StaleRpcError(connection.chainId), null)\n }, STALE_NOTIFY_TIMEOUT)\n }\n }\n }\n\n private releaseConnection(chainId: DotNetworkId, socketUserId: SocketUserId): void {\n const connection = this.#connections[chainId]\n if (!connection) return\n\n connection.users.delete(socketUserId)\n if (connection.users.size > 0 || connection.idleTimeout) return\n\n connection.idleTimeout = setTimeout(() => {\n connection.idleTimeout = null\n if (connection.users.size > 0 || this.#connections[chainId] !== connection) return\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n }, IDLE_CLOSE_DELAY)\n }\n\n private destroyConnection(connection: Connection): void {\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n if (connection.staleTimeout) clearTimeout(connection.staleTimeout)\n if (connection.idleTimeout) clearTimeout(connection.idleTimeout)\n connection.keepAliveInterval = null\n connection.staleTimeout = null\n connection.idleTimeout = null\n\n // detach subscriptions before destroying the client so their callbacks don't receive a DestroyedError\n for (const subscription of connection.subscriptions) {\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n subscription.stopFollow = null\n subscription.cancelRequest = null\n subscription.serverSubId = null\n }\n\n try {\n connection.client.destroy()\n } catch (error) {\n log.warn(`Error occurred destroying connection ${connection.chainId}`, error)\n }\n }\n\n private async getGenesisHash(chainId: DotNetworkId): Promise<string> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const { genesisHash } = chain\n if (typeof genesisHash !== \"string\")\n throw new Error(`Chain ${chainId} has no genesisHash in store`)\n\n return genesisHash\n }\n\n /** continues to generate a random number until it finds one which is not present in the exclude list */\n private getExclusiveRandomId(exclude: number[] = []): number {\n let id = this.getRandomId()\n while (exclude.includes(id)) {\n id = this.getRandomId()\n }\n return id\n }\n /** generates a random number */\n private getRandomId(): number {\n return Math.trunc(Math.random() * 10 ** 8)\n }\n\n private getTalismanSub() {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n const talismanSub = typeof window !== \"undefined\" && (window as any).talismanSub\n\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSend: Function | undefined = talismanSub?.rpcByGenesisHashSend\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSubscribe: Function | undefined = talismanSub?.rpcByGenesisHashSubscribe\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashUnsubscribe: Function | undefined =\n talismanSub?.rpcByGenesisHashUnsubscribe\n\n if (typeof rpcByGenesisHashSend !== \"function\") return\n if (typeof rpcByGenesisHashSubscribe !== \"function\") return\n if (typeof rpcByGenesisHashUnsubscribe !== \"function\") return\n\n return {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n send: <T = any>(genesisHash: string, method: string, params: unknown[]): Promise<T> =>\n rpcByGenesisHashSend(genesisHash, method, params),\n\n subscribe: (\n genesisHash: string,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false\n ): Promise<string> =>\n rpcByGenesisHashSubscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n ),\n\n unsubscribe: (subscriptionId: string, unsubscribeMethod: string): Promise<void> =>\n rpcByGenesisHashUnsubscribe(subscriptionId, unsubscribeMethod),\n }\n }\n}\n","import type { DotNetworkId } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport { StaleRpcError } from \"./ChainConnectorDot\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst RESPONSE_TIMEOUT = 30_000\nconst FAILURES_BEFORE_FIRST_RESULT = 3\n\ntype HexString = `0x${string}`\ntype StorageChanges = { block: HexString; changes: [HexString, HexString | null][] }\n\n/** The parts of a polkadot-api `PolkadotClient` that the connector uses */\nexport type PapiClient = {\n /** `PolkadotClient` types it without `abortSignal`, but it is substrate-client's `request`, which honours it */\n _request: <Reply>(method: string, params: unknown[], abortSignal?: AbortSignal) => Promise<Reply>\n bestBlocks$: {\n subscribe: (observer: {\n next: (blocks: { hash: string }[]) => void\n error: (error: unknown) => void\n complete: () => void\n }) => { unsubscribe: () => void }\n }\n}\n\n/**\n * Runs `@talismn/balances` over a dapp's polkadot-api clients, so the dapp and its balances share one socket per chain.\n *\n * `state_subscribeStorage` is the only subscription balances uses. It is served by querying the keys at each new\n * best block and reporting the values that changed, like the node does. One query runs at a time, for the latest\n * best block. A failed query is retried at the next block, because balances treats a subscription error as final\n * and would stop updating that network. Only when the first three queries fail does the subscription report the error.\n */\nexport class ChainConnectorDotPapi implements IChainConnectorDot {\n #clientFor: (networkId: DotNetworkId) => PapiClient | undefined\n\n constructor(clientFor: (networkId: DotNetworkId) => PapiClient | undefined) {\n this.#clientFor = clientFor\n }\n\n async send<T = unknown>(networkId: DotNetworkId, method: string, params: unknown[]): Promise<T> {\n return requestWithTimeout<T>(this.getClient(networkId), method, params, new AbortController())\n }\n\n async subscribe(\n networkId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000\n ): Promise<(unsubscribeMethod: string) => void> {\n const client = this.getClient(networkId)\n if (subscribeMethod !== \"state_subscribeStorage\")\n throw new Error(`ChainConnectorDotPapi does not support ${subscribeMethod}`)\n\n const [keys] = params as [HexString[]]\n const values = new Map<HexString, HexString | null>()\n let bestBlockHash: string | undefined\n let queriedBlockHash: string | undefined\n let inFlight: AbortController | undefined\n let delivered = false\n let failures = 0\n let active = true\n let subscription: { unsubscribe: () => void } | undefined\n const staleTimer = timeout\n ? setTimeout(() => callback(new StaleRpcError(networkId), null), timeout)\n : undefined\n\n const stop = () => {\n active = false\n clearTimeout(staleTimer)\n inFlight?.abort()\n subscription?.unsubscribe()\n }\n\n const finish = (error: Error) => {\n if (!active) return\n stop()\n callback(error, null)\n }\n\n const reportChanges = (result: StorageChanges) => {\n const changes = result.changes.filter(([key, value]) => values.get(key) !== value)\n for (const [key, value] of changes) values.set(key, value)\n if (!changes.length) return\n\n delivered = true\n clearTimeout(staleTimer)\n callback(null, { block: result.block, changes })\n }\n\n const reportFailure = (error: Error) => {\n if (delivered || ++failures < FAILURES_BEFORE_FIRST_RESULT)\n return log.warn(\n `state_queryStorageAt failed on ${networkId}, retrying at the next block`,\n error\n )\n finish(error)\n }\n\n const queryBestBlock = async () => {\n if (!active || inFlight || !bestBlockHash || bestBlockHash === queriedBlockHash) return\n const blockHash = bestBlockHash\n queriedBlockHash = blockHash\n const controller = new AbortController()\n inFlight = controller\n\n try {\n const [result] = await requestWithTimeout<StorageChanges[]>(\n client,\n \"state_queryStorageAt\",\n [keys, blockHash],\n controller\n )\n if (!active) return\n if (!result) throw new Error(`Empty state_queryStorageAt response on ${networkId}`)\n reportChanges(result)\n } catch (error) {\n if (active) reportFailure(error as Error)\n } finally {\n if (inFlight === controller) inFlight = undefined\n queryBestBlock()\n }\n }\n\n try {\n subscription = client.bestBlocks$.subscribe({\n next: ([best]) => {\n bestBlockHash = best?.hash\n queryBestBlock()\n },\n error: (error) => finish(error as Error),\n complete: () =>\n finish(new Error(`polkadot-api client for ${networkId} stopped following blocks`)),\n })\n } catch (error) {\n stop()\n throw error\n }\n if (!active) subscription.unsubscribe()\n\n return stop\n }\n\n async reset() {}\n\n private getClient(networkId: DotNetworkId): PapiClient {\n const client = this.#clientFor(networkId)\n if (!client) throw new Error(`No polkadot-api client for network ${networkId}`)\n return client\n }\n}\n\n/** rejects on its own timer too, so a client that ignores the abort signal cannot hang the caller */\nconst requestWithTimeout = <T>(\n client: PapiClient,\n method: string,\n params: unknown[],\n controller: AbortController\n) =>\n new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n controller.abort()\n reject(new Error(\"Timeout\"))\n }, RESPONSE_TIMEOUT)\n try {\n client\n ._request<T>(method, params, controller.signal)\n .then(resolve, reject)\n .finally(() => clearTimeout(timer))\n } catch (error) {\n clearTimeout(timer)\n reject(error)\n }\n })\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport { getWsProvider } from \"@polkadot-api/ws-provider\"\nimport type { DotNetwork, DotNetworkId } from \"@talismn/chaindata-provider\"\nimport { throwAfter } from \"@talismn/util\"\n\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst TIMEOUT = 10_000\n\nexport class ChainConnectorDotStub implements IChainConnectorDot {\n #client: SubstrateClient\n\n constructor(network: DotNetwork) {\n this.#client = createClient(getWsProvider(network.rpcs.concat()))\n }\n\n async send<T = unknown>(\n _chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean\n ): Promise<T> {\n return await Promise.race([\n this.#client.request<T>(method, params),\n throwAfter(TIMEOUT, `Request ${method} timed out after ${TIMEOUT}ms`),\n ])\n }\n\n async subscribe(\n _chainId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout?: number | false\n ): Promise<(unsubscribeMethod: string) => void> {\n let stopFollow: (() => void) | null = null\n let unsubscribed = false\n\n const serverSubId = await Promise.race([\n new Promise<string | number>((resolve, reject) => {\n this.#client._request<string | number, unknown>(subscribeMethod, params, {\n onSuccess: (subId, follow) => {\n stopFollow = follow(subId as string, {\n next: (result) => callback(null, result),\n error: (error) => callback(error, null),\n })\n resolve(subId)\n },\n onError: reject,\n })\n }),\n throwAfter(timeout || TIMEOUT, `Subscription timed out after ${timeout || TIMEOUT}ms`),\n ])\n\n return (unsubscribeMethod: string) => {\n if (unsubscribed) return\n unsubscribed = true\n stopFollow?.()\n this.#client.request(unsubscribeMethod, [serverSubId]).catch(() => {}) // connection may already be gone\n }\n }\n\n reset(): Promise<void> {\n throw new Error(\"ChainConnectorDotStub does not implement reset\")\n }\n\n destroy() {\n this.#client.destroy()\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport { camelCase, fromPairs, toPairs } from \"lodash-es\"\nimport type { Chain, ChainContract } from \"viem\"\nimport * as viemChains from \"viem/chains\"\n\n// exclude zoraTestnet which uses Hyperliquid's chain id\nconst { zoraTestnet, ...validViemChains } = viemChains\n\n// viem chains benefit from multicall config & other viem goodies\nconst VIEM_CHAINS = Object.keys(validViemChains).reduce(\n (acc, curr) => {\n const chain = validViemChains[curr as keyof typeof validViemChains]\n acc[chain.id] = chain\n return acc\n },\n {} as Record<number, Chain>\n)\n\nconst chainsCache = new Map<string, Chain>()\n\nexport const clearChainsCache = (networkId?: EthNetworkId) => {\n if (networkId) chainsCache.delete(networkId)\n else chainsCache.clear()\n}\n\nexport const getChainFromEvmNetwork = (network: EthNetwork): Chain => {\n const { symbol, decimals } = network.nativeCurrency\n\n if (!chainsCache.has(network.id)) {\n const chainRpcs = network.rpcs ?? []\n\n const viemChain = VIEM_CHAINS[Number(network.id)] ?? {}\n\n const chain: Chain = {\n ...viemChain,\n id: Number(network.id),\n name: network.name ?? `Ethereum Chain ${network.id}`,\n rpcUrls: {\n public: { http: chainRpcs },\n default: { http: chainRpcs },\n },\n nativeCurrency: {\n symbol,\n decimals,\n name: symbol,\n },\n contracts: {\n ...viemChain.contracts,\n ...(network.contracts\n ? fromPairs(\n toPairs(network.contracts).map(([name, address]): [string, ChainContract] => [\n camelCase(name),\n { address },\n ])\n )\n : {}),\n },\n }\n\n chainsCache.set(network.id, chain)\n }\n\n return chainsCache.get(network.id) as Chain\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { fallback, http, shouldThrow } from \"viem\"\n\nexport type TransportOptions = {\n batch?:\n | boolean\n | {\n batchSize?: number | undefined\n wait?: number | undefined\n }\n}\n\n// Frontier nodes report reverts with a message viem does not recognize, which makes fallback retry every rpc\nconst FRONTIER_EXECUTION_ERROR = /VM Exception while processing transaction/\n\nconst isFinalError = (error: Error) =>\n shouldThrow(error) || FRONTIER_EXECUTION_ERROR.test(error.message)\n\nexport const getTransportForEvmNetwork = (\n evmNetwork: EthNetwork,\n options: TransportOptions = {}\n) => {\n if (!evmNetwork.rpcs?.length) throw new Error(\"No RPCs found for EVM network\")\n\n const { batch } = options\n\n return fallback(\n evmNetwork.rpcs.map((url) => http(url, { batch, retryCount: 0 })),\n { retryCount: 0, shouldThrow: isFinalError }\n )\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { createPublicClient, type PublicClient } from \"viem\"\n\nimport { clearChainsCache, getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork, type TransportOptions } from \"./getTransportForEvmNetwork\"\n\nconst MUTLICALL_BATCH_WAIT = 25\nconst MUTLICALL_BATCH_SIZE = 100\n\nconst HTTP_BATCH_WAIT = 25\nconst HTTP_BATCH_SIZE_WITH_MULTICALL = 10\nconst HTTP_BATCH_SIZE_WITHOUT_MULTICALL = 30\n\n// cache to reuse previously created public clients\nconst publicClientCache = new Map<string, PublicClient>()\n\nexport const clearPublicClientCache = (evmNetworkId?: string) => {\n clearChainsCache(evmNetworkId)\n\n if (evmNetworkId) publicClientCache.delete(evmNetworkId)\n else publicClientCache.clear()\n}\n\nexport const getEvmNetworkPublicClient = (network: EthNetwork): PublicClient => {\n const chain = getChainFromEvmNetwork(network)\n\n if (!publicClientCache.has(network.id)) {\n if (!network.rpcs.length) throw new Error(\"No RPCs found for Ethereum network\")\n\n const batch = chain.contracts?.multicall3\n ? { multicall: { wait: MUTLICALL_BATCH_WAIT, batchSize: MUTLICALL_BATCH_SIZE } }\n : undefined\n\n const transportOptions: TransportOptions = {\n batch: {\n batchSize: chain.contracts?.multicall3\n ? HTTP_BATCH_SIZE_WITH_MULTICALL\n : HTTP_BATCH_SIZE_WITHOUT_MULTICALL,\n wait: HTTP_BATCH_WAIT,\n },\n }\n\n const transport = getTransportForEvmNetwork(network, transportOptions)\n\n publicClientCache.set(\n network.id,\n createPublicClient({\n chain,\n transport,\n batch,\n })\n )\n }\n\n return publicClientCache.get(network.id) as PublicClient\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { type Account, createWalletClient, type WalletClient } from \"viem\"\n\nimport { getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork } from \"./getTransportForEvmNetwork\"\n\ntype WalletClientOptions = {\n account?: `0x${string}` | Account\n}\n\nexport const getEvmNetworkWalletClient = (\n network: EthNetwork,\n options: WalletClientOptions = {}\n): WalletClient => {\n const chain = getChainFromEvmNetwork(network)\n\n const transport = getTransportForEvmNetwork(network)\n\n return createWalletClient({ chain, transport, account: options.account })\n}\n","import type {\n EthNetworkId,\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n} from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { clearPublicClientCache, getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEth implements IChainConnectorEth {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async getPublicClientForEvmNetwork(evmNetworkId: EthNetworkId): Promise<PublicClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkPublicClient(network)\n }\n\n async getWalletClientForEvmNetwork(\n evmNetworkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkWalletClient(network, { account })\n }\n\n public clearRpcProvidersCache(evmNetworkId?: EthNetworkId) {\n clearPublicClientCache(evmNetworkId)\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEthStub implements IChainConnectorEth {\n #network: EthNetwork\n\n constructor(network: EthNetwork) {\n this.#network = network\n }\n\n async getPublicClientForEvmNetwork(): Promise<PublicClient | null> {\n return getEvmNetworkPublicClient(this.#network)\n }\n\n async getWalletClientForEvmNetwork(\n _networkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n return getEvmNetworkWalletClient(this.#network, { account })\n }\n\n clearRpcProvidersCache(): void {\n // No-op for stub\n }\n}\n","import type { Rpc, RpcTransport, SolanaRpcApi } from \"@solana/kit\"\nimport { createDefaultRpcTransport, createSolanaRpcFromTransport, isSolanaError } from \"@solana/kit\"\nimport type { SolNetworkId } from \"@talismn/chaindata-provider\"\n\nexport type SolRpc = Rpc<SolanaRpcApi>\n\n// Public Solana RPC nodes rate-limit aggressively with HTTP 429. kit's default transport is\n// single-shot, unlike the old web3.js `Connection` which retried 429 up to 5x with backoff, so a\n// single 429 would fail an otherwise-valid request (e.g. a user's transaction submission, or token\n// discovery silently returning no tokens). This wrapper restores that behaviour.\nconst MAX_429_RETRIES = 5\nconst BASE_BACKOFF_MS = 500\n\ntype HttpErrorContext = { statusCode?: number; headers?: Headers }\n\nconst getRateLimitContext = (error: unknown): HttpErrorContext | null => {\n if (!isSolanaError(error)) return null\n\n const context = error.context as HttpErrorContext\n return context.statusCode === 429 ? context : null\n}\n\n/** Returns the delay to wait before retrying, or `null` if the error is not a retryable 429. */\nconst get429RetryDelay = (error: unknown, attempt: number): number | null => {\n const context = getRateLimitContext(error)\n if (!context) return null\n\n // honour the server's Retry-After header (delta-seconds) when present\n const retryAfter = Number(context.headers?.get(\"retry-after\"))\n if (Number.isFinite(retryAfter) && retryAfter > 0) return retryAfter * 1000\n\n // otherwise exponential backoff: 500ms, 1s, 2s, 4s, 8s\n return BASE_BACKOFF_MS * 2 ** attempt\n}\n\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason)\n\n const onAbort = () => {\n clearTimeout(timeout)\n reject(signal?.reason)\n }\n const timeout = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort)\n resolve()\n }, ms)\n signal?.addEventListener(\"abort\", onAbort, { once: true })\n })\n\n/**\n * Wraps a transport so HTTP 429 responses are retried with backoff. Solana RPC requests are\n * idempotent (`sendTransaction` is keyed by signature), so replaying a rate-limited request is safe.\n */\nconst withRetryOn429 = (transport: RpcTransport): RpcTransport => {\n const wrapped = async (config: Parameters<RpcTransport>[0]) => {\n for (let attempt = 0; ; attempt++) {\n try {\n return await transport(config)\n } catch (error) {\n const delay = attempt < MAX_429_RETRIES ? get429RetryDelay(error, attempt) : null\n if (delay === null) throw error\n await sleep(delay, config.signal)\n }\n }\n }\n return wrapped as RpcTransport\n}\n\n/**\n * How long a request may wait on an RPC before moving on to the next one. The last RPC tried gets\n * no timeout, so a slow but working node still answers when every other one has failed.\n */\nconst FAILOVER_TIMEOUT_MS = 20_000\n\nconst sendWithTimeout = async <TResponse>(\n transport: RpcTransport,\n config: RpcTransportConfig,\n timeoutMs: number\n): Promise<TResponse> => {\n const controller = new AbortController()\n const onAbort = () => controller.abort(config.signal?.reason)\n config.signal?.addEventListener(\"abort\", onAbort, { once: true })\n const timeout = setTimeout(\n () => controller.abort(new Error(`RPC request timed out after ${timeoutMs}ms`)),\n timeoutMs\n )\n\n try {\n return await transport<TResponse>({ ...config, signal: controller.signal })\n } finally {\n clearTimeout(timeout)\n config.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\ntype RpcTransportConfig = Parameters<RpcTransport>[0]\n\nconst isSendTransactionPayload = (\n payload: unknown\n): payload is { method: \"sendTransaction\"; params: unknown[] } =>\n typeof payload === \"object\" &&\n payload !== null &&\n \"method\" in payload &&\n payload.method === \"sendTransaction\" &&\n \"params\" in payload &&\n Array.isArray(payload.params)\n\nconst withoutPreflight = (config: RpcTransportConfig): RpcTransportConfig => {\n if (!isSendTransactionPayload(config.payload)) return config\n\n const [transaction, sendConfig] = config.payload.params\n return {\n ...config,\n payload: {\n ...config.payload,\n params: [transaction, { ...(sendConfig as object | undefined), skipPreflight: true }],\n },\n }\n}\n\nexport type SolTransportOptions = {\n /** Called with the url of the RPC that answered, after every successful request */\n onRpcSuccess?: (url: string) => void\n}\n\n/**\n * Sends each request to one RPC at a time, starting from the one that answered last, and moves on to\n * the next when the request fails. A transport only throws for connection, timeout and HTTP errors:\n * JSON-RPC errors come back in the response body and are returned as is.\n *\n * A failed RPC other than a rate limited one may still have forwarded a transaction. Resending it is\n * safe, as the network processes a signature once, but its preflight simulation on the next RPC\n * could then fail although it landed. So after such a failure, every resend of that transaction,\n * including the retries after a rate limit, skips preflight.\n */\nconst withFailover = (urls: string[], options: SolTransportOptions): RpcTransport => {\n const transports = urls.map((url) => createDefaultRpcTransport({ url }))\n let preferred = 0\n const mayHaveBeenProcessed = new WeakSet<RpcTransportConfig>()\n\n const failover = async <TResponse>(config: RpcTransportConfig): Promise<TResponse> => {\n if (!transports.length) throw new Error(\"No RPCs found for Solana network\")\n\n const start = preferred\n let lastError: unknown\n let rateLimitError: unknown\n for (let attempt = 0; attempt < transports.length; attempt++) {\n config.signal?.throwIfAborted()\n const index = (start + attempt) % transports.length\n const transport = transports[index] as RpcTransport\n const isLastAttempt = attempt === transports.length - 1\n const request = mayHaveBeenProcessed.has(config) ? withoutPreflight(config) : config\n\n try {\n const response = isLastAttempt\n ? await transport<TResponse>(request)\n : await sendWithTimeout<TResponse>(transport, request, FAILOVER_TIMEOUT_MS)\n preferred = index\n options.onRpcSuccess?.(urls[index] as string)\n return response\n } catch (error) {\n if (config.signal?.aborted) throw error\n lastError = error\n if (!getRateLimitContext(error)) mayHaveBeenProcessed.add(config)\n else rateLimitError ??= error\n }\n }\n throw rateLimitError ?? lastError\n }\n return failover as RpcTransport\n}\n\n/**\n * Returns a transport over all of the network's RPCs, in the given order. A request fails over to\n * the next RPC on error, and the RPC that answered is tried first for the next request. When every\n * RPC fails and one of them answered HTTP 429, the whole list is retried with backoff.\n */\nexport const getSolTransport = (\n _networkId: SolNetworkId,\n rpcs: string[],\n options: SolTransportOptions = {}\n): RpcTransport => {\n return withRetryOn429(withFailover(rpcs, options))\n}\n\nexport const getSolRpc = (\n networkId: SolNetworkId,\n rpcs: string[],\n options?: SolTransportOptions\n): SolRpc => createSolanaRpcFromTransport(getSolTransport(networkId, rpcs, options))\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type {\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n SolNetworkId,\n} from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSol implements IChainConnectorSol {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n #transports = new Map<SolNetworkId, RpcTransport>()\n #rpcs = new Map<SolNetworkId, SolRpc>()\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async #getNetworkRpcs(networkId: SolNetworkId): Promise<string[]> {\n const network = await this.#chaindataProvider.getNetworkById(networkId, \"solana\")\n if (!network) throw new Error(`Network not found: ${networkId}`)\n\n return network.rpcs\n }\n\n async getTransport(networkId: SolNetworkId): Promise<RpcTransport> {\n if (!this.#transports.has(networkId))\n this.#transports.set(\n networkId,\n getSolTransport(networkId, await this.#getNetworkRpcs(networkId))\n )\n\n return this.#transports.get(networkId)!\n }\n\n async getRpc(networkId: SolNetworkId): Promise<SolRpc> {\n if (!this.#rpcs.has(networkId))\n this.#rpcs.set(networkId, createSolanaRpcFromTransport(await this.getTransport(networkId)))\n\n return this.#rpcs.get(networkId)!\n }\n\n /** Drops cached transports/rpcs so the next call re-reads the network's rpcs from chaindata */\n clearRpcProvidersCache(networkId?: SolNetworkId) {\n if (networkId) {\n this.#transports.delete(networkId)\n this.#rpcs.delete(networkId)\n } else {\n this.#transports.clear()\n this.#rpcs.clear()\n }\n }\n}\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type { SolNetwork } from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSolStub implements IChainConnectorSol {\n #transport: RpcTransport\n #rpc: SolRpc\n\n constructor(network: Pick<SolNetwork, \"id\" | \"rpcs\">) {\n this.#transport = getSolTransport(network.id, network.rpcs)\n this.#rpc = createSolanaRpcFromTransport(this.#transport)\n }\n\n async getRpc(): Promise<SolRpc> {\n return this.#rpc\n }\n\n async getTransport(): Promise<RpcTransport> {\n return this.#transport\n }\n}\n"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -17,6 +17,12 @@ const BAD_RPC_ERRORS = {
|
|
|
17
17
|
};
|
|
18
18
|
const RESPONSE_TIMEOUT$1 = 3e4;
|
|
19
19
|
const KEEP_ALIVE_INTERVAL = 2e4;
|
|
20
|
+
/**
|
|
21
|
+
* How long a connection stays open once its last user releases it. A one-off request is
|
|
22
|
+
* often followed by more traffic to the same chain (balances read the runtime version,
|
|
23
|
+
* then subscribe to storage), which then reuses the socket instead of opening a new one.
|
|
24
|
+
*/
|
|
25
|
+
const IDLE_CLOSE_DELAY = 3e4;
|
|
20
26
|
/** in-flight requests reject with DestroyedError when a connection is torn down - expected, not worth logging */
|
|
21
27
|
const isDestroyedError = (error) => error instanceof Error && error.name === "DestroyedError";
|
|
22
28
|
const STALE_NOTIFY_TIMEOUT = 3e4;
|
|
@@ -29,6 +35,10 @@ var ChainConnectionError = class extends Error {
|
|
|
29
35
|
this.chainId = chainId;
|
|
30
36
|
}
|
|
31
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Passed to subscription callbacks when the chain has been unreachable for a while. Not
|
|
40
|
+
* terminal: the subscription stays registered and is re-issued when a socket connects.
|
|
41
|
+
*/
|
|
32
42
|
var StaleRpcError = class extends Error {
|
|
33
43
|
type;
|
|
34
44
|
chainId;
|
|
@@ -54,10 +64,12 @@ var StaleRpcError = class extends Error {
|
|
|
54
64
|
*/
|
|
55
65
|
var ChainConnectorDot = class {
|
|
56
66
|
#chaindataChainProvider;
|
|
67
|
+
#connectionTimeout;
|
|
57
68
|
#connections = {};
|
|
58
69
|
#pendingConnections = {};
|
|
59
|
-
constructor(chaindataChainProvider) {
|
|
70
|
+
constructor(chaindataChainProvider, options) {
|
|
60
71
|
this.#chaindataChainProvider = chaindataChainProvider;
|
|
72
|
+
this.#connectionTimeout = options?.connectionTimeout;
|
|
61
73
|
}
|
|
62
74
|
async send(chainId, method, params, _isCacheable, extraOptions) {
|
|
63
75
|
const talismanSub = this.getTalismanSub();
|
|
@@ -146,8 +158,7 @@ var ChainConnectorDot = class {
|
|
|
146
158
|
subscription.cancelRequest?.();
|
|
147
159
|
subscription.stopFollow?.();
|
|
148
160
|
const current = this.#connections[chainId];
|
|
149
|
-
|
|
150
|
-
if (subscription.serverSubId !== null && current && !isLastUser) try {
|
|
161
|
+
if (subscription.serverSubId !== null && current) try {
|
|
151
162
|
current.client.request(unsubscribeMethod, [subscription.serverSubId]).catch((error) => {
|
|
152
163
|
if (!isDestroyedError(error)) log_default.warn(`Failed to unsubscribe from ${chainId}`, error);
|
|
153
164
|
});
|
|
@@ -177,7 +188,7 @@ var ChainConnectorDot = class {
|
|
|
177
188
|
for (const subscription of fresh.subscriptions) this.startSubscription(fresh, subscription);
|
|
178
189
|
} catch (error) {
|
|
179
190
|
log_default.warn(`Failed to recreate connection for ${chainId} after reset`, error);
|
|
180
|
-
for (const subscription of connection.subscriptions) subscription.callback(new
|
|
191
|
+
for (const subscription of connection.subscriptions) subscription.callback(new ChainConnectionError(chainId, { cause: error }), null);
|
|
181
192
|
}
|
|
182
193
|
}
|
|
183
194
|
/** Sends a request over a connection, throwing `Error("TIMEOUT")` if no response arrives in time */
|
|
@@ -235,6 +246,10 @@ var ChainConnectorDot = class {
|
|
|
235
246
|
});
|
|
236
247
|
connection = await this.#pendingConnections[chainId];
|
|
237
248
|
}
|
|
249
|
+
if (connection.idleTimeout) {
|
|
250
|
+
clearTimeout(connection.idleTimeout);
|
|
251
|
+
connection.idleTimeout = null;
|
|
252
|
+
}
|
|
238
253
|
const socketUserId = this.getExclusiveRandomId([...connection.users]);
|
|
239
254
|
connection.users.add(socketUserId);
|
|
240
255
|
return [socketUserId, connection];
|
|
@@ -245,7 +260,10 @@ var ChainConnectorDot = class {
|
|
|
245
260
|
const rpcs = chain.rpcs.concat();
|
|
246
261
|
if (!rpcs.length) throw new Error(`No healthy RPCs available for chain ${chainId}`);
|
|
247
262
|
let connection = null;
|
|
248
|
-
const provider = getWsProvider(rpcs, {
|
|
263
|
+
const provider = getWsProvider(rpcs, {
|
|
264
|
+
onStatusChanged: (status) => this.handleStatusChange(connection, status),
|
|
265
|
+
...this.#connectionTimeout !== void 0 && { timeout: this.#connectionTimeout }
|
|
266
|
+
});
|
|
249
267
|
connection = {
|
|
250
268
|
chainId,
|
|
251
269
|
provider,
|
|
@@ -254,7 +272,8 @@ var ChainConnectorDot = class {
|
|
|
254
272
|
subscriptions: /* @__PURE__ */ new Set(),
|
|
255
273
|
wasConnected: false,
|
|
256
274
|
keepAliveInterval: null,
|
|
257
|
-
staleTimeout: null
|
|
275
|
+
staleTimeout: null,
|
|
276
|
+
idleTimeout: null
|
|
258
277
|
};
|
|
259
278
|
return connection;
|
|
260
279
|
}
|
|
@@ -296,15 +315,21 @@ var ChainConnectorDot = class {
|
|
|
296
315
|
const connection = this.#connections[chainId];
|
|
297
316
|
if (!connection) return;
|
|
298
317
|
connection.users.delete(socketUserId);
|
|
299
|
-
if (connection.users.size > 0) return;
|
|
300
|
-
|
|
301
|
-
|
|
318
|
+
if (connection.users.size > 0 || connection.idleTimeout) return;
|
|
319
|
+
connection.idleTimeout = setTimeout(() => {
|
|
320
|
+
connection.idleTimeout = null;
|
|
321
|
+
if (connection.users.size > 0 || this.#connections[chainId] !== connection) return;
|
|
322
|
+
this.destroyConnection(connection);
|
|
323
|
+
delete this.#connections[chainId];
|
|
324
|
+
}, IDLE_CLOSE_DELAY);
|
|
302
325
|
}
|
|
303
326
|
destroyConnection(connection) {
|
|
304
327
|
if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval);
|
|
305
328
|
if (connection.staleTimeout) clearTimeout(connection.staleTimeout);
|
|
329
|
+
if (connection.idleTimeout) clearTimeout(connection.idleTimeout);
|
|
306
330
|
connection.keepAliveInterval = null;
|
|
307
331
|
connection.staleTimeout = null;
|
|
332
|
+
connection.idleTimeout = null;
|
|
308
333
|
for (const subscription of connection.subscriptions) {
|
|
309
334
|
subscription.stopFollow?.();
|
|
310
335
|
subscription.cancelRequest?.();
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["packageJson.name","RESPONSE_TIMEOUT","log"],"sources":["../package.json","../src/log.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/getChainFromEvmNetwork.ts","../src/eth/getTransportForEvmNetwork.ts","../src/eth/getEvmNetworkPublicClient.ts","../src/eth/getEvmNetworkWalletClient.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"sourcesContent":["","import anylogger from \"anylogger\"\n\nimport packageJson from \"../package.json\"\n\nexport default anylogger(packageJson.name)\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport {\n getWsProvider,\n type StatusChange,\n WsEvent,\n type WsJsonRpcProvider,\n} from \"@polkadot-api/ws-provider\"\nimport type { DotNetworkId, IChaindataNetworkProvider } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\n// errors that require an rpc fallback\n// https://docs.blastapi.io/blast-documentation/things-you-need-to-know/error-reference\nconst BAD_RPC_ERRORS: Record<string, string> = {\n \"-32097\": \"Rate limit exceeded\",\n \"-32098\": \"Capacity exceeded\",\n}\n\nconst RESPONSE_TIMEOUT = 30_000 // max wait for an rpc response (including connection time)\nconst KEEP_ALIVE_INTERVAL = 20_000 // periodic system_health to keep idle sockets alive (ws-provider kills quiet sockets after its 40s heartbeat)\n\n/** in-flight requests reject with DestroyedError when a connection is torn down - expected, not worth logging */\nconst isDestroyedError = (error: unknown): boolean =>\n error instanceof Error && error.name === \"DestroyedError\"\nconst STALE_NOTIFY_TIMEOUT = 30_000 // how long a chain can be disconnected before subscribers are notified\n\nexport class ChainConnectionError extends Error {\n type: \"CHAIN_CONNECTION_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`Unable to connect to chain ${chainId}`, options)\n\n this.type = \"CHAIN_CONNECTION_ERROR\"\n this.chainId = chainId\n }\n}\n\nexport class StaleRpcError extends Error {\n type: \"STALE_RPC_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`RPCs are stale/unavailable for chain ${chainId}`, options)\n\n this.type = \"STALE_RPC_ERROR\"\n this.chainId = chainId\n }\n}\n\ntype SocketUserId = number\n\ntype Subscription = {\n subscribeMethod: string\n params: unknown[]\n callback: SubscriptionCallback\n /** cancels the pending subscribe request, if any */\n cancelRequest: (() => void) | null\n /** stops routing notifications to the callback */\n stopFollow: (() => void) | null\n serverSubId: string | number | null\n unsubscribed: boolean\n}\n\ntype Connection = {\n chainId: DotNetworkId\n provider: WsJsonRpcProvider\n client: SubstrateClient\n users: Set<SocketUserId>\n subscriptions: Set<Subscription>\n wasConnected: boolean\n keepAliveInterval: ReturnType<typeof setInterval> | null\n staleTimeout: ReturnType<typeof setTimeout> | null\n}\n\n/**\n * ChainConnector provides an interface similar to a websocket JSON-RPC provider, but with three points of difference:\n *\n * 1. ChainConnector methods all accept a `chainId` instead of an array of RPCs. RPCs are then fetched internally from chaindata.\n * 2. ChainConnector creates only one socket connection per chain (via polkadot-api's ws-provider, which handles\n * endpoint rotation, reconnection and stale-socket detection) and ensures that all downstream requests to a chain\n * share that connection.\n * 3. Subscriptions return a callable `unsubscribe` method instead of an id, and are automatically re-established\n * when the provider reconnects (possibly to another endpoint).\n *\n * Additionally, when run on the clientside of a dapp where `window.talismanSub` is available, instead of spinning up new websocket\n * connections this class will forward all requests through to the wallet backend - where another instance of this class will\n * handle the websocket connections.\n */\nexport class ChainConnectorDot implements IChainConnectorDot {\n #chaindataChainProvider: IChaindataNetworkProvider\n\n #connections: Record<DotNetworkId, Connection> = {}\n #pendingConnections: Record<DotNetworkId, Promise<Connection>> = {}\n\n constructor(chaindataChainProvider: IChaindataNetworkProvider) {\n this.#chaindataChainProvider = chaindataChainProvider\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n async send<T = any>(\n chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean | undefined,\n extraOptions?: {\n /**\n * Set to `true` if this query is speculative, i.e. if on some chains it's expected that it will raise a wasm unreachable error of the form:\n *\n * 4003: Client error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\n *\n * By setting expectErrors to true, this method won't pollute the logs with errors we intend to have happen.\n * An example use case of this is when you plan to catch the wasm unreachable error on chains that don't support the query, and then fall back\n * to another query or perhaps an empty result.\n */\n expectErrors?: boolean\n }\n ): Promise<T> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n return await talismanSub.send(genesisHash, method, params)\n } catch (error) {\n log.warn(\n `Failed to make wallet-proxied send request for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n try {\n return await this.request<T>(connection, method, params)\n } catch (err) {\n const error = err as (Error & { code?: number; data?: unknown }) | null\n\n if (error?.message === \"TIMEOUT\") {\n log.error(`ChainConnector timeout`, { chainId, error })\n connection.provider.switch()\n throw new Error(\"Timeout\")\n }\n\n const badRpcError = BAD_RPC_ERRORS[error?.code?.toString() ?? \"\"]\n if (badRpcError) {\n log.error(`ChainConnector ${badRpcError}`, { error, chainId })\n connection.provider.switch()\n throw new Error(badRpcError)\n }\n\n if (!extraOptions?.expectErrors)\n log.error(\n `Failed to send ${method} on chain ${chainId}\\nparams: ${JSON.stringify(params)}`,\n {\n error,\n }\n )\n\n throw error\n } finally {\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n async subscribe(\n chainId: DotNetworkId,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000 // 30 seconds in milliseconds\n ): Promise<(unsubscribeMethod: string) => void> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n\n const subscriptionId = await talismanSub.subscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n )\n\n return (unsubscribeMethod: string) =>\n talismanSub.unsubscribe(subscriptionId, unsubscribeMethod)\n } catch (error) {\n log.warn(\n `Failed to create wallet-proxied subscription for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n const subscription: Subscription = {\n subscribeMethod,\n params,\n callback,\n cancelRequest: null,\n stopFollow: null,\n serverSubId: null,\n unsubscribed: false,\n }\n connection.subscriptions.add(subscription)\n\n // if the chain can't be reached at all, let the caller know after a while (the provider keeps retrying)\n if (timeout && !connection.wasConnected) {\n const staleWarning = setTimeout(() => {\n if (!subscription.unsubscribed && !connection.wasConnected)\n callback(new StaleRpcError(chainId), null)\n }, timeout)\n const clear = () => clearTimeout(staleWarning)\n // piggyback on the follow setup to clear the warning once anything happens\n const originalCallback = subscription.callback\n subscription.callback = (error, result) => {\n clear()\n subscription.callback = originalCallback\n originalCallback(error, result)\n }\n }\n\n this.startSubscription(connection, subscription)\n\n return (unsubscribeMethod: string) => {\n if (subscription.unsubscribed) return\n subscription.unsubscribed = true\n\n subscription.cancelRequest?.()\n subscription.stopFollow?.()\n\n // the connection may have been replaced by a reset() since we subscribed\n const current = this.#connections[chainId]\n // if we are the last user the connection is about to be destroyed: skip the\n // unsubscribe call, server-side subscriptions die with the socket anyway\n const isLastUser = !!current && current.users.size === 1 && current.users.has(socketUserId)\n if (subscription.serverSubId !== null && current && !isLastUser)\n try {\n current.client.request(unsubscribeMethod, [subscription.serverSubId]).catch((error) => {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n })\n } catch (error) {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n }\n\n current?.subscriptions.delete(subscription)\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n /**\n * Kills and recreates the connection for a chain, if any.\n * Useful after changing a network's rpcs to make sure the new list is applied for further requests.\n * Active subscriptions are automatically re-established on the new connection.\n */\n async reset(chainId: DotNetworkId) {\n log.info(\"ChainConnector reset\", chainId)\n const connection = this.#connections[chainId]\n if (!connection) return\n\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n\n // recreate a connection for the active subscriptions, if any\n if (connection.subscriptions.size) {\n try {\n const fresh = await this.createConnection(chainId)\n fresh.users = connection.users\n fresh.subscriptions = connection.subscriptions\n this.#connections[chainId] = fresh\n for (const subscription of fresh.subscriptions) this.startSubscription(fresh, subscription)\n } catch (error) {\n log.warn(`Failed to recreate connection for ${chainId} after reset`, error)\n for (const subscription of connection.subscriptions)\n subscription.callback(new StaleRpcError(chainId, { cause: error }), null)\n }\n }\n }\n\n /** Sends a request over a connection, throwing `Error(\"TIMEOUT\")` if no response arrives in time */\n private request<T>(\n connection: Connection,\n method: string,\n params: unknown[],\n timeoutMs = RESPONSE_TIMEOUT\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n cancel()\n reject(new Error(\"TIMEOUT\"))\n }, timeoutMs)\n\n const cancel = connection.client._request<T, unknown>(method, params, {\n onSuccess: (result) => {\n clearTimeout(timer)\n resolve(result)\n },\n onError: (error) => {\n clearTimeout(timer)\n reject(error)\n },\n })\n })\n }\n\n /** Issues the subscribe request and routes notifications to the subscription callback */\n private startSubscription(connection: Connection, subscription: Subscription) {\n subscription.serverSubId = null\n subscription.stopFollow = null\n\n subscription.cancelRequest = connection.client._request<string | number, unknown>(\n subscription.subscribeMethod,\n subscription.params,\n {\n onSuccess: (serverSubId, follow) => {\n subscription.cancelRequest = null\n if (subscription.unsubscribed) return\n\n subscription.serverSubId = serverSubId\n // raw-client matches notifications by the raw (not stringified) subscription id, but types it as string\n subscription.stopFollow = follow(serverSubId as string, {\n next: (result) => subscription.callback(null, result),\n error: (error) => subscription.callback(error, null),\n })\n },\n onError: (error) => {\n subscription.cancelRequest = null\n if (!subscription.unsubscribed) subscription.callback(error, null)\n },\n }\n )\n }\n\n /**\n * Get (or create) the shared connection for a chain.\n *\n * The caller must call releaseConnection with the returned SocketUserId once they are finished with it.\n */\n private async acquireConnection(chainId: DotNetworkId): Promise<[SocketUserId, Connection]> {\n // a single creation promise per chain guarantees that concurrent callers share the same connection\n let connection = this.#connections[chainId]\n if (!connection) {\n if (!this.#pendingConnections[chainId]) {\n this.#pendingConnections[chainId] = this.createConnection(chainId)\n .then((created) => {\n this.#connections[chainId] = created\n return created\n })\n .finally(() => {\n delete this.#pendingConnections[chainId]\n })\n }\n connection = await this.#pendingConnections[chainId]\n }\n\n const socketUserId = this.getExclusiveRandomId([...connection.users])\n connection.users.add(socketUserId)\n\n return [socketUserId, connection]\n }\n\n private async createConnection(chainId: DotNetworkId): Promise<Connection> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const rpcs = chain.rpcs.concat()\n if (!rpcs.length) throw new Error(`No healthy RPCs available for chain ${chainId}`)\n\n // will be assigned below - the provider config needs to reference the connection\n let connection: Connection = null as unknown as Connection\n\n const provider = getWsProvider(rpcs, {\n onStatusChanged: (status: StatusChange) => this.handleStatusChange(connection, status),\n })\n\n const client = createClient(provider)\n\n connection = {\n chainId,\n provider,\n client,\n users: new Set(),\n subscriptions: new Set(),\n wasConnected: false,\n keepAliveInterval: null,\n staleTimeout: null,\n }\n\n return connection\n }\n\n private handleStatusChange(connection: Connection, status: StatusChange) {\n // connection is still being constructed on the initial CONNECTING event\n if (!connection) return\n // ignore events from a connection that has been reset/destroyed\n if (this.#connections[connection.chainId] !== connection) return\n\n if (status.type === WsEvent.CONNECTED) {\n if (connection.staleTimeout) {\n clearTimeout(connection.staleTimeout)\n connection.staleTimeout = null\n }\n\n const isReconnect = connection.wasConnected\n connection.wasConnected = true\n\n // periodically send a request to keep the socket alive when there is no other traffic\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = setInterval(() => {\n this.request(connection, \"system_health\", [], KEEP_ALIVE_INTERVAL).catch((error) => {\n if (!isDestroyedError(error))\n log.warn(`Failed keep-alive for socket ${connection.chainId}`, error)\n })\n }, KEEP_ALIVE_INTERVAL)\n\n // server-side subscriptions died with the previous socket : re-establish them\n // (skip author_* subscriptions : resubmitting an extrinsic is not safe)\n if (isReconnect)\n for (const subscription of connection.subscriptions) {\n if (subscription.unsubscribed) continue\n if (subscription.subscribeMethod.startsWith(\"author_\")) continue\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n this.startSubscription(connection, subscription)\n }\n } else {\n if (connection.keepAliveInterval) {\n clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = null\n }\n\n // notify subscribers if the chain stays unreachable for too long\n if (!connection.staleTimeout && connection.subscriptions.size) {\n connection.staleTimeout = setTimeout(() => {\n connection.staleTimeout = null\n for (const subscription of connection.subscriptions)\n if (!subscription.unsubscribed)\n subscription.callback(new StaleRpcError(connection.chainId), null)\n }, STALE_NOTIFY_TIMEOUT)\n }\n }\n }\n\n private releaseConnection(chainId: DotNetworkId, socketUserId: SocketUserId): void {\n const connection = this.#connections[chainId]\n if (!connection) return\n\n connection.users.delete(socketUserId)\n if (connection.users.size > 0) return\n\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n }\n\n private destroyConnection(connection: Connection): void {\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n if (connection.staleTimeout) clearTimeout(connection.staleTimeout)\n connection.keepAliveInterval = null\n connection.staleTimeout = null\n\n // detach subscriptions before destroying the client so their callbacks don't receive a DestroyedError\n for (const subscription of connection.subscriptions) {\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n subscription.stopFollow = null\n subscription.cancelRequest = null\n subscription.serverSubId = null\n }\n\n try {\n connection.client.destroy()\n } catch (error) {\n log.warn(`Error occurred destroying connection ${connection.chainId}`, error)\n }\n }\n\n private async getGenesisHash(chainId: DotNetworkId): Promise<string> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const { genesisHash } = chain\n if (typeof genesisHash !== \"string\")\n throw new Error(`Chain ${chainId} has no genesisHash in store`)\n\n return genesisHash\n }\n\n /** continues to generate a random number until it finds one which is not present in the exclude list */\n private getExclusiveRandomId(exclude: number[] = []): number {\n let id = this.getRandomId()\n while (exclude.includes(id)) {\n id = this.getRandomId()\n }\n return id\n }\n /** generates a random number */\n private getRandomId(): number {\n return Math.trunc(Math.random() * 10 ** 8)\n }\n\n private getTalismanSub() {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n const talismanSub = typeof window !== \"undefined\" && (window as any).talismanSub\n\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSend: Function | undefined = talismanSub?.rpcByGenesisHashSend\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSubscribe: Function | undefined = talismanSub?.rpcByGenesisHashSubscribe\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashUnsubscribe: Function | undefined =\n talismanSub?.rpcByGenesisHashUnsubscribe\n\n if (typeof rpcByGenesisHashSend !== \"function\") return\n if (typeof rpcByGenesisHashSubscribe !== \"function\") return\n if (typeof rpcByGenesisHashUnsubscribe !== \"function\") return\n\n return {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n send: <T = any>(genesisHash: string, method: string, params: unknown[]): Promise<T> =>\n rpcByGenesisHashSend(genesisHash, method, params),\n\n subscribe: (\n genesisHash: string,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false\n ): Promise<string> =>\n rpcByGenesisHashSubscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n ),\n\n unsubscribe: (subscriptionId: string, unsubscribeMethod: string): Promise<void> =>\n rpcByGenesisHashUnsubscribe(subscriptionId, unsubscribeMethod),\n }\n }\n}\n","import type { DotNetworkId } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport { StaleRpcError } from \"./ChainConnectorDot\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst RESPONSE_TIMEOUT = 30_000\nconst FAILURES_BEFORE_FIRST_RESULT = 3\n\ntype HexString = `0x${string}`\ntype StorageChanges = { block: HexString; changes: [HexString, HexString | null][] }\n\n/** The parts of a polkadot-api `PolkadotClient` that the connector uses */\nexport type PapiClient = {\n /** `PolkadotClient` types it without `abortSignal`, but it is substrate-client's `request`, which honours it */\n _request: <Reply>(method: string, params: unknown[], abortSignal?: AbortSignal) => Promise<Reply>\n bestBlocks$: {\n subscribe: (observer: {\n next: (blocks: { hash: string }[]) => void\n error: (error: unknown) => void\n complete: () => void\n }) => { unsubscribe: () => void }\n }\n}\n\n/**\n * Runs `@talismn/balances` over a dapp's polkadot-api clients, so the dapp and its balances share one socket per chain.\n *\n * `state_subscribeStorage` is the only subscription balances uses. It is served by querying the keys at each new\n * best block and reporting the values that changed, like the node does. One query runs at a time, for the latest\n * best block. A failed query is retried at the next block, because balances treats a subscription error as final\n * and would stop updating that network. Only when the first three queries fail does the subscription report the error.\n */\nexport class ChainConnectorDotPapi implements IChainConnectorDot {\n #clientFor: (networkId: DotNetworkId) => PapiClient | undefined\n\n constructor(clientFor: (networkId: DotNetworkId) => PapiClient | undefined) {\n this.#clientFor = clientFor\n }\n\n async send<T = unknown>(networkId: DotNetworkId, method: string, params: unknown[]): Promise<T> {\n return requestWithTimeout<T>(this.getClient(networkId), method, params, new AbortController())\n }\n\n async subscribe(\n networkId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000\n ): Promise<(unsubscribeMethod: string) => void> {\n const client = this.getClient(networkId)\n if (subscribeMethod !== \"state_subscribeStorage\")\n throw new Error(`ChainConnectorDotPapi does not support ${subscribeMethod}`)\n\n const [keys] = params as [HexString[]]\n const values = new Map<HexString, HexString | null>()\n let bestBlockHash: string | undefined\n let queriedBlockHash: string | undefined\n let inFlight: AbortController | undefined\n let delivered = false\n let failures = 0\n let active = true\n let subscription: { unsubscribe: () => void } | undefined\n const staleTimer = timeout\n ? setTimeout(() => callback(new StaleRpcError(networkId), null), timeout)\n : undefined\n\n const stop = () => {\n active = false\n clearTimeout(staleTimer)\n inFlight?.abort()\n subscription?.unsubscribe()\n }\n\n const finish = (error: Error) => {\n if (!active) return\n stop()\n callback(error, null)\n }\n\n const reportChanges = (result: StorageChanges) => {\n const changes = result.changes.filter(([key, value]) => values.get(key) !== value)\n for (const [key, value] of changes) values.set(key, value)\n if (!changes.length) return\n\n delivered = true\n clearTimeout(staleTimer)\n callback(null, { block: result.block, changes })\n }\n\n const reportFailure = (error: Error) => {\n if (delivered || ++failures < FAILURES_BEFORE_FIRST_RESULT)\n return log.warn(\n `state_queryStorageAt failed on ${networkId}, retrying at the next block`,\n error\n )\n finish(error)\n }\n\n const queryBestBlock = async () => {\n if (!active || inFlight || !bestBlockHash || bestBlockHash === queriedBlockHash) return\n const blockHash = bestBlockHash\n queriedBlockHash = blockHash\n const controller = new AbortController()\n inFlight = controller\n\n try {\n const [result] = await requestWithTimeout<StorageChanges[]>(\n client,\n \"state_queryStorageAt\",\n [keys, blockHash],\n controller\n )\n if (!active) return\n if (!result) throw new Error(`Empty state_queryStorageAt response on ${networkId}`)\n reportChanges(result)\n } catch (error) {\n if (active) reportFailure(error as Error)\n } finally {\n if (inFlight === controller) inFlight = undefined\n queryBestBlock()\n }\n }\n\n try {\n subscription = client.bestBlocks$.subscribe({\n next: ([best]) => {\n bestBlockHash = best?.hash\n queryBestBlock()\n },\n error: (error) => finish(error as Error),\n complete: () =>\n finish(new Error(`polkadot-api client for ${networkId} stopped following blocks`)),\n })\n } catch (error) {\n stop()\n throw error\n }\n if (!active) subscription.unsubscribe()\n\n return stop\n }\n\n async reset() {}\n\n private getClient(networkId: DotNetworkId): PapiClient {\n const client = this.#clientFor(networkId)\n if (!client) throw new Error(`No polkadot-api client for network ${networkId}`)\n return client\n }\n}\n\n/** rejects on its own timer too, so a client that ignores the abort signal cannot hang the caller */\nconst requestWithTimeout = <T>(\n client: PapiClient,\n method: string,\n params: unknown[],\n controller: AbortController\n) =>\n new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n controller.abort()\n reject(new Error(\"Timeout\"))\n }, RESPONSE_TIMEOUT)\n try {\n client\n ._request<T>(method, params, controller.signal)\n .then(resolve, reject)\n .finally(() => clearTimeout(timer))\n } catch (error) {\n clearTimeout(timer)\n reject(error)\n }\n })\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport { getWsProvider } from \"@polkadot-api/ws-provider\"\nimport type { DotNetwork, DotNetworkId } from \"@talismn/chaindata-provider\"\nimport { throwAfter } from \"@talismn/util\"\n\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst TIMEOUT = 10_000\n\nexport class ChainConnectorDotStub implements IChainConnectorDot {\n #client: SubstrateClient\n\n constructor(network: DotNetwork) {\n this.#client = createClient(getWsProvider(network.rpcs.concat()))\n }\n\n async send<T = unknown>(\n _chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean\n ): Promise<T> {\n return await Promise.race([\n this.#client.request<T>(method, params),\n throwAfter(TIMEOUT, `Request ${method} timed out after ${TIMEOUT}ms`),\n ])\n }\n\n async subscribe(\n _chainId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout?: number | false\n ): Promise<(unsubscribeMethod: string) => void> {\n let stopFollow: (() => void) | null = null\n let unsubscribed = false\n\n const serverSubId = await Promise.race([\n new Promise<string | number>((resolve, reject) => {\n this.#client._request<string | number, unknown>(subscribeMethod, params, {\n onSuccess: (subId, follow) => {\n stopFollow = follow(subId as string, {\n next: (result) => callback(null, result),\n error: (error) => callback(error, null),\n })\n resolve(subId)\n },\n onError: reject,\n })\n }),\n throwAfter(timeout || TIMEOUT, `Subscription timed out after ${timeout || TIMEOUT}ms`),\n ])\n\n return (unsubscribeMethod: string) => {\n if (unsubscribed) return\n unsubscribed = true\n stopFollow?.()\n this.#client.request(unsubscribeMethod, [serverSubId]).catch(() => {}) // connection may already be gone\n }\n }\n\n reset(): Promise<void> {\n throw new Error(\"ChainConnectorDotStub does not implement reset\")\n }\n\n destroy() {\n this.#client.destroy()\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport { camelCase, fromPairs, toPairs } from \"lodash-es\"\nimport type { Chain, ChainContract } from \"viem\"\nimport * as viemChains from \"viem/chains\"\n\n// exclude zoraTestnet which uses Hyperliquid's chain id\nconst { zoraTestnet, ...validViemChains } = viemChains\n\n// viem chains benefit from multicall config & other viem goodies\nconst VIEM_CHAINS = Object.keys(validViemChains).reduce(\n (acc, curr) => {\n const chain = validViemChains[curr as keyof typeof validViemChains]\n acc[chain.id] = chain\n return acc\n },\n {} as Record<number, Chain>\n)\n\nconst chainsCache = new Map<string, Chain>()\n\nexport const clearChainsCache = (networkId?: EthNetworkId) => {\n if (networkId) chainsCache.delete(networkId)\n else chainsCache.clear()\n}\n\nexport const getChainFromEvmNetwork = (network: EthNetwork): Chain => {\n const { symbol, decimals } = network.nativeCurrency\n\n if (!chainsCache.has(network.id)) {\n const chainRpcs = network.rpcs ?? []\n\n const viemChain = VIEM_CHAINS[Number(network.id)] ?? {}\n\n const chain: Chain = {\n ...viemChain,\n id: Number(network.id),\n name: network.name ?? `Ethereum Chain ${network.id}`,\n rpcUrls: {\n public: { http: chainRpcs },\n default: { http: chainRpcs },\n },\n nativeCurrency: {\n symbol,\n decimals,\n name: symbol,\n },\n contracts: {\n ...viemChain.contracts,\n ...(network.contracts\n ? fromPairs(\n toPairs(network.contracts).map(([name, address]): [string, ChainContract] => [\n camelCase(name),\n { address },\n ])\n )\n : {}),\n },\n }\n\n chainsCache.set(network.id, chain)\n }\n\n return chainsCache.get(network.id) as Chain\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { fallback, http, shouldThrow } from \"viem\"\n\nexport type TransportOptions = {\n batch?:\n | boolean\n | {\n batchSize?: number | undefined\n wait?: number | undefined\n }\n}\n\n// Frontier nodes report reverts with a message viem does not recognize, which makes fallback retry every rpc\nconst FRONTIER_EXECUTION_ERROR = /VM Exception while processing transaction/\n\nconst isFinalError = (error: Error) =>\n shouldThrow(error) || FRONTIER_EXECUTION_ERROR.test(error.message)\n\nexport const getTransportForEvmNetwork = (\n evmNetwork: EthNetwork,\n options: TransportOptions = {}\n) => {\n if (!evmNetwork.rpcs?.length) throw new Error(\"No RPCs found for EVM network\")\n\n const { batch } = options\n\n return fallback(\n evmNetwork.rpcs.map((url) => http(url, { batch, retryCount: 0 })),\n { retryCount: 0, shouldThrow: isFinalError }\n )\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { createPublicClient, type PublicClient } from \"viem\"\n\nimport { clearChainsCache, getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork, type TransportOptions } from \"./getTransportForEvmNetwork\"\n\nconst MUTLICALL_BATCH_WAIT = 25\nconst MUTLICALL_BATCH_SIZE = 100\n\nconst HTTP_BATCH_WAIT = 25\nconst HTTP_BATCH_SIZE_WITH_MULTICALL = 10\nconst HTTP_BATCH_SIZE_WITHOUT_MULTICALL = 30\n\n// cache to reuse previously created public clients\nconst publicClientCache = new Map<string, PublicClient>()\n\nexport const clearPublicClientCache = (evmNetworkId?: string) => {\n clearChainsCache(evmNetworkId)\n\n if (evmNetworkId) publicClientCache.delete(evmNetworkId)\n else publicClientCache.clear()\n}\n\nexport const getEvmNetworkPublicClient = (network: EthNetwork): PublicClient => {\n const chain = getChainFromEvmNetwork(network)\n\n if (!publicClientCache.has(network.id)) {\n if (!network.rpcs.length) throw new Error(\"No RPCs found for Ethereum network\")\n\n const batch = chain.contracts?.multicall3\n ? { multicall: { wait: MUTLICALL_BATCH_WAIT, batchSize: MUTLICALL_BATCH_SIZE } }\n : undefined\n\n const transportOptions: TransportOptions = {\n batch: {\n batchSize: chain.contracts?.multicall3\n ? HTTP_BATCH_SIZE_WITH_MULTICALL\n : HTTP_BATCH_SIZE_WITHOUT_MULTICALL,\n wait: HTTP_BATCH_WAIT,\n },\n }\n\n const transport = getTransportForEvmNetwork(network, transportOptions)\n\n publicClientCache.set(\n network.id,\n createPublicClient({\n chain,\n transport,\n batch,\n })\n )\n }\n\n return publicClientCache.get(network.id) as PublicClient\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { type Account, createWalletClient, type WalletClient } from \"viem\"\n\nimport { getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork } from \"./getTransportForEvmNetwork\"\n\ntype WalletClientOptions = {\n account?: `0x${string}` | Account\n}\n\nexport const getEvmNetworkWalletClient = (\n network: EthNetwork,\n options: WalletClientOptions = {}\n): WalletClient => {\n const chain = getChainFromEvmNetwork(network)\n\n const transport = getTransportForEvmNetwork(network)\n\n return createWalletClient({ chain, transport, account: options.account })\n}\n","import type {\n EthNetworkId,\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n} from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { clearPublicClientCache, getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEth implements IChainConnectorEth {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async getPublicClientForEvmNetwork(evmNetworkId: EthNetworkId): Promise<PublicClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkPublicClient(network)\n }\n\n async getWalletClientForEvmNetwork(\n evmNetworkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkWalletClient(network, { account })\n }\n\n public clearRpcProvidersCache(evmNetworkId?: EthNetworkId) {\n clearPublicClientCache(evmNetworkId)\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEthStub implements IChainConnectorEth {\n #network: EthNetwork\n\n constructor(network: EthNetwork) {\n this.#network = network\n }\n\n async getPublicClientForEvmNetwork(): Promise<PublicClient | null> {\n return getEvmNetworkPublicClient(this.#network)\n }\n\n async getWalletClientForEvmNetwork(\n _networkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n return getEvmNetworkWalletClient(this.#network, { account })\n }\n\n clearRpcProvidersCache(): void {\n // No-op for stub\n }\n}\n","import type { Rpc, RpcTransport, SolanaRpcApi } from \"@solana/kit\"\nimport { createDefaultRpcTransport, createSolanaRpcFromTransport, isSolanaError } from \"@solana/kit\"\nimport type { SolNetworkId } from \"@talismn/chaindata-provider\"\n\nexport type SolRpc = Rpc<SolanaRpcApi>\n\n// Public Solana RPC nodes rate-limit aggressively with HTTP 429. kit's default transport is\n// single-shot, unlike the old web3.js `Connection` which retried 429 up to 5x with backoff, so a\n// single 429 would fail an otherwise-valid request (e.g. a user's transaction submission, or token\n// discovery silently returning no tokens). This wrapper restores that behaviour.\nconst MAX_429_RETRIES = 5\nconst BASE_BACKOFF_MS = 500\n\ntype HttpErrorContext = { statusCode?: number; headers?: Headers }\n\nconst getRateLimitContext = (error: unknown): HttpErrorContext | null => {\n if (!isSolanaError(error)) return null\n\n const context = error.context as HttpErrorContext\n return context.statusCode === 429 ? context : null\n}\n\n/** Returns the delay to wait before retrying, or `null` if the error is not a retryable 429. */\nconst get429RetryDelay = (error: unknown, attempt: number): number | null => {\n const context = getRateLimitContext(error)\n if (!context) return null\n\n // honour the server's Retry-After header (delta-seconds) when present\n const retryAfter = Number(context.headers?.get(\"retry-after\"))\n if (Number.isFinite(retryAfter) && retryAfter > 0) return retryAfter * 1000\n\n // otherwise exponential backoff: 500ms, 1s, 2s, 4s, 8s\n return BASE_BACKOFF_MS * 2 ** attempt\n}\n\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason)\n\n const onAbort = () => {\n clearTimeout(timeout)\n reject(signal?.reason)\n }\n const timeout = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort)\n resolve()\n }, ms)\n signal?.addEventListener(\"abort\", onAbort, { once: true })\n })\n\n/**\n * Wraps a transport so HTTP 429 responses are retried with backoff. Solana RPC requests are\n * idempotent (`sendTransaction` is keyed by signature), so replaying a rate-limited request is safe.\n */\nconst withRetryOn429 = (transport: RpcTransport): RpcTransport => {\n const wrapped = async (config: Parameters<RpcTransport>[0]) => {\n for (let attempt = 0; ; attempt++) {\n try {\n return await transport(config)\n } catch (error) {\n const delay = attempt < MAX_429_RETRIES ? get429RetryDelay(error, attempt) : null\n if (delay === null) throw error\n await sleep(delay, config.signal)\n }\n }\n }\n return wrapped as RpcTransport\n}\n\n/**\n * How long a request may wait on an RPC before moving on to the next one. The last RPC tried gets\n * no timeout, so a slow but working node still answers when every other one has failed.\n */\nconst FAILOVER_TIMEOUT_MS = 20_000\n\nconst sendWithTimeout = async <TResponse>(\n transport: RpcTransport,\n config: RpcTransportConfig,\n timeoutMs: number\n): Promise<TResponse> => {\n const controller = new AbortController()\n const onAbort = () => controller.abort(config.signal?.reason)\n config.signal?.addEventListener(\"abort\", onAbort, { once: true })\n const timeout = setTimeout(\n () => controller.abort(new Error(`RPC request timed out after ${timeoutMs}ms`)),\n timeoutMs\n )\n\n try {\n return await transport<TResponse>({ ...config, signal: controller.signal })\n } finally {\n clearTimeout(timeout)\n config.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\ntype RpcTransportConfig = Parameters<RpcTransport>[0]\n\nconst isSendTransactionPayload = (\n payload: unknown\n): payload is { method: \"sendTransaction\"; params: unknown[] } =>\n typeof payload === \"object\" &&\n payload !== null &&\n \"method\" in payload &&\n payload.method === \"sendTransaction\" &&\n \"params\" in payload &&\n Array.isArray(payload.params)\n\nconst withoutPreflight = (config: RpcTransportConfig): RpcTransportConfig => {\n if (!isSendTransactionPayload(config.payload)) return config\n\n const [transaction, sendConfig] = config.payload.params\n return {\n ...config,\n payload: {\n ...config.payload,\n params: [transaction, { ...(sendConfig as object | undefined), skipPreflight: true }],\n },\n }\n}\n\nexport type SolTransportOptions = {\n /** Called with the url of the RPC that answered, after every successful request */\n onRpcSuccess?: (url: string) => void\n}\n\n/**\n * Sends each request to one RPC at a time, starting from the one that answered last, and moves on to\n * the next when the request fails. A transport only throws for connection, timeout and HTTP errors:\n * JSON-RPC errors come back in the response body and are returned as is.\n *\n * A failed RPC other than a rate limited one may still have forwarded a transaction. Resending it is\n * safe, as the network processes a signature once, but its preflight simulation on the next RPC\n * could then fail although it landed. So after such a failure, every resend of that transaction,\n * including the retries after a rate limit, skips preflight.\n */\nconst withFailover = (urls: string[], options: SolTransportOptions): RpcTransport => {\n const transports = urls.map((url) => createDefaultRpcTransport({ url }))\n let preferred = 0\n const mayHaveBeenProcessed = new WeakSet<RpcTransportConfig>()\n\n const failover = async <TResponse>(config: RpcTransportConfig): Promise<TResponse> => {\n if (!transports.length) throw new Error(\"No RPCs found for Solana network\")\n\n const start = preferred\n let lastError: unknown\n let rateLimitError: unknown\n for (let attempt = 0; attempt < transports.length; attempt++) {\n config.signal?.throwIfAborted()\n const index = (start + attempt) % transports.length\n const transport = transports[index] as RpcTransport\n const isLastAttempt = attempt === transports.length - 1\n const request = mayHaveBeenProcessed.has(config) ? withoutPreflight(config) : config\n\n try {\n const response = isLastAttempt\n ? await transport<TResponse>(request)\n : await sendWithTimeout<TResponse>(transport, request, FAILOVER_TIMEOUT_MS)\n preferred = index\n options.onRpcSuccess?.(urls[index] as string)\n return response\n } catch (error) {\n if (config.signal?.aborted) throw error\n lastError = error\n if (!getRateLimitContext(error)) mayHaveBeenProcessed.add(config)\n else rateLimitError ??= error\n }\n }\n throw rateLimitError ?? lastError\n }\n return failover as RpcTransport\n}\n\n/**\n * Returns a transport over all of the network's RPCs, in the given order. A request fails over to\n * the next RPC on error, and the RPC that answered is tried first for the next request. When every\n * RPC fails and one of them answered HTTP 429, the whole list is retried with backoff.\n */\nexport const getSolTransport = (\n _networkId: SolNetworkId,\n rpcs: string[],\n options: SolTransportOptions = {}\n): RpcTransport => {\n return withRetryOn429(withFailover(rpcs, options))\n}\n\nexport const getSolRpc = (\n networkId: SolNetworkId,\n rpcs: string[],\n options?: SolTransportOptions\n): SolRpc => createSolanaRpcFromTransport(getSolTransport(networkId, rpcs, options))\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type {\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n SolNetworkId,\n} from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSol implements IChainConnectorSol {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n #transports = new Map<SolNetworkId, RpcTransport>()\n #rpcs = new Map<SolNetworkId, SolRpc>()\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async #getNetworkRpcs(networkId: SolNetworkId): Promise<string[]> {\n const network = await this.#chaindataProvider.getNetworkById(networkId, \"solana\")\n if (!network) throw new Error(`Network not found: ${networkId}`)\n\n return network.rpcs\n }\n\n async getTransport(networkId: SolNetworkId): Promise<RpcTransport> {\n if (!this.#transports.has(networkId))\n this.#transports.set(\n networkId,\n getSolTransport(networkId, await this.#getNetworkRpcs(networkId))\n )\n\n return this.#transports.get(networkId)!\n }\n\n async getRpc(networkId: SolNetworkId): Promise<SolRpc> {\n if (!this.#rpcs.has(networkId))\n this.#rpcs.set(networkId, createSolanaRpcFromTransport(await this.getTransport(networkId)))\n\n return this.#rpcs.get(networkId)!\n }\n\n /** Drops cached transports/rpcs so the next call re-reads the network's rpcs from chaindata */\n clearRpcProvidersCache(networkId?: SolNetworkId) {\n if (networkId) {\n this.#transports.delete(networkId)\n this.#rpcs.delete(networkId)\n } else {\n this.#transports.clear()\n this.#rpcs.clear()\n }\n }\n}\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type { SolNetwork } from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSolStub implements IChainConnectorSol {\n #transport: RpcTransport\n #rpc: SolRpc\n\n constructor(network: Pick<SolNetwork, \"id\" | \"rpcs\">) {\n this.#transport = getSolTransport(network.id, network.rpcs)\n this.#rpc = createSolanaRpcFromTransport(this.#transport)\n }\n\n async getRpc(): Promise<SolRpc> {\n return this.#rpc\n }\n\n async getTransport(): Promise<RpcTransport> {\n return this.#transport\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["packageJson.name","RESPONSE_TIMEOUT","log"],"sources":["../package.json","../src/log.ts","../src/dot/ChainConnectorDot.ts","../src/dot/ChainConnectorDotPapi.ts","../src/dot/ChainConnectorDotStub.ts","../src/eth/getChainFromEvmNetwork.ts","../src/eth/getTransportForEvmNetwork.ts","../src/eth/getEvmNetworkPublicClient.ts","../src/eth/getEvmNetworkWalletClient.ts","../src/eth/ChainConnectorEth.ts","../src/eth/ChainConnectorEthStub.ts","../src/sol/getSolRpc.ts","../src/sol/ChainConnectorSol.ts","../src/sol/ChainConnectorSolStub.ts"],"sourcesContent":["","import anylogger from \"anylogger\"\n\nimport packageJson from \"../package.json\"\n\nexport default anylogger(packageJson.name)\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport {\n getWsProvider,\n type StatusChange,\n WsEvent,\n type WsJsonRpcProvider,\n} from \"@polkadot-api/ws-provider\"\nimport type { DotNetworkId, IChaindataNetworkProvider } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\n// errors that require an rpc fallback\n// https://docs.blastapi.io/blast-documentation/things-you-need-to-know/error-reference\nconst BAD_RPC_ERRORS: Record<string, string> = {\n \"-32097\": \"Rate limit exceeded\",\n \"-32098\": \"Capacity exceeded\",\n}\n\nconst RESPONSE_TIMEOUT = 30_000 // max wait for an rpc response (including connection time)\nconst KEEP_ALIVE_INTERVAL = 20_000 // periodic system_health to keep idle sockets alive (ws-provider kills quiet sockets after its 40s heartbeat)\n/**\n * How long a connection stays open once its last user releases it. A one-off request is\n * often followed by more traffic to the same chain (balances read the runtime version,\n * then subscribe to storage), which then reuses the socket instead of opening a new one.\n */\nconst IDLE_CLOSE_DELAY = 30_000\n\n/** in-flight requests reject with DestroyedError when a connection is torn down - expected, not worth logging */\nconst isDestroyedError = (error: unknown): boolean =>\n error instanceof Error && error.name === \"DestroyedError\"\nconst STALE_NOTIFY_TIMEOUT = 30_000 // how long a chain can be disconnected before subscribers are notified\n\nexport class ChainConnectionError extends Error {\n type: \"CHAIN_CONNECTION_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`Unable to connect to chain ${chainId}`, options)\n\n this.type = \"CHAIN_CONNECTION_ERROR\"\n this.chainId = chainId\n }\n}\n\n/**\n * Passed to subscription callbacks when the chain has been unreachable for a while. Not\n * terminal: the subscription stays registered and is re-issued when a socket connects.\n */\nexport class StaleRpcError extends Error {\n type: \"STALE_RPC_ERROR\"\n chainId: string\n\n constructor(chainId: string, options?: ErrorOptions) {\n super(`RPCs are stale/unavailable for chain ${chainId}`, options)\n\n this.type = \"STALE_RPC_ERROR\"\n this.chainId = chainId\n }\n}\n\ntype SocketUserId = number\n\ntype Subscription = {\n subscribeMethod: string\n params: unknown[]\n callback: SubscriptionCallback\n /** cancels the pending subscribe request, if any */\n cancelRequest: (() => void) | null\n /** stops routing notifications to the callback */\n stopFollow: (() => void) | null\n serverSubId: string | number | null\n unsubscribed: boolean\n}\n\ntype Connection = {\n chainId: DotNetworkId\n provider: WsJsonRpcProvider\n client: SubstrateClient\n users: Set<SocketUserId>\n subscriptions: Set<Subscription>\n wasConnected: boolean\n keepAliveInterval: ReturnType<typeof setInterval> | null\n staleTimeout: ReturnType<typeof setTimeout> | null\n /** closes the connection once it has had no users for IDLE_CLOSE_DELAY */\n idleTimeout: ReturnType<typeof setTimeout> | null\n}\n\nexport type ChainConnectorDotOptions = {\n /**\n * How long a new socket may take to open before the provider gives up on the endpoint\n * and tries the next one. Defaults to polkadot-api's 5 seconds. A slow device or\n * network can take longer than that to connect while it is busy, as a phone app is\n * at startup, and every endpoint then times out in turn.\n */\n connectionTimeout?: number\n}\n\n/**\n * ChainConnector provides an interface similar to a websocket JSON-RPC provider, but with three points of difference:\n *\n * 1. ChainConnector methods all accept a `chainId` instead of an array of RPCs. RPCs are then fetched internally from chaindata.\n * 2. ChainConnector creates only one socket connection per chain (via polkadot-api's ws-provider, which handles\n * endpoint rotation, reconnection and stale-socket detection) and ensures that all downstream requests to a chain\n * share that connection.\n * 3. Subscriptions return a callable `unsubscribe` method instead of an id, and are automatically re-established\n * when the provider reconnects (possibly to another endpoint).\n *\n * Additionally, when run on the clientside of a dapp where `window.talismanSub` is available, instead of spinning up new websocket\n * connections this class will forward all requests through to the wallet backend - where another instance of this class will\n * handle the websocket connections.\n */\nexport class ChainConnectorDot implements IChainConnectorDot {\n #chaindataChainProvider: IChaindataNetworkProvider\n #connectionTimeout: number | undefined\n\n #connections: Record<DotNetworkId, Connection> = {}\n #pendingConnections: Record<DotNetworkId, Promise<Connection>> = {}\n\n constructor(\n chaindataChainProvider: IChaindataNetworkProvider,\n options?: ChainConnectorDotOptions\n ) {\n this.#chaindataChainProvider = chaindataChainProvider\n this.#connectionTimeout = options?.connectionTimeout\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n async send<T = any>(\n chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean | undefined,\n extraOptions?: {\n /**\n * Set to `true` if this query is speculative, i.e. if on some chains it's expected that it will raise a wasm unreachable error of the form:\n *\n * 4003: Client error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\n *\n * By setting expectErrors to true, this method won't pollute the logs with errors we intend to have happen.\n * An example use case of this is when you plan to catch the wasm unreachable error on chains that don't support the query, and then fall back\n * to another query or perhaps an empty result.\n */\n expectErrors?: boolean\n }\n ): Promise<T> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n return await talismanSub.send(genesisHash, method, params)\n } catch (error) {\n log.warn(\n `Failed to make wallet-proxied send request for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n try {\n return await this.request<T>(connection, method, params)\n } catch (err) {\n const error = err as (Error & { code?: number; data?: unknown }) | null\n\n if (error?.message === \"TIMEOUT\") {\n log.error(`ChainConnector timeout`, { chainId, error })\n connection.provider.switch()\n throw new Error(\"Timeout\")\n }\n\n const badRpcError = BAD_RPC_ERRORS[error?.code?.toString() ?? \"\"]\n if (badRpcError) {\n log.error(`ChainConnector ${badRpcError}`, { error, chainId })\n connection.provider.switch()\n throw new Error(badRpcError)\n }\n\n if (!extraOptions?.expectErrors)\n log.error(\n `Failed to send ${method} on chain ${chainId}\\nparams: ${JSON.stringify(params)}`,\n {\n error,\n }\n )\n\n throw error\n } finally {\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n async subscribe(\n chainId: DotNetworkId,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000 // 30 seconds in milliseconds\n ): Promise<(unsubscribeMethod: string) => void> {\n const talismanSub = this.getTalismanSub()\n if (talismanSub !== undefined) {\n try {\n const genesisHash = await this.getGenesisHash(chainId)\n\n const subscriptionId = await talismanSub.subscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n )\n\n return (unsubscribeMethod: string) =>\n talismanSub.unsubscribe(subscriptionId, unsubscribeMethod)\n } catch (error) {\n log.warn(\n `Failed to create wallet-proxied subscription for chain ${chainId}. Falling back to plain websocket`,\n error\n )\n }\n }\n\n let socketUserId: SocketUserId\n let connection: Connection\n try {\n ;[socketUserId, connection] = await this.acquireConnection(chainId)\n } catch (error) {\n throw new StaleRpcError(chainId, { cause: error })\n }\n\n const subscription: Subscription = {\n subscribeMethod,\n params,\n callback,\n cancelRequest: null,\n stopFollow: null,\n serverSubId: null,\n unsubscribed: false,\n }\n connection.subscriptions.add(subscription)\n\n // if the chain can't be reached at all, let the caller know after a while (the provider keeps retrying)\n if (timeout && !connection.wasConnected) {\n const staleWarning = setTimeout(() => {\n if (!subscription.unsubscribed && !connection.wasConnected)\n callback(new StaleRpcError(chainId), null)\n }, timeout)\n const clear = () => clearTimeout(staleWarning)\n // piggyback on the follow setup to clear the warning once anything happens\n const originalCallback = subscription.callback\n subscription.callback = (error, result) => {\n clear()\n subscription.callback = originalCallback\n originalCallback(error, result)\n }\n }\n\n this.startSubscription(connection, subscription)\n\n return (unsubscribeMethod: string) => {\n if (subscription.unsubscribed) return\n subscription.unsubscribed = true\n\n subscription.cancelRequest?.()\n subscription.stopFollow?.()\n\n // the connection may have been replaced by a reset() since we subscribed. It stays\n // open for a while after its last user leaves, so unsubscribe on the server even then\n const current = this.#connections[chainId]\n if (subscription.serverSubId !== null && current)\n try {\n current.client.request(unsubscribeMethod, [subscription.serverSubId]).catch((error) => {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n })\n } catch (error) {\n if (!isDestroyedError(error)) log.warn(`Failed to unsubscribe from ${chainId}`, error)\n }\n\n current?.subscriptions.delete(subscription)\n this.releaseConnection(chainId, socketUserId)\n }\n }\n\n /**\n * Kills and recreates the connection for a chain, if any.\n * Useful after changing a network's rpcs to make sure the new list is applied for further requests.\n * Active subscriptions are automatically re-established on the new connection.\n */\n async reset(chainId: DotNetworkId) {\n log.info(\"ChainConnector reset\", chainId)\n const connection = this.#connections[chainId]\n if (!connection) return\n\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n\n // recreate a connection for the active subscriptions, if any\n if (connection.subscriptions.size) {\n try {\n const fresh = await this.createConnection(chainId)\n fresh.users = connection.users\n fresh.subscriptions = connection.subscriptions\n this.#connections[chainId] = fresh\n for (const subscription of fresh.subscriptions) this.startSubscription(fresh, subscription)\n } catch (error) {\n log.warn(`Failed to recreate connection for ${chainId} after reset`, error)\n // not a StaleRpcError: no connection is left to re-issue these subscriptions,\n // so subscribers must treat this one as terminal\n for (const subscription of connection.subscriptions)\n subscription.callback(new ChainConnectionError(chainId, { cause: error }), null)\n }\n }\n }\n\n /** Sends a request over a connection, throwing `Error(\"TIMEOUT\")` if no response arrives in time */\n private request<T>(\n connection: Connection,\n method: string,\n params: unknown[],\n timeoutMs = RESPONSE_TIMEOUT\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n cancel()\n reject(new Error(\"TIMEOUT\"))\n }, timeoutMs)\n\n const cancel = connection.client._request<T, unknown>(method, params, {\n onSuccess: (result) => {\n clearTimeout(timer)\n resolve(result)\n },\n onError: (error) => {\n clearTimeout(timer)\n reject(error)\n },\n })\n })\n }\n\n /** Issues the subscribe request and routes notifications to the subscription callback */\n private startSubscription(connection: Connection, subscription: Subscription) {\n subscription.serverSubId = null\n subscription.stopFollow = null\n\n subscription.cancelRequest = connection.client._request<string | number, unknown>(\n subscription.subscribeMethod,\n subscription.params,\n {\n onSuccess: (serverSubId, follow) => {\n subscription.cancelRequest = null\n if (subscription.unsubscribed) return\n\n subscription.serverSubId = serverSubId\n // raw-client matches notifications by the raw (not stringified) subscription id, but types it as string\n subscription.stopFollow = follow(serverSubId as string, {\n next: (result) => subscription.callback(null, result),\n error: (error) => subscription.callback(error, null),\n })\n },\n onError: (error) => {\n subscription.cancelRequest = null\n if (!subscription.unsubscribed) subscription.callback(error, null)\n },\n }\n )\n }\n\n /**\n * Get (or create) the shared connection for a chain.\n *\n * The caller must call releaseConnection with the returned SocketUserId once they are finished with it.\n */\n private async acquireConnection(chainId: DotNetworkId): Promise<[SocketUserId, Connection]> {\n // a single creation promise per chain guarantees that concurrent callers share the same connection\n let connection = this.#connections[chainId]\n if (!connection) {\n if (!this.#pendingConnections[chainId]) {\n this.#pendingConnections[chainId] = this.createConnection(chainId)\n .then((created) => {\n this.#connections[chainId] = created\n return created\n })\n .finally(() => {\n delete this.#pendingConnections[chainId]\n })\n }\n connection = await this.#pendingConnections[chainId]\n }\n\n if (connection.idleTimeout) {\n clearTimeout(connection.idleTimeout)\n connection.idleTimeout = null\n }\n const socketUserId = this.getExclusiveRandomId([...connection.users])\n connection.users.add(socketUserId)\n\n return [socketUserId, connection]\n }\n\n private async createConnection(chainId: DotNetworkId): Promise<Connection> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const rpcs = chain.rpcs.concat()\n if (!rpcs.length) throw new Error(`No healthy RPCs available for chain ${chainId}`)\n\n // will be assigned below - the provider config needs to reference the connection\n let connection: Connection = null as unknown as Connection\n\n const provider = getWsProvider(rpcs, {\n onStatusChanged: (status: StatusChange) => this.handleStatusChange(connection, status),\n ...(this.#connectionTimeout !== undefined && { timeout: this.#connectionTimeout }),\n })\n\n const client = createClient(provider)\n\n connection = {\n chainId,\n provider,\n client,\n users: new Set(),\n subscriptions: new Set(),\n wasConnected: false,\n keepAliveInterval: null,\n staleTimeout: null,\n idleTimeout: null,\n }\n\n return connection\n }\n\n private handleStatusChange(connection: Connection, status: StatusChange) {\n // connection is still being constructed on the initial CONNECTING event\n if (!connection) return\n // ignore events from a connection that has been reset/destroyed\n if (this.#connections[connection.chainId] !== connection) return\n\n if (status.type === WsEvent.CONNECTED) {\n if (connection.staleTimeout) {\n clearTimeout(connection.staleTimeout)\n connection.staleTimeout = null\n }\n\n const isReconnect = connection.wasConnected\n connection.wasConnected = true\n\n // periodically send a request to keep the socket alive when there is no other traffic\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = setInterval(() => {\n this.request(connection, \"system_health\", [], KEEP_ALIVE_INTERVAL).catch((error) => {\n if (!isDestroyedError(error))\n log.warn(`Failed keep-alive for socket ${connection.chainId}`, error)\n })\n }, KEEP_ALIVE_INTERVAL)\n\n // server-side subscriptions died with the previous socket : re-establish them\n // (skip author_* subscriptions : resubmitting an extrinsic is not safe)\n if (isReconnect)\n for (const subscription of connection.subscriptions) {\n if (subscription.unsubscribed) continue\n if (subscription.subscribeMethod.startsWith(\"author_\")) continue\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n this.startSubscription(connection, subscription)\n }\n } else {\n if (connection.keepAliveInterval) {\n clearInterval(connection.keepAliveInterval)\n connection.keepAliveInterval = null\n }\n\n // notify subscribers if the chain stays unreachable for too long\n if (!connection.staleTimeout && connection.subscriptions.size) {\n connection.staleTimeout = setTimeout(() => {\n connection.staleTimeout = null\n for (const subscription of connection.subscriptions)\n if (!subscription.unsubscribed)\n subscription.callback(new StaleRpcError(connection.chainId), null)\n }, STALE_NOTIFY_TIMEOUT)\n }\n }\n }\n\n private releaseConnection(chainId: DotNetworkId, socketUserId: SocketUserId): void {\n const connection = this.#connections[chainId]\n if (!connection) return\n\n connection.users.delete(socketUserId)\n if (connection.users.size > 0 || connection.idleTimeout) return\n\n connection.idleTimeout = setTimeout(() => {\n connection.idleTimeout = null\n if (connection.users.size > 0 || this.#connections[chainId] !== connection) return\n this.destroyConnection(connection)\n delete this.#connections[chainId]\n }, IDLE_CLOSE_DELAY)\n }\n\n private destroyConnection(connection: Connection): void {\n if (connection.keepAliveInterval) clearInterval(connection.keepAliveInterval)\n if (connection.staleTimeout) clearTimeout(connection.staleTimeout)\n if (connection.idleTimeout) clearTimeout(connection.idleTimeout)\n connection.keepAliveInterval = null\n connection.staleTimeout = null\n connection.idleTimeout = null\n\n // detach subscriptions before destroying the client so their callbacks don't receive a DestroyedError\n for (const subscription of connection.subscriptions) {\n subscription.stopFollow?.()\n subscription.cancelRequest?.()\n subscription.stopFollow = null\n subscription.cancelRequest = null\n subscription.serverSubId = null\n }\n\n try {\n connection.client.destroy()\n } catch (error) {\n log.warn(`Error occurred destroying connection ${connection.chainId}`, error)\n }\n }\n\n private async getGenesisHash(chainId: DotNetworkId): Promise<string> {\n const chain = await this.#chaindataChainProvider.getNetworkById(chainId, \"polkadot\")\n if (!chain) throw new Error(`Chain ${chainId} not found in store`)\n\n const { genesisHash } = chain\n if (typeof genesisHash !== \"string\")\n throw new Error(`Chain ${chainId} has no genesisHash in store`)\n\n return genesisHash\n }\n\n /** continues to generate a random number until it finds one which is not present in the exclude list */\n private getExclusiveRandomId(exclude: number[] = []): number {\n let id = this.getRandomId()\n while (exclude.includes(id)) {\n id = this.getRandomId()\n }\n return id\n }\n /** generates a random number */\n private getRandomId(): number {\n return Math.trunc(Math.random() * 10 ** 8)\n }\n\n private getTalismanSub() {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n const talismanSub = typeof window !== \"undefined\" && (window as any).talismanSub\n\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSend: Function | undefined = talismanSub?.rpcByGenesisHashSend\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashSubscribe: Function | undefined = talismanSub?.rpcByGenesisHashSubscribe\n // biome-ignore lint/complexity/noBannedTypes: legacy\n const rpcByGenesisHashUnsubscribe: Function | undefined =\n talismanSub?.rpcByGenesisHashUnsubscribe\n\n if (typeof rpcByGenesisHashSend !== \"function\") return\n if (typeof rpcByGenesisHashSubscribe !== \"function\") return\n if (typeof rpcByGenesisHashUnsubscribe !== \"function\") return\n\n return {\n // biome-ignore lint/suspicious/noExplicitAny: legacy\n send: <T = any>(genesisHash: string, method: string, params: unknown[]): Promise<T> =>\n rpcByGenesisHashSend(genesisHash, method, params),\n\n subscribe: (\n genesisHash: string,\n subscribeMethod: string,\n responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false\n ): Promise<string> =>\n rpcByGenesisHashSubscribe(\n genesisHash,\n subscribeMethod,\n responseMethod,\n params,\n callback,\n timeout\n ),\n\n unsubscribe: (subscriptionId: string, unsubscribeMethod: string): Promise<void> =>\n rpcByGenesisHashUnsubscribe(subscriptionId, unsubscribeMethod),\n }\n }\n}\n","import type { DotNetworkId } from \"@talismn/chaindata-provider\"\n\nimport log from \"../log\"\nimport { StaleRpcError } from \"./ChainConnectorDot\"\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst RESPONSE_TIMEOUT = 30_000\nconst FAILURES_BEFORE_FIRST_RESULT = 3\n\ntype HexString = `0x${string}`\ntype StorageChanges = { block: HexString; changes: [HexString, HexString | null][] }\n\n/** The parts of a polkadot-api `PolkadotClient` that the connector uses */\nexport type PapiClient = {\n /** `PolkadotClient` types it without `abortSignal`, but it is substrate-client's `request`, which honours it */\n _request: <Reply>(method: string, params: unknown[], abortSignal?: AbortSignal) => Promise<Reply>\n bestBlocks$: {\n subscribe: (observer: {\n next: (blocks: { hash: string }[]) => void\n error: (error: unknown) => void\n complete: () => void\n }) => { unsubscribe: () => void }\n }\n}\n\n/**\n * Runs `@talismn/balances` over a dapp's polkadot-api clients, so the dapp and its balances share one socket per chain.\n *\n * `state_subscribeStorage` is the only subscription balances uses. It is served by querying the keys at each new\n * best block and reporting the values that changed, like the node does. One query runs at a time, for the latest\n * best block. A failed query is retried at the next block, because balances treats a subscription error as final\n * and would stop updating that network. Only when the first three queries fail does the subscription report the error.\n */\nexport class ChainConnectorDotPapi implements IChainConnectorDot {\n #clientFor: (networkId: DotNetworkId) => PapiClient | undefined\n\n constructor(clientFor: (networkId: DotNetworkId) => PapiClient | undefined) {\n this.#clientFor = clientFor\n }\n\n async send<T = unknown>(networkId: DotNetworkId, method: string, params: unknown[]): Promise<T> {\n return requestWithTimeout<T>(this.getClient(networkId), method, params, new AbortController())\n }\n\n async subscribe(\n networkId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout: number | false = 30_000\n ): Promise<(unsubscribeMethod: string) => void> {\n const client = this.getClient(networkId)\n if (subscribeMethod !== \"state_subscribeStorage\")\n throw new Error(`ChainConnectorDotPapi does not support ${subscribeMethod}`)\n\n const [keys] = params as [HexString[]]\n const values = new Map<HexString, HexString | null>()\n let bestBlockHash: string | undefined\n let queriedBlockHash: string | undefined\n let inFlight: AbortController | undefined\n let delivered = false\n let failures = 0\n let active = true\n let subscription: { unsubscribe: () => void } | undefined\n const staleTimer = timeout\n ? setTimeout(() => callback(new StaleRpcError(networkId), null), timeout)\n : undefined\n\n const stop = () => {\n active = false\n clearTimeout(staleTimer)\n inFlight?.abort()\n subscription?.unsubscribe()\n }\n\n const finish = (error: Error) => {\n if (!active) return\n stop()\n callback(error, null)\n }\n\n const reportChanges = (result: StorageChanges) => {\n const changes = result.changes.filter(([key, value]) => values.get(key) !== value)\n for (const [key, value] of changes) values.set(key, value)\n if (!changes.length) return\n\n delivered = true\n clearTimeout(staleTimer)\n callback(null, { block: result.block, changes })\n }\n\n const reportFailure = (error: Error) => {\n if (delivered || ++failures < FAILURES_BEFORE_FIRST_RESULT)\n return log.warn(\n `state_queryStorageAt failed on ${networkId}, retrying at the next block`,\n error\n )\n finish(error)\n }\n\n const queryBestBlock = async () => {\n if (!active || inFlight || !bestBlockHash || bestBlockHash === queriedBlockHash) return\n const blockHash = bestBlockHash\n queriedBlockHash = blockHash\n const controller = new AbortController()\n inFlight = controller\n\n try {\n const [result] = await requestWithTimeout<StorageChanges[]>(\n client,\n \"state_queryStorageAt\",\n [keys, blockHash],\n controller\n )\n if (!active) return\n if (!result) throw new Error(`Empty state_queryStorageAt response on ${networkId}`)\n reportChanges(result)\n } catch (error) {\n if (active) reportFailure(error as Error)\n } finally {\n if (inFlight === controller) inFlight = undefined\n queryBestBlock()\n }\n }\n\n try {\n subscription = client.bestBlocks$.subscribe({\n next: ([best]) => {\n bestBlockHash = best?.hash\n queryBestBlock()\n },\n error: (error) => finish(error as Error),\n complete: () =>\n finish(new Error(`polkadot-api client for ${networkId} stopped following blocks`)),\n })\n } catch (error) {\n stop()\n throw error\n }\n if (!active) subscription.unsubscribe()\n\n return stop\n }\n\n async reset() {}\n\n private getClient(networkId: DotNetworkId): PapiClient {\n const client = this.#clientFor(networkId)\n if (!client) throw new Error(`No polkadot-api client for network ${networkId}`)\n return client\n }\n}\n\n/** rejects on its own timer too, so a client that ignores the abort signal cannot hang the caller */\nconst requestWithTimeout = <T>(\n client: PapiClient,\n method: string,\n params: unknown[],\n controller: AbortController\n) =>\n new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n controller.abort()\n reject(new Error(\"Timeout\"))\n }, RESPONSE_TIMEOUT)\n try {\n client\n ._request<T>(method, params, controller.signal)\n .then(resolve, reject)\n .finally(() => clearTimeout(timer))\n } catch (error) {\n clearTimeout(timer)\n reject(error)\n }\n })\n","import { createClient, type SubstrateClient } from \"@polkadot-api/substrate-client\"\nimport { getWsProvider } from \"@polkadot-api/ws-provider\"\nimport type { DotNetwork, DotNetworkId } from \"@talismn/chaindata-provider\"\nimport { throwAfter } from \"@talismn/util\"\n\nimport type { IChainConnectorDot, SubscriptionCallback } from \"./IChainConnectorDot\"\n\nconst TIMEOUT = 10_000\n\nexport class ChainConnectorDotStub implements IChainConnectorDot {\n #client: SubstrateClient\n\n constructor(network: DotNetwork) {\n this.#client = createClient(getWsProvider(network.rpcs.concat()))\n }\n\n async send<T = unknown>(\n _chainId: DotNetworkId,\n method: string,\n params: unknown[],\n _isCacheable?: boolean\n ): Promise<T> {\n return await Promise.race([\n this.#client.request<T>(method, params),\n throwAfter(TIMEOUT, `Request ${method} timed out after ${TIMEOUT}ms`),\n ])\n }\n\n async subscribe(\n _chainId: DotNetworkId,\n subscribeMethod: string,\n _responseMethod: string,\n params: unknown[],\n callback: SubscriptionCallback,\n timeout?: number | false\n ): Promise<(unsubscribeMethod: string) => void> {\n let stopFollow: (() => void) | null = null\n let unsubscribed = false\n\n const serverSubId = await Promise.race([\n new Promise<string | number>((resolve, reject) => {\n this.#client._request<string | number, unknown>(subscribeMethod, params, {\n onSuccess: (subId, follow) => {\n stopFollow = follow(subId as string, {\n next: (result) => callback(null, result),\n error: (error) => callback(error, null),\n })\n resolve(subId)\n },\n onError: reject,\n })\n }),\n throwAfter(timeout || TIMEOUT, `Subscription timed out after ${timeout || TIMEOUT}ms`),\n ])\n\n return (unsubscribeMethod: string) => {\n if (unsubscribed) return\n unsubscribed = true\n stopFollow?.()\n this.#client.request(unsubscribeMethod, [serverSubId]).catch(() => {}) // connection may already be gone\n }\n }\n\n reset(): Promise<void> {\n throw new Error(\"ChainConnectorDotStub does not implement reset\")\n }\n\n destroy() {\n this.#client.destroy()\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport { camelCase, fromPairs, toPairs } from \"lodash-es\"\nimport type { Chain, ChainContract } from \"viem\"\nimport * as viemChains from \"viem/chains\"\n\n// exclude zoraTestnet which uses Hyperliquid's chain id\nconst { zoraTestnet, ...validViemChains } = viemChains\n\n// viem chains benefit from multicall config & other viem goodies\nconst VIEM_CHAINS = Object.keys(validViemChains).reduce(\n (acc, curr) => {\n const chain = validViemChains[curr as keyof typeof validViemChains]\n acc[chain.id] = chain\n return acc\n },\n {} as Record<number, Chain>\n)\n\nconst chainsCache = new Map<string, Chain>()\n\nexport const clearChainsCache = (networkId?: EthNetworkId) => {\n if (networkId) chainsCache.delete(networkId)\n else chainsCache.clear()\n}\n\nexport const getChainFromEvmNetwork = (network: EthNetwork): Chain => {\n const { symbol, decimals } = network.nativeCurrency\n\n if (!chainsCache.has(network.id)) {\n const chainRpcs = network.rpcs ?? []\n\n const viemChain = VIEM_CHAINS[Number(network.id)] ?? {}\n\n const chain: Chain = {\n ...viemChain,\n id: Number(network.id),\n name: network.name ?? `Ethereum Chain ${network.id}`,\n rpcUrls: {\n public: { http: chainRpcs },\n default: { http: chainRpcs },\n },\n nativeCurrency: {\n symbol,\n decimals,\n name: symbol,\n },\n contracts: {\n ...viemChain.contracts,\n ...(network.contracts\n ? fromPairs(\n toPairs(network.contracts).map(([name, address]): [string, ChainContract] => [\n camelCase(name),\n { address },\n ])\n )\n : {}),\n },\n }\n\n chainsCache.set(network.id, chain)\n }\n\n return chainsCache.get(network.id) as Chain\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { fallback, http, shouldThrow } from \"viem\"\n\nexport type TransportOptions = {\n batch?:\n | boolean\n | {\n batchSize?: number | undefined\n wait?: number | undefined\n }\n}\n\n// Frontier nodes report reverts with a message viem does not recognize, which makes fallback retry every rpc\nconst FRONTIER_EXECUTION_ERROR = /VM Exception while processing transaction/\n\nconst isFinalError = (error: Error) =>\n shouldThrow(error) || FRONTIER_EXECUTION_ERROR.test(error.message)\n\nexport const getTransportForEvmNetwork = (\n evmNetwork: EthNetwork,\n options: TransportOptions = {}\n) => {\n if (!evmNetwork.rpcs?.length) throw new Error(\"No RPCs found for EVM network\")\n\n const { batch } = options\n\n return fallback(\n evmNetwork.rpcs.map((url) => http(url, { batch, retryCount: 0 })),\n { retryCount: 0, shouldThrow: isFinalError }\n )\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { createPublicClient, type PublicClient } from \"viem\"\n\nimport { clearChainsCache, getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork, type TransportOptions } from \"./getTransportForEvmNetwork\"\n\nconst MUTLICALL_BATCH_WAIT = 25\nconst MUTLICALL_BATCH_SIZE = 100\n\nconst HTTP_BATCH_WAIT = 25\nconst HTTP_BATCH_SIZE_WITH_MULTICALL = 10\nconst HTTP_BATCH_SIZE_WITHOUT_MULTICALL = 30\n\n// cache to reuse previously created public clients\nconst publicClientCache = new Map<string, PublicClient>()\n\nexport const clearPublicClientCache = (evmNetworkId?: string) => {\n clearChainsCache(evmNetworkId)\n\n if (evmNetworkId) publicClientCache.delete(evmNetworkId)\n else publicClientCache.clear()\n}\n\nexport const getEvmNetworkPublicClient = (network: EthNetwork): PublicClient => {\n const chain = getChainFromEvmNetwork(network)\n\n if (!publicClientCache.has(network.id)) {\n if (!network.rpcs.length) throw new Error(\"No RPCs found for Ethereum network\")\n\n const batch = chain.contracts?.multicall3\n ? { multicall: { wait: MUTLICALL_BATCH_WAIT, batchSize: MUTLICALL_BATCH_SIZE } }\n : undefined\n\n const transportOptions: TransportOptions = {\n batch: {\n batchSize: chain.contracts?.multicall3\n ? HTTP_BATCH_SIZE_WITH_MULTICALL\n : HTTP_BATCH_SIZE_WITHOUT_MULTICALL,\n wait: HTTP_BATCH_WAIT,\n },\n }\n\n const transport = getTransportForEvmNetwork(network, transportOptions)\n\n publicClientCache.set(\n network.id,\n createPublicClient({\n chain,\n transport,\n batch,\n })\n )\n }\n\n return publicClientCache.get(network.id) as PublicClient\n}\n","import type { EthNetwork } from \"@talismn/chaindata-provider\"\nimport { type Account, createWalletClient, type WalletClient } from \"viem\"\n\nimport { getChainFromEvmNetwork } from \"./getChainFromEvmNetwork\"\nimport { getTransportForEvmNetwork } from \"./getTransportForEvmNetwork\"\n\ntype WalletClientOptions = {\n account?: `0x${string}` | Account\n}\n\nexport const getEvmNetworkWalletClient = (\n network: EthNetwork,\n options: WalletClientOptions = {}\n): WalletClient => {\n const chain = getChainFromEvmNetwork(network)\n\n const transport = getTransportForEvmNetwork(network)\n\n return createWalletClient({ chain, transport, account: options.account })\n}\n","import type {\n EthNetworkId,\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n} from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { clearPublicClientCache, getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEth implements IChainConnectorEth {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async getPublicClientForEvmNetwork(evmNetworkId: EthNetworkId): Promise<PublicClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkPublicClient(network)\n }\n\n async getWalletClientForEvmNetwork(\n evmNetworkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n const network = await this.#chaindataProvider.getNetworkById(evmNetworkId, \"ethereum\")\n if (!network) return null\n\n return getEvmNetworkWalletClient(network, { account })\n }\n\n public clearRpcProvidersCache(evmNetworkId?: EthNetworkId) {\n clearPublicClientCache(evmNetworkId)\n }\n}\n","import type { EthNetwork, EthNetworkId } from \"@talismn/chaindata-provider\"\nimport type { Account, PublicClient, WalletClient } from \"viem\"\n\nimport { getEvmNetworkPublicClient } from \"./getEvmNetworkPublicClient\"\nimport { getEvmNetworkWalletClient } from \"./getEvmNetworkWalletClient\"\nimport type { IChainConnectorEth } from \"./IChainConnectorEth\"\n\nexport class ChainConnectorEthStub implements IChainConnectorEth {\n #network: EthNetwork\n\n constructor(network: EthNetwork) {\n this.#network = network\n }\n\n async getPublicClientForEvmNetwork(): Promise<PublicClient | null> {\n return getEvmNetworkPublicClient(this.#network)\n }\n\n async getWalletClientForEvmNetwork(\n _networkId: EthNetworkId,\n account?: `0x${string}` | Account\n ): Promise<WalletClient | null> {\n return getEvmNetworkWalletClient(this.#network, { account })\n }\n\n clearRpcProvidersCache(): void {\n // No-op for stub\n }\n}\n","import type { Rpc, RpcTransport, SolanaRpcApi } from \"@solana/kit\"\nimport { createDefaultRpcTransport, createSolanaRpcFromTransport, isSolanaError } from \"@solana/kit\"\nimport type { SolNetworkId } from \"@talismn/chaindata-provider\"\n\nexport type SolRpc = Rpc<SolanaRpcApi>\n\n// Public Solana RPC nodes rate-limit aggressively with HTTP 429. kit's default transport is\n// single-shot, unlike the old web3.js `Connection` which retried 429 up to 5x with backoff, so a\n// single 429 would fail an otherwise-valid request (e.g. a user's transaction submission, or token\n// discovery silently returning no tokens). This wrapper restores that behaviour.\nconst MAX_429_RETRIES = 5\nconst BASE_BACKOFF_MS = 500\n\ntype HttpErrorContext = { statusCode?: number; headers?: Headers }\n\nconst getRateLimitContext = (error: unknown): HttpErrorContext | null => {\n if (!isSolanaError(error)) return null\n\n const context = error.context as HttpErrorContext\n return context.statusCode === 429 ? context : null\n}\n\n/** Returns the delay to wait before retrying, or `null` if the error is not a retryable 429. */\nconst get429RetryDelay = (error: unknown, attempt: number): number | null => {\n const context = getRateLimitContext(error)\n if (!context) return null\n\n // honour the server's Retry-After header (delta-seconds) when present\n const retryAfter = Number(context.headers?.get(\"retry-after\"))\n if (Number.isFinite(retryAfter) && retryAfter > 0) return retryAfter * 1000\n\n // otherwise exponential backoff: 500ms, 1s, 2s, 4s, 8s\n return BASE_BACKOFF_MS * 2 ** attempt\n}\n\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason)\n\n const onAbort = () => {\n clearTimeout(timeout)\n reject(signal?.reason)\n }\n const timeout = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort)\n resolve()\n }, ms)\n signal?.addEventListener(\"abort\", onAbort, { once: true })\n })\n\n/**\n * Wraps a transport so HTTP 429 responses are retried with backoff. Solana RPC requests are\n * idempotent (`sendTransaction` is keyed by signature), so replaying a rate-limited request is safe.\n */\nconst withRetryOn429 = (transport: RpcTransport): RpcTransport => {\n const wrapped = async (config: Parameters<RpcTransport>[0]) => {\n for (let attempt = 0; ; attempt++) {\n try {\n return await transport(config)\n } catch (error) {\n const delay = attempt < MAX_429_RETRIES ? get429RetryDelay(error, attempt) : null\n if (delay === null) throw error\n await sleep(delay, config.signal)\n }\n }\n }\n return wrapped as RpcTransport\n}\n\n/**\n * How long a request may wait on an RPC before moving on to the next one. The last RPC tried gets\n * no timeout, so a slow but working node still answers when every other one has failed.\n */\nconst FAILOVER_TIMEOUT_MS = 20_000\n\nconst sendWithTimeout = async <TResponse>(\n transport: RpcTransport,\n config: RpcTransportConfig,\n timeoutMs: number\n): Promise<TResponse> => {\n const controller = new AbortController()\n const onAbort = () => controller.abort(config.signal?.reason)\n config.signal?.addEventListener(\"abort\", onAbort, { once: true })\n const timeout = setTimeout(\n () => controller.abort(new Error(`RPC request timed out after ${timeoutMs}ms`)),\n timeoutMs\n )\n\n try {\n return await transport<TResponse>({ ...config, signal: controller.signal })\n } finally {\n clearTimeout(timeout)\n config.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\ntype RpcTransportConfig = Parameters<RpcTransport>[0]\n\nconst isSendTransactionPayload = (\n payload: unknown\n): payload is { method: \"sendTransaction\"; params: unknown[] } =>\n typeof payload === \"object\" &&\n payload !== null &&\n \"method\" in payload &&\n payload.method === \"sendTransaction\" &&\n \"params\" in payload &&\n Array.isArray(payload.params)\n\nconst withoutPreflight = (config: RpcTransportConfig): RpcTransportConfig => {\n if (!isSendTransactionPayload(config.payload)) return config\n\n const [transaction, sendConfig] = config.payload.params\n return {\n ...config,\n payload: {\n ...config.payload,\n params: [transaction, { ...(sendConfig as object | undefined), skipPreflight: true }],\n },\n }\n}\n\nexport type SolTransportOptions = {\n /** Called with the url of the RPC that answered, after every successful request */\n onRpcSuccess?: (url: string) => void\n}\n\n/**\n * Sends each request to one RPC at a time, starting from the one that answered last, and moves on to\n * the next when the request fails. A transport only throws for connection, timeout and HTTP errors:\n * JSON-RPC errors come back in the response body and are returned as is.\n *\n * A failed RPC other than a rate limited one may still have forwarded a transaction. Resending it is\n * safe, as the network processes a signature once, but its preflight simulation on the next RPC\n * could then fail although it landed. So after such a failure, every resend of that transaction,\n * including the retries after a rate limit, skips preflight.\n */\nconst withFailover = (urls: string[], options: SolTransportOptions): RpcTransport => {\n const transports = urls.map((url) => createDefaultRpcTransport({ url }))\n let preferred = 0\n const mayHaveBeenProcessed = new WeakSet<RpcTransportConfig>()\n\n const failover = async <TResponse>(config: RpcTransportConfig): Promise<TResponse> => {\n if (!transports.length) throw new Error(\"No RPCs found for Solana network\")\n\n const start = preferred\n let lastError: unknown\n let rateLimitError: unknown\n for (let attempt = 0; attempt < transports.length; attempt++) {\n config.signal?.throwIfAborted()\n const index = (start + attempt) % transports.length\n const transport = transports[index] as RpcTransport\n const isLastAttempt = attempt === transports.length - 1\n const request = mayHaveBeenProcessed.has(config) ? withoutPreflight(config) : config\n\n try {\n const response = isLastAttempt\n ? await transport<TResponse>(request)\n : await sendWithTimeout<TResponse>(transport, request, FAILOVER_TIMEOUT_MS)\n preferred = index\n options.onRpcSuccess?.(urls[index] as string)\n return response\n } catch (error) {\n if (config.signal?.aborted) throw error\n lastError = error\n if (!getRateLimitContext(error)) mayHaveBeenProcessed.add(config)\n else rateLimitError ??= error\n }\n }\n throw rateLimitError ?? lastError\n }\n return failover as RpcTransport\n}\n\n/**\n * Returns a transport over all of the network's RPCs, in the given order. A request fails over to\n * the next RPC on error, and the RPC that answered is tried first for the next request. When every\n * RPC fails and one of them answered HTTP 429, the whole list is retried with backoff.\n */\nexport const getSolTransport = (\n _networkId: SolNetworkId,\n rpcs: string[],\n options: SolTransportOptions = {}\n): RpcTransport => {\n return withRetryOn429(withFailover(rpcs, options))\n}\n\nexport const getSolRpc = (\n networkId: SolNetworkId,\n rpcs: string[],\n options?: SolTransportOptions\n): SolRpc => createSolanaRpcFromTransport(getSolTransport(networkId, rpcs, options))\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type {\n IChaindataNetworkProvider,\n IChaindataTokenProvider,\n SolNetworkId,\n} from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSol implements IChainConnectorSol {\n #chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider\n #transports = new Map<SolNetworkId, RpcTransport>()\n #rpcs = new Map<SolNetworkId, SolRpc>()\n\n constructor(chaindataProvider: IChaindataNetworkProvider & IChaindataTokenProvider) {\n this.#chaindataProvider = chaindataProvider\n }\n\n async #getNetworkRpcs(networkId: SolNetworkId): Promise<string[]> {\n const network = await this.#chaindataProvider.getNetworkById(networkId, \"solana\")\n if (!network) throw new Error(`Network not found: ${networkId}`)\n\n return network.rpcs\n }\n\n async getTransport(networkId: SolNetworkId): Promise<RpcTransport> {\n if (!this.#transports.has(networkId))\n this.#transports.set(\n networkId,\n getSolTransport(networkId, await this.#getNetworkRpcs(networkId))\n )\n\n return this.#transports.get(networkId)!\n }\n\n async getRpc(networkId: SolNetworkId): Promise<SolRpc> {\n if (!this.#rpcs.has(networkId))\n this.#rpcs.set(networkId, createSolanaRpcFromTransport(await this.getTransport(networkId)))\n\n return this.#rpcs.get(networkId)!\n }\n\n /** Drops cached transports/rpcs so the next call re-reads the network's rpcs from chaindata */\n clearRpcProvidersCache(networkId?: SolNetworkId) {\n if (networkId) {\n this.#transports.delete(networkId)\n this.#rpcs.delete(networkId)\n } else {\n this.#transports.clear()\n this.#rpcs.clear()\n }\n }\n}\n","import type { RpcTransport } from \"@solana/kit\"\nimport { createSolanaRpcFromTransport } from \"@solana/kit\"\nimport type { SolNetwork } from \"@talismn/chaindata-provider\"\n\nimport type { SolRpc } from \"./getSolRpc\"\nimport { getSolTransport } from \"./getSolRpc\"\nimport type { IChainConnectorSol } from \"./IChainConnectorSol\"\n\nexport class ChainConnectorSolStub implements IChainConnectorSol {\n #transport: RpcTransport\n #rpc: SolRpc\n\n constructor(network: Pick<SolNetwork, \"id\" | \"rpcs\">) {\n this.#transport = getSolTransport(network.id, network.rpcs)\n this.#rpc = createSolanaRpcFromTransport(this.#transport)\n }\n\n async getRpc(): Promise<SolRpc> {\n return this.#rpc\n }\n\n async getTransport(): Promise<RpcTransport> {\n return this.#transport\n }\n}\n"],"mappings":";;;;;;;;;;ACIA,IAAA,cAAe,UAAUA,2BAAgB;;;ACUzC,MAAM,iBAAyC;CAC7C,UAAU;CACV,UAAU;AACZ;AAEA,MAAMC,qBAAmB;AACzB,MAAM,sBAAsB;;;;;;AAM5B,MAAM,mBAAmB;;AAGzB,MAAM,oBAAoB,UACxB,iBAAiB,SAAS,MAAM,SAAS;AAC3C,MAAM,uBAAuB;AAE7B,IAAa,uBAAb,cAA0C,MAAM;CAC9C;CACA;CAEA,YAAY,SAAiB,SAAwB;EACnD,MAAM,8BAA8B,WAAW,OAAO;EAEtD,KAAK,OAAO;EACZ,KAAK,UAAU;CACjB;AACF;;;;;AAMA,IAAa,gBAAb,cAAmC,MAAM;CACvC;CACA;CAEA,YAAY,SAAiB,SAAwB;EACnD,MAAM,wCAAwC,WAAW,OAAO;EAEhE,KAAK,OAAO;EACZ,KAAK,UAAU;CACjB;AACF;;;;;;;;;;;;;;;AAqDA,IAAa,oBAAb,MAA6D;CAC3D;CACA;CAEA,eAAiD,CAAC;CAClD,sBAAiE,CAAC;CAElE,YACE,wBACA,SACA;EACA,KAAK,0BAA0B;EAC/B,KAAK,qBAAqB,SAAS;CACrC;CAGA,MAAM,KACJ,SACA,QACA,QACA,cACA,cAYY;EACZ,MAAM,cAAc,KAAK,eAAe;EACxC,IAAI,gBAAgB,KAAA,GAClB,IAAI;GACF,MAAM,cAAc,MAAM,KAAK,eAAe,OAAO;GACrD,OAAO,MAAM,YAAY,KAAK,aAAa,QAAQ,MAAM;EAC3D,SAAS,OAAO;GACd,YAAI,KACF,wDAAwD,QAAQ,oCAChE,KACF;EACF;EAGF,IAAI;EACJ,IAAI;EACJ,IAAI;GACD,CAAC,cAAc,cAAc,MAAM,KAAK,kBAAkB,OAAO;EACpE,SAAS,OAAO;GACd,MAAM,IAAI,cAAc,SAAS,EAAE,OAAO,MAAM,CAAC;EACnD;EAEA,IAAI;GACF,OAAO,MAAM,KAAK,QAAW,YAAY,QAAQ,MAAM;EACzD,SAAS,KAAK;GACZ,MAAM,QAAQ;GAEd,IAAI,OAAO,YAAY,WAAW;IAChC,YAAI,MAAM,0BAA0B;KAAE;KAAS;IAAM,CAAC;IACtD,WAAW,SAAS,OAAO;IAC3B,MAAM,IAAI,MAAM,SAAS;GAC3B;GAEA,MAAM,cAAc,eAAe,OAAO,MAAM,SAAS,KAAK;GAC9D,IAAI,aAAa;IACf,YAAI,MAAM,kBAAkB,eAAe;KAAE;KAAO;IAAQ,CAAC;IAC7D,WAAW,SAAS,OAAO;IAC3B,MAAM,IAAI,MAAM,WAAW;GAC7B;GAEA,IAAI,CAAC,cAAc,cACjB,YAAI,MACF,kBAAkB,OAAO,YAAY,QAAQ,YAAY,KAAK,UAAU,MAAM,KAC9E,EACE,MACF,CACF;GAEF,MAAM;EACR,UAAU;GACR,KAAK,kBAAkB,SAAS,YAAY;EAC9C;CACF;CAEA,MAAM,UACJ,SACA,iBACA,gBACA,QACA,UACA,UAA0B,KACoB;EAC9C,MAAM,cAAc,KAAK,eAAe;EACxC,IAAI,gBAAgB,KAAA,GAClB,IAAI;GACF,MAAM,cAAc,MAAM,KAAK,eAAe,OAAO;GAErD,MAAM,iBAAiB,MAAM,YAAY,UACvC,aACA,iBACA,gBACA,QACA,UACA,OACF;GAEA,QAAQ,sBACN,YAAY,YAAY,gBAAgB,iBAAiB;EAC7D,SAAS,OAAO;GACd,YAAI,KACF,0DAA0D,QAAQ,oCAClE,KACF;EACF;EAGF,IAAI;EACJ,IAAI;EACJ,IAAI;GACD,CAAC,cAAc,cAAc,MAAM,KAAK,kBAAkB,OAAO;EACpE,SAAS,OAAO;GACd,MAAM,IAAI,cAAc,SAAS,EAAE,OAAO,MAAM,CAAC;EACnD;EAEA,MAAM,eAA6B;GACjC;GACA;GACA;GACA,eAAe;GACf,YAAY;GACZ,aAAa;GACb,cAAc;EAChB;EACA,WAAW,cAAc,IAAI,YAAY;EAGzC,IAAI,WAAW,CAAC,WAAW,cAAc;GACvC,MAAM,eAAe,iBAAiB;IACpC,IAAI,CAAC,aAAa,gBAAgB,CAAC,WAAW,cAC5C,SAAS,IAAI,cAAc,OAAO,GAAG,IAAI;GAC7C,GAAG,OAAO;GACV,MAAM,cAAc,aAAa,YAAY;GAE7C,MAAM,mBAAmB,aAAa;GACtC,aAAa,YAAY,OAAO,WAAW;IACzC,MAAM;IACN,aAAa,WAAW;IACxB,iBAAiB,OAAO,MAAM;GAChC;EACF;EAEA,KAAK,kBAAkB,YAAY,YAAY;EAE/C,QAAQ,sBAA8B;GACpC,IAAI,aAAa,cAAc;GAC/B,aAAa,eAAe;GAE5B,aAAa,gBAAgB;GAC7B,aAAa,aAAa;GAI1B,MAAM,UAAU,KAAK,aAAa;GAClC,IAAI,aAAa,gBAAgB,QAAQ,SACvC,IAAI;IACF,QAAQ,OAAO,QAAQ,mBAAmB,CAAC,aAAa,WAAW,CAAC,CAAC,CAAC,OAAO,UAAU;KACrF,IAAI,CAAC,iBAAiB,KAAK,GAAG,YAAI,KAAK,8BAA8B,WAAW,KAAK;IACvF,CAAC;GACH,SAAS,OAAO;IACd,IAAI,CAAC,iBAAiB,KAAK,GAAG,YAAI,KAAK,8BAA8B,WAAW,KAAK;GACvF;GAEF,SAAS,cAAc,OAAO,YAAY;GAC1C,KAAK,kBAAkB,SAAS,YAAY;EAC9C;CACF;;;;;;CAOA,MAAM,MAAM,SAAuB;EACjC,YAAI,KAAK,wBAAwB,OAAO;EACxC,MAAM,aAAa,KAAK,aAAa;EACrC,IAAI,CAAC,YAAY;EAEjB,KAAK,kBAAkB,UAAU;EACjC,OAAO,KAAK,aAAa;EAGzB,IAAI,WAAW,cAAc,MAC3B,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,iBAAiB,OAAO;GACjD,MAAM,QAAQ,WAAW;GACzB,MAAM,gBAAgB,WAAW;GACjC,KAAK,aAAa,WAAW;GAC7B,KAAK,MAAM,gBAAgB,MAAM,eAAe,KAAK,kBAAkB,OAAO,YAAY;EAC5F,SAAS,OAAO;GACd,YAAI,KAAK,qCAAqC,QAAQ,eAAe,KAAK;GAG1E,KAAK,MAAM,gBAAgB,WAAW,eACpC,aAAa,SAAS,IAAI,qBAAqB,SAAS,EAAE,OAAO,MAAM,CAAC,GAAG,IAAI;EACnF;CAEJ;;CAGA,QACE,YACA,QACA,QACA,YAAYA,oBACA;EACZ,OAAO,IAAI,SAAY,SAAS,WAAW;GACzC,MAAM,QAAQ,iBAAiB;IAC7B,OAAO;IACP,uBAAO,IAAI,MAAM,SAAS,CAAC;GAC7B,GAAG,SAAS;GAEZ,MAAM,SAAS,WAAW,OAAO,SAAqB,QAAQ,QAAQ;IACpE,YAAY,WAAW;KACrB,aAAa,KAAK;KAClB,QAAQ,MAAM;IAChB;IACA,UAAU,UAAU;KAClB,aAAa,KAAK;KAClB,OAAO,KAAK;IACd;GACF,CAAC;EACH,CAAC;CACH;;CAGA,kBAA0B,YAAwB,cAA4B;EAC5E,aAAa,cAAc;EAC3B,aAAa,aAAa;EAE1B,aAAa,gBAAgB,WAAW,OAAO,SAC7C,aAAa,iBACb,aAAa,QACb;GACE,YAAY,aAAa,WAAW;IAClC,aAAa,gBAAgB;IAC7B,IAAI,aAAa,cAAc;IAE/B,aAAa,cAAc;IAE3B,aAAa,aAAa,OAAO,aAAuB;KACtD,OAAO,WAAW,aAAa,SAAS,MAAM,MAAM;KACpD,QAAQ,UAAU,aAAa,SAAS,OAAO,IAAI;IACrD,CAAC;GACH;GACA,UAAU,UAAU;IAClB,aAAa,gBAAgB;IAC7B,IAAI,CAAC,aAAa,cAAc,aAAa,SAAS,OAAO,IAAI;GACnE;EACF,CACF;CACF;;;;;;CAOA,MAAc,kBAAkB,SAA4D;EAE1F,IAAI,aAAa,KAAK,aAAa;EACnC,IAAI,CAAC,YAAY;GACf,IAAI,CAAC,KAAK,oBAAoB,UAC5B,KAAK,oBAAoB,WAAW,KAAK,iBAAiB,OAAO,CAAC,CAC/D,MAAM,YAAY;IACjB,KAAK,aAAa,WAAW;IAC7B,OAAO;GACT,CAAC,CAAC,CACD,cAAc;IACb,OAAO,KAAK,oBAAoB;GAClC,CAAC;GAEL,aAAa,MAAM,KAAK,oBAAoB;EAC9C;EAEA,IAAI,WAAW,aAAa;GAC1B,aAAa,WAAW,WAAW;GACnC,WAAW,cAAc;EAC3B;EACA,MAAM,eAAe,KAAK,qBAAqB,CAAC,GAAG,WAAW,KAAK,CAAC;EACpE,WAAW,MAAM,IAAI,YAAY;EAEjC,OAAO,CAAC,cAAc,UAAU;CAClC;CAEA,MAAc,iBAAiB,SAA4C;EACzE,MAAM,QAAQ,MAAM,KAAK,wBAAwB,eAAe,SAAS,UAAU;EACnF,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,SAAS,QAAQ,oBAAoB;EAEjE,MAAM,OAAO,MAAM,KAAK,OAAO;EAC/B,IAAI,CAAC,KAAK,QAAQ,MAAM,IAAI,MAAM,uCAAuC,SAAS;EAGlF,IAAI,aAAyB;EAE7B,MAAM,WAAW,cAAc,MAAM;GACnC,kBAAkB,WAAyB,KAAK,mBAAmB,YAAY,MAAM;GACrF,GAAI,KAAK,uBAAuB,KAAA,KAAa,EAAE,SAAS,KAAK,mBAAmB;EAClF,CAAC;EAID,aAAa;GACX;GACA;GACA,QALa,aAAa,QAKrB;GACL,uBAAO,IAAI,IAAI;GACf,+BAAe,IAAI,IAAI;GACvB,cAAc;GACd,mBAAmB;GACnB,cAAc;GACd,aAAa;EACf;EAEA,OAAO;CACT;CAEA,mBAA2B,YAAwB,QAAsB;EAEvE,IAAI,CAAC,YAAY;EAEjB,IAAI,KAAK,aAAa,WAAW,aAAa,YAAY;EAE1D,IAAI,OAAO,SAAS,QAAQ,WAAW;GACrC,IAAI,WAAW,cAAc;IAC3B,aAAa,WAAW,YAAY;IACpC,WAAW,eAAe;GAC5B;GAEA,MAAM,cAAc,WAAW;GAC/B,WAAW,eAAe;GAG1B,IAAI,WAAW,mBAAmB,cAAc,WAAW,iBAAiB;GAC5E,WAAW,oBAAoB,kBAAkB;IAC/C,KAAK,QAAQ,YAAY,iBAAiB,CAAC,GAAG,mBAAmB,CAAC,CAAC,OAAO,UAAU;KAClF,IAAI,CAAC,iBAAiB,KAAK,GACzB,YAAI,KAAK,gCAAgC,WAAW,WAAW,KAAK;IACxE,CAAC;GACH,GAAG,mBAAmB;GAItB,IAAI,aACF,KAAK,MAAM,gBAAgB,WAAW,eAAe;IACnD,IAAI,aAAa,cAAc;IAC/B,IAAI,aAAa,gBAAgB,WAAW,SAAS,GAAG;IACxD,aAAa,aAAa;IAC1B,aAAa,gBAAgB;IAC7B,KAAK,kBAAkB,YAAY,YAAY;GACjD;EACJ,OAAO;GACL,IAAI,WAAW,mBAAmB;IAChC,cAAc,WAAW,iBAAiB;IAC1C,WAAW,oBAAoB;GACjC;GAGA,IAAI,CAAC,WAAW,gBAAgB,WAAW,cAAc,MACvD,WAAW,eAAe,iBAAiB;IACzC,WAAW,eAAe;IAC1B,KAAK,MAAM,gBAAgB,WAAW,eACpC,IAAI,CAAC,aAAa,cAChB,aAAa,SAAS,IAAI,cAAc,WAAW,OAAO,GAAG,IAAI;GACvE,GAAG,oBAAoB;EAE3B;CACF;CAEA,kBAA0B,SAAuB,cAAkC;EACjF,MAAM,aAAa,KAAK,aAAa;EACrC,IAAI,CAAC,YAAY;EAEjB,WAAW,MAAM,OAAO,YAAY;EACpC,IAAI,WAAW,MAAM,OAAO,KAAK,WAAW,aAAa;EAEzD,WAAW,cAAc,iBAAiB;GACxC,WAAW,cAAc;GACzB,IAAI,WAAW,MAAM,OAAO,KAAK,KAAK,aAAa,aAAa,YAAY;GAC5E,KAAK,kBAAkB,UAAU;GACjC,OAAO,KAAK,aAAa;EAC3B,GAAG,gBAAgB;CACrB;CAEA,kBAA0B,YAA8B;EACtD,IAAI,WAAW,mBAAmB,cAAc,WAAW,iBAAiB;EAC5E,IAAI,WAAW,cAAc,aAAa,WAAW,YAAY;EACjE,IAAI,WAAW,aAAa,aAAa,WAAW,WAAW;EAC/D,WAAW,oBAAoB;EAC/B,WAAW,eAAe;EAC1B,WAAW,cAAc;EAGzB,KAAK,MAAM,gBAAgB,WAAW,eAAe;GACnD,aAAa,aAAa;GAC1B,aAAa,gBAAgB;GAC7B,aAAa,aAAa;GAC1B,aAAa,gBAAgB;GAC7B,aAAa,cAAc;EAC7B;EAEA,IAAI;GACF,WAAW,OAAO,QAAQ;EAC5B,SAAS,OAAO;GACd,YAAI,KAAK,wCAAwC,WAAW,WAAW,KAAK;EAC9E;CACF;CAEA,MAAc,eAAe,SAAwC;EACnE,MAAM,QAAQ,MAAM,KAAK,wBAAwB,eAAe,SAAS,UAAU;EACnF,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,SAAS,QAAQ,oBAAoB;EAEjE,MAAM,EAAE,gBAAgB;EACxB,IAAI,OAAO,gBAAgB,UACzB,MAAM,IAAI,MAAM,SAAS,QAAQ,6BAA6B;EAEhE,OAAO;CACT;;CAGA,qBAA6B,UAAoB,CAAC,GAAW;EAC3D,IAAI,KAAK,KAAK,YAAY;EAC1B,OAAO,QAAQ,SAAS,EAAE,GACxB,KAAK,KAAK,YAAY;EAExB,OAAO;CACT;;CAEA,cAA8B;EAC5B,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC;CAC3C;CAEA,iBAAyB;EAEvB,MAAM,cAAc,OAAO,WAAW,eAAgB,OAAe;EAGrE,MAAM,uBAA6C,aAAa;EAEhE,MAAM,4BAAkD,aAAa;EAErE,MAAM,8BACJ,aAAa;EAEf,IAAI,OAAO,yBAAyB,YAAY;EAChD,IAAI,OAAO,8BAA8B,YAAY;EACrD,IAAI,OAAO,gCAAgC,YAAY;EAEvD,OAAO;GAEL,OAAgB,aAAqB,QAAgB,WACnD,qBAAqB,aAAa,QAAQ,MAAM;GAElD,YACE,aACA,iBACA,gBACA,QACA,UACA,YAEA,0BACE,aACA,iBACA,gBACA,QACA,UACA,OACF;GAEF,cAAc,gBAAwB,sBACpC,4BAA4B,gBAAgB,iBAAiB;EACjE;CACF;AACF;;;AChlBA,MAAM,mBAAmB;AACzB,MAAM,+BAA+B;;;;;;;;;AA0BrC,IAAa,wBAAb,MAAiE;CAC/D;CAEA,YAAY,WAAgE;EAC1E,KAAK,aAAa;CACpB;CAEA,MAAM,KAAkB,WAAyB,QAAgB,QAA+B;EAC9F,OAAO,mBAAsB,KAAK,UAAU,SAAS,GAAG,QAAQ,QAAQ,IAAI,gBAAgB,CAAC;CAC/F;CAEA,MAAM,UACJ,WACA,iBACA,iBACA,QACA,UACA,UAA0B,KACoB;EAC9C,MAAM,SAAS,KAAK,UAAU,SAAS;EACvC,IAAI,oBAAoB,0BACtB,MAAM,IAAI,MAAM,0CAA0C,iBAAiB;EAE7E,MAAM,CAAC,QAAQ;EACf,MAAM,yBAAS,IAAI,IAAiC;EACpD,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI,YAAY;EAChB,IAAI,WAAW;EACf,IAAI,SAAS;EACb,IAAI;EACJ,MAAM,aAAa,UACf,iBAAiB,SAAS,IAAI,cAAc,SAAS,GAAG,IAAI,GAAG,OAAO,IACtE,KAAA;EAEJ,MAAM,aAAa;GACjB,SAAS;GACT,aAAa,UAAU;GACvB,UAAU,MAAM;GAChB,cAAc,YAAY;EAC5B;EAEA,MAAM,UAAU,UAAiB;GAC/B,IAAI,CAAC,QAAQ;GACb,KAAK;GACL,SAAS,OAAO,IAAI;EACtB;EAEA,MAAM,iBAAiB,WAA2B;GAChD,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,KAAK,WAAW,OAAO,IAAI,GAAG,MAAM,KAAK;GACjF,KAAK,MAAM,CAAC,KAAK,UAAU,SAAS,OAAO,IAAI,KAAK,KAAK;GACzD,IAAI,CAAC,QAAQ,QAAQ;GAErB,YAAY;GACZ,aAAa,UAAU;GACvB,SAAS,MAAM;IAAE,OAAO,OAAO;IAAO;GAAQ,CAAC;EACjD;EAEA,MAAM,iBAAiB,UAAiB;GACtC,IAAI,aAAa,EAAE,WAAW,8BAC5B,OAAOC,YAAI,KACT,kCAAkC,UAAU,+BAC5C,KACF;GACF,OAAO,KAAK;EACd;EAEA,MAAM,iBAAiB,YAAY;GACjC,IAAI,CAAC,UAAU,YAAY,CAAC,iBAAiB,kBAAkB,kBAAkB;GACjF,MAAM,YAAY;GAClB,mBAAmB;GACnB,MAAM,aAAa,IAAI,gBAAgB;GACvC,WAAW;GAEX,IAAI;IACF,MAAM,CAAC,UAAU,MAAM,mBACrB,QACA,wBACA,CAAC,MAAM,SAAS,GAChB,UACF;IACA,IAAI,CAAC,QAAQ;IACb,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,0CAA0C,WAAW;IAClF,cAAc,MAAM;GACtB,SAAS,OAAO;IACd,IAAI,QAAQ,cAAc,KAAc;GAC1C,UAAU;IACR,IAAI,aAAa,YAAY,WAAW,KAAA;IACxC,eAAe;GACjB;EACF;EAEA,IAAI;GACF,eAAe,OAAO,YAAY,UAAU;IAC1C,OAAO,CAAC,UAAU;KAChB,gBAAgB,MAAM;KACtB,eAAe;IACjB;IACA,QAAQ,UAAU,OAAO,KAAc;IACvC,gBACE,uBAAO,IAAI,MAAM,2BAA2B,UAAU,0BAA0B,CAAC;GACrF,CAAC;EACH,SAAS,OAAO;GACd,KAAK;GACL,MAAM;EACR;EACA,IAAI,CAAC,QAAQ,aAAa,YAAY;EAEtC,OAAO;CACT;CAEA,MAAM,QAAQ,CAAC;CAEf,UAAkB,WAAqC;EACrD,MAAM,SAAS,KAAK,WAAW,SAAS;EACxC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,sCAAsC,WAAW;EAC9E,OAAO;CACT;AACF;;AAGA,MAAM,sBACJ,QACA,QACA,QACA,eAEA,IAAI,SAAY,SAAS,WAAW;CAClC,MAAM,QAAQ,iBAAiB;EAC7B,WAAW,MAAM;EACjB,uBAAO,IAAI,MAAM,SAAS,CAAC;CAC7B,GAAG,gBAAgB;CACnB,IAAI;EACF,OACG,SAAY,QAAQ,QAAQ,WAAW,MAAM,CAAC,CAC9C,KAAK,SAAS,MAAM,CAAC,CACrB,cAAc,aAAa,KAAK,CAAC;CACtC,SAAS,OAAO;EACd,aAAa,KAAK;EAClB,OAAO,KAAK;CACd;AACF,CAAC;;;ACxKH,MAAM,UAAU;AAEhB,IAAa,wBAAb,MAAiE;CAC/D;CAEA,YAAY,SAAqB;EAC/B,KAAK,UAAU,aAAa,cAAc,QAAQ,KAAK,OAAO,CAAC,CAAC;CAClE;CAEA,MAAM,KACJ,UACA,QACA,QACA,cACY;EACZ,OAAO,MAAM,QAAQ,KAAK,CACxB,KAAK,QAAQ,QAAW,QAAQ,MAAM,GACtC,WAAW,SAAS,WAAW,OAAO,mBAAmB,QAAQ,GAAG,CACtE,CAAC;CACH;CAEA,MAAM,UACJ,UACA,iBACA,iBACA,QACA,UACA,SAC8C;EAC9C,IAAI,aAAkC;EACtC,IAAI,eAAe;EAEnB,MAAM,cAAc,MAAM,QAAQ,KAAK,CACrC,IAAI,SAA0B,SAAS,WAAW;GAChD,KAAK,QAAQ,SAAmC,iBAAiB,QAAQ;IACvE,YAAY,OAAO,WAAW;KAC5B,aAAa,OAAO,OAAiB;MACnC,OAAO,WAAW,SAAS,MAAM,MAAM;MACvC,QAAQ,UAAU,SAAS,OAAO,IAAI;KACxC,CAAC;KACD,QAAQ,KAAK;IACf;IACA,SAAS;GACX,CAAC;EACH,CAAC,GACD,WAAW,WAAW,SAAS,gCAAgC,WAAW,QAAQ,GAAG,CACvF,CAAC;EAED,QAAQ,sBAA8B;GACpC,IAAI,cAAc;GAClB,eAAe;GACf,aAAa;GACb,KAAK,QAAQ,QAAQ,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;EACvE;CACF;CAEA,QAAuB;EACrB,MAAM,IAAI,MAAM,gDAAgD;CAClE;CAEA,UAAU;EACR,KAAK,QAAQ,QAAQ;CACvB;AACF;;;AChEA,MAAM,EAAE,aAAa,GAAG,oBAAoB;AAG5C,MAAM,cAAc,OAAO,KAAK,eAAe,CAAC,CAAC,QAC9C,KAAK,SAAS;CACb,MAAM,QAAQ,gBAAgB;CAC9B,IAAI,MAAM,MAAM;CAChB,OAAO;AACT,GACA,CAAC,CACH;AAEA,MAAM,8BAAc,IAAI,IAAmB;AAE3C,MAAa,oBAAoB,cAA6B;CAC5D,IAAI,WAAW,YAAY,OAAO,SAAS;MACtC,YAAY,MAAM;AACzB;AAEA,MAAa,0BAA0B,YAA+B;CACpE,MAAM,EAAE,QAAQ,aAAa,QAAQ;CAErC,IAAI,CAAC,YAAY,IAAI,QAAQ,EAAE,GAAG;EAChC,MAAM,YAAY,QAAQ,QAAQ,CAAC;EAEnC,MAAM,YAAY,YAAY,OAAO,QAAQ,EAAE,MAAM,CAAC;EAEtD,MAAM,QAAe;GACnB,GAAG;GACH,IAAI,OAAO,QAAQ,EAAE;GACrB,MAAM,QAAQ,QAAQ,kBAAkB,QAAQ;GAChD,SAAS;IACP,QAAQ,EAAE,MAAM,UAAU;IAC1B,SAAS,EAAE,MAAM,UAAU;GAC7B;GACA,gBAAgB;IACd;IACA;IACA,MAAM;GACR;GACA,WAAW;IACT,GAAG,UAAU;IACb,GAAI,QAAQ,YACR,UACE,QAAQ,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,MAAM,aAAsC,CAC3E,UAAU,IAAI,GACd,EAAE,QAAQ,CACZ,CAAC,CACH,IACA,CAAC;GACP;EACF;EAEA,YAAY,IAAI,QAAQ,IAAI,KAAK;CACnC;CAEA,OAAO,YAAY,IAAI,QAAQ,EAAE;AACnC;;;AClDA,MAAM,2BAA2B;AAEjC,MAAM,gBAAgB,UACpB,YAAY,KAAK,KAAK,yBAAyB,KAAK,MAAM,OAAO;AAEnE,MAAa,6BACX,YACA,UAA4B,CAAC,MAC1B;CACH,IAAI,CAAC,WAAW,MAAM,QAAQ,MAAM,IAAI,MAAM,+BAA+B;CAE7E,MAAM,EAAE,UAAU;CAElB,OAAO,SACL,WAAW,KAAK,KAAK,QAAQ,KAAK,KAAK;EAAE;EAAO,YAAY;CAAE,CAAC,CAAC,GAChE;EAAE,YAAY;EAAG,aAAa;CAAa,CAC7C;AACF;;;ACxBA,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAE7B,MAAM,kBAAkB;AACxB,MAAM,iCAAiC;AACvC,MAAM,oCAAoC;AAG1C,MAAM,oCAAoB,IAAI,IAA0B;AAExD,MAAa,0BAA0B,iBAA0B;CAC/D,iBAAiB,YAAY;CAE7B,IAAI,cAAc,kBAAkB,OAAO,YAAY;MAClD,kBAAkB,MAAM;AAC/B;AAEA,MAAa,6BAA6B,YAAsC;CAC9E,MAAM,QAAQ,uBAAuB,OAAO;CAE5C,IAAI,CAAC,kBAAkB,IAAI,QAAQ,EAAE,GAAG;EACtC,IAAI,CAAC,QAAQ,KAAK,QAAQ,MAAM,IAAI,MAAM,oCAAoC;EAE9E,MAAM,QAAQ,MAAM,WAAW,aAC3B,EAAE,WAAW;GAAE,MAAM;GAAsB,WAAW;EAAqB,EAAE,IAC7E,KAAA;EAEJ,MAAM,mBAAqC,EACzC,OAAO;GACL,WAAW,MAAM,WAAW,aACxB,iCACA;GACJ,MAAM;EACR,EACF;EAEA,MAAM,YAAY,0BAA0B,SAAS,gBAAgB;EAErE,kBAAkB,IAChB,QAAQ,IACR,mBAAmB;GACjB;GACA;GACA;EACF,CAAC,CACH;CACF;CAEA,OAAO,kBAAkB,IAAI,QAAQ,EAAE;AACzC;;;AC7CA,MAAa,6BACX,SACA,UAA+B,CAAC,MACf;CACjB,MAAM,QAAQ,uBAAuB,OAAO;CAE5C,MAAM,YAAY,0BAA0B,OAAO;CAEnD,OAAO,mBAAmB;EAAE;EAAO;EAAW,SAAS,QAAQ;CAAQ,CAAC;AAC1E;;;ACRA,IAAa,oBAAb,MAA6D;CAC3D;CAEA,YAAY,mBAAwE;EAClF,KAAK,qBAAqB;CAC5B;CAEA,MAAM,6BAA6B,cAA0D;EAC3F,MAAM,UAAU,MAAM,KAAK,mBAAmB,eAAe,cAAc,UAAU;EACrF,IAAI,CAAC,SAAS,OAAO;EAErB,OAAO,0BAA0B,OAAO;CAC1C;CAEA,MAAM,6BACJ,cACA,SAC8B;EAC9B,MAAM,UAAU,MAAM,KAAK,mBAAmB,eAAe,cAAc,UAAU;EACrF,IAAI,CAAC,SAAS,OAAO;EAErB,OAAO,0BAA0B,SAAS,EAAE,QAAQ,CAAC;CACvD;CAEA,uBAA8B,cAA6B;EACzD,uBAAuB,YAAY;CACrC;AACF;;;AC/BA,IAAa,wBAAb,MAAiE;CAC/D;CAEA,YAAY,SAAqB;EAC/B,KAAK,WAAW;CAClB;CAEA,MAAM,+BAA6D;EACjE,OAAO,0BAA0B,KAAK,QAAQ;CAChD;CAEA,MAAM,6BACJ,YACA,SAC8B;EAC9B,OAAO,0BAA0B,KAAK,UAAU,EAAE,QAAQ,CAAC;CAC7D;CAEA,yBAA+B,CAE/B;AACF;;;AClBA,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AAIxB,MAAM,uBAAuB,UAA4C;CACvE,IAAI,CAAC,cAAc,KAAK,GAAG,OAAO;CAElC,MAAM,UAAU,MAAM;CACtB,OAAO,QAAQ,eAAe,MAAM,UAAU;AAChD;;AAGA,MAAM,oBAAoB,OAAgB,YAAmC;CAC3E,MAAM,UAAU,oBAAoB,KAAK;CACzC,IAAI,CAAC,SAAS,OAAO;CAGrB,MAAM,aAAa,OAAO,QAAQ,SAAS,IAAI,aAAa,CAAC;CAC7D,IAAI,OAAO,SAAS,UAAU,KAAK,aAAa,GAAG,OAAO,aAAa;CAGvE,OAAO,kBAAkB,KAAK;AAChC;AAEA,MAAM,SAAS,IAAY,WACzB,IAAI,SAAS,SAAS,WAAW;CAC/B,IAAI,QAAQ,SAAS,OAAO,OAAO,OAAO,MAAM;CAEhD,MAAM,gBAAgB;EACpB,aAAa,OAAO;EACpB,OAAO,QAAQ,MAAM;CACvB;CACA,MAAM,UAAU,iBAAiB;EAC/B,QAAQ,oBAAoB,SAAS,OAAO;EAC5C,QAAQ;CACV,GAAG,EAAE;CACL,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAC3D,CAAC;;;;;AAMH,MAAM,kBAAkB,cAA0C;CAChE,MAAM,UAAU,OAAO,WAAwC;EAC7D,KAAK,IAAI,UAAU,IAAK,WACtB,IAAI;GACF,OAAO,MAAM,UAAU,MAAM;EAC/B,SAAS,OAAO;GACd,MAAM,QAAQ,UAAU,kBAAkB,iBAAiB,OAAO,OAAO,IAAI;GAC7E,IAAI,UAAU,MAAM,MAAM;GAC1B,MAAM,MAAM,OAAO,OAAO,MAAM;EAClC;CAEJ;CACA,OAAO;AACT;;;;;AAMA,MAAM,sBAAsB;AAE5B,MAAM,kBAAkB,OACtB,WACA,QACA,cACuB;CACvB,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,gBAAgB,WAAW,MAAM,OAAO,QAAQ,MAAM;CAC5D,OAAO,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAChE,MAAM,UAAU,iBACR,WAAW,sBAAM,IAAI,MAAM,+BAA+B,UAAU,GAAG,CAAC,GAC9E,SACF;CAEA,IAAI;EACF,OAAO,MAAM,UAAqB;GAAE,GAAG;GAAQ,QAAQ,WAAW;EAAO,CAAC;CAC5E,UAAU;EACR,aAAa,OAAO;EACpB,OAAO,QAAQ,oBAAoB,SAAS,OAAO;CACrD;AACF;AAIA,MAAM,4BACJ,YAEA,OAAO,YAAY,YACnB,YAAY,QACZ,YAAY,WACZ,QAAQ,WAAW,qBACnB,YAAY,WACZ,MAAM,QAAQ,QAAQ,MAAM;AAE9B,MAAM,oBAAoB,WAAmD;CAC3E,IAAI,CAAC,yBAAyB,OAAO,OAAO,GAAG,OAAO;CAEtD,MAAM,CAAC,aAAa,cAAc,OAAO,QAAQ;CACjD,OAAO;EACL,GAAG;EACH,SAAS;GACP,GAAG,OAAO;GACV,QAAQ,CAAC,aAAa;IAAE,GAAI;IAAmC,eAAe;GAAK,CAAC;EACtF;CACF;AACF;;;;;;;;;;;AAiBA,MAAM,gBAAgB,MAAgB,YAA+C;CACnF,MAAM,aAAa,KAAK,KAAK,QAAQ,0BAA0B,EAAE,IAAI,CAAC,CAAC;CACvE,IAAI,YAAY;CAChB,MAAM,uCAAuB,IAAI,QAA4B;CAE7D,MAAM,WAAW,OAAkB,WAAmD;EACpF,IAAI,CAAC,WAAW,QAAQ,MAAM,IAAI,MAAM,kCAAkC;EAE1E,MAAM,QAAQ;EACd,IAAI;EACJ,IAAI;EACJ,KAAK,IAAI,UAAU,GAAG,UAAU,WAAW,QAAQ,WAAW;GAC5D,OAAO,QAAQ,eAAe;GAC9B,MAAM,SAAS,QAAQ,WAAW,WAAW;GAC7C,MAAM,YAAY,WAAW;GAC7B,MAAM,gBAAgB,YAAY,WAAW,SAAS;GACtD,MAAM,UAAU,qBAAqB,IAAI,MAAM,IAAI,iBAAiB,MAAM,IAAI;GAE9E,IAAI;IACF,MAAM,WAAW,gBACb,MAAM,UAAqB,OAAO,IAClC,MAAM,gBAA2B,WAAW,SAAS,mBAAmB;IAC5E,YAAY;IACZ,QAAQ,eAAe,KAAK,MAAgB;IAC5C,OAAO;GACT,SAAS,OAAO;IACd,IAAI,OAAO,QAAQ,SAAS,MAAM;IAClC,YAAY;IACZ,IAAI,CAAC,oBAAoB,KAAK,GAAG,qBAAqB,IAAI,MAAM;SAC3D,mBAAmB;GAC1B;EACF;EACA,MAAM,kBAAkB;CAC1B;CACA,OAAO;AACT;;;;;;AAOA,MAAa,mBACX,YACA,MACA,UAA+B,CAAC,MACf;CACjB,OAAO,eAAe,aAAa,MAAM,OAAO,CAAC;AACnD;AAEA,MAAa,aACX,WACA,MACA,YACW,6BAA6B,gBAAgB,WAAW,MAAM,OAAO,CAAC;;;AClLnF,IAAa,oBAAb,MAA6D;CAC3D;CACA,8BAAc,IAAI,IAAgC;CAClD,wBAAQ,IAAI,IAA0B;CAEtC,YAAY,mBAAwE;EAClF,KAAK,qBAAqB;CAC5B;CAEA,MAAM,gBAAgB,WAA4C;EAChE,MAAM,UAAU,MAAM,KAAK,mBAAmB,eAAe,WAAW,QAAQ;EAChF,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,sBAAsB,WAAW;EAE/D,OAAO,QAAQ;CACjB;CAEA,MAAM,aAAa,WAAgD;EACjE,IAAI,CAAC,KAAK,YAAY,IAAI,SAAS,GACjC,KAAK,YAAY,IACf,WACA,gBAAgB,WAAW,MAAM,KAAK,gBAAgB,SAAS,CAAC,CAClE;EAEF,OAAO,KAAK,YAAY,IAAI,SAAS;CACvC;CAEA,MAAM,OAAO,WAA0C;EACrD,IAAI,CAAC,KAAK,MAAM,IAAI,SAAS,GAC3B,KAAK,MAAM,IAAI,WAAW,6BAA6B,MAAM,KAAK,aAAa,SAAS,CAAC,CAAC;EAE5F,OAAO,KAAK,MAAM,IAAI,SAAS;CACjC;;CAGA,uBAAuB,WAA0B;EAC/C,IAAI,WAAW;GACb,KAAK,YAAY,OAAO,SAAS;GACjC,KAAK,MAAM,OAAO,SAAS;EAC7B,OAAO;GACL,KAAK,YAAY,MAAM;GACvB,KAAK,MAAM,MAAM;EACnB;CACF;AACF;;;AC/CA,IAAa,wBAAb,MAAiE;CAC/D;CACA;CAEA,YAAY,SAA0C;EACpD,KAAK,aAAa,gBAAgB,QAAQ,IAAI,QAAQ,IAAI;EAC1D,KAAK,OAAO,6BAA6B,KAAK,UAAU;CAC1D;CAEA,MAAM,SAA0B;EAC9B,OAAO,KAAK;CACd;CAEA,MAAM,eAAsC;EAC1C,OAAO,KAAK;CACd;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talismn/chain-connectors",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "RPC connectors for Polkadot SDK, EVM and Solana networks",
|
|
5
5
|
"author": "Talisman",
|
|
6
6
|
"homepage": "https://talisman.xyz",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@polkadot-api/substrate-client": "0.7.0",
|
|
26
26
|
"@polkadot-api/ws-provider": "0.9.2",
|
|
27
27
|
"@solana/kit": "8.3.0",
|
|
28
|
-
"@talismn/chaindata-provider": "2.3.
|
|
28
|
+
"@talismn/chaindata-provider": "2.3.1",
|
|
29
29
|
"@talismn/util": "2.1.1",
|
|
30
30
|
"anylogger": "^1.0.11",
|
|
31
31
|
"lodash-es": "4.18.1",
|