@cfxdevkit/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +72 -0
  3. package/README.md +257 -0
  4. package/dist/clients/index.cjs +2053 -0
  5. package/dist/clients/index.cjs.map +1 -0
  6. package/dist/clients/index.d.cts +7 -0
  7. package/dist/clients/index.d.ts +7 -0
  8. package/dist/clients/index.js +2043 -0
  9. package/dist/clients/index.js.map +1 -0
  10. package/dist/config/index.cjs +423 -0
  11. package/dist/config/index.cjs.map +1 -0
  12. package/dist/config/index.d.cts +99 -0
  13. package/dist/config/index.d.ts +99 -0
  14. package/dist/config/index.js +380 -0
  15. package/dist/config/index.js.map +1 -0
  16. package/dist/config-BMtaWM0X.d.cts +165 -0
  17. package/dist/config-BMtaWM0X.d.ts +165 -0
  18. package/dist/core-C5qe16RS.d.ts +352 -0
  19. package/dist/core-RZA4aKwj.d.cts +352 -0
  20. package/dist/index-BhCpy6Fz.d.cts +165 -0
  21. package/dist/index-Qz84U9Oq.d.ts +165 -0
  22. package/dist/index.cjs +3773 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.cts +945 -0
  25. package/dist/index.d.ts +945 -0
  26. package/dist/index.js +3730 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/types/index.cjs +44 -0
  29. package/dist/types/index.cjs.map +1 -0
  30. package/dist/types/index.d.cts +5 -0
  31. package/dist/types/index.d.ts +5 -0
  32. package/dist/types/index.js +17 -0
  33. package/dist/types/index.js.map +1 -0
  34. package/dist/utils/index.cjs +83 -0
  35. package/dist/utils/index.cjs.map +1 -0
  36. package/dist/utils/index.d.cts +11 -0
  37. package/dist/utils/index.d.ts +11 -0
  38. package/dist/utils/index.js +56 -0
  39. package/dist/utils/index.js.map +1 -0
  40. package/dist/wallet/index.cjs +852 -0
  41. package/dist/wallet/index.cjs.map +1 -0
  42. package/dist/wallet/index.d.cts +726 -0
  43. package/dist/wallet/index.d.ts +726 -0
  44. package/dist/wallet/index.js +815 -0
  45. package/dist/wallet/index.js.map +1 -0
  46. package/package.json +119 -0
@@ -0,0 +1,2053 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/clients/index.ts
21
+ var clients_exports = {};
22
+ __export(clients_exports, {
23
+ ClientManager: () => ClientManager,
24
+ CoreClient: () => CoreClient,
25
+ CoreTestClient: () => CoreTestClient,
26
+ CoreWalletClient: () => CoreWalletClient,
27
+ EspaceClient: () => EspaceClient,
28
+ EspaceTestClient: () => EspaceTestClient,
29
+ EspaceWalletClient: () => EspaceWalletClient
30
+ });
31
+ module.exports = __toCommonJS(clients_exports);
32
+
33
+ // src/clients/core.ts
34
+ var import_cive = require("cive");
35
+ var import_accounts = require("cive/accounts");
36
+ var import_utils2 = require("cive/utils");
37
+ var import_viem2 = require("viem");
38
+
39
+ // src/config/chains.ts
40
+ var import_utils = require("cive/utils");
41
+ var import_viem = require("viem");
42
+ var CORE_MAINNET = {
43
+ id: 1029,
44
+ name: "conflux-core",
45
+ type: "core",
46
+ testnet: false,
47
+ nativeCurrency: {
48
+ name: "Conflux",
49
+ symbol: "CFX",
50
+ decimals: 18
51
+ },
52
+ rpcUrls: {
53
+ default: {
54
+ http: ["https://main.confluxrpc.com"],
55
+ webSocket: ["wss://main.confluxrpc.com/ws"]
56
+ }
57
+ },
58
+ blockExplorers: {
59
+ default: {
60
+ name: "ConfluxScan",
61
+ url: "https://confluxscan.io"
62
+ }
63
+ }
64
+ };
65
+ var CORE_TESTNET = {
66
+ id: 1,
67
+ name: "conflux-core-testnet",
68
+ type: "core",
69
+ testnet: true,
70
+ nativeCurrency: {
71
+ name: "Conflux",
72
+ symbol: "CFX",
73
+ decimals: 18
74
+ },
75
+ rpcUrls: {
76
+ default: {
77
+ http: ["https://test.confluxrpc.com"],
78
+ webSocket: ["wss://test.confluxrpc.com/ws"]
79
+ }
80
+ },
81
+ blockExplorers: {
82
+ default: {
83
+ name: "ConfluxScan Testnet",
84
+ url: "https://testnet.confluxscan.io"
85
+ }
86
+ }
87
+ };
88
+ var CORE_LOCAL = {
89
+ id: 2029,
90
+ name: "conflux-core-local",
91
+ type: "core",
92
+ testnet: true,
93
+ nativeCurrency: {
94
+ name: "Conflux",
95
+ symbol: "CFX",
96
+ decimals: 18
97
+ },
98
+ rpcUrls: {
99
+ default: {
100
+ http: ["http://localhost:12537"],
101
+ webSocket: ["ws://localhost:12536"]
102
+ }
103
+ }
104
+ };
105
+ var EVM_MAINNET = {
106
+ id: 1030,
107
+ name: "conflux-espace",
108
+ type: "evm",
109
+ testnet: false,
110
+ nativeCurrency: {
111
+ name: "Conflux",
112
+ symbol: "CFX",
113
+ decimals: 18
114
+ },
115
+ rpcUrls: {
116
+ default: {
117
+ http: ["https://evm.confluxrpc.com"]
118
+ }
119
+ },
120
+ blockExplorers: {
121
+ default: {
122
+ name: "ConfluxScan eSpace",
123
+ url: "https://evm.confluxscan.net"
124
+ }
125
+ },
126
+ contracts: {
127
+ multicall3: {
128
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11",
129
+ blockCreated: 62512243
130
+ }
131
+ }
132
+ };
133
+ var EVM_TESTNET = {
134
+ id: 71,
135
+ name: "conflux-espace-testnet",
136
+ type: "evm",
137
+ testnet: true,
138
+ nativeCurrency: {
139
+ name: "Conflux",
140
+ symbol: "CFX",
141
+ decimals: 18
142
+ },
143
+ rpcUrls: {
144
+ default: {
145
+ http: ["https://evmtestnet.confluxrpc.com"]
146
+ }
147
+ },
148
+ blockExplorers: {
149
+ default: {
150
+ name: "ConfluxScan eSpace Testnet",
151
+ url: "https://evmtestnet.confluxscan.net"
152
+ }
153
+ },
154
+ contracts: {
155
+ multicall3: {
156
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11",
157
+ blockCreated: 117499050
158
+ }
159
+ }
160
+ };
161
+ var EVM_LOCAL = {
162
+ id: 2030,
163
+ name: "conflux-espace-local",
164
+ type: "evm",
165
+ testnet: true,
166
+ nativeCurrency: {
167
+ name: "Conflux",
168
+ symbol: "CFX",
169
+ decimals: 18
170
+ },
171
+ rpcUrls: {
172
+ default: {
173
+ http: ["http://localhost:8545"]
174
+ }
175
+ }
176
+ };
177
+ var SUPPORTED_CHAINS = {
178
+ 1029: CORE_MAINNET,
179
+ 1: CORE_TESTNET,
180
+ 2029: CORE_LOCAL,
181
+ 1030: EVM_MAINNET,
182
+ 71: EVM_TESTNET,
183
+ 2030: EVM_LOCAL
184
+ };
185
+ function getChainConfig(chainId) {
186
+ const config = SUPPORTED_CHAINS[chainId];
187
+ if (!config) {
188
+ throw new Error(`Unsupported chain ID: ${chainId}`);
189
+ }
190
+ return config;
191
+ }
192
+ function isValidChainId(chainId) {
193
+ return chainId in SUPPORTED_CHAINS;
194
+ }
195
+ var NetworkSelector = class {
196
+ currentChainId;
197
+ previousChainId = null;
198
+ listeners = /* @__PURE__ */ new Set();
199
+ nodeRunningListeners = /* @__PURE__ */ new Set();
200
+ isNodeRunning = false;
201
+ lockedToLocal = false;
202
+ constructor(initialChainId = 1) {
203
+ this.currentChainId = initialChainId;
204
+ }
205
+ getCurrentChain() {
206
+ return getChainConfig(this.currentChainId);
207
+ }
208
+ getCurrentChainId() {
209
+ return this.currentChainId;
210
+ }
211
+ /**
212
+ * Switch to a specific chain
213
+ * @param chainId - Chain ID to switch to
214
+ * @param force - Force switch even if node is running (for wallet operations)
215
+ */
216
+ switchChain(chainId, force = false) {
217
+ if (!isValidChainId(chainId)) {
218
+ throw new Error(`Invalid chain ID: ${chainId}`);
219
+ }
220
+ if (this.isNodeRunning && !this.isLocalChain(chainId) && !force) {
221
+ console.warn(
222
+ `Cannot switch to chain ${chainId} while local node is running. Use force=true for wallet operations.`
223
+ );
224
+ return;
225
+ }
226
+ if (this.currentChainId !== chainId) {
227
+ this.currentChainId = chainId;
228
+ this.notifyListeners();
229
+ }
230
+ }
231
+ /**
232
+ * Called when local node starts - automatically switches to local chains
233
+ */
234
+ onNodeStart(coreChainId = 2029, evmChainId = 2030) {
235
+ if (!this.isNodeRunning) {
236
+ if (!this.isLocal()) {
237
+ this.previousChainId = this.currentChainId;
238
+ }
239
+ this.isNodeRunning = true;
240
+ this.lockedToLocal = true;
241
+ const targetLocalChain = this.isEvm() ? evmChainId : coreChainId;
242
+ this.switchChain(targetLocalChain, true);
243
+ this.notifyNodeRunningListeners();
244
+ }
245
+ }
246
+ /**
247
+ * Called when local node stops - can restore previous chain
248
+ */
249
+ onNodeStop(restorePrevious = true) {
250
+ if (this.isNodeRunning) {
251
+ this.isNodeRunning = false;
252
+ this.lockedToLocal = false;
253
+ if (restorePrevious && this.previousChainId) {
254
+ this.switchChain(this.previousChainId, true);
255
+ this.previousChainId = null;
256
+ }
257
+ this.notifyNodeRunningListeners();
258
+ }
259
+ }
260
+ /**
261
+ * Check if node is currently running
262
+ */
263
+ getNodeRunningStatus() {
264
+ return this.isNodeRunning;
265
+ }
266
+ /**
267
+ * Check if selector is locked to local chains
268
+ */
269
+ isLockedToLocal() {
270
+ return this.lockedToLocal;
271
+ }
272
+ onChainChange(listener) {
273
+ this.listeners.add(listener);
274
+ return () => this.listeners.delete(listener);
275
+ }
276
+ onNodeRunningChange(listener) {
277
+ this.nodeRunningListeners.add(listener);
278
+ return () => this.nodeRunningListeners.delete(listener);
279
+ }
280
+ notifyListeners() {
281
+ for (const listener of this.listeners) {
282
+ try {
283
+ listener(this.currentChainId);
284
+ } catch (error) {
285
+ console.error("Error in chain change listener:", error);
286
+ }
287
+ }
288
+ }
289
+ notifyNodeRunningListeners() {
290
+ for (const listener of this.nodeRunningListeners) {
291
+ try {
292
+ listener(this.isNodeRunning);
293
+ } catch (error) {
294
+ console.error("Error in node running listener:", error);
295
+ }
296
+ }
297
+ }
298
+ isLocalChain(chainId) {
299
+ return chainId === 2029 || chainId === 2030;
300
+ }
301
+ // Helper methods for chain type detection
302
+ isCore() {
303
+ return this.getCurrentChain().type === "core";
304
+ }
305
+ isEvm() {
306
+ return this.getCurrentChain().type === "evm";
307
+ }
308
+ isTestnet() {
309
+ return this.getCurrentChain().testnet;
310
+ }
311
+ isLocal() {
312
+ return this.currentChainId === 2029 || this.currentChainId === 2030;
313
+ }
314
+ // Get corresponding chain IDs
315
+ getCorrespondingChainId() {
316
+ switch (this.currentChainId) {
317
+ case 1029:
318
+ return 1030;
319
+ // Core mainnet -> eSpace mainnet
320
+ case 1030:
321
+ return 1029;
322
+ // eSpace mainnet -> Core mainnet
323
+ case 1:
324
+ return 71;
325
+ // Core testnet -> eSpace testnet
326
+ case 71:
327
+ return 1;
328
+ // eSpace testnet -> Core testnet
329
+ case 2029:
330
+ return 2030;
331
+ // Core local -> eSpace local
332
+ case 2030:
333
+ return 2029;
334
+ // eSpace local -> Core local
335
+ default:
336
+ return null;
337
+ }
338
+ }
339
+ /**
340
+ * Update local chain configurations with actual node URLs
341
+ * Called when ServerManager starts with specific ports
342
+ */
343
+ updateLocalChainUrls(coreRpcPort, evmRpcPort, wsPort) {
344
+ const coreLocal = SUPPORTED_CHAINS[2029];
345
+ if (coreLocal) {
346
+ coreLocal.rpcUrls.default.http = [`http://localhost:${coreRpcPort}`];
347
+ if (wsPort) {
348
+ coreLocal.rpcUrls.default.webSocket = [`ws://localhost:${wsPort}`];
349
+ }
350
+ }
351
+ const evmLocal = SUPPORTED_CHAINS[2030];
352
+ if (evmLocal) {
353
+ evmLocal.rpcUrls.default.http = [`http://localhost:${evmRpcPort}`];
354
+ }
355
+ }
356
+ };
357
+ var defaultNetworkSelector = new NetworkSelector();
358
+
359
+ // src/types/config.ts
360
+ var NodeError = class extends Error {
361
+ code;
362
+ chain;
363
+ context;
364
+ constructor(message, code, chain, context) {
365
+ super(message);
366
+ this.name = "NodeError";
367
+ this.code = code;
368
+ this.chain = chain;
369
+ this.context = context;
370
+ }
371
+ };
372
+
373
+ // src/clients/core.ts
374
+ var conflux = (0, import_utils2.defineChain)({
375
+ id: 1029,
376
+ name: "Conflux Core",
377
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
378
+ rpcUrls: { default: { http: ["https://main.confluxrpc.com"] } }
379
+ });
380
+ var confluxTestnet = (0, import_utils2.defineChain)({
381
+ id: 1,
382
+ name: "Conflux Core Testnet",
383
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
384
+ rpcUrls: { default: { http: ["https://test.confluxrpc.com"] } }
385
+ });
386
+ var CoreClient = class {
387
+ chainType = "core";
388
+ chainId;
389
+ address;
390
+ publicClient;
391
+ chain;
392
+ constructor(config) {
393
+ this.chainId = config.chainId;
394
+ this.chain = (0, import_utils2.defineChain)({
395
+ id: this.chainId,
396
+ name: `ConfluxCore-${this.chainId}`,
397
+ nativeCurrency: {
398
+ decimals: 18,
399
+ name: "Conflux",
400
+ symbol: "CFX"
401
+ },
402
+ rpcUrls: {
403
+ default: {
404
+ http: [config.rpcUrl],
405
+ webSocket: config.wsUrl ? [config.wsUrl] : void 0
406
+ }
407
+ }
408
+ });
409
+ this.publicClient = (0, import_cive.createPublicClient)({
410
+ chain: this.chain,
411
+ transport: (0, import_cive.http)(config.rpcUrl),
412
+ pollingInterval: config.pollingInterval || 1e3
413
+ });
414
+ this.address = "";
415
+ }
416
+ async getBlockNumber() {
417
+ try {
418
+ const epochNumber = await this.publicClient.getEpochNumber();
419
+ return BigInt(epochNumber.toString());
420
+ } catch (error) {
421
+ throw new NodeError(
422
+ `Failed to get block number: ${error instanceof Error ? error.message : String(error)}`,
423
+ "BLOCK_NUMBER_ERROR",
424
+ "core",
425
+ { originalError: error }
426
+ );
427
+ }
428
+ }
429
+ async getBalance(address) {
430
+ if (!(0, import_utils2.isAddress)(address)) {
431
+ throw new NodeError(
432
+ "Invalid Core address format",
433
+ "INVALID_ADDRESS",
434
+ "core"
435
+ );
436
+ }
437
+ try {
438
+ const balance = await this.publicClient.getBalance({ address });
439
+ return (0, import_cive.formatCFX)(balance);
440
+ } catch (error) {
441
+ throw new NodeError(
442
+ `Failed to get balance: ${error instanceof Error ? error.message : String(error)}`,
443
+ "BALANCE_ERROR",
444
+ "core",
445
+ { address, originalError: error }
446
+ );
447
+ }
448
+ }
449
+ async getGasPrice() {
450
+ try {
451
+ const gasPrice = await this.publicClient.getGasPrice();
452
+ return gasPrice;
453
+ } catch (error) {
454
+ throw new NodeError(
455
+ `Failed to get gas price: ${error instanceof Error ? error.message : String(error)}`,
456
+ "GAS_PRICE_ERROR",
457
+ "core",
458
+ { originalError: error }
459
+ );
460
+ }
461
+ }
462
+ async estimateGas(tx) {
463
+ try {
464
+ const estimate = await this.publicClient.request({
465
+ method: "cfx_estimateGasAndCollateral",
466
+ params: [
467
+ {
468
+ to: tx.to,
469
+ value: tx.value ? `0x${tx.value.toString(16)}` : void 0,
470
+ data: tx.data
471
+ }
472
+ ]
473
+ });
474
+ return BigInt(estimate.gasLimit);
475
+ } catch (error) {
476
+ throw new NodeError(
477
+ `Failed to estimate gas: ${error instanceof Error ? error.message : String(error)}`,
478
+ "GAS_ESTIMATE_ERROR",
479
+ "core",
480
+ { transaction: tx, originalError: error }
481
+ );
482
+ }
483
+ }
484
+ async sendTransaction(_tx) {
485
+ throw new NodeError(
486
+ "Cannot send transaction from public client. Use wallet client instead.",
487
+ "WALLET_REQUIRED",
488
+ "core"
489
+ );
490
+ }
491
+ async waitForTransaction(hash) {
492
+ try {
493
+ const receipt = await this.publicClient.waitForTransactionReceipt({
494
+ hash
495
+ });
496
+ return {
497
+ hash: receipt.transactionHash,
498
+ blockNumber: BigInt(receipt.epochNumber?.toString() || "0"),
499
+ blockHash: receipt.blockHash || "",
500
+ transactionIndex: Number(receipt.index || 0),
501
+ status: receipt.outcomeStatus === "success" ? "success" : "reverted",
502
+ gasUsed: receipt.gasUsed || 0n,
503
+ contractAddress: receipt.contractCreated || void 0,
504
+ logs: receipt.log?.map((log) => ({
505
+ address: log.address || "",
506
+ topics: log.topics || [],
507
+ data: log.data || "0x",
508
+ blockNumber: BigInt(log.epochNumber?.toString() || "0"),
509
+ transactionHash: log.transactionHash || "",
510
+ logIndex: Number(log.logIndex || 0)
511
+ })) || []
512
+ };
513
+ } catch (error) {
514
+ throw new NodeError(
515
+ `Failed to wait for transaction: ${error instanceof Error ? error.message : String(error)}`,
516
+ "TRANSACTION_WAIT_ERROR",
517
+ "core",
518
+ { hash, originalError: error }
519
+ );
520
+ }
521
+ }
522
+ async getTokenBalance(tokenAddress, holderAddress) {
523
+ const holder = holderAddress || this.address;
524
+ if (!this.isValidAddress(tokenAddress)) {
525
+ throw new NodeError(
526
+ "Invalid token address format",
527
+ "INVALID_ADDRESS",
528
+ "core",
529
+ { tokenAddress }
530
+ );
531
+ }
532
+ if (!this.isValidAddress(holder)) {
533
+ throw new NodeError(
534
+ "Invalid holder address format",
535
+ "INVALID_ADDRESS",
536
+ "core",
537
+ { holder }
538
+ );
539
+ }
540
+ try {
541
+ const [balance, decimals] = await Promise.all([
542
+ this.publicClient.readContract({
543
+ address: tokenAddress,
544
+ abi: [
545
+ {
546
+ name: "balanceOf",
547
+ type: "function",
548
+ inputs: [{ name: "account", type: "address" }],
549
+ outputs: [{ name: "", type: "uint256" }],
550
+ stateMutability: "view"
551
+ }
552
+ ],
553
+ functionName: "balanceOf",
554
+ args: [holder]
555
+ }),
556
+ this.publicClient.readContract({
557
+ address: tokenAddress,
558
+ abi: [
559
+ {
560
+ name: "decimals",
561
+ type: "function",
562
+ inputs: [],
563
+ outputs: [{ name: "", type: "uint8" }],
564
+ stateMutability: "view"
565
+ }
566
+ ],
567
+ functionName: "decimals"
568
+ })
569
+ ]);
570
+ return this.formatTokenAmount(balance, Number(decimals));
571
+ } catch (error) {
572
+ throw new NodeError(
573
+ `Failed to get token balance: ${error instanceof Error ? error.message : String(error)}`,
574
+ "TOKEN_BALANCE_ERROR",
575
+ "core",
576
+ { tokenAddress, holder, originalError: error }
577
+ );
578
+ }
579
+ }
580
+ watchBlocks(callback) {
581
+ return this.publicClient.watchEpochNumber({
582
+ emitMissed: false,
583
+ epochTag: "latest_mined",
584
+ onEpochNumber: async (epochNumber) => {
585
+ try {
586
+ const blockHashes = await this.publicClient.getBlocksByEpoch({
587
+ epochNumber
588
+ });
589
+ for (const hash of blockHashes) {
590
+ try {
591
+ const block = await this.publicClient.getBlock({
592
+ blockHash: hash
593
+ });
594
+ const blockEvent = {
595
+ chainType: "core",
596
+ blockNumber: BigInt(block.epochNumber?.toString() || "0"),
597
+ blockHash: block.hash || "",
598
+ timestamp: Number(block.timestamp || 0),
599
+ transactionCount: block.transactions?.length || 0
600
+ };
601
+ callback(blockEvent);
602
+ } catch (error) {
603
+ console.error(`Failed to process block ${hash}:`, error);
604
+ }
605
+ }
606
+ } catch (error) {
607
+ console.error(
608
+ `Failed to get blocks for epoch ${epochNumber}:`,
609
+ error
610
+ );
611
+ }
612
+ }
613
+ });
614
+ }
615
+ watchTransactions(callback) {
616
+ return this.publicClient.watchEpochNumber({
617
+ emitMissed: false,
618
+ epochTag: "latest_mined",
619
+ onEpochNumber: async (epochNumber) => {
620
+ try {
621
+ const blockHashes = await this.publicClient.getBlocksByEpoch({
622
+ epochNumber
623
+ });
624
+ for (const hash of blockHashes) {
625
+ try {
626
+ const block = await this.publicClient.getBlock({
627
+ blockHash: hash
628
+ });
629
+ await Promise.all(
630
+ (block.transactions || []).map(
631
+ async (txHash) => {
632
+ try {
633
+ const tx = await this.publicClient.getTransaction({
634
+ hash: txHash
635
+ });
636
+ const txEvent = {
637
+ chainType: "core",
638
+ hash: tx.hash,
639
+ from: tx.from,
640
+ to: tx.to || void 0,
641
+ value: tx.value || 0n,
642
+ blockNumber: BigInt(
643
+ block.epochNumber?.toString() || "0"
644
+ )
645
+ };
646
+ callback(txEvent);
647
+ } catch (error) {
648
+ console.error(
649
+ `Failed to get transaction ${txHash}:`,
650
+ error
651
+ );
652
+ }
653
+ }
654
+ )
655
+ );
656
+ } catch (error) {
657
+ console.error(`Failed to process block ${hash}:`, error);
658
+ }
659
+ }
660
+ } catch (error) {
661
+ console.error(
662
+ `Failed to get blocks for epoch ${epochNumber}:`,
663
+ error
664
+ );
665
+ }
666
+ }
667
+ });
668
+ }
669
+ isValidAddress(address) {
670
+ return (0, import_utils2.isAddress)(address);
671
+ }
672
+ formatAmount(amount) {
673
+ return (0, import_cive.formatCFX)(amount);
674
+ }
675
+ parseAmount(amount) {
676
+ return (0, import_cive.parseCFX)(amount);
677
+ }
678
+ getInternalClient() {
679
+ return this.publicClient;
680
+ }
681
+ formatTokenAmount(amount, decimals) {
682
+ const formatted = (0, import_utils2.formatUnits)(amount, decimals);
683
+ return Number(formatted).toFixed(4);
684
+ }
685
+ };
686
+ var CoreWalletClient = class {
687
+ chainType = "core";
688
+ address;
689
+ chainId;
690
+ walletClient;
691
+ publicClient;
692
+ account;
693
+ chain;
694
+ constructor(config) {
695
+ this.chainId = config.chainId;
696
+ this.chain = (0, import_utils2.defineChain)({
697
+ id: config.chainId,
698
+ name: `ConfluxCore-${config.chainId}`,
699
+ nativeCurrency: {
700
+ decimals: 18,
701
+ name: "Conflux",
702
+ symbol: "CFX"
703
+ },
704
+ rpcUrls: {
705
+ default: {
706
+ http: [config.rpcUrl],
707
+ webSocket: config.wsUrl ? [config.wsUrl] : void 0
708
+ }
709
+ }
710
+ });
711
+ this.account = (0, import_accounts.privateKeyToAccount)(config.privateKey, {
712
+ networkId: config.chainId
713
+ });
714
+ this.address = this.account.address;
715
+ this.walletClient = (0, import_cive.createWalletClient)({
716
+ account: this.account,
717
+ chain: this.chain,
718
+ transport: (0, import_cive.http)(config.rpcUrl),
719
+ pollingInterval: config.pollingInterval || 1e3
720
+ });
721
+ this.publicClient = (0, import_cive.createPublicClient)({
722
+ chain: this.chain,
723
+ transport: (0, import_cive.http)(config.rpcUrl),
724
+ pollingInterval: config.pollingInterval || 1e3
725
+ });
726
+ }
727
+ async sendTransaction(tx) {
728
+ try {
729
+ return await this.walletClient.sendTransaction({
730
+ to: tx.to,
731
+ value: tx.value,
732
+ data: tx.data,
733
+ gas: tx.gasLimit,
734
+ gasPrice: tx.gasPrice,
735
+ nonce: tx.nonce,
736
+ account: this.account,
737
+ chain: this.chain
738
+ });
739
+ } catch (error) {
740
+ throw new NodeError(
741
+ `Failed to send transaction: ${error instanceof Error ? error.message : String(error)}`,
742
+ "TRANSACTION_SEND_ERROR",
743
+ "core",
744
+ { transaction: tx, originalError: error }
745
+ );
746
+ }
747
+ }
748
+ async signMessage(message) {
749
+ try {
750
+ return await this.walletClient.signMessage({
751
+ account: this.account,
752
+ message
753
+ });
754
+ } catch (error) {
755
+ throw new NodeError(
756
+ `Failed to sign message: ${error instanceof Error ? error.message : String(error)}`,
757
+ "MESSAGE_SIGN_ERROR",
758
+ "core",
759
+ { message, originalError: error }
760
+ );
761
+ }
762
+ }
763
+ getInternalClient() {
764
+ return this.walletClient;
765
+ }
766
+ async waitForTransaction(hash) {
767
+ try {
768
+ const receipt = await this.publicClient.waitForTransactionReceipt({
769
+ hash,
770
+ timeout: 5e3
771
+ // 5 second timeout for faster response
772
+ });
773
+ return {
774
+ hash: receipt.transactionHash,
775
+ blockNumber: BigInt(receipt.epochNumber?.toString() || "0"),
776
+ blockHash: receipt.blockHash || "",
777
+ transactionIndex: Number(receipt.index || 0),
778
+ status: receipt.outcomeStatus === "success" ? "success" : "reverted",
779
+ gasUsed: receipt.gasUsed || 0n,
780
+ contractAddress: receipt.contractCreated || void 0,
781
+ logs: receipt.log?.map((log) => ({
782
+ address: log.address || "",
783
+ topics: log.topics || [],
784
+ data: log.data || "0x",
785
+ blockNumber: BigInt(log.epochNumber?.toString() || "0"),
786
+ transactionHash: log.transactionHash || "",
787
+ logIndex: Number(log.logIndex || 0)
788
+ })) || []
789
+ };
790
+ } catch (error) {
791
+ throw new NodeError(
792
+ `Failed to wait for transaction: ${error instanceof Error ? error.message : String(error)}`,
793
+ "TRANSACTION_WAIT_ERROR",
794
+ "core",
795
+ { hash, originalError: error }
796
+ );
797
+ }
798
+ }
799
+ /**
800
+ * Unified faucet functionality
801
+ * Automatically detects address type and sends CFX accordingly:
802
+ * - Core address: Direct transfer
803
+ * - eSpace address: Cross-chain transfer via internal contract
804
+ */
805
+ async faucet(address, amount) {
806
+ const isCoreAddr = (0, import_utils2.isAddress)(address);
807
+ const isEspaceAddr = (0, import_viem2.isAddress)(address);
808
+ if (!isCoreAddr && !isEspaceAddr) {
809
+ throw new NodeError(
810
+ "Invalid address format (must be Core or eSpace address)",
811
+ "INVALID_ADDRESS",
812
+ "core",
813
+ { address }
814
+ );
815
+ }
816
+ try {
817
+ if (isCoreAddr) {
818
+ return await this.walletClient.sendTransaction({
819
+ chain: this.chain,
820
+ account: this.account,
821
+ to: address,
822
+ value: (0, import_cive.parseCFX)(amount)
823
+ });
824
+ } else {
825
+ return await this.walletClient.sendTransaction({
826
+ chain: this.chain,
827
+ account: this.account,
828
+ to: (0, import_utils2.hexAddressToBase32)({
829
+ hexAddress: "0x0888000000000000000000000000000000000006",
830
+ networkId: this.chain.id
831
+ }),
832
+ value: (0, import_cive.parseCFX)(amount),
833
+ data: (0, import_utils2.encodeFunctionData)({
834
+ abi: [
835
+ {
836
+ type: "function",
837
+ name: "transferEVM",
838
+ inputs: [{ name: "to", type: "bytes20" }],
839
+ outputs: [{ name: "output", type: "bytes" }],
840
+ stateMutability: "payable"
841
+ }
842
+ ],
843
+ functionName: "transferEVM",
844
+ args: [address]
845
+ })
846
+ });
847
+ }
848
+ } catch (error) {
849
+ throw new NodeError(
850
+ `Failed to send faucet transaction: ${error instanceof Error ? error.message : String(error)}`,
851
+ "FAUCET_ERROR",
852
+ "core",
853
+ { address, amount, originalError: error }
854
+ );
855
+ }
856
+ }
857
+ /**
858
+ * Cross-chain faucet functionality (Core → eSpace)
859
+ * Sends CFX from Core space to eSpace address via internal contract
860
+ * @deprecated Use faucet() instead which auto-detects address type
861
+ */
862
+ async faucetToEspace(espaceAddress, amount) {
863
+ if (!(0, import_viem2.isAddress)(espaceAddress)) {
864
+ throw new NodeError(
865
+ "Invalid eSpace address format",
866
+ "INVALID_ADDRESS",
867
+ "core",
868
+ { espaceAddress }
869
+ );
870
+ }
871
+ try {
872
+ return await this.walletClient.sendTransaction({
873
+ chain: this.chain,
874
+ account: this.account,
875
+ to: (0, import_utils2.hexAddressToBase32)({
876
+ hexAddress: "0x0888000000000000000000000000000000000006",
877
+ networkId: this.chain.id
878
+ }),
879
+ value: (0, import_cive.parseCFX)(amount),
880
+ data: (0, import_utils2.encodeFunctionData)({
881
+ abi: [
882
+ {
883
+ type: "function",
884
+ name: "transferEVM",
885
+ inputs: [{ name: "to", type: "bytes20" }],
886
+ outputs: [{ name: "output", type: "bytes" }],
887
+ stateMutability: "payable"
888
+ }
889
+ ],
890
+ functionName: "transferEVM",
891
+ args: [espaceAddress]
892
+ })
893
+ });
894
+ } catch (error) {
895
+ throw new NodeError(
896
+ `Failed to send faucet transaction to eSpace: ${error instanceof Error ? error.message : String(error)}`,
897
+ "FAUCET_ERROR",
898
+ "core",
899
+ { espaceAddress, amount, originalError: error }
900
+ );
901
+ }
902
+ }
903
+ /**
904
+ * Deploy a contract to Core Space
905
+ */
906
+ async deployContract(abi, bytecode, constructorArgs = []) {
907
+ try {
908
+ const hash = await this.walletClient.deployContract({
909
+ account: this.account,
910
+ chain: this.chain,
911
+ abi,
912
+ bytecode,
913
+ args: constructorArgs
914
+ });
915
+ const receipt = await this.waitForTransaction(hash);
916
+ if (!receipt.contractAddress) {
917
+ throw new Error("Contract address not found in transaction receipt");
918
+ }
919
+ return receipt.contractAddress;
920
+ } catch (error) {
921
+ throw new NodeError(
922
+ `Failed to deploy contract: ${error instanceof Error ? error.message : String(error)}`,
923
+ "DEPLOYMENT_ERROR",
924
+ "core",
925
+ { abi, bytecode, constructorArgs, originalError: error }
926
+ );
927
+ }
928
+ }
929
+ /**
930
+ * Call a contract method (read-only)
931
+ */
932
+ async callContract(address, abi, functionName, args = []) {
933
+ try {
934
+ const result = await this.publicClient.readContract({
935
+ address,
936
+ abi,
937
+ functionName,
938
+ args
939
+ });
940
+ return result;
941
+ } catch (error) {
942
+ throw new NodeError(
943
+ `Failed to call contract: ${error instanceof Error ? error.message : String(error)}`,
944
+ "CONTRACT_CALL_ERROR",
945
+ "core",
946
+ { address, functionName, args, originalError: error }
947
+ );
948
+ }
949
+ }
950
+ /**
951
+ * Write to a contract (transaction)
952
+ */
953
+ async writeContract(address, abi, functionName, args = [], value) {
954
+ try {
955
+ const hash = await this.walletClient.writeContract({
956
+ account: this.account,
957
+ chain: this.chain,
958
+ address,
959
+ abi,
960
+ functionName,
961
+ args,
962
+ value
963
+ });
964
+ return hash;
965
+ } catch (error) {
966
+ throw new NodeError(
967
+ `Failed to write to contract: ${error instanceof Error ? error.message : String(error)}`,
968
+ "CONTRACT_WRITE_ERROR",
969
+ "core",
970
+ { address, functionName, args, value, originalError: error }
971
+ );
972
+ }
973
+ }
974
+ };
975
+ var CoreTestClient = class extends CoreClient {
976
+ testClient;
977
+ constructor(config) {
978
+ super(config);
979
+ this.testClient = (0, import_cive.createTestClient)({
980
+ chain: this.chainId === 1029 ? conflux : confluxTestnet,
981
+ transport: (0, import_cive.http)(config.rpcUrl),
982
+ pollingInterval: config.pollingInterval || 1e3
983
+ });
984
+ }
985
+ async mine(blocks = 1) {
986
+ try {
987
+ await this.testClient.mine({ blocks });
988
+ } catch (error) {
989
+ throw new NodeError(
990
+ `Failed to mine blocks: ${error instanceof Error ? error.message : String(error)}`,
991
+ "MINE_ERROR",
992
+ "core",
993
+ { blocks, originalError: error }
994
+ );
995
+ }
996
+ }
997
+ async setNextBlockTimestamp(_timestamp) {
998
+ throw new NodeError(
999
+ "setNextBlockTimestamp not implemented for Core client",
1000
+ "NOT_IMPLEMENTED",
1001
+ "core"
1002
+ );
1003
+ }
1004
+ async increaseTime(_seconds) {
1005
+ throw new NodeError(
1006
+ "increaseTime not implemented for Core client",
1007
+ "NOT_IMPLEMENTED",
1008
+ "core"
1009
+ );
1010
+ }
1011
+ async impersonateAccount(_address) {
1012
+ throw new NodeError(
1013
+ "impersonateAccount not implemented for Core client",
1014
+ "NOT_IMPLEMENTED",
1015
+ "core"
1016
+ );
1017
+ }
1018
+ async stopImpersonatingAccount(_address) {
1019
+ throw new NodeError(
1020
+ "stopImpersonatingAccount not implemented for Core client",
1021
+ "NOT_IMPLEMENTED",
1022
+ "core"
1023
+ );
1024
+ }
1025
+ async setBalance(_address, _balance) {
1026
+ throw new NodeError(
1027
+ "setBalance not implemented for Core client",
1028
+ "NOT_IMPLEMENTED",
1029
+ "core"
1030
+ );
1031
+ }
1032
+ async getStorageAt(_address, _slot) {
1033
+ throw new NodeError(
1034
+ "getStorageAt not implemented for Core client",
1035
+ "NOT_IMPLEMENTED",
1036
+ "core"
1037
+ );
1038
+ }
1039
+ async setStorageAt(_address, _slot, _value) {
1040
+ throw new NodeError(
1041
+ "setStorageAt not implemented for Core client",
1042
+ "NOT_IMPLEMENTED",
1043
+ "core"
1044
+ );
1045
+ }
1046
+ getInternalTestClient() {
1047
+ return this.testClient;
1048
+ }
1049
+ };
1050
+ async function createCoreClient(config) {
1051
+ const chainConfig = getChainConfig(config.chainId);
1052
+ if (chainConfig.type !== "core") {
1053
+ throw new NodeError(
1054
+ `Invalid chain type for Core client: ${chainConfig.type}`,
1055
+ "INVALID_CHAIN_TYPE",
1056
+ "core"
1057
+ );
1058
+ }
1059
+ const clientConfig = {
1060
+ ...config,
1061
+ rpcUrl: config.rpcUrl || chainConfig.rpcUrls.default.http[0] || "http://localhost:12537",
1062
+ wsUrl: config.wsUrl || chainConfig.rpcUrls.default.webSocket?.[0]
1063
+ };
1064
+ const publicClient = new CoreClient(clientConfig);
1065
+ let walletClient;
1066
+ let testClient;
1067
+ if (config.account) {
1068
+ let privateKey;
1069
+ if (typeof config.account === "string") {
1070
+ privateKey = config.account;
1071
+ } else {
1072
+ privateKey = config.account.privateKey;
1073
+ }
1074
+ const walletConfig = {
1075
+ ...clientConfig,
1076
+ privateKey,
1077
+ accountIndex: typeof config.account === "object" ? config.account.accountIndex : 0
1078
+ };
1079
+ walletClient = new CoreWalletClient(walletConfig);
1080
+ }
1081
+ if (config.testMode) {
1082
+ const testConfig = {
1083
+ ...clientConfig,
1084
+ enableTestMode: true
1085
+ };
1086
+ testClient = new CoreTestClient(testConfig);
1087
+ }
1088
+ return {
1089
+ publicClient,
1090
+ walletClient,
1091
+ testClient
1092
+ };
1093
+ }
1094
+
1095
+ // src/clients/evm.ts
1096
+ var import_viem3 = require("viem");
1097
+ var import_accounts2 = require("viem/accounts");
1098
+ var espaceMainnet = (0, import_viem3.defineChain)({
1099
+ id: 1030,
1100
+ name: "Conflux eSpace",
1101
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
1102
+ rpcUrls: { default: { http: ["https://evm.confluxrpc.com"] } },
1103
+ blockExplorers: {
1104
+ default: { name: "ConfluxScan", url: "https://evm.confluxscan.net" }
1105
+ }
1106
+ });
1107
+ var espaceTestnet = (0, import_viem3.defineChain)({
1108
+ id: 71,
1109
+ name: "Conflux eSpace Testnet",
1110
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
1111
+ rpcUrls: { default: { http: ["https://evmtestnet.confluxrpc.com"] } },
1112
+ blockExplorers: {
1113
+ default: { name: "ConfluxScan", url: "https://evmtestnet.confluxscan.net" }
1114
+ }
1115
+ });
1116
+ var EspaceClient = class {
1117
+ chainId;
1118
+ chainType = "evm";
1119
+ publicClient;
1120
+ chain;
1121
+ address;
1122
+ constructor(config) {
1123
+ this.chainId = config.chainId;
1124
+ if (config.chainId === 1030) {
1125
+ this.chain = espaceMainnet;
1126
+ } else if (config.chainId === 71) {
1127
+ this.chain = espaceTestnet;
1128
+ } else {
1129
+ this.chain = (0, import_viem3.defineChain)({
1130
+ id: config.chainId,
1131
+ name: `Conflux eSpace (${config.chainId})`,
1132
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
1133
+ rpcUrls: { default: { http: [config.rpcUrl] } }
1134
+ });
1135
+ }
1136
+ this.publicClient = (0, import_viem3.createPublicClient)({
1137
+ chain: this.chain,
1138
+ transport: (0, import_viem3.http)(config.rpcUrl),
1139
+ pollingInterval: config.pollingInterval || 1e3
1140
+ });
1141
+ this.address = "";
1142
+ }
1143
+ async getBlockNumber() {
1144
+ try {
1145
+ const blockNumber = await this.publicClient.getBlockNumber();
1146
+ return blockNumber;
1147
+ } catch (error) {
1148
+ throw new NodeError(
1149
+ `Failed to get block number: ${error instanceof Error ? error.message : String(error)}`,
1150
+ "BLOCK_NUMBER_ERROR",
1151
+ "evm",
1152
+ { originalError: error }
1153
+ );
1154
+ }
1155
+ }
1156
+ async getBalance(address) {
1157
+ if (!(0, import_viem3.isAddress)(address)) {
1158
+ throw new NodeError(
1159
+ "Invalid EVM address format",
1160
+ "INVALID_ADDRESS",
1161
+ "evm"
1162
+ );
1163
+ }
1164
+ try {
1165
+ const balance = await this.publicClient.getBalance({ address });
1166
+ return (0, import_viem3.formatEther)(balance);
1167
+ } catch (error) {
1168
+ throw new NodeError(
1169
+ `Failed to get balance: ${error instanceof Error ? error.message : String(error)}`,
1170
+ "BALANCE_ERROR",
1171
+ "evm",
1172
+ { address, originalError: error }
1173
+ );
1174
+ }
1175
+ }
1176
+ async estimateGas(tx) {
1177
+ try {
1178
+ const gas = await this.publicClient.estimateGas({
1179
+ to: tx.to,
1180
+ value: tx.value,
1181
+ data: tx.data
1182
+ });
1183
+ return gas;
1184
+ } catch (error) {
1185
+ throw new NodeError(
1186
+ `Failed to estimate gas: ${error instanceof Error ? error.message : String(error)}`,
1187
+ "GAS_ESTIMATE_ERROR",
1188
+ "evm",
1189
+ { transaction: tx, originalError: error }
1190
+ );
1191
+ }
1192
+ }
1193
+ async waitForTransaction(hash) {
1194
+ try {
1195
+ const receipt = await this.publicClient.waitForTransactionReceipt({
1196
+ hash,
1197
+ timeout: 5e3
1198
+ // 5 second timeout for faster response
1199
+ });
1200
+ return {
1201
+ hash: receipt.transactionHash,
1202
+ blockNumber: receipt.blockNumber,
1203
+ blockHash: receipt.blockHash,
1204
+ transactionIndex: receipt.transactionIndex,
1205
+ status: receipt.status === "success" ? "success" : "reverted",
1206
+ gasUsed: receipt.gasUsed,
1207
+ contractAddress: receipt.contractAddress || void 0,
1208
+ logs: receipt.logs.map((log) => ({
1209
+ address: log.address,
1210
+ topics: log.topics,
1211
+ data: log.data,
1212
+ blockNumber: log.blockNumber || 0n,
1213
+ transactionHash: log.transactionHash || "",
1214
+ logIndex: log.logIndex || 0
1215
+ }))
1216
+ };
1217
+ } catch (error) {
1218
+ throw new NodeError(
1219
+ `Failed to wait for transaction: ${error instanceof Error ? error.message : String(error)}`,
1220
+ "TRANSACTION_WAIT_ERROR",
1221
+ "evm",
1222
+ { hash, originalError: error }
1223
+ );
1224
+ }
1225
+ }
1226
+ async getGasPrice() {
1227
+ try {
1228
+ const gasPrice = await this.publicClient.getGasPrice();
1229
+ return gasPrice;
1230
+ } catch (error) {
1231
+ throw new NodeError(
1232
+ `Failed to get gas price: ${error instanceof Error ? error.message : String(error)}`,
1233
+ "GAS_PRICE_ERROR",
1234
+ "evm",
1235
+ { originalError: error }
1236
+ );
1237
+ }
1238
+ }
1239
+ /**
1240
+ * Get the current chain ID from the network
1241
+ */
1242
+ async getChainId() {
1243
+ try {
1244
+ const chainId = await this.publicClient.getChainId();
1245
+ return chainId;
1246
+ } catch (error) {
1247
+ throw new NodeError(
1248
+ `Failed to get chain ID: ${error instanceof Error ? error.message : String(error)}`,
1249
+ "CHAIN_ID_ERROR",
1250
+ "evm",
1251
+ { originalError: error }
1252
+ );
1253
+ }
1254
+ }
1255
+ /**
1256
+ * Check if the client is connected to the network
1257
+ */
1258
+ async isConnected() {
1259
+ try {
1260
+ await this.publicClient.getBlockNumber();
1261
+ return true;
1262
+ } catch {
1263
+ return false;
1264
+ }
1265
+ }
1266
+ // Base implementation - should be overridden by WalletClient
1267
+ async sendTransaction(_tx) {
1268
+ throw new NodeError(
1269
+ "sendTransaction not available on public client",
1270
+ "METHOD_NOT_AVAILABLE",
1271
+ "evm"
1272
+ );
1273
+ }
1274
+ async getTokenBalance(_address, _tokenAddress) {
1275
+ try {
1276
+ const balance = await this.publicClient.readContract({
1277
+ address: _tokenAddress,
1278
+ abi: [
1279
+ {
1280
+ type: "function",
1281
+ name: "balanceOf",
1282
+ inputs: [{ name: "account", type: "address" }],
1283
+ outputs: [{ name: "balance", type: "uint256" }],
1284
+ stateMutability: "view"
1285
+ }
1286
+ ],
1287
+ functionName: "balanceOf",
1288
+ args: [_address]
1289
+ });
1290
+ return balance.toString();
1291
+ } catch (error) {
1292
+ throw new NodeError(
1293
+ `Failed to get token balance: ${error instanceof Error ? error.message : String(error)}`,
1294
+ "TOKEN_BALANCE_ERROR",
1295
+ "evm",
1296
+ { address: _address, tokenAddress: _tokenAddress, originalError: error }
1297
+ );
1298
+ }
1299
+ }
1300
+ watchBlocks(callback) {
1301
+ const unwatch = this.publicClient.watchBlocks({
1302
+ onBlock: (block) => callback({
1303
+ chainType: "evm",
1304
+ blockNumber: block.number || 0n,
1305
+ blockHash: block.hash || "",
1306
+ timestamp: Number(block.timestamp || 0),
1307
+ transactionCount: block.transactions?.length || 0
1308
+ })
1309
+ });
1310
+ return unwatch;
1311
+ }
1312
+ async watchTransaction(_hash, _callback) {
1313
+ const pollTransaction = async () => {
1314
+ try {
1315
+ const receipt = await this.waitForTransaction(_hash);
1316
+ _callback(receipt);
1317
+ } catch {
1318
+ setTimeout(pollTransaction, 1e3);
1319
+ }
1320
+ };
1321
+ setTimeout(pollTransaction, 1e3);
1322
+ return () => {
1323
+ };
1324
+ }
1325
+ getInternalClient() {
1326
+ return this.publicClient;
1327
+ }
1328
+ // Base implementation - should be overridden by TestClient
1329
+ watchTransactions(_callback) {
1330
+ throw new NodeError(
1331
+ "watchTransactions not available on public client",
1332
+ "METHOD_NOT_AVAILABLE",
1333
+ "evm"
1334
+ );
1335
+ }
1336
+ isValidAddress(address) {
1337
+ return (0, import_viem3.isAddress)(address);
1338
+ }
1339
+ formatAmount(amount) {
1340
+ return (0, import_viem3.formatEther)(amount);
1341
+ }
1342
+ parseAmount(amount) {
1343
+ return (0, import_viem3.parseEther)(amount);
1344
+ }
1345
+ };
1346
+ var EspaceWalletClient = class extends EspaceClient {
1347
+ walletClient;
1348
+ account;
1349
+ constructor(config) {
1350
+ super(config);
1351
+ this.account = (0, import_accounts2.privateKeyToAccount)(config.privateKey);
1352
+ this.address = this.account.address;
1353
+ this.walletClient = (0, import_viem3.createWalletClient)({
1354
+ account: this.account,
1355
+ chain: this.chain,
1356
+ transport: (0, import_viem3.http)(config.rpcUrl)
1357
+ });
1358
+ }
1359
+ getAddress() {
1360
+ return this.address;
1361
+ }
1362
+ async sendTransaction(tx) {
1363
+ try {
1364
+ const hash = await this.walletClient.sendTransaction({
1365
+ account: this.account,
1366
+ chain: this.chain,
1367
+ to: tx.to,
1368
+ value: tx.value,
1369
+ data: tx.data,
1370
+ gas: tx.gasLimit,
1371
+ gasPrice: tx.gasPrice,
1372
+ nonce: tx.nonce
1373
+ });
1374
+ return hash;
1375
+ } catch (error) {
1376
+ throw new NodeError(
1377
+ `Failed to send transaction: ${error instanceof Error ? error.message : String(error)}`,
1378
+ "TRANSACTION_ERROR",
1379
+ "evm",
1380
+ { transaction: tx, originalError: error }
1381
+ );
1382
+ }
1383
+ }
1384
+ async signMessage(message) {
1385
+ try {
1386
+ const signature = await this.walletClient.signMessage({
1387
+ account: this.account,
1388
+ message
1389
+ });
1390
+ return signature;
1391
+ } catch (error) {
1392
+ throw new NodeError(
1393
+ `Failed to sign message: ${error instanceof Error ? error.message : String(error)}`,
1394
+ "SIGNING_ERROR",
1395
+ "evm",
1396
+ { message, originalError: error }
1397
+ );
1398
+ }
1399
+ }
1400
+ async deployContract(abi, bytecode, constructorArgs = []) {
1401
+ try {
1402
+ const hash = await this.walletClient.deployContract({
1403
+ account: this.account,
1404
+ chain: this.chain,
1405
+ abi,
1406
+ bytecode,
1407
+ args: constructorArgs
1408
+ });
1409
+ const receipt = await this.waitForTransaction(hash);
1410
+ if (!receipt.contractAddress) {
1411
+ throw new Error("Contract address not found in transaction receipt");
1412
+ }
1413
+ return receipt.contractAddress;
1414
+ } catch (error) {
1415
+ throw new NodeError(
1416
+ `Failed to deploy contract: ${error instanceof Error ? error.message : String(error)}`,
1417
+ "DEPLOYMENT_ERROR",
1418
+ "evm",
1419
+ { bytecode, constructorArgs, originalError: error }
1420
+ );
1421
+ }
1422
+ }
1423
+ async callContract(address, abi, functionName, args = []) {
1424
+ try {
1425
+ const result = await this.publicClient.readContract({
1426
+ address,
1427
+ abi,
1428
+ functionName,
1429
+ args
1430
+ });
1431
+ return result;
1432
+ } catch (error) {
1433
+ throw new NodeError(
1434
+ `Failed to call contract: ${error instanceof Error ? error.message : String(error)}`,
1435
+ "CONTRACT_CALL_ERROR",
1436
+ "evm",
1437
+ { address, functionName, args, originalError: error }
1438
+ );
1439
+ }
1440
+ }
1441
+ async writeContract(address, abi, functionName, args = [], value) {
1442
+ try {
1443
+ const hash = await this.walletClient.writeContract({
1444
+ account: this.account,
1445
+ chain: this.chain,
1446
+ address,
1447
+ abi,
1448
+ functionName,
1449
+ args,
1450
+ value
1451
+ });
1452
+ return hash;
1453
+ } catch (error) {
1454
+ throw new NodeError(
1455
+ `Failed to write contract: ${error instanceof Error ? error.message : String(error)}`,
1456
+ "CONTRACT_WRITE_ERROR",
1457
+ "evm",
1458
+ { address, functionName, args, value, originalError: error }
1459
+ );
1460
+ }
1461
+ }
1462
+ /**
1463
+ * Transfer CFX from eSpace to Core Space
1464
+ * Uses the built-in withdrawal mechanism
1465
+ */
1466
+ async faucetToCore(coreAddress, amount) {
1467
+ if (!coreAddress.startsWith("cfx:") || coreAddress.length < 30) {
1468
+ throw new NodeError(
1469
+ "Invalid Core address format",
1470
+ "INVALID_ADDRESS",
1471
+ "evm",
1472
+ { coreAddress }
1473
+ );
1474
+ }
1475
+ try {
1476
+ const hash = await this.walletClient.sendTransaction({
1477
+ account: this.account,
1478
+ chain: this.chain,
1479
+ to: "0x0888000000000000000000000000000000000006",
1480
+ // CrossSpaceCall precompiled address
1481
+ value: (0, import_viem3.parseEther)(amount),
1482
+ data: (0, import_viem3.encodeFunctionData)({
1483
+ abi: [
1484
+ {
1485
+ type: "function",
1486
+ name: "withdrawFromMapped",
1487
+ inputs: [{ name: "value", type: "uint256" }],
1488
+ outputs: [],
1489
+ stateMutability: "payable"
1490
+ }
1491
+ ],
1492
+ functionName: "withdrawFromMapped",
1493
+ args: [(0, import_viem3.parseEther)(amount)]
1494
+ })
1495
+ });
1496
+ return hash;
1497
+ } catch (error) {
1498
+ throw new NodeError(
1499
+ `Failed to send faucet transaction to Core: ${error instanceof Error ? error.message : String(error)}`,
1500
+ "FAUCET_ERROR",
1501
+ "evm",
1502
+ { coreAddress, amount, originalError: error }
1503
+ );
1504
+ }
1505
+ }
1506
+ getInternalClient() {
1507
+ return this.walletClient;
1508
+ }
1509
+ };
1510
+ var EspaceTestClient = class extends EspaceWalletClient {
1511
+ testClient;
1512
+ constructor(config) {
1513
+ super(config);
1514
+ this.testClient = (0, import_viem3.createTestClient)({
1515
+ mode: "anvil",
1516
+ chain: this.chainId === 1030 ? espaceMainnet : espaceTestnet,
1517
+ transport: (0, import_viem3.http)(config.rpcUrl),
1518
+ pollingInterval: config.pollingInterval || 1e3
1519
+ });
1520
+ }
1521
+ async mine(blocks = 1) {
1522
+ try {
1523
+ await this.testClient.mine({ blocks });
1524
+ } catch (error) {
1525
+ throw new NodeError(
1526
+ `Failed to mine blocks: ${error instanceof Error ? error.message : String(error)}`,
1527
+ "MINING_ERROR",
1528
+ "evm",
1529
+ { blocks, originalError: error }
1530
+ );
1531
+ }
1532
+ }
1533
+ async setNextBlockTimestamp(timestamp) {
1534
+ try {
1535
+ await this.testClient.setNextBlockTimestamp({
1536
+ timestamp: BigInt(timestamp)
1537
+ });
1538
+ } catch (error) {
1539
+ throw new NodeError(
1540
+ `Failed to set next block timestamp: ${error instanceof Error ? error.message : String(error)}`,
1541
+ "TIMESTAMP_ERROR",
1542
+ "evm",
1543
+ { timestamp, originalError: error }
1544
+ );
1545
+ }
1546
+ }
1547
+ async increaseTime(seconds) {
1548
+ try {
1549
+ await this.testClient.increaseTime({ seconds });
1550
+ } catch (error) {
1551
+ throw new NodeError(
1552
+ `Failed to increase time: ${error instanceof Error ? error.message : String(error)}`,
1553
+ "TIME_INCREASE_ERROR",
1554
+ "evm",
1555
+ { seconds, originalError: error }
1556
+ );
1557
+ }
1558
+ }
1559
+ async impersonateAccount(address) {
1560
+ try {
1561
+ await this.testClient.impersonateAccount({ address });
1562
+ } catch (error) {
1563
+ throw new NodeError(
1564
+ `Failed to impersonate account: ${error instanceof Error ? error.message : String(error)}`,
1565
+ "IMPERSONATION_ERROR",
1566
+ "evm",
1567
+ { address, originalError: error }
1568
+ );
1569
+ }
1570
+ }
1571
+ async stopImpersonatingAccount(address) {
1572
+ try {
1573
+ await this.testClient.stopImpersonatingAccount({
1574
+ address
1575
+ });
1576
+ } catch (error) {
1577
+ throw new NodeError(
1578
+ `Failed to stop impersonating account: ${error instanceof Error ? error.message : String(error)}`,
1579
+ "IMPERSONATION_STOP_ERROR",
1580
+ "evm",
1581
+ { address, originalError: error }
1582
+ );
1583
+ }
1584
+ }
1585
+ async setBalance(address, balance) {
1586
+ try {
1587
+ await this.testClient.setBalance({
1588
+ address,
1589
+ value: balance
1590
+ });
1591
+ } catch (error) {
1592
+ throw new NodeError(
1593
+ `Failed to set balance: ${error instanceof Error ? error.message : String(error)}`,
1594
+ "BALANCE_SET_ERROR",
1595
+ "evm",
1596
+ { address, balance, originalError: error }
1597
+ );
1598
+ }
1599
+ }
1600
+ async snapshot() {
1601
+ try {
1602
+ const snapshotId = await this.testClient.snapshot();
1603
+ return snapshotId;
1604
+ } catch (error) {
1605
+ throw new NodeError(
1606
+ `Failed to create snapshot: ${error instanceof Error ? error.message : String(error)}`,
1607
+ "SNAPSHOT_ERROR",
1608
+ "evm",
1609
+ { originalError: error }
1610
+ );
1611
+ }
1612
+ }
1613
+ async revert(snapshotId) {
1614
+ try {
1615
+ await this.testClient.revert({ id: snapshotId });
1616
+ } catch (error) {
1617
+ throw new NodeError(
1618
+ `Failed to revert to snapshot: ${error instanceof Error ? error.message : String(error)}`,
1619
+ "REVERT_ERROR",
1620
+ "evm",
1621
+ { snapshotId, originalError: error }
1622
+ );
1623
+ }
1624
+ }
1625
+ async getStorageAt(address, slot) {
1626
+ try {
1627
+ const value = await this.publicClient.getStorageAt({
1628
+ address,
1629
+ slot
1630
+ });
1631
+ return value || "0x";
1632
+ } catch (error) {
1633
+ throw new NodeError(
1634
+ `Failed to get storage: ${error instanceof Error ? error.message : String(error)}`,
1635
+ "STORAGE_GET_ERROR",
1636
+ "evm",
1637
+ { address, slot, originalError: error }
1638
+ );
1639
+ }
1640
+ }
1641
+ async setStorageAt(address, slot, value) {
1642
+ try {
1643
+ await this.testClient.setStorageAt({
1644
+ address,
1645
+ index: slot,
1646
+ value
1647
+ });
1648
+ } catch (error) {
1649
+ throw new NodeError(
1650
+ `Failed to set storage: ${error instanceof Error ? error.message : String(error)}`,
1651
+ "STORAGE_SET_ERROR",
1652
+ "evm",
1653
+ { address, slot, value, originalError: error }
1654
+ );
1655
+ }
1656
+ }
1657
+ watchTransactions(callback) {
1658
+ const unwatch = this.publicClient.watchPendingTransactions({
1659
+ onTransactions: (hashes) => {
1660
+ for (const hash of hashes) {
1661
+ callback({
1662
+ chainType: "evm",
1663
+ hash,
1664
+ from: "",
1665
+ // Would need to fetch transaction details
1666
+ to: "",
1667
+ // Would need to fetch transaction details
1668
+ value: 0n,
1669
+ // Would need to fetch transaction details
1670
+ blockNumber: 0n
1671
+ // Would need to fetch transaction details
1672
+ });
1673
+ }
1674
+ }
1675
+ });
1676
+ return unwatch;
1677
+ }
1678
+ isValidAddress(address) {
1679
+ return (0, import_viem3.isAddress)(address);
1680
+ }
1681
+ async getCurrentEpoch() {
1682
+ return await this.getBlockNumber();
1683
+ }
1684
+ async generateAccounts(count) {
1685
+ const accounts = [];
1686
+ for (let i = 0; i < count; i++) {
1687
+ const privateKey = `0x${"0".repeat(64 - 2)}${i.toString(16).padStart(2, "0")}${"0".repeat(60)}`;
1688
+ const account = (0, import_accounts2.privateKeyToAccount)(privateKey);
1689
+ accounts.push(account.address);
1690
+ }
1691
+ return accounts;
1692
+ }
1693
+ };
1694
+ async function createEspaceClient(config) {
1695
+ const chainConfig = getChainConfig(config.chainId);
1696
+ if (chainConfig.type !== "evm") {
1697
+ throw new NodeError(
1698
+ `Invalid chain type for eSpace client: ${chainConfig.type}`,
1699
+ "INVALID_CHAIN_TYPE",
1700
+ "evm"
1701
+ );
1702
+ }
1703
+ const clientConfig = {
1704
+ ...config,
1705
+ rpcUrl: config.rpcUrl || chainConfig.rpcUrls.default.http[0] || "http://localhost:8545"
1706
+ };
1707
+ const publicClient = new EspaceClient(clientConfig);
1708
+ let walletClient;
1709
+ let testClient;
1710
+ if (config.account) {
1711
+ let privateKey;
1712
+ if (typeof config.account === "string") {
1713
+ privateKey = config.account;
1714
+ } else {
1715
+ privateKey = config.account.privateKey;
1716
+ }
1717
+ const walletConfig = {
1718
+ ...clientConfig,
1719
+ privateKey,
1720
+ accountIndex: typeof config.account === "object" ? config.account.accountIndex : 0
1721
+ };
1722
+ walletClient = new EspaceWalletClient(walletConfig);
1723
+ }
1724
+ if (config.testMode) {
1725
+ let privateKey;
1726
+ if (config.account) {
1727
+ if (typeof config.account === "string") {
1728
+ privateKey = config.account;
1729
+ } else {
1730
+ privateKey = config.account.privateKey;
1731
+ }
1732
+ } else {
1733
+ privateKey = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
1734
+ }
1735
+ const testConfig = {
1736
+ ...clientConfig,
1737
+ enableTestMode: true,
1738
+ privateKey
1739
+ };
1740
+ testClient = new EspaceTestClient(testConfig);
1741
+ }
1742
+ return {
1743
+ publicClient,
1744
+ walletClient,
1745
+ testClient
1746
+ };
1747
+ }
1748
+
1749
+ // src/clients/manager.ts
1750
+ var import_node_events = require("events");
1751
+ var HEALTH_CHECK_INTERVAL = 3e4;
1752
+ var HEALTH_CHECK_TIMEOUT = 5e3;
1753
+ var ClientManager = class extends import_node_events.EventEmitter {
1754
+ config;
1755
+ coreClient = null;
1756
+ evmClient = null;
1757
+ healthCheckInterval = null;
1758
+ networkSelectorUnsubscribe = null;
1759
+ nodeRunningUnsubscribe = null;
1760
+ initialized = false;
1761
+ constructor(config) {
1762
+ super();
1763
+ this.config = {
1764
+ enableHealthMonitoring: true,
1765
+ healthCheckInterval: HEALTH_CHECK_INTERVAL,
1766
+ healthCheckTimeout: HEALTH_CHECK_TIMEOUT,
1767
+ ...config
1768
+ };
1769
+ }
1770
+ /**
1771
+ * Initialize the Client Manager
1772
+ * Sets up clients, server, and monitoring
1773
+ */
1774
+ async initialize() {
1775
+ if (this.initialized) {
1776
+ return;
1777
+ }
1778
+ try {
1779
+ this.setupNetworkListeners();
1780
+ await this.initializeClients();
1781
+ if (this.config.enableHealthMonitoring) {
1782
+ this.startHealthMonitoring();
1783
+ }
1784
+ this.initialized = true;
1785
+ this.emit("manager:ready");
1786
+ } catch (error) {
1787
+ const managerError = error instanceof Error ? error : new Error(String(error));
1788
+ this.emit("manager:error", { error: managerError });
1789
+ throw managerError;
1790
+ }
1791
+ }
1792
+ /**
1793
+ * Gracefully shutdown the Client Manager
1794
+ */
1795
+ async shutdown() {
1796
+ if (!this.initialized) {
1797
+ return;
1798
+ }
1799
+ try {
1800
+ this.stopHealthMonitoring();
1801
+ if (this.networkSelectorUnsubscribe) {
1802
+ this.networkSelectorUnsubscribe();
1803
+ this.networkSelectorUnsubscribe = null;
1804
+ }
1805
+ if (this.nodeRunningUnsubscribe) {
1806
+ this.nodeRunningUnsubscribe();
1807
+ this.nodeRunningUnsubscribe = null;
1808
+ }
1809
+ this.coreClient = null;
1810
+ this.evmClient = null;
1811
+ this.initialized = false;
1812
+ this.removeAllListeners();
1813
+ } catch (error) {
1814
+ const shutdownError = error instanceof Error ? error : new Error(String(error));
1815
+ this.emit("manager:error", { error: shutdownError });
1816
+ throw shutdownError;
1817
+ }
1818
+ }
1819
+ /**
1820
+ * Get current Core Space client
1821
+ */
1822
+ getCoreClient() {
1823
+ return this.coreClient;
1824
+ }
1825
+ /**
1826
+ * Get current eSpace client
1827
+ */
1828
+ getEvmClient() {
1829
+ return this.evmClient;
1830
+ }
1831
+ /**
1832
+ * Get comprehensive status
1833
+ */
1834
+ getStatus() {
1835
+ const currentChainId = defaultNetworkSelector.getCurrentChainId();
1836
+ const currentChain = getChainConfig(currentChainId);
1837
+ return {
1838
+ initialized: this.initialized,
1839
+ coreClient: {
1840
+ connected: !!this.coreClient,
1841
+ chainId: currentChain.type === "core" ? currentChainId : defaultNetworkSelector.getCorrespondingChainId() || 1,
1842
+ health: "unknown",
1843
+ // TODO: Implement health status tracking
1844
+ lastHealthCheck: void 0
1845
+ },
1846
+ evmClient: {
1847
+ connected: !!this.evmClient,
1848
+ chainId: currentChain.type === "evm" ? currentChainId : defaultNetworkSelector.getCorrespondingChainId() || 71,
1849
+ health: "unknown",
1850
+ // TODO: Implement health status tracking
1851
+ lastHealthCheck: void 0
1852
+ },
1853
+ networkSelector: {
1854
+ currentChain: currentChainId,
1855
+ isLocalNode: defaultNetworkSelector.getNodeRunningStatus(),
1856
+ lockedToLocal: defaultNetworkSelector.isLockedToLocal()
1857
+ }
1858
+ };
1859
+ }
1860
+ /**
1861
+ * Switch to a specific network
1862
+ * @param chainId - Target chain ID
1863
+ * @param force - Force switch even if node is running (for wallet operations)
1864
+ */
1865
+ async switchNetwork(chainId, force = false) {
1866
+ if (!isValidChainId(chainId)) {
1867
+ throw new Error(`Invalid chain ID: ${chainId}`);
1868
+ }
1869
+ const previousChainId = defaultNetworkSelector.getCurrentChainId();
1870
+ if (previousChainId === chainId) {
1871
+ return;
1872
+ }
1873
+ defaultNetworkSelector.switchChain(chainId, force);
1874
+ if (defaultNetworkSelector.getCurrentChainId() === chainId) {
1875
+ await this.initializeClients();
1876
+ this.emit("network:switched", { from: previousChainId, to: chainId });
1877
+ }
1878
+ }
1879
+ /**
1880
+ * Initialize or reinitialize client instances based on current network
1881
+ */
1882
+ async initializeClients() {
1883
+ const currentChainId = defaultNetworkSelector.getCurrentChainId();
1884
+ const currentChain = getChainConfig(currentChainId);
1885
+ try {
1886
+ if (currentChain.type === "core") {
1887
+ const evmChainId = defaultNetworkSelector.getCorrespondingChainId() || 71;
1888
+ this.coreClient = await createCoreClient({
1889
+ ...this.config.core,
1890
+ chainId: currentChainId
1891
+ });
1892
+ this.evmClient = await createEspaceClient({
1893
+ ...this.config.evm,
1894
+ chainId: evmChainId
1895
+ });
1896
+ } else {
1897
+ const coreChainId = defaultNetworkSelector.getCorrespondingChainId() || 1;
1898
+ this.coreClient = await createCoreClient({
1899
+ ...this.config.core,
1900
+ chainId: coreChainId
1901
+ });
1902
+ this.evmClient = await createEspaceClient({
1903
+ ...this.config.evm,
1904
+ chainId: currentChainId
1905
+ });
1906
+ }
1907
+ this.emit("client:ready", {
1908
+ type: "core",
1909
+ chainId: this.coreClient.publicClient.chainId
1910
+ });
1911
+ this.emit("client:ready", {
1912
+ type: "evm",
1913
+ chainId: this.evmClient.publicClient.chainId
1914
+ });
1915
+ } catch (error) {
1916
+ const clientError = error instanceof Error ? error : new Error(String(error));
1917
+ this.emit("manager:error", { error: clientError });
1918
+ throw clientError;
1919
+ }
1920
+ }
1921
+ /**
1922
+ * Set up network selector event listeners
1923
+ */
1924
+ setupNetworkListeners() {
1925
+ this.networkSelectorUnsubscribe = defaultNetworkSelector.onChainChange(
1926
+ async (_chainId) => {
1927
+ try {
1928
+ await this.initializeClients();
1929
+ } catch (error) {
1930
+ const networkError = error instanceof Error ? error : new Error(String(error));
1931
+ this.emit("manager:error", { error: networkError });
1932
+ }
1933
+ }
1934
+ );
1935
+ this.nodeRunningUnsubscribe = defaultNetworkSelector.onNodeRunningChange(
1936
+ async (isRunning) => {
1937
+ if (isRunning) {
1938
+ } else {
1939
+ }
1940
+ }
1941
+ );
1942
+ }
1943
+ /**
1944
+ * Start health monitoring for all clients
1945
+ */
1946
+ startHealthMonitoring() {
1947
+ if (this.healthCheckInterval) {
1948
+ return;
1949
+ }
1950
+ this.healthCheckInterval = setInterval(async () => {
1951
+ await this.performHealthChecks();
1952
+ }, this.config.healthCheckInterval || HEALTH_CHECK_INTERVAL);
1953
+ setTimeout(() => this.performHealthChecks(), 1e3);
1954
+ }
1955
+ /**
1956
+ * Stop health monitoring
1957
+ */
1958
+ stopHealthMonitoring() {
1959
+ if (this.healthCheckInterval) {
1960
+ clearInterval(this.healthCheckInterval);
1961
+ this.healthCheckInterval = null;
1962
+ }
1963
+ }
1964
+ /**
1965
+ * Perform health checks on all clients
1966
+ */
1967
+ async performHealthChecks() {
1968
+ const timeout = this.config.healthCheckTimeout || HEALTH_CHECK_TIMEOUT;
1969
+ if (this.coreClient) {
1970
+ try {
1971
+ const healthPromise = this.checkCoreClientHealth();
1972
+ const result = await Promise.race([
1973
+ healthPromise,
1974
+ new Promise(
1975
+ (_, reject) => setTimeout(() => reject(new Error("Health check timeout")), timeout)
1976
+ )
1977
+ ]);
1978
+ this.emit("client:health", {
1979
+ type: "core",
1980
+ chainId: this.coreClient.publicClient.chainId,
1981
+ status: result
1982
+ });
1983
+ } catch (error) {
1984
+ this.emit("client:error", {
1985
+ type: "core",
1986
+ chainId: this.coreClient.publicClient.chainId,
1987
+ error: error instanceof Error ? error : new Error(String(error))
1988
+ });
1989
+ }
1990
+ }
1991
+ if (this.evmClient) {
1992
+ try {
1993
+ const healthPromise = this.checkEvmClientHealth();
1994
+ const result = await Promise.race([
1995
+ healthPromise,
1996
+ new Promise(
1997
+ (_, reject) => setTimeout(() => reject(new Error("Health check timeout")), timeout)
1998
+ )
1999
+ ]);
2000
+ this.emit("client:health", {
2001
+ type: "evm",
2002
+ chainId: this.evmClient.publicClient.chainId,
2003
+ status: result
2004
+ });
2005
+ } catch (error) {
2006
+ this.emit("client:error", {
2007
+ type: "evm",
2008
+ chainId: this.evmClient.publicClient.chainId,
2009
+ error: error instanceof Error ? error : new Error(String(error))
2010
+ });
2011
+ }
2012
+ }
2013
+ }
2014
+ /**
2015
+ * Check Core client health
2016
+ */
2017
+ async checkCoreClientHealth() {
2018
+ if (!this.coreClient) {
2019
+ return "disconnected";
2020
+ }
2021
+ try {
2022
+ await this.coreClient.publicClient.getBlockNumber();
2023
+ return "healthy";
2024
+ } catch (_error) {
2025
+ return "unhealthy";
2026
+ }
2027
+ }
2028
+ /**
2029
+ * Check eSpace client health
2030
+ */
2031
+ async checkEvmClientHealth() {
2032
+ if (!this.evmClient) {
2033
+ return "disconnected";
2034
+ }
2035
+ try {
2036
+ await this.evmClient.publicClient.getBlockNumber();
2037
+ return "healthy";
2038
+ } catch (_error) {
2039
+ return "unhealthy";
2040
+ }
2041
+ }
2042
+ };
2043
+ // Annotate the CommonJS export names for ESM import in node:
2044
+ 0 && (module.exports = {
2045
+ ClientManager,
2046
+ CoreClient,
2047
+ CoreTestClient,
2048
+ CoreWalletClient,
2049
+ EspaceClient,
2050
+ EspaceTestClient,
2051
+ EspaceWalletClient
2052
+ });
2053
+ //# sourceMappingURL=index.cjs.map