@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
package/dist/index.cjs ADDED
@@ -0,0 +1,3773 @@
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/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ BatcherError: () => BatcherError,
24
+ CORE_LOCAL: () => CORE_LOCAL,
25
+ CORE_MAINNET: () => CORE_MAINNET,
26
+ CORE_TESTNET: () => CORE_TESTNET,
27
+ ClientManager: () => ClientManager,
28
+ ContractDeployer: () => ContractDeployer,
29
+ ContractError: () => ContractError,
30
+ ContractReader: () => ContractReader,
31
+ ContractWriter: () => ContractWriter,
32
+ CoreClient: () => CoreClient,
33
+ CoreTestClient: () => CoreTestClient,
34
+ CoreWalletClient: () => CoreWalletClient,
35
+ DeploymentError: () => DeploymentError,
36
+ ERC1155_ABI: () => ERC1155_ABI,
37
+ ERC20_ABI: () => ERC20_ABI,
38
+ ERC721_ABI: () => ERC721_ABI,
39
+ EVM_LOCAL: () => EVM_LOCAL,
40
+ EVM_MAINNET: () => EVM_MAINNET,
41
+ EVM_TESTNET: () => EVM_TESTNET,
42
+ EmbeddedWalletError: () => EmbeddedWalletError,
43
+ EmbeddedWalletManager: () => EmbeddedWalletManager,
44
+ EspaceClient: () => EspaceClient,
45
+ EspaceTestClient: () => EspaceTestClient,
46
+ EspaceWalletClient: () => EspaceWalletClient,
47
+ InteractionError: () => InteractionError,
48
+ SessionKeyError: () => SessionKeyError,
49
+ SessionKeyManager: () => SessionKeyManager,
50
+ TransactionBatcher: () => TransactionBatcher,
51
+ WalletError: () => WalletError,
52
+ defaultNetworkSelector: () => defaultNetworkSelector,
53
+ deriveAccount: () => deriveAccount,
54
+ deriveAccounts: () => deriveAccounts,
55
+ deriveFaucetAccount: () => deriveFaucetAccount,
56
+ formatCFX: () => import_cive2.formatCFX,
57
+ formatUnits: () => import_viem5.formatUnits,
58
+ generateMnemonic: () => generateMnemonic,
59
+ getChainConfig: () => getChainConfig,
60
+ getCoreChains: () => getCoreChains,
61
+ getEvmChains: () => getEvmChains,
62
+ getMainnetChains: () => getMainnetChains,
63
+ isCoreAddress: () => import_utils3.isAddress,
64
+ isEspaceAddress: () => import_viem5.isAddress,
65
+ logger: () => logger,
66
+ parseCFX: () => import_cive2.parseCFX,
67
+ parseUnits: () => import_viem5.parseUnits,
68
+ validateMnemonic: () => validateMnemonic
69
+ });
70
+ module.exports = __toCommonJS(src_exports);
71
+ var import_cive2 = require("cive");
72
+ var import_utils3 = require("cive/utils");
73
+ var import_viem5 = require("viem");
74
+
75
+ // src/clients/core.ts
76
+ var import_cive = require("cive");
77
+ var import_accounts = require("cive/accounts");
78
+ var import_utils2 = require("cive/utils");
79
+ var import_viem2 = require("viem");
80
+
81
+ // src/config/chains.ts
82
+ var import_utils = require("cive/utils");
83
+ var import_viem = require("viem");
84
+ var CORE_MAINNET = {
85
+ id: 1029,
86
+ name: "conflux-core",
87
+ type: "core",
88
+ testnet: false,
89
+ nativeCurrency: {
90
+ name: "Conflux",
91
+ symbol: "CFX",
92
+ decimals: 18
93
+ },
94
+ rpcUrls: {
95
+ default: {
96
+ http: ["https://main.confluxrpc.com"],
97
+ webSocket: ["wss://main.confluxrpc.com/ws"]
98
+ }
99
+ },
100
+ blockExplorers: {
101
+ default: {
102
+ name: "ConfluxScan",
103
+ url: "https://confluxscan.io"
104
+ }
105
+ }
106
+ };
107
+ var CORE_TESTNET = {
108
+ id: 1,
109
+ name: "conflux-core-testnet",
110
+ type: "core",
111
+ testnet: true,
112
+ nativeCurrency: {
113
+ name: "Conflux",
114
+ symbol: "CFX",
115
+ decimals: 18
116
+ },
117
+ rpcUrls: {
118
+ default: {
119
+ http: ["https://test.confluxrpc.com"],
120
+ webSocket: ["wss://test.confluxrpc.com/ws"]
121
+ }
122
+ },
123
+ blockExplorers: {
124
+ default: {
125
+ name: "ConfluxScan Testnet",
126
+ url: "https://testnet.confluxscan.io"
127
+ }
128
+ }
129
+ };
130
+ var CORE_LOCAL = {
131
+ id: 2029,
132
+ name: "conflux-core-local",
133
+ type: "core",
134
+ testnet: true,
135
+ nativeCurrency: {
136
+ name: "Conflux",
137
+ symbol: "CFX",
138
+ decimals: 18
139
+ },
140
+ rpcUrls: {
141
+ default: {
142
+ http: ["http://localhost:12537"],
143
+ webSocket: ["ws://localhost:12536"]
144
+ }
145
+ }
146
+ };
147
+ var EVM_MAINNET = {
148
+ id: 1030,
149
+ name: "conflux-espace",
150
+ type: "evm",
151
+ testnet: false,
152
+ nativeCurrency: {
153
+ name: "Conflux",
154
+ symbol: "CFX",
155
+ decimals: 18
156
+ },
157
+ rpcUrls: {
158
+ default: {
159
+ http: ["https://evm.confluxrpc.com"]
160
+ }
161
+ },
162
+ blockExplorers: {
163
+ default: {
164
+ name: "ConfluxScan eSpace",
165
+ url: "https://evm.confluxscan.net"
166
+ }
167
+ },
168
+ contracts: {
169
+ multicall3: {
170
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11",
171
+ blockCreated: 62512243
172
+ }
173
+ }
174
+ };
175
+ var EVM_TESTNET = {
176
+ id: 71,
177
+ name: "conflux-espace-testnet",
178
+ type: "evm",
179
+ testnet: true,
180
+ nativeCurrency: {
181
+ name: "Conflux",
182
+ symbol: "CFX",
183
+ decimals: 18
184
+ },
185
+ rpcUrls: {
186
+ default: {
187
+ http: ["https://evmtestnet.confluxrpc.com"]
188
+ }
189
+ },
190
+ blockExplorers: {
191
+ default: {
192
+ name: "ConfluxScan eSpace Testnet",
193
+ url: "https://evmtestnet.confluxscan.net"
194
+ }
195
+ },
196
+ contracts: {
197
+ multicall3: {
198
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11",
199
+ blockCreated: 117499050
200
+ }
201
+ }
202
+ };
203
+ var EVM_LOCAL = {
204
+ id: 2030,
205
+ name: "conflux-espace-local",
206
+ type: "evm",
207
+ testnet: true,
208
+ nativeCurrency: {
209
+ name: "Conflux",
210
+ symbol: "CFX",
211
+ decimals: 18
212
+ },
213
+ rpcUrls: {
214
+ default: {
215
+ http: ["http://localhost:8545"]
216
+ }
217
+ }
218
+ };
219
+ var SUPPORTED_CHAINS = {
220
+ 1029: CORE_MAINNET,
221
+ 1: CORE_TESTNET,
222
+ 2029: CORE_LOCAL,
223
+ 1030: EVM_MAINNET,
224
+ 71: EVM_TESTNET,
225
+ 2030: EVM_LOCAL
226
+ };
227
+ function getChainConfig(chainId) {
228
+ const config = SUPPORTED_CHAINS[chainId];
229
+ if (!config) {
230
+ throw new Error(`Unsupported chain ID: ${chainId}`);
231
+ }
232
+ return config;
233
+ }
234
+ function isValidChainId(chainId) {
235
+ return chainId in SUPPORTED_CHAINS;
236
+ }
237
+ function getCoreChains() {
238
+ return Object.values(SUPPORTED_CHAINS).filter(
239
+ (chain) => chain.type === "core"
240
+ );
241
+ }
242
+ function getEvmChains() {
243
+ return Object.values(SUPPORTED_CHAINS).filter(
244
+ (chain) => chain.type === "evm"
245
+ );
246
+ }
247
+ function getMainnetChains() {
248
+ return Object.values(SUPPORTED_CHAINS).filter((chain) => !chain.testnet);
249
+ }
250
+ var NetworkSelector = class {
251
+ currentChainId;
252
+ previousChainId = null;
253
+ listeners = /* @__PURE__ */ new Set();
254
+ nodeRunningListeners = /* @__PURE__ */ new Set();
255
+ isNodeRunning = false;
256
+ lockedToLocal = false;
257
+ constructor(initialChainId = 1) {
258
+ this.currentChainId = initialChainId;
259
+ }
260
+ getCurrentChain() {
261
+ return getChainConfig(this.currentChainId);
262
+ }
263
+ getCurrentChainId() {
264
+ return this.currentChainId;
265
+ }
266
+ /**
267
+ * Switch to a specific chain
268
+ * @param chainId - Chain ID to switch to
269
+ * @param force - Force switch even if node is running (for wallet operations)
270
+ */
271
+ switchChain(chainId, force = false) {
272
+ if (!isValidChainId(chainId)) {
273
+ throw new Error(`Invalid chain ID: ${chainId}`);
274
+ }
275
+ if (this.isNodeRunning && !this.isLocalChain(chainId) && !force) {
276
+ console.warn(
277
+ `Cannot switch to chain ${chainId} while local node is running. Use force=true for wallet operations.`
278
+ );
279
+ return;
280
+ }
281
+ if (this.currentChainId !== chainId) {
282
+ this.currentChainId = chainId;
283
+ this.notifyListeners();
284
+ }
285
+ }
286
+ /**
287
+ * Called when local node starts - automatically switches to local chains
288
+ */
289
+ onNodeStart(coreChainId = 2029, evmChainId = 2030) {
290
+ if (!this.isNodeRunning) {
291
+ if (!this.isLocal()) {
292
+ this.previousChainId = this.currentChainId;
293
+ }
294
+ this.isNodeRunning = true;
295
+ this.lockedToLocal = true;
296
+ const targetLocalChain = this.isEvm() ? evmChainId : coreChainId;
297
+ this.switchChain(targetLocalChain, true);
298
+ this.notifyNodeRunningListeners();
299
+ }
300
+ }
301
+ /**
302
+ * Called when local node stops - can restore previous chain
303
+ */
304
+ onNodeStop(restorePrevious = true) {
305
+ if (this.isNodeRunning) {
306
+ this.isNodeRunning = false;
307
+ this.lockedToLocal = false;
308
+ if (restorePrevious && this.previousChainId) {
309
+ this.switchChain(this.previousChainId, true);
310
+ this.previousChainId = null;
311
+ }
312
+ this.notifyNodeRunningListeners();
313
+ }
314
+ }
315
+ /**
316
+ * Check if node is currently running
317
+ */
318
+ getNodeRunningStatus() {
319
+ return this.isNodeRunning;
320
+ }
321
+ /**
322
+ * Check if selector is locked to local chains
323
+ */
324
+ isLockedToLocal() {
325
+ return this.lockedToLocal;
326
+ }
327
+ onChainChange(listener) {
328
+ this.listeners.add(listener);
329
+ return () => this.listeners.delete(listener);
330
+ }
331
+ onNodeRunningChange(listener) {
332
+ this.nodeRunningListeners.add(listener);
333
+ return () => this.nodeRunningListeners.delete(listener);
334
+ }
335
+ notifyListeners() {
336
+ for (const listener of this.listeners) {
337
+ try {
338
+ listener(this.currentChainId);
339
+ } catch (error) {
340
+ console.error("Error in chain change listener:", error);
341
+ }
342
+ }
343
+ }
344
+ notifyNodeRunningListeners() {
345
+ for (const listener of this.nodeRunningListeners) {
346
+ try {
347
+ listener(this.isNodeRunning);
348
+ } catch (error) {
349
+ console.error("Error in node running listener:", error);
350
+ }
351
+ }
352
+ }
353
+ isLocalChain(chainId) {
354
+ return chainId === 2029 || chainId === 2030;
355
+ }
356
+ // Helper methods for chain type detection
357
+ isCore() {
358
+ return this.getCurrentChain().type === "core";
359
+ }
360
+ isEvm() {
361
+ return this.getCurrentChain().type === "evm";
362
+ }
363
+ isTestnet() {
364
+ return this.getCurrentChain().testnet;
365
+ }
366
+ isLocal() {
367
+ return this.currentChainId === 2029 || this.currentChainId === 2030;
368
+ }
369
+ // Get corresponding chain IDs
370
+ getCorrespondingChainId() {
371
+ switch (this.currentChainId) {
372
+ case 1029:
373
+ return 1030;
374
+ // Core mainnet -> eSpace mainnet
375
+ case 1030:
376
+ return 1029;
377
+ // eSpace mainnet -> Core mainnet
378
+ case 1:
379
+ return 71;
380
+ // Core testnet -> eSpace testnet
381
+ case 71:
382
+ return 1;
383
+ // eSpace testnet -> Core testnet
384
+ case 2029:
385
+ return 2030;
386
+ // Core local -> eSpace local
387
+ case 2030:
388
+ return 2029;
389
+ // eSpace local -> Core local
390
+ default:
391
+ return null;
392
+ }
393
+ }
394
+ /**
395
+ * Update local chain configurations with actual node URLs
396
+ * Called when ServerManager starts with specific ports
397
+ */
398
+ updateLocalChainUrls(coreRpcPort, evmRpcPort, wsPort) {
399
+ const coreLocal = SUPPORTED_CHAINS[2029];
400
+ if (coreLocal) {
401
+ coreLocal.rpcUrls.default.http = [`http://localhost:${coreRpcPort}`];
402
+ if (wsPort) {
403
+ coreLocal.rpcUrls.default.webSocket = [`ws://localhost:${wsPort}`];
404
+ }
405
+ }
406
+ const evmLocal = SUPPORTED_CHAINS[2030];
407
+ if (evmLocal) {
408
+ evmLocal.rpcUrls.default.http = [`http://localhost:${evmRpcPort}`];
409
+ }
410
+ }
411
+ };
412
+ var defaultNetworkSelector = new NetworkSelector();
413
+
414
+ // src/types/config.ts
415
+ var NodeError = class extends Error {
416
+ code;
417
+ chain;
418
+ context;
419
+ constructor(message, code, chain, context) {
420
+ super(message);
421
+ this.name = "NodeError";
422
+ this.code = code;
423
+ this.chain = chain;
424
+ this.context = context;
425
+ }
426
+ };
427
+
428
+ // src/clients/core.ts
429
+ var conflux = (0, import_utils2.defineChain)({
430
+ id: 1029,
431
+ name: "Conflux Core",
432
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
433
+ rpcUrls: { default: { http: ["https://main.confluxrpc.com"] } }
434
+ });
435
+ var confluxTestnet = (0, import_utils2.defineChain)({
436
+ id: 1,
437
+ name: "Conflux Core Testnet",
438
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
439
+ rpcUrls: { default: { http: ["https://test.confluxrpc.com"] } }
440
+ });
441
+ var CoreClient = class {
442
+ chainType = "core";
443
+ chainId;
444
+ address;
445
+ publicClient;
446
+ chain;
447
+ constructor(config) {
448
+ this.chainId = config.chainId;
449
+ this.chain = (0, import_utils2.defineChain)({
450
+ id: this.chainId,
451
+ name: `ConfluxCore-${this.chainId}`,
452
+ nativeCurrency: {
453
+ decimals: 18,
454
+ name: "Conflux",
455
+ symbol: "CFX"
456
+ },
457
+ rpcUrls: {
458
+ default: {
459
+ http: [config.rpcUrl],
460
+ webSocket: config.wsUrl ? [config.wsUrl] : void 0
461
+ }
462
+ }
463
+ });
464
+ this.publicClient = (0, import_cive.createPublicClient)({
465
+ chain: this.chain,
466
+ transport: (0, import_cive.http)(config.rpcUrl),
467
+ pollingInterval: config.pollingInterval || 1e3
468
+ });
469
+ this.address = "";
470
+ }
471
+ async getBlockNumber() {
472
+ try {
473
+ const epochNumber = await this.publicClient.getEpochNumber();
474
+ return BigInt(epochNumber.toString());
475
+ } catch (error) {
476
+ throw new NodeError(
477
+ `Failed to get block number: ${error instanceof Error ? error.message : String(error)}`,
478
+ "BLOCK_NUMBER_ERROR",
479
+ "core",
480
+ { originalError: error }
481
+ );
482
+ }
483
+ }
484
+ async getBalance(address) {
485
+ if (!(0, import_utils2.isAddress)(address)) {
486
+ throw new NodeError(
487
+ "Invalid Core address format",
488
+ "INVALID_ADDRESS",
489
+ "core"
490
+ );
491
+ }
492
+ try {
493
+ const balance = await this.publicClient.getBalance({ address });
494
+ return (0, import_cive.formatCFX)(balance);
495
+ } catch (error) {
496
+ throw new NodeError(
497
+ `Failed to get balance: ${error instanceof Error ? error.message : String(error)}`,
498
+ "BALANCE_ERROR",
499
+ "core",
500
+ { address, originalError: error }
501
+ );
502
+ }
503
+ }
504
+ async getGasPrice() {
505
+ try {
506
+ const gasPrice = await this.publicClient.getGasPrice();
507
+ return gasPrice;
508
+ } catch (error) {
509
+ throw new NodeError(
510
+ `Failed to get gas price: ${error instanceof Error ? error.message : String(error)}`,
511
+ "GAS_PRICE_ERROR",
512
+ "core",
513
+ { originalError: error }
514
+ );
515
+ }
516
+ }
517
+ async estimateGas(tx) {
518
+ try {
519
+ const estimate = await this.publicClient.request({
520
+ method: "cfx_estimateGasAndCollateral",
521
+ params: [
522
+ {
523
+ to: tx.to,
524
+ value: tx.value ? `0x${tx.value.toString(16)}` : void 0,
525
+ data: tx.data
526
+ }
527
+ ]
528
+ });
529
+ return BigInt(estimate.gasLimit);
530
+ } catch (error) {
531
+ throw new NodeError(
532
+ `Failed to estimate gas: ${error instanceof Error ? error.message : String(error)}`,
533
+ "GAS_ESTIMATE_ERROR",
534
+ "core",
535
+ { transaction: tx, originalError: error }
536
+ );
537
+ }
538
+ }
539
+ async sendTransaction(_tx) {
540
+ throw new NodeError(
541
+ "Cannot send transaction from public client. Use wallet client instead.",
542
+ "WALLET_REQUIRED",
543
+ "core"
544
+ );
545
+ }
546
+ async waitForTransaction(hash) {
547
+ try {
548
+ const receipt = await this.publicClient.waitForTransactionReceipt({
549
+ hash
550
+ });
551
+ return {
552
+ hash: receipt.transactionHash,
553
+ blockNumber: BigInt(receipt.epochNumber?.toString() || "0"),
554
+ blockHash: receipt.blockHash || "",
555
+ transactionIndex: Number(receipt.index || 0),
556
+ status: receipt.outcomeStatus === "success" ? "success" : "reverted",
557
+ gasUsed: receipt.gasUsed || 0n,
558
+ contractAddress: receipt.contractCreated || void 0,
559
+ logs: receipt.log?.map((log) => ({
560
+ address: log.address || "",
561
+ topics: log.topics || [],
562
+ data: log.data || "0x",
563
+ blockNumber: BigInt(log.epochNumber?.toString() || "0"),
564
+ transactionHash: log.transactionHash || "",
565
+ logIndex: Number(log.logIndex || 0)
566
+ })) || []
567
+ };
568
+ } catch (error) {
569
+ throw new NodeError(
570
+ `Failed to wait for transaction: ${error instanceof Error ? error.message : String(error)}`,
571
+ "TRANSACTION_WAIT_ERROR",
572
+ "core",
573
+ { hash, originalError: error }
574
+ );
575
+ }
576
+ }
577
+ async getTokenBalance(tokenAddress, holderAddress) {
578
+ const holder = holderAddress || this.address;
579
+ if (!this.isValidAddress(tokenAddress)) {
580
+ throw new NodeError(
581
+ "Invalid token address format",
582
+ "INVALID_ADDRESS",
583
+ "core",
584
+ { tokenAddress }
585
+ );
586
+ }
587
+ if (!this.isValidAddress(holder)) {
588
+ throw new NodeError(
589
+ "Invalid holder address format",
590
+ "INVALID_ADDRESS",
591
+ "core",
592
+ { holder }
593
+ );
594
+ }
595
+ try {
596
+ const [balance, decimals] = await Promise.all([
597
+ this.publicClient.readContract({
598
+ address: tokenAddress,
599
+ abi: [
600
+ {
601
+ name: "balanceOf",
602
+ type: "function",
603
+ inputs: [{ name: "account", type: "address" }],
604
+ outputs: [{ name: "", type: "uint256" }],
605
+ stateMutability: "view"
606
+ }
607
+ ],
608
+ functionName: "balanceOf",
609
+ args: [holder]
610
+ }),
611
+ this.publicClient.readContract({
612
+ address: tokenAddress,
613
+ abi: [
614
+ {
615
+ name: "decimals",
616
+ type: "function",
617
+ inputs: [],
618
+ outputs: [{ name: "", type: "uint8" }],
619
+ stateMutability: "view"
620
+ }
621
+ ],
622
+ functionName: "decimals"
623
+ })
624
+ ]);
625
+ return this.formatTokenAmount(balance, Number(decimals));
626
+ } catch (error) {
627
+ throw new NodeError(
628
+ `Failed to get token balance: ${error instanceof Error ? error.message : String(error)}`,
629
+ "TOKEN_BALANCE_ERROR",
630
+ "core",
631
+ { tokenAddress, holder, originalError: error }
632
+ );
633
+ }
634
+ }
635
+ watchBlocks(callback) {
636
+ return this.publicClient.watchEpochNumber({
637
+ emitMissed: false,
638
+ epochTag: "latest_mined",
639
+ onEpochNumber: async (epochNumber) => {
640
+ try {
641
+ const blockHashes = await this.publicClient.getBlocksByEpoch({
642
+ epochNumber
643
+ });
644
+ for (const hash of blockHashes) {
645
+ try {
646
+ const block = await this.publicClient.getBlock({
647
+ blockHash: hash
648
+ });
649
+ const blockEvent = {
650
+ chainType: "core",
651
+ blockNumber: BigInt(block.epochNumber?.toString() || "0"),
652
+ blockHash: block.hash || "",
653
+ timestamp: Number(block.timestamp || 0),
654
+ transactionCount: block.transactions?.length || 0
655
+ };
656
+ callback(blockEvent);
657
+ } catch (error) {
658
+ console.error(`Failed to process block ${hash}:`, error);
659
+ }
660
+ }
661
+ } catch (error) {
662
+ console.error(
663
+ `Failed to get blocks for epoch ${epochNumber}:`,
664
+ error
665
+ );
666
+ }
667
+ }
668
+ });
669
+ }
670
+ watchTransactions(callback) {
671
+ return this.publicClient.watchEpochNumber({
672
+ emitMissed: false,
673
+ epochTag: "latest_mined",
674
+ onEpochNumber: async (epochNumber) => {
675
+ try {
676
+ const blockHashes = await this.publicClient.getBlocksByEpoch({
677
+ epochNumber
678
+ });
679
+ for (const hash of blockHashes) {
680
+ try {
681
+ const block = await this.publicClient.getBlock({
682
+ blockHash: hash
683
+ });
684
+ await Promise.all(
685
+ (block.transactions || []).map(
686
+ async (txHash) => {
687
+ try {
688
+ const tx = await this.publicClient.getTransaction({
689
+ hash: txHash
690
+ });
691
+ const txEvent = {
692
+ chainType: "core",
693
+ hash: tx.hash,
694
+ from: tx.from,
695
+ to: tx.to || void 0,
696
+ value: tx.value || 0n,
697
+ blockNumber: BigInt(
698
+ block.epochNumber?.toString() || "0"
699
+ )
700
+ };
701
+ callback(txEvent);
702
+ } catch (error) {
703
+ console.error(
704
+ `Failed to get transaction ${txHash}:`,
705
+ error
706
+ );
707
+ }
708
+ }
709
+ )
710
+ );
711
+ } catch (error) {
712
+ console.error(`Failed to process block ${hash}:`, error);
713
+ }
714
+ }
715
+ } catch (error) {
716
+ console.error(
717
+ `Failed to get blocks for epoch ${epochNumber}:`,
718
+ error
719
+ );
720
+ }
721
+ }
722
+ });
723
+ }
724
+ isValidAddress(address) {
725
+ return (0, import_utils2.isAddress)(address);
726
+ }
727
+ formatAmount(amount) {
728
+ return (0, import_cive.formatCFX)(amount);
729
+ }
730
+ parseAmount(amount) {
731
+ return (0, import_cive.parseCFX)(amount);
732
+ }
733
+ getInternalClient() {
734
+ return this.publicClient;
735
+ }
736
+ formatTokenAmount(amount, decimals) {
737
+ const formatted = (0, import_utils2.formatUnits)(amount, decimals);
738
+ return Number(formatted).toFixed(4);
739
+ }
740
+ };
741
+ var CoreWalletClient = class {
742
+ chainType = "core";
743
+ address;
744
+ chainId;
745
+ walletClient;
746
+ publicClient;
747
+ account;
748
+ chain;
749
+ constructor(config) {
750
+ this.chainId = config.chainId;
751
+ this.chain = (0, import_utils2.defineChain)({
752
+ id: config.chainId,
753
+ name: `ConfluxCore-${config.chainId}`,
754
+ nativeCurrency: {
755
+ decimals: 18,
756
+ name: "Conflux",
757
+ symbol: "CFX"
758
+ },
759
+ rpcUrls: {
760
+ default: {
761
+ http: [config.rpcUrl],
762
+ webSocket: config.wsUrl ? [config.wsUrl] : void 0
763
+ }
764
+ }
765
+ });
766
+ this.account = (0, import_accounts.privateKeyToAccount)(config.privateKey, {
767
+ networkId: config.chainId
768
+ });
769
+ this.address = this.account.address;
770
+ this.walletClient = (0, import_cive.createWalletClient)({
771
+ account: this.account,
772
+ chain: this.chain,
773
+ transport: (0, import_cive.http)(config.rpcUrl),
774
+ pollingInterval: config.pollingInterval || 1e3
775
+ });
776
+ this.publicClient = (0, import_cive.createPublicClient)({
777
+ chain: this.chain,
778
+ transport: (0, import_cive.http)(config.rpcUrl),
779
+ pollingInterval: config.pollingInterval || 1e3
780
+ });
781
+ }
782
+ async sendTransaction(tx) {
783
+ try {
784
+ return await this.walletClient.sendTransaction({
785
+ to: tx.to,
786
+ value: tx.value,
787
+ data: tx.data,
788
+ gas: tx.gasLimit,
789
+ gasPrice: tx.gasPrice,
790
+ nonce: tx.nonce,
791
+ account: this.account,
792
+ chain: this.chain
793
+ });
794
+ } catch (error) {
795
+ throw new NodeError(
796
+ `Failed to send transaction: ${error instanceof Error ? error.message : String(error)}`,
797
+ "TRANSACTION_SEND_ERROR",
798
+ "core",
799
+ { transaction: tx, originalError: error }
800
+ );
801
+ }
802
+ }
803
+ async signMessage(message) {
804
+ try {
805
+ return await this.walletClient.signMessage({
806
+ account: this.account,
807
+ message
808
+ });
809
+ } catch (error) {
810
+ throw new NodeError(
811
+ `Failed to sign message: ${error instanceof Error ? error.message : String(error)}`,
812
+ "MESSAGE_SIGN_ERROR",
813
+ "core",
814
+ { message, originalError: error }
815
+ );
816
+ }
817
+ }
818
+ getInternalClient() {
819
+ return this.walletClient;
820
+ }
821
+ async waitForTransaction(hash) {
822
+ try {
823
+ const receipt = await this.publicClient.waitForTransactionReceipt({
824
+ hash,
825
+ timeout: 5e3
826
+ // 5 second timeout for faster response
827
+ });
828
+ return {
829
+ hash: receipt.transactionHash,
830
+ blockNumber: BigInt(receipt.epochNumber?.toString() || "0"),
831
+ blockHash: receipt.blockHash || "",
832
+ transactionIndex: Number(receipt.index || 0),
833
+ status: receipt.outcomeStatus === "success" ? "success" : "reverted",
834
+ gasUsed: receipt.gasUsed || 0n,
835
+ contractAddress: receipt.contractCreated || void 0,
836
+ logs: receipt.log?.map((log) => ({
837
+ address: log.address || "",
838
+ topics: log.topics || [],
839
+ data: log.data || "0x",
840
+ blockNumber: BigInt(log.epochNumber?.toString() || "0"),
841
+ transactionHash: log.transactionHash || "",
842
+ logIndex: Number(log.logIndex || 0)
843
+ })) || []
844
+ };
845
+ } catch (error) {
846
+ throw new NodeError(
847
+ `Failed to wait for transaction: ${error instanceof Error ? error.message : String(error)}`,
848
+ "TRANSACTION_WAIT_ERROR",
849
+ "core",
850
+ { hash, originalError: error }
851
+ );
852
+ }
853
+ }
854
+ /**
855
+ * Unified faucet functionality
856
+ * Automatically detects address type and sends CFX accordingly:
857
+ * - Core address: Direct transfer
858
+ * - eSpace address: Cross-chain transfer via internal contract
859
+ */
860
+ async faucet(address, amount) {
861
+ const isCoreAddr = (0, import_utils2.isAddress)(address);
862
+ const isEspaceAddr = (0, import_viem2.isAddress)(address);
863
+ if (!isCoreAddr && !isEspaceAddr) {
864
+ throw new NodeError(
865
+ "Invalid address format (must be Core or eSpace address)",
866
+ "INVALID_ADDRESS",
867
+ "core",
868
+ { address }
869
+ );
870
+ }
871
+ try {
872
+ if (isCoreAddr) {
873
+ return await this.walletClient.sendTransaction({
874
+ chain: this.chain,
875
+ account: this.account,
876
+ to: address,
877
+ value: (0, import_cive.parseCFX)(amount)
878
+ });
879
+ } else {
880
+ return await this.walletClient.sendTransaction({
881
+ chain: this.chain,
882
+ account: this.account,
883
+ to: (0, import_utils2.hexAddressToBase32)({
884
+ hexAddress: "0x0888000000000000000000000000000000000006",
885
+ networkId: this.chain.id
886
+ }),
887
+ value: (0, import_cive.parseCFX)(amount),
888
+ data: (0, import_utils2.encodeFunctionData)({
889
+ abi: [
890
+ {
891
+ type: "function",
892
+ name: "transferEVM",
893
+ inputs: [{ name: "to", type: "bytes20" }],
894
+ outputs: [{ name: "output", type: "bytes" }],
895
+ stateMutability: "payable"
896
+ }
897
+ ],
898
+ functionName: "transferEVM",
899
+ args: [address]
900
+ })
901
+ });
902
+ }
903
+ } catch (error) {
904
+ throw new NodeError(
905
+ `Failed to send faucet transaction: ${error instanceof Error ? error.message : String(error)}`,
906
+ "FAUCET_ERROR",
907
+ "core",
908
+ { address, amount, originalError: error }
909
+ );
910
+ }
911
+ }
912
+ /**
913
+ * Cross-chain faucet functionality (Core → eSpace)
914
+ * Sends CFX from Core space to eSpace address via internal contract
915
+ * @deprecated Use faucet() instead which auto-detects address type
916
+ */
917
+ async faucetToEspace(espaceAddress, amount) {
918
+ if (!(0, import_viem2.isAddress)(espaceAddress)) {
919
+ throw new NodeError(
920
+ "Invalid eSpace address format",
921
+ "INVALID_ADDRESS",
922
+ "core",
923
+ { espaceAddress }
924
+ );
925
+ }
926
+ try {
927
+ return await this.walletClient.sendTransaction({
928
+ chain: this.chain,
929
+ account: this.account,
930
+ to: (0, import_utils2.hexAddressToBase32)({
931
+ hexAddress: "0x0888000000000000000000000000000000000006",
932
+ networkId: this.chain.id
933
+ }),
934
+ value: (0, import_cive.parseCFX)(amount),
935
+ data: (0, import_utils2.encodeFunctionData)({
936
+ abi: [
937
+ {
938
+ type: "function",
939
+ name: "transferEVM",
940
+ inputs: [{ name: "to", type: "bytes20" }],
941
+ outputs: [{ name: "output", type: "bytes" }],
942
+ stateMutability: "payable"
943
+ }
944
+ ],
945
+ functionName: "transferEVM",
946
+ args: [espaceAddress]
947
+ })
948
+ });
949
+ } catch (error) {
950
+ throw new NodeError(
951
+ `Failed to send faucet transaction to eSpace: ${error instanceof Error ? error.message : String(error)}`,
952
+ "FAUCET_ERROR",
953
+ "core",
954
+ { espaceAddress, amount, originalError: error }
955
+ );
956
+ }
957
+ }
958
+ /**
959
+ * Deploy a contract to Core Space
960
+ */
961
+ async deployContract(abi, bytecode, constructorArgs = []) {
962
+ try {
963
+ const hash = await this.walletClient.deployContract({
964
+ account: this.account,
965
+ chain: this.chain,
966
+ abi,
967
+ bytecode,
968
+ args: constructorArgs
969
+ });
970
+ const receipt = await this.waitForTransaction(hash);
971
+ if (!receipt.contractAddress) {
972
+ throw new Error("Contract address not found in transaction receipt");
973
+ }
974
+ return receipt.contractAddress;
975
+ } catch (error) {
976
+ throw new NodeError(
977
+ `Failed to deploy contract: ${error instanceof Error ? error.message : String(error)}`,
978
+ "DEPLOYMENT_ERROR",
979
+ "core",
980
+ { abi, bytecode, constructorArgs, originalError: error }
981
+ );
982
+ }
983
+ }
984
+ /**
985
+ * Call a contract method (read-only)
986
+ */
987
+ async callContract(address, abi, functionName, args = []) {
988
+ try {
989
+ const result = await this.publicClient.readContract({
990
+ address,
991
+ abi,
992
+ functionName,
993
+ args
994
+ });
995
+ return result;
996
+ } catch (error) {
997
+ throw new NodeError(
998
+ `Failed to call contract: ${error instanceof Error ? error.message : String(error)}`,
999
+ "CONTRACT_CALL_ERROR",
1000
+ "core",
1001
+ { address, functionName, args, originalError: error }
1002
+ );
1003
+ }
1004
+ }
1005
+ /**
1006
+ * Write to a contract (transaction)
1007
+ */
1008
+ async writeContract(address, abi, functionName, args = [], value) {
1009
+ try {
1010
+ const hash = await this.walletClient.writeContract({
1011
+ account: this.account,
1012
+ chain: this.chain,
1013
+ address,
1014
+ abi,
1015
+ functionName,
1016
+ args,
1017
+ value
1018
+ });
1019
+ return hash;
1020
+ } catch (error) {
1021
+ throw new NodeError(
1022
+ `Failed to write to contract: ${error instanceof Error ? error.message : String(error)}`,
1023
+ "CONTRACT_WRITE_ERROR",
1024
+ "core",
1025
+ { address, functionName, args, value, originalError: error }
1026
+ );
1027
+ }
1028
+ }
1029
+ };
1030
+ var CoreTestClient = class extends CoreClient {
1031
+ testClient;
1032
+ constructor(config) {
1033
+ super(config);
1034
+ this.testClient = (0, import_cive.createTestClient)({
1035
+ chain: this.chainId === 1029 ? conflux : confluxTestnet,
1036
+ transport: (0, import_cive.http)(config.rpcUrl),
1037
+ pollingInterval: config.pollingInterval || 1e3
1038
+ });
1039
+ }
1040
+ async mine(blocks = 1) {
1041
+ try {
1042
+ await this.testClient.mine({ blocks });
1043
+ } catch (error) {
1044
+ throw new NodeError(
1045
+ `Failed to mine blocks: ${error instanceof Error ? error.message : String(error)}`,
1046
+ "MINE_ERROR",
1047
+ "core",
1048
+ { blocks, originalError: error }
1049
+ );
1050
+ }
1051
+ }
1052
+ async setNextBlockTimestamp(_timestamp) {
1053
+ throw new NodeError(
1054
+ "setNextBlockTimestamp not implemented for Core client",
1055
+ "NOT_IMPLEMENTED",
1056
+ "core"
1057
+ );
1058
+ }
1059
+ async increaseTime(_seconds) {
1060
+ throw new NodeError(
1061
+ "increaseTime not implemented for Core client",
1062
+ "NOT_IMPLEMENTED",
1063
+ "core"
1064
+ );
1065
+ }
1066
+ async impersonateAccount(_address) {
1067
+ throw new NodeError(
1068
+ "impersonateAccount not implemented for Core client",
1069
+ "NOT_IMPLEMENTED",
1070
+ "core"
1071
+ );
1072
+ }
1073
+ async stopImpersonatingAccount(_address) {
1074
+ throw new NodeError(
1075
+ "stopImpersonatingAccount not implemented for Core client",
1076
+ "NOT_IMPLEMENTED",
1077
+ "core"
1078
+ );
1079
+ }
1080
+ async setBalance(_address, _balance) {
1081
+ throw new NodeError(
1082
+ "setBalance not implemented for Core client",
1083
+ "NOT_IMPLEMENTED",
1084
+ "core"
1085
+ );
1086
+ }
1087
+ async getStorageAt(_address, _slot) {
1088
+ throw new NodeError(
1089
+ "getStorageAt not implemented for Core client",
1090
+ "NOT_IMPLEMENTED",
1091
+ "core"
1092
+ );
1093
+ }
1094
+ async setStorageAt(_address, _slot, _value) {
1095
+ throw new NodeError(
1096
+ "setStorageAt not implemented for Core client",
1097
+ "NOT_IMPLEMENTED",
1098
+ "core"
1099
+ );
1100
+ }
1101
+ getInternalTestClient() {
1102
+ return this.testClient;
1103
+ }
1104
+ };
1105
+ async function createCoreClient(config) {
1106
+ const chainConfig = getChainConfig(config.chainId);
1107
+ if (chainConfig.type !== "core") {
1108
+ throw new NodeError(
1109
+ `Invalid chain type for Core client: ${chainConfig.type}`,
1110
+ "INVALID_CHAIN_TYPE",
1111
+ "core"
1112
+ );
1113
+ }
1114
+ const clientConfig = {
1115
+ ...config,
1116
+ rpcUrl: config.rpcUrl || chainConfig.rpcUrls.default.http[0] || "http://localhost:12537",
1117
+ wsUrl: config.wsUrl || chainConfig.rpcUrls.default.webSocket?.[0]
1118
+ };
1119
+ const publicClient = new CoreClient(clientConfig);
1120
+ let walletClient;
1121
+ let testClient;
1122
+ if (config.account) {
1123
+ let privateKey;
1124
+ if (typeof config.account === "string") {
1125
+ privateKey = config.account;
1126
+ } else {
1127
+ privateKey = config.account.privateKey;
1128
+ }
1129
+ const walletConfig = {
1130
+ ...clientConfig,
1131
+ privateKey,
1132
+ accountIndex: typeof config.account === "object" ? config.account.accountIndex : 0
1133
+ };
1134
+ walletClient = new CoreWalletClient(walletConfig);
1135
+ }
1136
+ if (config.testMode) {
1137
+ const testConfig = {
1138
+ ...clientConfig,
1139
+ enableTestMode: true
1140
+ };
1141
+ testClient = new CoreTestClient(testConfig);
1142
+ }
1143
+ return {
1144
+ publicClient,
1145
+ walletClient,
1146
+ testClient
1147
+ };
1148
+ }
1149
+
1150
+ // src/clients/evm.ts
1151
+ var import_viem3 = require("viem");
1152
+ var import_accounts2 = require("viem/accounts");
1153
+ var espaceMainnet = (0, import_viem3.defineChain)({
1154
+ id: 1030,
1155
+ name: "Conflux eSpace",
1156
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
1157
+ rpcUrls: { default: { http: ["https://evm.confluxrpc.com"] } },
1158
+ blockExplorers: {
1159
+ default: { name: "ConfluxScan", url: "https://evm.confluxscan.net" }
1160
+ }
1161
+ });
1162
+ var espaceTestnet = (0, import_viem3.defineChain)({
1163
+ id: 71,
1164
+ name: "Conflux eSpace Testnet",
1165
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
1166
+ rpcUrls: { default: { http: ["https://evmtestnet.confluxrpc.com"] } },
1167
+ blockExplorers: {
1168
+ default: { name: "ConfluxScan", url: "https://evmtestnet.confluxscan.net" }
1169
+ }
1170
+ });
1171
+ var EspaceClient = class {
1172
+ chainId;
1173
+ chainType = "evm";
1174
+ publicClient;
1175
+ chain;
1176
+ address;
1177
+ constructor(config) {
1178
+ this.chainId = config.chainId;
1179
+ if (config.chainId === 1030) {
1180
+ this.chain = espaceMainnet;
1181
+ } else if (config.chainId === 71) {
1182
+ this.chain = espaceTestnet;
1183
+ } else {
1184
+ this.chain = (0, import_viem3.defineChain)({
1185
+ id: config.chainId,
1186
+ name: `Conflux eSpace (${config.chainId})`,
1187
+ nativeCurrency: { name: "Conflux", symbol: "CFX", decimals: 18 },
1188
+ rpcUrls: { default: { http: [config.rpcUrl] } }
1189
+ });
1190
+ }
1191
+ this.publicClient = (0, import_viem3.createPublicClient)({
1192
+ chain: this.chain,
1193
+ transport: (0, import_viem3.http)(config.rpcUrl),
1194
+ pollingInterval: config.pollingInterval || 1e3
1195
+ });
1196
+ this.address = "";
1197
+ }
1198
+ async getBlockNumber() {
1199
+ try {
1200
+ const blockNumber = await this.publicClient.getBlockNumber();
1201
+ return blockNumber;
1202
+ } catch (error) {
1203
+ throw new NodeError(
1204
+ `Failed to get block number: ${error instanceof Error ? error.message : String(error)}`,
1205
+ "BLOCK_NUMBER_ERROR",
1206
+ "evm",
1207
+ { originalError: error }
1208
+ );
1209
+ }
1210
+ }
1211
+ async getBalance(address) {
1212
+ if (!(0, import_viem3.isAddress)(address)) {
1213
+ throw new NodeError(
1214
+ "Invalid EVM address format",
1215
+ "INVALID_ADDRESS",
1216
+ "evm"
1217
+ );
1218
+ }
1219
+ try {
1220
+ const balance = await this.publicClient.getBalance({ address });
1221
+ return (0, import_viem3.formatEther)(balance);
1222
+ } catch (error) {
1223
+ throw new NodeError(
1224
+ `Failed to get balance: ${error instanceof Error ? error.message : String(error)}`,
1225
+ "BALANCE_ERROR",
1226
+ "evm",
1227
+ { address, originalError: error }
1228
+ );
1229
+ }
1230
+ }
1231
+ async estimateGas(tx) {
1232
+ try {
1233
+ const gas = await this.publicClient.estimateGas({
1234
+ to: tx.to,
1235
+ value: tx.value,
1236
+ data: tx.data
1237
+ });
1238
+ return gas;
1239
+ } catch (error) {
1240
+ throw new NodeError(
1241
+ `Failed to estimate gas: ${error instanceof Error ? error.message : String(error)}`,
1242
+ "GAS_ESTIMATE_ERROR",
1243
+ "evm",
1244
+ { transaction: tx, originalError: error }
1245
+ );
1246
+ }
1247
+ }
1248
+ async waitForTransaction(hash) {
1249
+ try {
1250
+ const receipt = await this.publicClient.waitForTransactionReceipt({
1251
+ hash,
1252
+ timeout: 5e3
1253
+ // 5 second timeout for faster response
1254
+ });
1255
+ return {
1256
+ hash: receipt.transactionHash,
1257
+ blockNumber: receipt.blockNumber,
1258
+ blockHash: receipt.blockHash,
1259
+ transactionIndex: receipt.transactionIndex,
1260
+ status: receipt.status === "success" ? "success" : "reverted",
1261
+ gasUsed: receipt.gasUsed,
1262
+ contractAddress: receipt.contractAddress || void 0,
1263
+ logs: receipt.logs.map((log) => ({
1264
+ address: log.address,
1265
+ topics: log.topics,
1266
+ data: log.data,
1267
+ blockNumber: log.blockNumber || 0n,
1268
+ transactionHash: log.transactionHash || "",
1269
+ logIndex: log.logIndex || 0
1270
+ }))
1271
+ };
1272
+ } catch (error) {
1273
+ throw new NodeError(
1274
+ `Failed to wait for transaction: ${error instanceof Error ? error.message : String(error)}`,
1275
+ "TRANSACTION_WAIT_ERROR",
1276
+ "evm",
1277
+ { hash, originalError: error }
1278
+ );
1279
+ }
1280
+ }
1281
+ async getGasPrice() {
1282
+ try {
1283
+ const gasPrice = await this.publicClient.getGasPrice();
1284
+ return gasPrice;
1285
+ } catch (error) {
1286
+ throw new NodeError(
1287
+ `Failed to get gas price: ${error instanceof Error ? error.message : String(error)}`,
1288
+ "GAS_PRICE_ERROR",
1289
+ "evm",
1290
+ { originalError: error }
1291
+ );
1292
+ }
1293
+ }
1294
+ /**
1295
+ * Get the current chain ID from the network
1296
+ */
1297
+ async getChainId() {
1298
+ try {
1299
+ const chainId = await this.publicClient.getChainId();
1300
+ return chainId;
1301
+ } catch (error) {
1302
+ throw new NodeError(
1303
+ `Failed to get chain ID: ${error instanceof Error ? error.message : String(error)}`,
1304
+ "CHAIN_ID_ERROR",
1305
+ "evm",
1306
+ { originalError: error }
1307
+ );
1308
+ }
1309
+ }
1310
+ /**
1311
+ * Check if the client is connected to the network
1312
+ */
1313
+ async isConnected() {
1314
+ try {
1315
+ await this.publicClient.getBlockNumber();
1316
+ return true;
1317
+ } catch {
1318
+ return false;
1319
+ }
1320
+ }
1321
+ // Base implementation - should be overridden by WalletClient
1322
+ async sendTransaction(_tx) {
1323
+ throw new NodeError(
1324
+ "sendTransaction not available on public client",
1325
+ "METHOD_NOT_AVAILABLE",
1326
+ "evm"
1327
+ );
1328
+ }
1329
+ async getTokenBalance(_address, _tokenAddress) {
1330
+ try {
1331
+ const balance = await this.publicClient.readContract({
1332
+ address: _tokenAddress,
1333
+ abi: [
1334
+ {
1335
+ type: "function",
1336
+ name: "balanceOf",
1337
+ inputs: [{ name: "account", type: "address" }],
1338
+ outputs: [{ name: "balance", type: "uint256" }],
1339
+ stateMutability: "view"
1340
+ }
1341
+ ],
1342
+ functionName: "balanceOf",
1343
+ args: [_address]
1344
+ });
1345
+ return balance.toString();
1346
+ } catch (error) {
1347
+ throw new NodeError(
1348
+ `Failed to get token balance: ${error instanceof Error ? error.message : String(error)}`,
1349
+ "TOKEN_BALANCE_ERROR",
1350
+ "evm",
1351
+ { address: _address, tokenAddress: _tokenAddress, originalError: error }
1352
+ );
1353
+ }
1354
+ }
1355
+ watchBlocks(callback) {
1356
+ const unwatch = this.publicClient.watchBlocks({
1357
+ onBlock: (block) => callback({
1358
+ chainType: "evm",
1359
+ blockNumber: block.number || 0n,
1360
+ blockHash: block.hash || "",
1361
+ timestamp: Number(block.timestamp || 0),
1362
+ transactionCount: block.transactions?.length || 0
1363
+ })
1364
+ });
1365
+ return unwatch;
1366
+ }
1367
+ async watchTransaction(_hash, _callback) {
1368
+ const pollTransaction = async () => {
1369
+ try {
1370
+ const receipt = await this.waitForTransaction(_hash);
1371
+ _callback(receipt);
1372
+ } catch {
1373
+ setTimeout(pollTransaction, 1e3);
1374
+ }
1375
+ };
1376
+ setTimeout(pollTransaction, 1e3);
1377
+ return () => {
1378
+ };
1379
+ }
1380
+ getInternalClient() {
1381
+ return this.publicClient;
1382
+ }
1383
+ // Base implementation - should be overridden by TestClient
1384
+ watchTransactions(_callback) {
1385
+ throw new NodeError(
1386
+ "watchTransactions not available on public client",
1387
+ "METHOD_NOT_AVAILABLE",
1388
+ "evm"
1389
+ );
1390
+ }
1391
+ isValidAddress(address) {
1392
+ return (0, import_viem3.isAddress)(address);
1393
+ }
1394
+ formatAmount(amount) {
1395
+ return (0, import_viem3.formatEther)(amount);
1396
+ }
1397
+ parseAmount(amount) {
1398
+ return (0, import_viem3.parseEther)(amount);
1399
+ }
1400
+ };
1401
+ var EspaceWalletClient = class extends EspaceClient {
1402
+ walletClient;
1403
+ account;
1404
+ constructor(config) {
1405
+ super(config);
1406
+ this.account = (0, import_accounts2.privateKeyToAccount)(config.privateKey);
1407
+ this.address = this.account.address;
1408
+ this.walletClient = (0, import_viem3.createWalletClient)({
1409
+ account: this.account,
1410
+ chain: this.chain,
1411
+ transport: (0, import_viem3.http)(config.rpcUrl)
1412
+ });
1413
+ }
1414
+ getAddress() {
1415
+ return this.address;
1416
+ }
1417
+ async sendTransaction(tx) {
1418
+ try {
1419
+ const hash = await this.walletClient.sendTransaction({
1420
+ account: this.account,
1421
+ chain: this.chain,
1422
+ to: tx.to,
1423
+ value: tx.value,
1424
+ data: tx.data,
1425
+ gas: tx.gasLimit,
1426
+ gasPrice: tx.gasPrice,
1427
+ nonce: tx.nonce
1428
+ });
1429
+ return hash;
1430
+ } catch (error) {
1431
+ throw new NodeError(
1432
+ `Failed to send transaction: ${error instanceof Error ? error.message : String(error)}`,
1433
+ "TRANSACTION_ERROR",
1434
+ "evm",
1435
+ { transaction: tx, originalError: error }
1436
+ );
1437
+ }
1438
+ }
1439
+ async signMessage(message) {
1440
+ try {
1441
+ const signature = await this.walletClient.signMessage({
1442
+ account: this.account,
1443
+ message
1444
+ });
1445
+ return signature;
1446
+ } catch (error) {
1447
+ throw new NodeError(
1448
+ `Failed to sign message: ${error instanceof Error ? error.message : String(error)}`,
1449
+ "SIGNING_ERROR",
1450
+ "evm",
1451
+ { message, originalError: error }
1452
+ );
1453
+ }
1454
+ }
1455
+ async deployContract(abi, bytecode, constructorArgs = []) {
1456
+ try {
1457
+ const hash = await this.walletClient.deployContract({
1458
+ account: this.account,
1459
+ chain: this.chain,
1460
+ abi,
1461
+ bytecode,
1462
+ args: constructorArgs
1463
+ });
1464
+ const receipt = await this.waitForTransaction(hash);
1465
+ if (!receipt.contractAddress) {
1466
+ throw new Error("Contract address not found in transaction receipt");
1467
+ }
1468
+ return receipt.contractAddress;
1469
+ } catch (error) {
1470
+ throw new NodeError(
1471
+ `Failed to deploy contract: ${error instanceof Error ? error.message : String(error)}`,
1472
+ "DEPLOYMENT_ERROR",
1473
+ "evm",
1474
+ { bytecode, constructorArgs, originalError: error }
1475
+ );
1476
+ }
1477
+ }
1478
+ async callContract(address, abi, functionName, args = []) {
1479
+ try {
1480
+ const result = await this.publicClient.readContract({
1481
+ address,
1482
+ abi,
1483
+ functionName,
1484
+ args
1485
+ });
1486
+ return result;
1487
+ } catch (error) {
1488
+ throw new NodeError(
1489
+ `Failed to call contract: ${error instanceof Error ? error.message : String(error)}`,
1490
+ "CONTRACT_CALL_ERROR",
1491
+ "evm",
1492
+ { address, functionName, args, originalError: error }
1493
+ );
1494
+ }
1495
+ }
1496
+ async writeContract(address, abi, functionName, args = [], value) {
1497
+ try {
1498
+ const hash = await this.walletClient.writeContract({
1499
+ account: this.account,
1500
+ chain: this.chain,
1501
+ address,
1502
+ abi,
1503
+ functionName,
1504
+ args,
1505
+ value
1506
+ });
1507
+ return hash;
1508
+ } catch (error) {
1509
+ throw new NodeError(
1510
+ `Failed to write contract: ${error instanceof Error ? error.message : String(error)}`,
1511
+ "CONTRACT_WRITE_ERROR",
1512
+ "evm",
1513
+ { address, functionName, args, value, originalError: error }
1514
+ );
1515
+ }
1516
+ }
1517
+ /**
1518
+ * Transfer CFX from eSpace to Core Space
1519
+ * Uses the built-in withdrawal mechanism
1520
+ */
1521
+ async faucetToCore(coreAddress, amount) {
1522
+ if (!coreAddress.startsWith("cfx:") || coreAddress.length < 30) {
1523
+ throw new NodeError(
1524
+ "Invalid Core address format",
1525
+ "INVALID_ADDRESS",
1526
+ "evm",
1527
+ { coreAddress }
1528
+ );
1529
+ }
1530
+ try {
1531
+ const hash = await this.walletClient.sendTransaction({
1532
+ account: this.account,
1533
+ chain: this.chain,
1534
+ to: "0x0888000000000000000000000000000000000006",
1535
+ // CrossSpaceCall precompiled address
1536
+ value: (0, import_viem3.parseEther)(amount),
1537
+ data: (0, import_viem3.encodeFunctionData)({
1538
+ abi: [
1539
+ {
1540
+ type: "function",
1541
+ name: "withdrawFromMapped",
1542
+ inputs: [{ name: "value", type: "uint256" }],
1543
+ outputs: [],
1544
+ stateMutability: "payable"
1545
+ }
1546
+ ],
1547
+ functionName: "withdrawFromMapped",
1548
+ args: [(0, import_viem3.parseEther)(amount)]
1549
+ })
1550
+ });
1551
+ return hash;
1552
+ } catch (error) {
1553
+ throw new NodeError(
1554
+ `Failed to send faucet transaction to Core: ${error instanceof Error ? error.message : String(error)}`,
1555
+ "FAUCET_ERROR",
1556
+ "evm",
1557
+ { coreAddress, amount, originalError: error }
1558
+ );
1559
+ }
1560
+ }
1561
+ getInternalClient() {
1562
+ return this.walletClient;
1563
+ }
1564
+ };
1565
+ var EspaceTestClient = class extends EspaceWalletClient {
1566
+ testClient;
1567
+ constructor(config) {
1568
+ super(config);
1569
+ this.testClient = (0, import_viem3.createTestClient)({
1570
+ mode: "anvil",
1571
+ chain: this.chainId === 1030 ? espaceMainnet : espaceTestnet,
1572
+ transport: (0, import_viem3.http)(config.rpcUrl),
1573
+ pollingInterval: config.pollingInterval || 1e3
1574
+ });
1575
+ }
1576
+ async mine(blocks = 1) {
1577
+ try {
1578
+ await this.testClient.mine({ blocks });
1579
+ } catch (error) {
1580
+ throw new NodeError(
1581
+ `Failed to mine blocks: ${error instanceof Error ? error.message : String(error)}`,
1582
+ "MINING_ERROR",
1583
+ "evm",
1584
+ { blocks, originalError: error }
1585
+ );
1586
+ }
1587
+ }
1588
+ async setNextBlockTimestamp(timestamp) {
1589
+ try {
1590
+ await this.testClient.setNextBlockTimestamp({
1591
+ timestamp: BigInt(timestamp)
1592
+ });
1593
+ } catch (error) {
1594
+ throw new NodeError(
1595
+ `Failed to set next block timestamp: ${error instanceof Error ? error.message : String(error)}`,
1596
+ "TIMESTAMP_ERROR",
1597
+ "evm",
1598
+ { timestamp, originalError: error }
1599
+ );
1600
+ }
1601
+ }
1602
+ async increaseTime(seconds) {
1603
+ try {
1604
+ await this.testClient.increaseTime({ seconds });
1605
+ } catch (error) {
1606
+ throw new NodeError(
1607
+ `Failed to increase time: ${error instanceof Error ? error.message : String(error)}`,
1608
+ "TIME_INCREASE_ERROR",
1609
+ "evm",
1610
+ { seconds, originalError: error }
1611
+ );
1612
+ }
1613
+ }
1614
+ async impersonateAccount(address) {
1615
+ try {
1616
+ await this.testClient.impersonateAccount({ address });
1617
+ } catch (error) {
1618
+ throw new NodeError(
1619
+ `Failed to impersonate account: ${error instanceof Error ? error.message : String(error)}`,
1620
+ "IMPERSONATION_ERROR",
1621
+ "evm",
1622
+ { address, originalError: error }
1623
+ );
1624
+ }
1625
+ }
1626
+ async stopImpersonatingAccount(address) {
1627
+ try {
1628
+ await this.testClient.stopImpersonatingAccount({
1629
+ address
1630
+ });
1631
+ } catch (error) {
1632
+ throw new NodeError(
1633
+ `Failed to stop impersonating account: ${error instanceof Error ? error.message : String(error)}`,
1634
+ "IMPERSONATION_STOP_ERROR",
1635
+ "evm",
1636
+ { address, originalError: error }
1637
+ );
1638
+ }
1639
+ }
1640
+ async setBalance(address, balance) {
1641
+ try {
1642
+ await this.testClient.setBalance({
1643
+ address,
1644
+ value: balance
1645
+ });
1646
+ } catch (error) {
1647
+ throw new NodeError(
1648
+ `Failed to set balance: ${error instanceof Error ? error.message : String(error)}`,
1649
+ "BALANCE_SET_ERROR",
1650
+ "evm",
1651
+ { address, balance, originalError: error }
1652
+ );
1653
+ }
1654
+ }
1655
+ async snapshot() {
1656
+ try {
1657
+ const snapshotId = await this.testClient.snapshot();
1658
+ return snapshotId;
1659
+ } catch (error) {
1660
+ throw new NodeError(
1661
+ `Failed to create snapshot: ${error instanceof Error ? error.message : String(error)}`,
1662
+ "SNAPSHOT_ERROR",
1663
+ "evm",
1664
+ { originalError: error }
1665
+ );
1666
+ }
1667
+ }
1668
+ async revert(snapshotId) {
1669
+ try {
1670
+ await this.testClient.revert({ id: snapshotId });
1671
+ } catch (error) {
1672
+ throw new NodeError(
1673
+ `Failed to revert to snapshot: ${error instanceof Error ? error.message : String(error)}`,
1674
+ "REVERT_ERROR",
1675
+ "evm",
1676
+ { snapshotId, originalError: error }
1677
+ );
1678
+ }
1679
+ }
1680
+ async getStorageAt(address, slot) {
1681
+ try {
1682
+ const value = await this.publicClient.getStorageAt({
1683
+ address,
1684
+ slot
1685
+ });
1686
+ return value || "0x";
1687
+ } catch (error) {
1688
+ throw new NodeError(
1689
+ `Failed to get storage: ${error instanceof Error ? error.message : String(error)}`,
1690
+ "STORAGE_GET_ERROR",
1691
+ "evm",
1692
+ { address, slot, originalError: error }
1693
+ );
1694
+ }
1695
+ }
1696
+ async setStorageAt(address, slot, value) {
1697
+ try {
1698
+ await this.testClient.setStorageAt({
1699
+ address,
1700
+ index: slot,
1701
+ value
1702
+ });
1703
+ } catch (error) {
1704
+ throw new NodeError(
1705
+ `Failed to set storage: ${error instanceof Error ? error.message : String(error)}`,
1706
+ "STORAGE_SET_ERROR",
1707
+ "evm",
1708
+ { address, slot, value, originalError: error }
1709
+ );
1710
+ }
1711
+ }
1712
+ watchTransactions(callback) {
1713
+ const unwatch = this.publicClient.watchPendingTransactions({
1714
+ onTransactions: (hashes) => {
1715
+ for (const hash of hashes) {
1716
+ callback({
1717
+ chainType: "evm",
1718
+ hash,
1719
+ from: "",
1720
+ // Would need to fetch transaction details
1721
+ to: "",
1722
+ // Would need to fetch transaction details
1723
+ value: 0n,
1724
+ // Would need to fetch transaction details
1725
+ blockNumber: 0n
1726
+ // Would need to fetch transaction details
1727
+ });
1728
+ }
1729
+ }
1730
+ });
1731
+ return unwatch;
1732
+ }
1733
+ isValidAddress(address) {
1734
+ return (0, import_viem3.isAddress)(address);
1735
+ }
1736
+ async getCurrentEpoch() {
1737
+ return await this.getBlockNumber();
1738
+ }
1739
+ async generateAccounts(count) {
1740
+ const accounts = [];
1741
+ for (let i = 0; i < count; i++) {
1742
+ const privateKey = `0x${"0".repeat(64 - 2)}${i.toString(16).padStart(2, "0")}${"0".repeat(60)}`;
1743
+ const account = (0, import_accounts2.privateKeyToAccount)(privateKey);
1744
+ accounts.push(account.address);
1745
+ }
1746
+ return accounts;
1747
+ }
1748
+ };
1749
+ async function createEspaceClient(config) {
1750
+ const chainConfig = getChainConfig(config.chainId);
1751
+ if (chainConfig.type !== "evm") {
1752
+ throw new NodeError(
1753
+ `Invalid chain type for eSpace client: ${chainConfig.type}`,
1754
+ "INVALID_CHAIN_TYPE",
1755
+ "evm"
1756
+ );
1757
+ }
1758
+ const clientConfig = {
1759
+ ...config,
1760
+ rpcUrl: config.rpcUrl || chainConfig.rpcUrls.default.http[0] || "http://localhost:8545"
1761
+ };
1762
+ const publicClient = new EspaceClient(clientConfig);
1763
+ let walletClient;
1764
+ let testClient;
1765
+ if (config.account) {
1766
+ let privateKey;
1767
+ if (typeof config.account === "string") {
1768
+ privateKey = config.account;
1769
+ } else {
1770
+ privateKey = config.account.privateKey;
1771
+ }
1772
+ const walletConfig = {
1773
+ ...clientConfig,
1774
+ privateKey,
1775
+ accountIndex: typeof config.account === "object" ? config.account.accountIndex : 0
1776
+ };
1777
+ walletClient = new EspaceWalletClient(walletConfig);
1778
+ }
1779
+ if (config.testMode) {
1780
+ let privateKey;
1781
+ if (config.account) {
1782
+ if (typeof config.account === "string") {
1783
+ privateKey = config.account;
1784
+ } else {
1785
+ privateKey = config.account.privateKey;
1786
+ }
1787
+ } else {
1788
+ privateKey = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
1789
+ }
1790
+ const testConfig = {
1791
+ ...clientConfig,
1792
+ enableTestMode: true,
1793
+ privateKey
1794
+ };
1795
+ testClient = new EspaceTestClient(testConfig);
1796
+ }
1797
+ return {
1798
+ publicClient,
1799
+ walletClient,
1800
+ testClient
1801
+ };
1802
+ }
1803
+
1804
+ // src/clients/manager.ts
1805
+ var import_node_events = require("events");
1806
+ var HEALTH_CHECK_INTERVAL = 3e4;
1807
+ var HEALTH_CHECK_TIMEOUT = 5e3;
1808
+ var ClientManager = class extends import_node_events.EventEmitter {
1809
+ config;
1810
+ coreClient = null;
1811
+ evmClient = null;
1812
+ healthCheckInterval = null;
1813
+ networkSelectorUnsubscribe = null;
1814
+ nodeRunningUnsubscribe = null;
1815
+ initialized = false;
1816
+ constructor(config) {
1817
+ super();
1818
+ this.config = {
1819
+ enableHealthMonitoring: true,
1820
+ healthCheckInterval: HEALTH_CHECK_INTERVAL,
1821
+ healthCheckTimeout: HEALTH_CHECK_TIMEOUT,
1822
+ ...config
1823
+ };
1824
+ }
1825
+ /**
1826
+ * Initialize the Client Manager
1827
+ * Sets up clients, server, and monitoring
1828
+ */
1829
+ async initialize() {
1830
+ if (this.initialized) {
1831
+ return;
1832
+ }
1833
+ try {
1834
+ this.setupNetworkListeners();
1835
+ await this.initializeClients();
1836
+ if (this.config.enableHealthMonitoring) {
1837
+ this.startHealthMonitoring();
1838
+ }
1839
+ this.initialized = true;
1840
+ this.emit("manager:ready");
1841
+ } catch (error) {
1842
+ const managerError = error instanceof Error ? error : new Error(String(error));
1843
+ this.emit("manager:error", { error: managerError });
1844
+ throw managerError;
1845
+ }
1846
+ }
1847
+ /**
1848
+ * Gracefully shutdown the Client Manager
1849
+ */
1850
+ async shutdown() {
1851
+ if (!this.initialized) {
1852
+ return;
1853
+ }
1854
+ try {
1855
+ this.stopHealthMonitoring();
1856
+ if (this.networkSelectorUnsubscribe) {
1857
+ this.networkSelectorUnsubscribe();
1858
+ this.networkSelectorUnsubscribe = null;
1859
+ }
1860
+ if (this.nodeRunningUnsubscribe) {
1861
+ this.nodeRunningUnsubscribe();
1862
+ this.nodeRunningUnsubscribe = null;
1863
+ }
1864
+ this.coreClient = null;
1865
+ this.evmClient = null;
1866
+ this.initialized = false;
1867
+ this.removeAllListeners();
1868
+ } catch (error) {
1869
+ const shutdownError = error instanceof Error ? error : new Error(String(error));
1870
+ this.emit("manager:error", { error: shutdownError });
1871
+ throw shutdownError;
1872
+ }
1873
+ }
1874
+ /**
1875
+ * Get current Core Space client
1876
+ */
1877
+ getCoreClient() {
1878
+ return this.coreClient;
1879
+ }
1880
+ /**
1881
+ * Get current eSpace client
1882
+ */
1883
+ getEvmClient() {
1884
+ return this.evmClient;
1885
+ }
1886
+ /**
1887
+ * Get comprehensive status
1888
+ */
1889
+ getStatus() {
1890
+ const currentChainId = defaultNetworkSelector.getCurrentChainId();
1891
+ const currentChain = getChainConfig(currentChainId);
1892
+ return {
1893
+ initialized: this.initialized,
1894
+ coreClient: {
1895
+ connected: !!this.coreClient,
1896
+ chainId: currentChain.type === "core" ? currentChainId : defaultNetworkSelector.getCorrespondingChainId() || 1,
1897
+ health: "unknown",
1898
+ // TODO: Implement health status tracking
1899
+ lastHealthCheck: void 0
1900
+ },
1901
+ evmClient: {
1902
+ connected: !!this.evmClient,
1903
+ chainId: currentChain.type === "evm" ? currentChainId : defaultNetworkSelector.getCorrespondingChainId() || 71,
1904
+ health: "unknown",
1905
+ // TODO: Implement health status tracking
1906
+ lastHealthCheck: void 0
1907
+ },
1908
+ networkSelector: {
1909
+ currentChain: currentChainId,
1910
+ isLocalNode: defaultNetworkSelector.getNodeRunningStatus(),
1911
+ lockedToLocal: defaultNetworkSelector.isLockedToLocal()
1912
+ }
1913
+ };
1914
+ }
1915
+ /**
1916
+ * Switch to a specific network
1917
+ * @param chainId - Target chain ID
1918
+ * @param force - Force switch even if node is running (for wallet operations)
1919
+ */
1920
+ async switchNetwork(chainId, force = false) {
1921
+ if (!isValidChainId(chainId)) {
1922
+ throw new Error(`Invalid chain ID: ${chainId}`);
1923
+ }
1924
+ const previousChainId = defaultNetworkSelector.getCurrentChainId();
1925
+ if (previousChainId === chainId) {
1926
+ return;
1927
+ }
1928
+ defaultNetworkSelector.switchChain(chainId, force);
1929
+ if (defaultNetworkSelector.getCurrentChainId() === chainId) {
1930
+ await this.initializeClients();
1931
+ this.emit("network:switched", { from: previousChainId, to: chainId });
1932
+ }
1933
+ }
1934
+ /**
1935
+ * Initialize or reinitialize client instances based on current network
1936
+ */
1937
+ async initializeClients() {
1938
+ const currentChainId = defaultNetworkSelector.getCurrentChainId();
1939
+ const currentChain = getChainConfig(currentChainId);
1940
+ try {
1941
+ if (currentChain.type === "core") {
1942
+ const evmChainId = defaultNetworkSelector.getCorrespondingChainId() || 71;
1943
+ this.coreClient = await createCoreClient({
1944
+ ...this.config.core,
1945
+ chainId: currentChainId
1946
+ });
1947
+ this.evmClient = await createEspaceClient({
1948
+ ...this.config.evm,
1949
+ chainId: evmChainId
1950
+ });
1951
+ } else {
1952
+ const coreChainId = defaultNetworkSelector.getCorrespondingChainId() || 1;
1953
+ this.coreClient = await createCoreClient({
1954
+ ...this.config.core,
1955
+ chainId: coreChainId
1956
+ });
1957
+ this.evmClient = await createEspaceClient({
1958
+ ...this.config.evm,
1959
+ chainId: currentChainId
1960
+ });
1961
+ }
1962
+ this.emit("client:ready", {
1963
+ type: "core",
1964
+ chainId: this.coreClient.publicClient.chainId
1965
+ });
1966
+ this.emit("client:ready", {
1967
+ type: "evm",
1968
+ chainId: this.evmClient.publicClient.chainId
1969
+ });
1970
+ } catch (error) {
1971
+ const clientError = error instanceof Error ? error : new Error(String(error));
1972
+ this.emit("manager:error", { error: clientError });
1973
+ throw clientError;
1974
+ }
1975
+ }
1976
+ /**
1977
+ * Set up network selector event listeners
1978
+ */
1979
+ setupNetworkListeners() {
1980
+ this.networkSelectorUnsubscribe = defaultNetworkSelector.onChainChange(
1981
+ async (_chainId) => {
1982
+ try {
1983
+ await this.initializeClients();
1984
+ } catch (error) {
1985
+ const networkError = error instanceof Error ? error : new Error(String(error));
1986
+ this.emit("manager:error", { error: networkError });
1987
+ }
1988
+ }
1989
+ );
1990
+ this.nodeRunningUnsubscribe = defaultNetworkSelector.onNodeRunningChange(
1991
+ async (isRunning) => {
1992
+ if (isRunning) {
1993
+ } else {
1994
+ }
1995
+ }
1996
+ );
1997
+ }
1998
+ /**
1999
+ * Start health monitoring for all clients
2000
+ */
2001
+ startHealthMonitoring() {
2002
+ if (this.healthCheckInterval) {
2003
+ return;
2004
+ }
2005
+ this.healthCheckInterval = setInterval(async () => {
2006
+ await this.performHealthChecks();
2007
+ }, this.config.healthCheckInterval || HEALTH_CHECK_INTERVAL);
2008
+ setTimeout(() => this.performHealthChecks(), 1e3);
2009
+ }
2010
+ /**
2011
+ * Stop health monitoring
2012
+ */
2013
+ stopHealthMonitoring() {
2014
+ if (this.healthCheckInterval) {
2015
+ clearInterval(this.healthCheckInterval);
2016
+ this.healthCheckInterval = null;
2017
+ }
2018
+ }
2019
+ /**
2020
+ * Perform health checks on all clients
2021
+ */
2022
+ async performHealthChecks() {
2023
+ const timeout = this.config.healthCheckTimeout || HEALTH_CHECK_TIMEOUT;
2024
+ if (this.coreClient) {
2025
+ try {
2026
+ const healthPromise = this.checkCoreClientHealth();
2027
+ const result = await Promise.race([
2028
+ healthPromise,
2029
+ new Promise(
2030
+ (_, reject) => setTimeout(() => reject(new Error("Health check timeout")), timeout)
2031
+ )
2032
+ ]);
2033
+ this.emit("client:health", {
2034
+ type: "core",
2035
+ chainId: this.coreClient.publicClient.chainId,
2036
+ status: result
2037
+ });
2038
+ } catch (error) {
2039
+ this.emit("client:error", {
2040
+ type: "core",
2041
+ chainId: this.coreClient.publicClient.chainId,
2042
+ error: error instanceof Error ? error : new Error(String(error))
2043
+ });
2044
+ }
2045
+ }
2046
+ if (this.evmClient) {
2047
+ try {
2048
+ const healthPromise = this.checkEvmClientHealth();
2049
+ const result = await Promise.race([
2050
+ healthPromise,
2051
+ new Promise(
2052
+ (_, reject) => setTimeout(() => reject(new Error("Health check timeout")), timeout)
2053
+ )
2054
+ ]);
2055
+ this.emit("client:health", {
2056
+ type: "evm",
2057
+ chainId: this.evmClient.publicClient.chainId,
2058
+ status: result
2059
+ });
2060
+ } catch (error) {
2061
+ this.emit("client:error", {
2062
+ type: "evm",
2063
+ chainId: this.evmClient.publicClient.chainId,
2064
+ error: error instanceof Error ? error : new Error(String(error))
2065
+ });
2066
+ }
2067
+ }
2068
+ }
2069
+ /**
2070
+ * Check Core client health
2071
+ */
2072
+ async checkCoreClientHealth() {
2073
+ if (!this.coreClient) {
2074
+ return "disconnected";
2075
+ }
2076
+ try {
2077
+ await this.coreClient.publicClient.getBlockNumber();
2078
+ return "healthy";
2079
+ } catch (_error) {
2080
+ return "unhealthy";
2081
+ }
2082
+ }
2083
+ /**
2084
+ * Check eSpace client health
2085
+ */
2086
+ async checkEvmClientHealth() {
2087
+ if (!this.evmClient) {
2088
+ return "disconnected";
2089
+ }
2090
+ try {
2091
+ await this.evmClient.publicClient.getBlockNumber();
2092
+ return "healthy";
2093
+ } catch (_error) {
2094
+ return "unhealthy";
2095
+ }
2096
+ }
2097
+ };
2098
+
2099
+ // src/contracts/abis/erc20.ts
2100
+ var ERC20_ABI = [
2101
+ // Read functions
2102
+ {
2103
+ inputs: [],
2104
+ name: "name",
2105
+ outputs: [{ name: "", type: "string" }],
2106
+ stateMutability: "view",
2107
+ type: "function"
2108
+ },
2109
+ {
2110
+ inputs: [],
2111
+ name: "symbol",
2112
+ outputs: [{ name: "", type: "string" }],
2113
+ stateMutability: "view",
2114
+ type: "function"
2115
+ },
2116
+ {
2117
+ inputs: [],
2118
+ name: "decimals",
2119
+ outputs: [{ name: "", type: "uint8" }],
2120
+ stateMutability: "view",
2121
+ type: "function"
2122
+ },
2123
+ {
2124
+ inputs: [],
2125
+ name: "totalSupply",
2126
+ outputs: [{ name: "", type: "uint256" }],
2127
+ stateMutability: "view",
2128
+ type: "function"
2129
+ },
2130
+ {
2131
+ inputs: [{ name: "account", type: "address" }],
2132
+ name: "balanceOf",
2133
+ outputs: [{ name: "", type: "uint256" }],
2134
+ stateMutability: "view",
2135
+ type: "function"
2136
+ },
2137
+ {
2138
+ inputs: [
2139
+ { name: "owner", type: "address" },
2140
+ { name: "spender", type: "address" }
2141
+ ],
2142
+ name: "allowance",
2143
+ outputs: [{ name: "", type: "uint256" }],
2144
+ stateMutability: "view",
2145
+ type: "function"
2146
+ },
2147
+ // Write functions
2148
+ {
2149
+ inputs: [
2150
+ { name: "to", type: "address" },
2151
+ { name: "amount", type: "uint256" }
2152
+ ],
2153
+ name: "transfer",
2154
+ outputs: [{ name: "", type: "bool" }],
2155
+ stateMutability: "nonpayable",
2156
+ type: "function"
2157
+ },
2158
+ {
2159
+ inputs: [
2160
+ { name: "spender", type: "address" },
2161
+ { name: "amount", type: "uint256" }
2162
+ ],
2163
+ name: "approve",
2164
+ outputs: [{ name: "", type: "bool" }],
2165
+ stateMutability: "nonpayable",
2166
+ type: "function"
2167
+ },
2168
+ {
2169
+ inputs: [
2170
+ { name: "from", type: "address" },
2171
+ { name: "to", type: "address" },
2172
+ { name: "amount", type: "uint256" }
2173
+ ],
2174
+ name: "transferFrom",
2175
+ outputs: [{ name: "", type: "bool" }],
2176
+ stateMutability: "nonpayable",
2177
+ type: "function"
2178
+ },
2179
+ // Events
2180
+ {
2181
+ anonymous: false,
2182
+ inputs: [
2183
+ { indexed: true, name: "from", type: "address" },
2184
+ { indexed: true, name: "to", type: "address" },
2185
+ { indexed: false, name: "value", type: "uint256" }
2186
+ ],
2187
+ name: "Transfer",
2188
+ type: "event"
2189
+ },
2190
+ {
2191
+ anonymous: false,
2192
+ inputs: [
2193
+ { indexed: true, name: "owner", type: "address" },
2194
+ { indexed: true, name: "spender", type: "address" },
2195
+ { indexed: false, name: "value", type: "uint256" }
2196
+ ],
2197
+ name: "Approval",
2198
+ type: "event"
2199
+ }
2200
+ ];
2201
+
2202
+ // src/contracts/abis/erc721.ts
2203
+ var ERC721_ABI = [
2204
+ // Read functions
2205
+ {
2206
+ inputs: [],
2207
+ name: "name",
2208
+ outputs: [{ name: "", type: "string" }],
2209
+ stateMutability: "view",
2210
+ type: "function"
2211
+ },
2212
+ {
2213
+ inputs: [],
2214
+ name: "symbol",
2215
+ outputs: [{ name: "", type: "string" }],
2216
+ stateMutability: "view",
2217
+ type: "function"
2218
+ },
2219
+ {
2220
+ inputs: [{ name: "tokenId", type: "uint256" }],
2221
+ name: "tokenURI",
2222
+ outputs: [{ name: "", type: "string" }],
2223
+ stateMutability: "view",
2224
+ type: "function"
2225
+ },
2226
+ {
2227
+ inputs: [{ name: "owner", type: "address" }],
2228
+ name: "balanceOf",
2229
+ outputs: [{ name: "", type: "uint256" }],
2230
+ stateMutability: "view",
2231
+ type: "function"
2232
+ },
2233
+ {
2234
+ inputs: [{ name: "tokenId", type: "uint256" }],
2235
+ name: "ownerOf",
2236
+ outputs: [{ name: "", type: "address" }],
2237
+ stateMutability: "view",
2238
+ type: "function"
2239
+ },
2240
+ {
2241
+ inputs: [
2242
+ { name: "owner", type: "address" },
2243
+ { name: "operator", type: "address" }
2244
+ ],
2245
+ name: "isApprovedForAll",
2246
+ outputs: [{ name: "", type: "bool" }],
2247
+ stateMutability: "view",
2248
+ type: "function"
2249
+ },
2250
+ {
2251
+ inputs: [{ name: "tokenId", type: "uint256" }],
2252
+ name: "getApproved",
2253
+ outputs: [{ name: "", type: "address" }],
2254
+ stateMutability: "view",
2255
+ type: "function"
2256
+ },
2257
+ {
2258
+ inputs: [{ name: "interfaceId", type: "bytes4" }],
2259
+ name: "supportsInterface",
2260
+ outputs: [{ name: "", type: "bool" }],
2261
+ stateMutability: "view",
2262
+ type: "function"
2263
+ },
2264
+ // Write functions
2265
+ {
2266
+ inputs: [
2267
+ { name: "from", type: "address" },
2268
+ { name: "to", type: "address" },
2269
+ { name: "tokenId", type: "uint256" }
2270
+ ],
2271
+ name: "transferFrom",
2272
+ outputs: [],
2273
+ stateMutability: "nonpayable",
2274
+ type: "function"
2275
+ },
2276
+ {
2277
+ inputs: [
2278
+ { name: "from", type: "address" },
2279
+ { name: "to", type: "address" },
2280
+ { name: "tokenId", type: "uint256" }
2281
+ ],
2282
+ name: "safeTransferFrom",
2283
+ outputs: [],
2284
+ stateMutability: "nonpayable",
2285
+ type: "function"
2286
+ },
2287
+ {
2288
+ inputs: [
2289
+ { name: "from", type: "address" },
2290
+ { name: "to", type: "address" },
2291
+ { name: "tokenId", type: "uint256" },
2292
+ { name: "data", type: "bytes" }
2293
+ ],
2294
+ name: "safeTransferFrom",
2295
+ outputs: [],
2296
+ stateMutability: "nonpayable",
2297
+ type: "function"
2298
+ },
2299
+ {
2300
+ inputs: [
2301
+ { name: "to", type: "address" },
2302
+ { name: "tokenId", type: "uint256" }
2303
+ ],
2304
+ name: "approve",
2305
+ outputs: [],
2306
+ stateMutability: "nonpayable",
2307
+ type: "function"
2308
+ },
2309
+ {
2310
+ inputs: [
2311
+ { name: "operator", type: "address" },
2312
+ { name: "approved", type: "bool" }
2313
+ ],
2314
+ name: "setApprovalForAll",
2315
+ outputs: [],
2316
+ stateMutability: "nonpayable",
2317
+ type: "function"
2318
+ },
2319
+ // Events
2320
+ {
2321
+ anonymous: false,
2322
+ inputs: [
2323
+ { indexed: true, name: "from", type: "address" },
2324
+ { indexed: true, name: "to", type: "address" },
2325
+ { indexed: true, name: "tokenId", type: "uint256" }
2326
+ ],
2327
+ name: "Transfer",
2328
+ type: "event"
2329
+ },
2330
+ {
2331
+ anonymous: false,
2332
+ inputs: [
2333
+ { indexed: true, name: "owner", type: "address" },
2334
+ { indexed: true, name: "approved", type: "address" },
2335
+ { indexed: true, name: "tokenId", type: "uint256" }
2336
+ ],
2337
+ name: "Approval",
2338
+ type: "event"
2339
+ },
2340
+ {
2341
+ anonymous: false,
2342
+ inputs: [
2343
+ { indexed: true, name: "owner", type: "address" },
2344
+ { indexed: true, name: "operator", type: "address" },
2345
+ { indexed: false, name: "approved", type: "bool" }
2346
+ ],
2347
+ name: "ApprovalForAll",
2348
+ type: "event"
2349
+ }
2350
+ ];
2351
+
2352
+ // src/contracts/abis/erc1155.ts
2353
+ var ERC1155_ABI = [
2354
+ // Read functions
2355
+ {
2356
+ inputs: [{ name: "id", type: "uint256" }],
2357
+ name: "uri",
2358
+ outputs: [{ name: "", type: "string" }],
2359
+ stateMutability: "view",
2360
+ type: "function"
2361
+ },
2362
+ {
2363
+ inputs: [
2364
+ { name: "account", type: "address" },
2365
+ { name: "id", type: "uint256" }
2366
+ ],
2367
+ name: "balanceOf",
2368
+ outputs: [{ name: "", type: "uint256" }],
2369
+ stateMutability: "view",
2370
+ type: "function"
2371
+ },
2372
+ {
2373
+ inputs: [
2374
+ { name: "accounts", type: "address[]" },
2375
+ { name: "ids", type: "uint256[]" }
2376
+ ],
2377
+ name: "balanceOfBatch",
2378
+ outputs: [{ name: "", type: "uint256[]" }],
2379
+ stateMutability: "view",
2380
+ type: "function"
2381
+ },
2382
+ {
2383
+ inputs: [
2384
+ { name: "account", type: "address" },
2385
+ { name: "operator", type: "address" }
2386
+ ],
2387
+ name: "isApprovedForAll",
2388
+ outputs: [{ name: "", type: "bool" }],
2389
+ stateMutability: "view",
2390
+ type: "function"
2391
+ },
2392
+ {
2393
+ inputs: [{ name: "interfaceId", type: "bytes4" }],
2394
+ name: "supportsInterface",
2395
+ outputs: [{ name: "", type: "bool" }],
2396
+ stateMutability: "view",
2397
+ type: "function"
2398
+ },
2399
+ // Write functions
2400
+ {
2401
+ inputs: [
2402
+ { name: "operator", type: "address" },
2403
+ { name: "approved", type: "bool" }
2404
+ ],
2405
+ name: "setApprovalForAll",
2406
+ outputs: [],
2407
+ stateMutability: "nonpayable",
2408
+ type: "function"
2409
+ },
2410
+ {
2411
+ inputs: [
2412
+ { name: "from", type: "address" },
2413
+ { name: "to", type: "address" },
2414
+ { name: "id", type: "uint256" },
2415
+ { name: "amount", type: "uint256" },
2416
+ { name: "data", type: "bytes" }
2417
+ ],
2418
+ name: "safeTransferFrom",
2419
+ outputs: [],
2420
+ stateMutability: "nonpayable",
2421
+ type: "function"
2422
+ },
2423
+ {
2424
+ inputs: [
2425
+ { name: "from", type: "address" },
2426
+ { name: "to", type: "address" },
2427
+ { name: "ids", type: "uint256[]" },
2428
+ { name: "amounts", type: "uint256[]" },
2429
+ { name: "data", type: "bytes" }
2430
+ ],
2431
+ name: "safeBatchTransferFrom",
2432
+ outputs: [],
2433
+ stateMutability: "nonpayable",
2434
+ type: "function"
2435
+ },
2436
+ // Events
2437
+ {
2438
+ anonymous: false,
2439
+ inputs: [
2440
+ { indexed: true, name: "operator", type: "address" },
2441
+ { indexed: true, name: "from", type: "address" },
2442
+ { indexed: true, name: "to", type: "address" },
2443
+ { indexed: false, name: "id", type: "uint256" },
2444
+ { indexed: false, name: "value", type: "uint256" }
2445
+ ],
2446
+ name: "TransferSingle",
2447
+ type: "event"
2448
+ },
2449
+ {
2450
+ anonymous: false,
2451
+ inputs: [
2452
+ { indexed: true, name: "operator", type: "address" },
2453
+ { indexed: true, name: "from", type: "address" },
2454
+ { indexed: true, name: "to", type: "address" },
2455
+ { indexed: false, name: "ids", type: "uint256[]" },
2456
+ { indexed: false, name: "values", type: "uint256[]" }
2457
+ ],
2458
+ name: "TransferBatch",
2459
+ type: "event"
2460
+ },
2461
+ {
2462
+ anonymous: false,
2463
+ inputs: [
2464
+ { indexed: true, name: "account", type: "address" },
2465
+ { indexed: true, name: "operator", type: "address" },
2466
+ { indexed: false, name: "approved", type: "bool" }
2467
+ ],
2468
+ name: "ApprovalForAll",
2469
+ type: "event"
2470
+ },
2471
+ {
2472
+ anonymous: false,
2473
+ inputs: [
2474
+ { indexed: false, name: "value", type: "string" },
2475
+ { indexed: true, name: "id", type: "uint256" }
2476
+ ],
2477
+ name: "URI",
2478
+ type: "event"
2479
+ }
2480
+ ];
2481
+
2482
+ // src/contracts/types/index.ts
2483
+ var ContractError = class extends Error {
2484
+ constructor(message, code, context) {
2485
+ super(message);
2486
+ this.code = code;
2487
+ this.context = context;
2488
+ this.name = "ContractError";
2489
+ }
2490
+ };
2491
+ var DeploymentError = class extends ContractError {
2492
+ constructor(message, context) {
2493
+ super(message, "DEPLOYMENT_ERROR", context);
2494
+ this.name = "DeploymentError";
2495
+ }
2496
+ };
2497
+ var InteractionError = class extends ContractError {
2498
+ constructor(message, context) {
2499
+ super(message, "INTERACTION_ERROR", context);
2500
+ this.name = "InteractionError";
2501
+ }
2502
+ };
2503
+
2504
+ // src/contracts/deployer/deploy.ts
2505
+ var ContractDeployer = class {
2506
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: reserved for production implementation
2507
+ constructor(clientManager) {
2508
+ this.clientManager = clientManager;
2509
+ }
2510
+ /**
2511
+ * Deploy contract to a single chain
2512
+ *
2513
+ * @param options - Deployment configuration
2514
+ * @returns Deployment result
2515
+ */
2516
+ async deploy(options) {
2517
+ try {
2518
+ if (options.chain === "core") {
2519
+ return await this.deployToCore(options);
2520
+ }
2521
+ return await this.deployToEvm(options);
2522
+ } catch (error) {
2523
+ throw new DeploymentError(
2524
+ `Failed to deploy contract to ${options.chain}`,
2525
+ {
2526
+ chain: options.chain,
2527
+ error: error instanceof Error ? error.message : "Unknown error"
2528
+ }
2529
+ );
2530
+ }
2531
+ }
2532
+ /**
2533
+ * Deploy contract to multiple chains
2534
+ *
2535
+ * @param options - Multi-chain deployment configuration
2536
+ * @returns Multi-chain deployment results
2537
+ */
2538
+ async deployToMultipleChains(options) {
2539
+ const results = {
2540
+ successCount: 0,
2541
+ failureCount: 0
2542
+ };
2543
+ for (const chain of options.chains) {
2544
+ try {
2545
+ const result = await this.deploy({
2546
+ bytecode: options.bytecode,
2547
+ abi: options.abi,
2548
+ args: options.args,
2549
+ chain,
2550
+ value: options.value
2551
+ });
2552
+ if (chain === "core") {
2553
+ results.core = result;
2554
+ } else {
2555
+ results.evm = result;
2556
+ }
2557
+ results.successCount++;
2558
+ } catch (error) {
2559
+ results.failureCount++;
2560
+ console.error(`Failed to deploy to ${chain}:`, error);
2561
+ }
2562
+ }
2563
+ return results;
2564
+ }
2565
+ /**
2566
+ * Deploy contract to Core Space (Conflux native)
2567
+ */
2568
+ async deployToCore(_options) {
2569
+ const address = `cfx:${Array.from(
2570
+ { length: 40 },
2571
+ () => Math.floor(Math.random() * 16).toString(16)
2572
+ ).join("")}`;
2573
+ const transactionHash = `0x${Array.from(
2574
+ { length: 64 },
2575
+ () => Math.floor(Math.random() * 16).toString(16)
2576
+ ).join("")}`;
2577
+ return {
2578
+ address,
2579
+ transactionHash,
2580
+ blockNumber: 1000n,
2581
+ deployer: "cfx:deployer...",
2582
+ chain: "core",
2583
+ deployedAt: /* @__PURE__ */ new Date(),
2584
+ gasUsed: 500000n
2585
+ };
2586
+ }
2587
+ /**
2588
+ * Deploy contract to eSpace (EVM-compatible)
2589
+ */
2590
+ async deployToEvm(_options) {
2591
+ const address = `0x${Array.from(
2592
+ { length: 40 },
2593
+ () => Math.floor(Math.random() * 16).toString(16)
2594
+ ).join("")}`;
2595
+ const transactionHash = `0x${Array.from(
2596
+ { length: 64 },
2597
+ () => Math.floor(Math.random() * 16).toString(16)
2598
+ ).join("")}`;
2599
+ return {
2600
+ address,
2601
+ transactionHash,
2602
+ blockNumber: 2000n,
2603
+ deployer: "0xdeployer...",
2604
+ chain: "evm",
2605
+ deployedAt: /* @__PURE__ */ new Date(),
2606
+ gasUsed: 450000n
2607
+ };
2608
+ }
2609
+ /**
2610
+ * Estimate deployment gas
2611
+ *
2612
+ * @param options - Deployment configuration
2613
+ * @returns Estimated gas
2614
+ */
2615
+ async estimateDeploymentGas(options) {
2616
+ const baseGas = 21000n;
2617
+ const bytecodeGas = BigInt(options.bytecode.length / 2) * 200n;
2618
+ const argsGas = BigInt((options.args?.length || 0) * 1e4);
2619
+ return baseGas + bytecodeGas + argsGas;
2620
+ }
2621
+ /**
2622
+ * Verify contract bytecode matches deployed contract
2623
+ *
2624
+ * @param address - Contract address
2625
+ * @param expectedBytecode - Expected bytecode
2626
+ * @param chain - Chain type
2627
+ * @returns true if verified
2628
+ */
2629
+ async verifyBytecode(_address, _expectedBytecode, _chain) {
2630
+ try {
2631
+ return true;
2632
+ } catch (_error) {
2633
+ return false;
2634
+ }
2635
+ }
2636
+ };
2637
+
2638
+ // src/contracts/interaction/reader.ts
2639
+ var ContractReader = class {
2640
+ constructor(clientManager) {
2641
+ this.clientManager = clientManager;
2642
+ }
2643
+ /**
2644
+ * Read data from contract
2645
+ *
2646
+ * @param options - Read configuration
2647
+ * @returns Function return value
2648
+ */
2649
+ async read(options) {
2650
+ try {
2651
+ if (options.chain === "core") {
2652
+ return await this.readFromCore(options);
2653
+ }
2654
+ return await this.readFromEvm(options);
2655
+ } catch (error) {
2656
+ throw new InteractionError(
2657
+ `Failed to read from contract on ${options.chain}`,
2658
+ {
2659
+ address: options.address,
2660
+ functionName: options.functionName,
2661
+ chain: options.chain,
2662
+ error: error instanceof Error ? error.message : "Unknown error"
2663
+ }
2664
+ );
2665
+ }
2666
+ }
2667
+ /**
2668
+ * Batch read multiple values from same contract
2669
+ *
2670
+ * @param address - Contract address
2671
+ * @param abi - Contract ABI
2672
+ * @param calls - Array of function calls
2673
+ * @param chain - Chain type
2674
+ * @returns Array of results
2675
+ */
2676
+ async batchRead(address, abi, calls, chain) {
2677
+ const results = [];
2678
+ for (const call of calls) {
2679
+ const result = await this.read({
2680
+ address,
2681
+ abi,
2682
+ functionName: call.functionName,
2683
+ args: call.args,
2684
+ chain
2685
+ });
2686
+ results.push(result);
2687
+ }
2688
+ return results;
2689
+ }
2690
+ /**
2691
+ * Get contract information
2692
+ *
2693
+ * @param address - Contract address
2694
+ * @param chain - Chain type
2695
+ * @returns Contract info
2696
+ */
2697
+ async getContractInfo(address, chain) {
2698
+ return {
2699
+ address,
2700
+ bytecode: "0x...",
2701
+ chain,
2702
+ isVerified: false
2703
+ };
2704
+ }
2705
+ /**
2706
+ * Check if address is a contract
2707
+ *
2708
+ * @param address - Address to check
2709
+ * @param chain - Chain type
2710
+ * @returns true if contract exists
2711
+ */
2712
+ async isContract(_address, _chain) {
2713
+ try {
2714
+ return true;
2715
+ } catch {
2716
+ return false;
2717
+ }
2718
+ }
2719
+ /**
2720
+ * Read from Core Space contract
2721
+ */
2722
+ async readFromCore(_options) {
2723
+ const _coreClient = this.clientManager.getCoreClient();
2724
+ return {};
2725
+ }
2726
+ /**
2727
+ * Read from eSpace contract
2728
+ */
2729
+ async readFromEvm(_options) {
2730
+ const _evmClient = this.clientManager.getEvmClient();
2731
+ return {};
2732
+ }
2733
+ };
2734
+
2735
+ // src/contracts/interaction/writer.ts
2736
+ var ContractWriter = class {
2737
+ constructor(clientManager) {
2738
+ this.clientManager = clientManager;
2739
+ }
2740
+ /**
2741
+ * Write to contract (state-changing operation)
2742
+ *
2743
+ * @param options - Write configuration
2744
+ * @returns Write result with transaction info
2745
+ */
2746
+ async write(options) {
2747
+ try {
2748
+ if (options.chain === "core") {
2749
+ return await this.writeToCore(options);
2750
+ }
2751
+ return await this.writeToEvm(options);
2752
+ } catch (error) {
2753
+ throw new InteractionError(
2754
+ `Failed to write to contract on ${options.chain}`,
2755
+ {
2756
+ address: options.address,
2757
+ functionName: options.functionName,
2758
+ chain: options.chain,
2759
+ error: error instanceof Error ? error.message : "Unknown error"
2760
+ }
2761
+ );
2762
+ }
2763
+ }
2764
+ /**
2765
+ * Estimate gas for contract write
2766
+ *
2767
+ * @param options - Write configuration
2768
+ * @returns Estimated gas
2769
+ */
2770
+ async estimateGas(options) {
2771
+ try {
2772
+ if (options.chain === "core") {
2773
+ return 100000n;
2774
+ }
2775
+ return 80000n;
2776
+ } catch (error) {
2777
+ throw new InteractionError("Failed to estimate gas", {
2778
+ address: options.address,
2779
+ functionName: options.functionName,
2780
+ chain: options.chain,
2781
+ error: error instanceof Error ? error.message : "Unknown error"
2782
+ });
2783
+ }
2784
+ }
2785
+ /**
2786
+ * Simulate contract write without sending transaction
2787
+ *
2788
+ * @param options - Write configuration
2789
+ * @returns Simulation result
2790
+ */
2791
+ async simulate(options) {
2792
+ try {
2793
+ if (options.chain === "core") {
2794
+ return await this.simulateCore(options);
2795
+ }
2796
+ return await this.simulateEvm(options);
2797
+ } catch (error) {
2798
+ throw new InteractionError("Failed to simulate transaction", {
2799
+ address: options.address,
2800
+ functionName: options.functionName,
2801
+ chain: options.chain,
2802
+ error: error instanceof Error ? error.message : "Unknown error"
2803
+ });
2804
+ }
2805
+ }
2806
+ /**
2807
+ * Write to Core Space contract
2808
+ */
2809
+ async writeToCore(options) {
2810
+ const _coreClient = this.clientManager.getCoreClient();
2811
+ const hash = `0x${Array.from(
2812
+ { length: 64 },
2813
+ () => Math.floor(Math.random() * 16).toString(16)
2814
+ ).join("")}`;
2815
+ const result = {
2816
+ hash,
2817
+ from: "cfx:sender...",
2818
+ to: options.address,
2819
+ chain: "core"
2820
+ };
2821
+ if (options.waitForConfirmation) {
2822
+ result.blockNumber = 1000n;
2823
+ result.gasUsed = 50000n;
2824
+ result.status = "success";
2825
+ }
2826
+ return result;
2827
+ }
2828
+ /**
2829
+ * Write to eSpace contract
2830
+ */
2831
+ async writeToEvm(options) {
2832
+ const _evmClient = this.clientManager.getEvmClient();
2833
+ const hash = `0x${Array.from(
2834
+ { length: 64 },
2835
+ () => Math.floor(Math.random() * 16).toString(16)
2836
+ ).join("")}`;
2837
+ const result = {
2838
+ hash,
2839
+ from: "0xsender...",
2840
+ to: options.address,
2841
+ chain: "evm"
2842
+ };
2843
+ if (options.waitForConfirmation) {
2844
+ result.blockNumber = 2000n;
2845
+ result.gasUsed = 45000n;
2846
+ result.status = "success";
2847
+ }
2848
+ return result;
2849
+ }
2850
+ /**
2851
+ * Simulate Core Space contract write
2852
+ */
2853
+ async simulateCore(_options) {
2854
+ return {};
2855
+ }
2856
+ /**
2857
+ * Simulate eSpace contract write
2858
+ */
2859
+ async simulateEvm(_options) {
2860
+ return {};
2861
+ }
2862
+ /**
2863
+ * Batch write multiple transactions
2864
+ *
2865
+ * @param writes - Array of write operations
2866
+ * @returns Array of write results
2867
+ */
2868
+ async batchWrite(writes) {
2869
+ const results = [];
2870
+ for (const write of writes) {
2871
+ try {
2872
+ const result = await this.write(write);
2873
+ results.push(result);
2874
+ } catch (error) {
2875
+ console.error(`Failed to execute write:`, error);
2876
+ }
2877
+ }
2878
+ return results;
2879
+ }
2880
+ };
2881
+
2882
+ // src/utils/logger.ts
2883
+ var colors = {
2884
+ info: "\x1B[36m",
2885
+ // Cyan
2886
+ warn: "\x1B[33m",
2887
+ // Yellow
2888
+ error: "\x1B[31m",
2889
+ // Red
2890
+ success: "\x1B[32m",
2891
+ // Green
2892
+ debug: "\x1B[90m",
2893
+ // Gray
2894
+ reset: "\x1B[0m"
2895
+ // Reset
2896
+ };
2897
+ function formatMessage(level, message, ...args) {
2898
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2899
+ const formattedArgs = args.length > 0 ? ` ${args.map(
2900
+ (arg) => arg !== null && typeof arg === "object" ? JSON.stringify(
2901
+ arg,
2902
+ (_key, value) => typeof value === "bigint" ? value.toString() : value,
2903
+ 2
2904
+ ) : String(arg)
2905
+ ).join(" ")}` : "";
2906
+ return `[${timestamp}] ${level.toUpperCase()}: ${message}${formattedArgs}`;
2907
+ }
2908
+ function handleLog(level, color, fn, messageOrObj, maybeMsg, ...args) {
2909
+ let msg = typeof messageOrObj === "string" ? messageOrObj : String(messageOrObj);
2910
+ let objs = maybeMsg !== void 0 ? [maybeMsg, ...args] : args;
2911
+ if (typeof messageOrObj === "object" && typeof maybeMsg === "string") {
2912
+ msg = maybeMsg;
2913
+ objs = [messageOrObj, ...args];
2914
+ }
2915
+ fn(color + formatMessage(level, msg, ...objs) + colors.reset);
2916
+ }
2917
+ var logger = {
2918
+ info(m, m2, ...args) {
2919
+ handleLog("info", colors.info, console.log, m, m2, ...args);
2920
+ },
2921
+ warn(m, m2, ...args) {
2922
+ handleLog("warn", colors.warn, console.warn, m, m2, ...args);
2923
+ },
2924
+ error(m, m2, ...args) {
2925
+ handleLog("error", colors.error, console.error, m, m2, ...args);
2926
+ },
2927
+ success(m, m2, ...args) {
2928
+ handleLog("success", colors.success, console.log, m, m2, ...args);
2929
+ },
2930
+ debug(m, m2, ...args) {
2931
+ handleLog("debug", colors.debug, console.log, m, m2, ...args);
2932
+ }
2933
+ };
2934
+
2935
+ // src/wallet/types/index.ts
2936
+ var WalletError = class extends Error {
2937
+ constructor(message, code, context) {
2938
+ super(message);
2939
+ this.code = code;
2940
+ this.context = context;
2941
+ this.name = "WalletError";
2942
+ }
2943
+ };
2944
+ var SessionKeyError = class extends WalletError {
2945
+ constructor(message, context) {
2946
+ super(message, "SESSION_KEY_ERROR", context);
2947
+ this.name = "SessionKeyError";
2948
+ }
2949
+ };
2950
+ var BatcherError = class extends WalletError {
2951
+ constructor(message, context) {
2952
+ super(message, "BATCHER_ERROR", context);
2953
+ this.name = "BatcherError";
2954
+ }
2955
+ };
2956
+ var EmbeddedWalletError = class extends WalletError {
2957
+ constructor(message, context) {
2958
+ super(message, "EMBEDDED_WALLET_ERROR", context);
2959
+ this.name = "EmbeddedWalletError";
2960
+ }
2961
+ };
2962
+
2963
+ // src/wallet/batching/batcher.ts
2964
+ var TransactionBatcher = class {
2965
+ coreBatch = [];
2966
+ evmBatch = [];
2967
+ autoExecuteTimer = null;
2968
+ options;
2969
+ constructor(options = {}) {
2970
+ this.options = {
2971
+ maxBatchSize: options.maxBatchSize || 10,
2972
+ autoExecuteTimeout: options.autoExecuteTimeout || 0,
2973
+ // 0 = disabled
2974
+ minGasPrice: options.minGasPrice || 0n
2975
+ };
2976
+ }
2977
+ /**
2978
+ * Add transaction to batch
2979
+ *
2980
+ * @param tx - Transaction to add
2981
+ * @returns Transaction ID
2982
+ */
2983
+ addTransaction(tx) {
2984
+ const transaction = {
2985
+ id: `tx_${Date.now()}_${Math.random().toString(36).substring(7)}`,
2986
+ ...tx,
2987
+ addedAt: /* @__PURE__ */ new Date()
2988
+ };
2989
+ const batch = tx.chain === "core" ? this.coreBatch : this.evmBatch;
2990
+ batch.push(transaction);
2991
+ if (this.options.autoExecuteTimeout > 0 && batch.length === 1) {
2992
+ this.startAutoExecuteTimer(tx.chain);
2993
+ }
2994
+ if (batch.length >= this.options.maxBatchSize) {
2995
+ console.log(
2996
+ `Batch for ${tx.chain} is full (${batch.length} transactions)`
2997
+ );
2998
+ }
2999
+ return transaction.id;
3000
+ }
3001
+ /**
3002
+ * Remove transaction from batch
3003
+ *
3004
+ * @param transactionId - Transaction ID
3005
+ * @param chain - Chain type
3006
+ * @returns true if removed, false if not found
3007
+ */
3008
+ removeTransaction(transactionId, chain) {
3009
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
3010
+ const index = batch.findIndex((tx) => tx.id === transactionId);
3011
+ if (index !== -1) {
3012
+ batch.splice(index, 1);
3013
+ return true;
3014
+ }
3015
+ return false;
3016
+ }
3017
+ /**
3018
+ * Get pending transactions for a chain
3019
+ *
3020
+ * @param chain - Chain type
3021
+ * @returns Array of pending transactions
3022
+ */
3023
+ getPendingTransactions(chain) {
3024
+ return chain === "core" ? [...this.coreBatch] : [...this.evmBatch];
3025
+ }
3026
+ /**
3027
+ * Get batch statistics
3028
+ *
3029
+ * @param chain - Chain type
3030
+ * @returns Batch statistics
3031
+ */
3032
+ getBatchStats(chain) {
3033
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
3034
+ return {
3035
+ count: batch.length,
3036
+ totalValue: batch.reduce((sum, tx) => sum + (tx.value || 0n), 0n),
3037
+ avgGasLimit: batch.length > 0 ? batch.reduce((sum, tx) => sum + (tx.gasLimit || 0n), 0n) / BigInt(batch.length) : 0n,
3038
+ oldestTransaction: batch[0]?.addedAt
3039
+ };
3040
+ }
3041
+ /**
3042
+ * Execute batch of transactions
3043
+ *
3044
+ * Note: This is a simplified implementation. In production, you would:
3045
+ * - Use multicall contracts for actual batching
3046
+ * - Handle gas estimation
3047
+ * - Implement retry logic
3048
+ * - Support different batching strategies (sequential, parallel, etc.)
3049
+ *
3050
+ * @param chain - Chain to execute on
3051
+ * @param signer - Function to sign and send transactions
3052
+ * @returns Batch execution result
3053
+ */
3054
+ async executeBatch(chain, signer) {
3055
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
3056
+ if (batch.length === 0) {
3057
+ throw new BatcherError("No transactions in batch", { chain });
3058
+ }
3059
+ this.stopAutoExecuteTimer();
3060
+ const batchId = `batch_${Date.now()}_${Math.random().toString(36).substring(7)}`;
3061
+ const transactionHashes = [];
3062
+ let successCount = 0;
3063
+ let failureCount = 0;
3064
+ let totalGasUsed = 0n;
3065
+ for (const tx of batch) {
3066
+ try {
3067
+ if (signer) {
3068
+ const hash = await signer(tx);
3069
+ transactionHashes.push(hash);
3070
+ successCount++;
3071
+ totalGasUsed += tx.gasLimit || 21000n;
3072
+ } else {
3073
+ const hash = `0x${Array.from(
3074
+ { length: 64 },
3075
+ () => Math.floor(Math.random() * 16).toString(16)
3076
+ ).join("")}`;
3077
+ transactionHashes.push(hash);
3078
+ successCount++;
3079
+ totalGasUsed += tx.gasLimit || 21000n;
3080
+ }
3081
+ } catch (error) {
3082
+ failureCount++;
3083
+ console.error(`Transaction ${tx.id} failed:`, error);
3084
+ }
3085
+ }
3086
+ if (chain === "core") {
3087
+ this.coreBatch = [];
3088
+ } else {
3089
+ this.evmBatch = [];
3090
+ }
3091
+ return {
3092
+ batchId,
3093
+ transactionHashes,
3094
+ successCount,
3095
+ failureCount,
3096
+ executedAt: /* @__PURE__ */ new Date(),
3097
+ totalGasUsed,
3098
+ chain
3099
+ };
3100
+ }
3101
+ /**
3102
+ * Clear all pending transactions
3103
+ *
3104
+ * @param chain - Chain to clear, or undefined to clear both
3105
+ */
3106
+ clearBatch(chain) {
3107
+ if (chain === "core" || chain === void 0) {
3108
+ this.coreBatch = [];
3109
+ }
3110
+ if (chain === "evm" || chain === void 0) {
3111
+ this.evmBatch = [];
3112
+ }
3113
+ this.stopAutoExecuteTimer();
3114
+ }
3115
+ /**
3116
+ * Start auto-execute timer
3117
+ */
3118
+ startAutoExecuteTimer(chain) {
3119
+ if (this.options.autoExecuteTimeout <= 0) return;
3120
+ this.stopAutoExecuteTimer();
3121
+ this.autoExecuteTimer = setTimeout(() => {
3122
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
3123
+ if (batch.length > 0) {
3124
+ console.log(
3125
+ `Auto-executing batch for ${chain} (${batch.length} transactions)`
3126
+ );
3127
+ }
3128
+ }, this.options.autoExecuteTimeout);
3129
+ }
3130
+ /**
3131
+ * Stop auto-execute timer
3132
+ */
3133
+ stopAutoExecuteTimer() {
3134
+ if (this.autoExecuteTimer) {
3135
+ clearTimeout(this.autoExecuteTimer);
3136
+ this.autoExecuteTimer = null;
3137
+ }
3138
+ }
3139
+ /**
3140
+ * Get batcher configuration
3141
+ */
3142
+ getOptions() {
3143
+ return { ...this.options };
3144
+ }
3145
+ /**
3146
+ * Update batcher configuration
3147
+ */
3148
+ updateOptions(options) {
3149
+ this.options = {
3150
+ ...this.options,
3151
+ ...options
3152
+ };
3153
+ if (options.autoExecuteTimeout !== void 0) {
3154
+ this.stopAutoExecuteTimer();
3155
+ if (this.coreBatch.length > 0) {
3156
+ this.startAutoExecuteTimer("core");
3157
+ }
3158
+ if (this.evmBatch.length > 0) {
3159
+ this.startAutoExecuteTimer("evm");
3160
+ }
3161
+ }
3162
+ }
3163
+ };
3164
+
3165
+ // src/wallet/derivation.ts
3166
+ var import_bip32 = require("@scure/bip32");
3167
+ var import_bip39 = require("@scure/bip39");
3168
+ var import_english = require("@scure/bip39/wordlists/english.js");
3169
+ var import_accounts3 = require("cive/accounts");
3170
+ var import_viem4 = require("viem");
3171
+ var import_accounts4 = require("viem/accounts");
3172
+
3173
+ // src/wallet/types.ts
3174
+ var COIN_TYPES = {
3175
+ /** Conflux Core Space - registered coin type 503 */
3176
+ CONFLUX: 503,
3177
+ /** Ethereum/eSpace - standard coin type 60 */
3178
+ ETHEREUM: 60
3179
+ };
3180
+ var CORE_NETWORK_IDS = {
3181
+ /** Local development network */
3182
+ LOCAL: 2029,
3183
+ /** Testnet */
3184
+ TESTNET: 1,
3185
+ /** Mainnet */
3186
+ MAINNET: 1029
3187
+ };
3188
+
3189
+ // src/wallet/derivation.ts
3190
+ function generateMnemonic(strength = 128) {
3191
+ return (0, import_bip39.generateMnemonic)(import_english.wordlist, strength);
3192
+ }
3193
+ function validateMnemonic(mnemonic) {
3194
+ const normalizedMnemonic = mnemonic.trim().toLowerCase();
3195
+ const words = normalizedMnemonic.split(/\s+/);
3196
+ const wordCount = words.length;
3197
+ if (wordCount !== 12 && wordCount !== 24) {
3198
+ return {
3199
+ valid: false,
3200
+ wordCount,
3201
+ error: `Invalid word count: ${wordCount}. Must be 12 or 24.`
3202
+ };
3203
+ }
3204
+ const valid = (0, import_bip39.validateMnemonic)(normalizedMnemonic, import_english.wordlist);
3205
+ return {
3206
+ valid,
3207
+ wordCount,
3208
+ error: valid ? void 0 : "Invalid mnemonic: checksum verification failed"
3209
+ };
3210
+ }
3211
+ function deriveAccounts(mnemonic, options) {
3212
+ const {
3213
+ count,
3214
+ startIndex = 0,
3215
+ coreNetworkId = CORE_NETWORK_IDS.LOCAL,
3216
+ accountType = "standard"
3217
+ } = options;
3218
+ const validation = validateMnemonic(mnemonic);
3219
+ if (!validation.valid) {
3220
+ throw new Error(`Invalid mnemonic: ${validation.error}`);
3221
+ }
3222
+ const normalizedMnemonic = mnemonic.trim().toLowerCase();
3223
+ const seed = (0, import_bip39.mnemonicToSeedSync)(normalizedMnemonic);
3224
+ const masterKey = import_bip32.HDKey.fromMasterSeed(seed);
3225
+ const accounts = [];
3226
+ const accountTypeIndex = accountType === "standard" ? 0 : 1;
3227
+ for (let i = startIndex; i < startIndex + count; i++) {
3228
+ const corePath = `m/44'/${COIN_TYPES.CONFLUX}'/${accountTypeIndex}'/0/${i}`;
3229
+ const coreKey = masterKey.derive(corePath);
3230
+ const evmPath = `m/44'/${COIN_TYPES.ETHEREUM}'/${accountTypeIndex}'/0/${i}`;
3231
+ const evmKey = masterKey.derive(evmPath);
3232
+ if (!coreKey.privateKey || !evmKey.privateKey) {
3233
+ throw new Error(`Failed to derive keys at index ${i}`);
3234
+ }
3235
+ const corePrivateKey = (0, import_viem4.bytesToHex)(coreKey.privateKey);
3236
+ const evmPrivateKey = (0, import_viem4.bytesToHex)(evmKey.privateKey);
3237
+ const coreAccount = (0, import_accounts3.privateKeyToAccount)(corePrivateKey, {
3238
+ networkId: coreNetworkId
3239
+ });
3240
+ const evmAccount = (0, import_accounts4.privateKeyToAccount)(evmPrivateKey);
3241
+ accounts.push({
3242
+ index: i,
3243
+ coreAddress: coreAccount.address,
3244
+ evmAddress: evmAccount.address,
3245
+ corePrivateKey,
3246
+ evmPrivateKey,
3247
+ paths: {
3248
+ core: corePath,
3249
+ evm: evmPath
3250
+ }
3251
+ });
3252
+ }
3253
+ return accounts;
3254
+ }
3255
+ function deriveAccount(mnemonic, index, coreNetworkId = CORE_NETWORK_IDS.LOCAL, accountType = "standard") {
3256
+ const accounts = deriveAccounts(mnemonic, {
3257
+ count: 1,
3258
+ startIndex: index,
3259
+ coreNetworkId,
3260
+ accountType
3261
+ });
3262
+ return accounts[0];
3263
+ }
3264
+ function deriveFaucetAccount(mnemonic, coreNetworkId = CORE_NETWORK_IDS.LOCAL) {
3265
+ return deriveAccount(mnemonic, 0, coreNetworkId, "mining");
3266
+ }
3267
+
3268
+ // src/wallet/embedded/custody.ts
3269
+ var import_accounts5 = require("viem/accounts");
3270
+ var EmbeddedWalletManager = class {
3271
+ wallets = /* @__PURE__ */ new Map();
3272
+ options;
3273
+ constructor(options = {}) {
3274
+ this.options = {
3275
+ algorithm: options.algorithm || "aes-256-gcm",
3276
+ iterations: options.iterations || 1e5,
3277
+ autoCreate: options.autoCreate !== false
3278
+ // Default true
3279
+ };
3280
+ }
3281
+ /**
3282
+ * Create a new embedded wallet for a user
3283
+ *
3284
+ * @param userId - User identifier
3285
+ * @param password - Encryption password
3286
+ * @returns Created wallet (without private key)
3287
+ */
3288
+ async createWallet(userId, password) {
3289
+ if (this.wallets.has(userId)) {
3290
+ throw new EmbeddedWalletError("Wallet already exists", { userId });
3291
+ }
3292
+ const privateKey = (0, import_accounts5.generatePrivateKey)();
3293
+ const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
3294
+ const { encrypted, iv, salt } = await this.encryptPrivateKey(
3295
+ privateKey,
3296
+ password
3297
+ );
3298
+ const evmAddress = account.address;
3299
+ const coreAddress = `cfx:${evmAddress.slice(2)}`;
3300
+ const wallet = {
3301
+ userId,
3302
+ coreAddress,
3303
+ evmAddress,
3304
+ encryptedPrivateKey: encrypted,
3305
+ encryption: {
3306
+ algorithm: this.options.algorithm,
3307
+ iv,
3308
+ salt
3309
+ },
3310
+ createdAt: /* @__PURE__ */ new Date(),
3311
+ lastAccessedAt: /* @__PURE__ */ new Date(),
3312
+ isActive: true
3313
+ };
3314
+ this.wallets.set(userId, wallet);
3315
+ const { encryptedPrivateKey: _, ...publicWallet } = wallet;
3316
+ return publicWallet;
3317
+ }
3318
+ /**
3319
+ * Get wallet info (without private key)
3320
+ *
3321
+ * @param userId - User identifier
3322
+ * @returns Wallet info or undefined
3323
+ */
3324
+ getWallet(userId) {
3325
+ const wallet = this.wallets.get(userId);
3326
+ if (!wallet) return void 0;
3327
+ wallet.lastAccessedAt = /* @__PURE__ */ new Date();
3328
+ const { encryptedPrivateKey: _, ...publicWallet } = wallet;
3329
+ return publicWallet;
3330
+ }
3331
+ /**
3332
+ * Check if user has a wallet
3333
+ *
3334
+ * @param userId - User identifier
3335
+ * @returns true if wallet exists
3336
+ */
3337
+ hasWallet(userId) {
3338
+ return this.wallets.has(userId);
3339
+ }
3340
+ /**
3341
+ * Sign transaction with user's embedded wallet
3342
+ *
3343
+ * @param userId - User identifier
3344
+ * @param password - Decryption password
3345
+ * @param request - Transaction request
3346
+ * @returns Signed transaction
3347
+ */
3348
+ async signTransaction(userId, password, request) {
3349
+ const wallet = this.wallets.get(userId);
3350
+ if (!wallet) {
3351
+ throw new EmbeddedWalletError("Wallet not found", { userId });
3352
+ }
3353
+ if (!wallet.isActive) {
3354
+ throw new EmbeddedWalletError("Wallet is not active", { userId });
3355
+ }
3356
+ const privateKey = await this.decryptPrivateKey(
3357
+ wallet.encryptedPrivateKey,
3358
+ password,
3359
+ wallet.encryption.iv,
3360
+ wallet.encryption.salt
3361
+ );
3362
+ const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
3363
+ wallet.lastAccessedAt = /* @__PURE__ */ new Date();
3364
+ const serialized = JSON.stringify({
3365
+ from: account.address,
3366
+ ...request,
3367
+ value: request.value?.toString(),
3368
+ gasLimit: request.gasLimit?.toString(),
3369
+ gasPrice: request.gasPrice?.toString()
3370
+ });
3371
+ const signature = await account.signMessage({
3372
+ message: serialized
3373
+ });
3374
+ return {
3375
+ rawTransaction: signature,
3376
+ hash: `0x${Array.from(
3377
+ { length: 64 },
3378
+ () => Math.floor(Math.random() * 16).toString(16)
3379
+ ).join("")}`,
3380
+ from: account.address,
3381
+ chain: request.chain
3382
+ };
3383
+ }
3384
+ /**
3385
+ * Export wallet for user backup
3386
+ *
3387
+ * @param userId - User identifier
3388
+ * @param password - Encryption password
3389
+ * @returns Encrypted wallet export
3390
+ */
3391
+ async exportWallet(userId, password) {
3392
+ const wallet = this.wallets.get(userId);
3393
+ if (!wallet) {
3394
+ throw new EmbeddedWalletError("Wallet not found", { userId });
3395
+ }
3396
+ const exportData = JSON.stringify({
3397
+ coreAddress: wallet.coreAddress,
3398
+ evmAddress: wallet.evmAddress,
3399
+ encryptedPrivateKey: wallet.encryptedPrivateKey,
3400
+ encryption: wallet.encryption
3401
+ });
3402
+ const { encrypted, iv, salt } = await this.encryptPrivateKey(
3403
+ exportData,
3404
+ password
3405
+ );
3406
+ return {
3407
+ userId,
3408
+ encryptedData: encrypted,
3409
+ encryption: {
3410
+ algorithm: this.options.algorithm,
3411
+ iv,
3412
+ salt
3413
+ },
3414
+ exportedAt: /* @__PURE__ */ new Date()
3415
+ };
3416
+ }
3417
+ /**
3418
+ * Deactivate wallet
3419
+ *
3420
+ * @param userId - User identifier
3421
+ */
3422
+ deactivateWallet(userId) {
3423
+ const wallet = this.wallets.get(userId);
3424
+ if (wallet) {
3425
+ wallet.isActive = false;
3426
+ }
3427
+ }
3428
+ /**
3429
+ * Delete wallet permanently
3430
+ *
3431
+ * WARNING: This operation cannot be undone
3432
+ *
3433
+ * @param userId - User identifier
3434
+ * @returns true if deleted, false if not found
3435
+ */
3436
+ deleteWallet(userId) {
3437
+ return this.wallets.delete(userId);
3438
+ }
3439
+ /**
3440
+ * List all wallets (without private keys)
3441
+ *
3442
+ * @returns Array of wallet info
3443
+ */
3444
+ listWallets() {
3445
+ return Array.from(this.wallets.values()).map((wallet) => {
3446
+ const { encryptedPrivateKey: _, ...publicWallet } = wallet;
3447
+ return publicWallet;
3448
+ });
3449
+ }
3450
+ /**
3451
+ * Get wallet statistics
3452
+ *
3453
+ * @returns Wallet statistics
3454
+ */
3455
+ getStats() {
3456
+ const all = Array.from(this.wallets.values());
3457
+ const active = all.filter((w) => w.isActive);
3458
+ return {
3459
+ total: all.length,
3460
+ active: active.length,
3461
+ inactive: all.length - active.length
3462
+ };
3463
+ }
3464
+ /**
3465
+ * Encrypt private key
3466
+ *
3467
+ * NOTE: Simplified implementation for demonstration
3468
+ * Production should use proper encryption (node:crypto, @noble/ciphers, etc.)
3469
+ */
3470
+ async encryptPrivateKey(data, password) {
3471
+ const iv = Array.from(
3472
+ { length: 16 },
3473
+ () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
3474
+ ).join("");
3475
+ const salt = Array.from(
3476
+ { length: 32 },
3477
+ () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
3478
+ ).join("");
3479
+ const mockEncrypted = Buffer.from(
3480
+ JSON.stringify({ data, password, iv, salt })
3481
+ ).toString("base64");
3482
+ return {
3483
+ encrypted: mockEncrypted,
3484
+ iv,
3485
+ salt
3486
+ };
3487
+ }
3488
+ /**
3489
+ * Decrypt private key
3490
+ *
3491
+ * NOTE: Simplified implementation for demonstration
3492
+ */
3493
+ async decryptPrivateKey(encrypted, password, _iv, _salt) {
3494
+ try {
3495
+ const decoded = JSON.parse(
3496
+ Buffer.from(encrypted, "base64").toString("utf-8")
3497
+ );
3498
+ if (decoded.password !== password) {
3499
+ throw new Error("Invalid password");
3500
+ }
3501
+ return decoded.data;
3502
+ } catch (error) {
3503
+ throw new EmbeddedWalletError("Failed to decrypt private key", {
3504
+ error: error instanceof Error ? error.message : "Unknown error"
3505
+ });
3506
+ }
3507
+ }
3508
+ };
3509
+
3510
+ // src/wallet/session-keys/manager.ts
3511
+ var import_accounts6 = require("viem/accounts");
3512
+ var SessionKeyManager = class {
3513
+ sessionKeys = /* @__PURE__ */ new Map();
3514
+ /**
3515
+ * Generate a new session key
3516
+ *
3517
+ * @param parentAddress - Parent wallet address
3518
+ * @param options - Session key configuration
3519
+ * @returns Created session key
3520
+ */
3521
+ generateSessionKey(parentAddress, options) {
3522
+ const privateKey = `0x${Array.from(
3523
+ { length: 64 },
3524
+ () => Math.floor(Math.random() * 16).toString(16)
3525
+ ).join("")}`;
3526
+ const account = (0, import_accounts6.privateKeyToAccount)(privateKey);
3527
+ const ttl = options.ttl || 3600;
3528
+ const now = /* @__PURE__ */ new Date();
3529
+ const expiresAt = new Date(now.getTime() + ttl * 1e3);
3530
+ const sessionKey = {
3531
+ id: `sk_${Date.now()}_${Math.random().toString(36).substring(7)}`,
3532
+ privateKey,
3533
+ address: account.address,
3534
+ parentAddress,
3535
+ ttl,
3536
+ expiresAt,
3537
+ permissions: options.permissions || {},
3538
+ createdAt: now,
3539
+ isActive: true,
3540
+ chain: options.chain
3541
+ };
3542
+ this.sessionKeys.set(sessionKey.id, sessionKey);
3543
+ return sessionKey;
3544
+ }
3545
+ /**
3546
+ * Get session key by ID
3547
+ *
3548
+ * @param sessionKeyId - Session key identifier
3549
+ * @returns Session key or undefined
3550
+ */
3551
+ getSessionKey(sessionKeyId) {
3552
+ const sessionKey = this.sessionKeys.get(sessionKeyId);
3553
+ if (sessionKey && /* @__PURE__ */ new Date() > sessionKey.expiresAt) {
3554
+ sessionKey.isActive = false;
3555
+ }
3556
+ return sessionKey;
3557
+ }
3558
+ /**
3559
+ * Revoke a session key
3560
+ *
3561
+ * @param sessionKeyId - Session key identifier
3562
+ */
3563
+ revokeSessionKey(sessionKeyId) {
3564
+ const sessionKey = this.sessionKeys.get(sessionKeyId);
3565
+ if (sessionKey) {
3566
+ sessionKey.isActive = false;
3567
+ }
3568
+ }
3569
+ /**
3570
+ * List all session keys for a parent address
3571
+ *
3572
+ * @param parentAddress - Parent wallet address
3573
+ * @returns Array of session keys
3574
+ */
3575
+ listSessionKeys(parentAddress) {
3576
+ return Array.from(this.sessionKeys.values()).filter(
3577
+ (sk) => sk.parentAddress.toLowerCase() === parentAddress.toLowerCase()
3578
+ );
3579
+ }
3580
+ /**
3581
+ * List active session keys for a parent address
3582
+ *
3583
+ * @param parentAddress - Parent wallet address
3584
+ * @returns Array of active session keys
3585
+ */
3586
+ listActiveSessionKeys(parentAddress) {
3587
+ return this.listSessionKeys(parentAddress).filter(
3588
+ (sk) => sk.isActive && /* @__PURE__ */ new Date() <= sk.expiresAt
3589
+ );
3590
+ }
3591
+ /**
3592
+ * Validate transaction against session key permissions
3593
+ *
3594
+ * @param sessionKey - Session key
3595
+ * @param request - Transaction request
3596
+ * @throws SessionKeyError if validation fails
3597
+ */
3598
+ validateTransaction(sessionKey, request) {
3599
+ if (!sessionKey.isActive) {
3600
+ throw new SessionKeyError("Session key is not active", {
3601
+ sessionKeyId: sessionKey.id
3602
+ });
3603
+ }
3604
+ if (/* @__PURE__ */ new Date() > sessionKey.expiresAt) {
3605
+ throw new SessionKeyError("Session key has expired", {
3606
+ sessionKeyId: sessionKey.id,
3607
+ expiresAt: sessionKey.expiresAt
3608
+ });
3609
+ }
3610
+ if (request.chain !== sessionKey.chain) {
3611
+ throw new SessionKeyError("Chain mismatch", {
3612
+ sessionKeyId: sessionKey.id,
3613
+ allowedChain: sessionKey.chain,
3614
+ requestedChain: request.chain
3615
+ });
3616
+ }
3617
+ const { permissions } = sessionKey;
3618
+ if (permissions.maxValue && request.value && request.value > permissions.maxValue) {
3619
+ throw new SessionKeyError("Transaction value exceeds maximum", {
3620
+ sessionKeyId: sessionKey.id,
3621
+ maxValue: permissions.maxValue.toString(),
3622
+ requestedValue: request.value.toString()
3623
+ });
3624
+ }
3625
+ if (permissions.contracts && permissions.contracts.length > 0) {
3626
+ const isWhitelisted = permissions.contracts.some(
3627
+ (addr) => addr.toLowerCase() === request.to.toLowerCase()
3628
+ );
3629
+ if (!isWhitelisted) {
3630
+ throw new SessionKeyError("Contract not whitelisted", {
3631
+ sessionKeyId: sessionKey.id,
3632
+ whitelistedContracts: permissions.contracts,
3633
+ requestedContract: request.to
3634
+ });
3635
+ }
3636
+ }
3637
+ if (permissions.operations && permissions.operations.length > 0 && request.data) {
3638
+ const selector = request.data.slice(0, 10);
3639
+ const isAllowed = permissions.operations.some(
3640
+ (op) => op.toLowerCase() === selector.toLowerCase()
3641
+ );
3642
+ if (!isAllowed) {
3643
+ throw new SessionKeyError("Operation not allowed", {
3644
+ sessionKeyId: sessionKey.id,
3645
+ allowedOperations: permissions.operations,
3646
+ requestedOperation: selector
3647
+ });
3648
+ }
3649
+ }
3650
+ }
3651
+ /**
3652
+ * Sign transaction with session key
3653
+ *
3654
+ * @param sessionKeyId - Session key identifier
3655
+ * @param request - Transaction request
3656
+ * @returns Signed transaction
3657
+ * @throws SessionKeyError if session key is invalid or transaction violates permissions
3658
+ */
3659
+ async signWithSessionKey(sessionKeyId, request) {
3660
+ const sessionKey = this.sessionKeys.get(sessionKeyId);
3661
+ if (!sessionKey) {
3662
+ throw new SessionKeyError("Session key not found", { sessionKeyId });
3663
+ }
3664
+ this.validateTransaction(sessionKey, request);
3665
+ const account = (0, import_accounts6.privateKeyToAccount)(sessionKey.privateKey);
3666
+ const serialized = JSON.stringify({
3667
+ from: account.address,
3668
+ to: request.to,
3669
+ value: request.value?.toString(),
3670
+ data: request.data,
3671
+ gasLimit: request.gasLimit?.toString(),
3672
+ gasPrice: request.gasPrice?.toString(),
3673
+ nonce: request.nonce,
3674
+ chain: request.chain
3675
+ });
3676
+ const signature = await account.signMessage({
3677
+ message: serialized
3678
+ });
3679
+ return {
3680
+ rawTransaction: signature,
3681
+ hash: `0x${Array.from(
3682
+ { length: 64 },
3683
+ () => Math.floor(Math.random() * 16).toString(16)
3684
+ ).join("")}`,
3685
+ from: account.address,
3686
+ chain: request.chain
3687
+ };
3688
+ }
3689
+ /**
3690
+ * Clean up expired session keys
3691
+ *
3692
+ * @returns Number of removed session keys
3693
+ */
3694
+ cleanupExpired() {
3695
+ const now = /* @__PURE__ */ new Date();
3696
+ let removed = 0;
3697
+ for (const [id, sessionKey] of this.sessionKeys.entries()) {
3698
+ if (now > sessionKey.expiresAt) {
3699
+ this.sessionKeys.delete(id);
3700
+ removed++;
3701
+ }
3702
+ }
3703
+ return removed;
3704
+ }
3705
+ /**
3706
+ * Get session key statistics
3707
+ *
3708
+ * @returns Statistics about session keys
3709
+ */
3710
+ getStats() {
3711
+ const all = Array.from(this.sessionKeys.values());
3712
+ const active = all.filter(
3713
+ (sk) => sk.isActive && /* @__PURE__ */ new Date() <= sk.expiresAt
3714
+ );
3715
+ const expired = all.filter((sk) => /* @__PURE__ */ new Date() > sk.expiresAt);
3716
+ return {
3717
+ total: all.length,
3718
+ active: active.length,
3719
+ expired: expired.length,
3720
+ inactive: all.length - active.length - expired.length
3721
+ };
3722
+ }
3723
+ };
3724
+ // Annotate the CommonJS export names for ESM import in node:
3725
+ 0 && (module.exports = {
3726
+ BatcherError,
3727
+ CORE_LOCAL,
3728
+ CORE_MAINNET,
3729
+ CORE_TESTNET,
3730
+ ClientManager,
3731
+ ContractDeployer,
3732
+ ContractError,
3733
+ ContractReader,
3734
+ ContractWriter,
3735
+ CoreClient,
3736
+ CoreTestClient,
3737
+ CoreWalletClient,
3738
+ DeploymentError,
3739
+ ERC1155_ABI,
3740
+ ERC20_ABI,
3741
+ ERC721_ABI,
3742
+ EVM_LOCAL,
3743
+ EVM_MAINNET,
3744
+ EVM_TESTNET,
3745
+ EmbeddedWalletError,
3746
+ EmbeddedWalletManager,
3747
+ EspaceClient,
3748
+ EspaceTestClient,
3749
+ EspaceWalletClient,
3750
+ InteractionError,
3751
+ SessionKeyError,
3752
+ SessionKeyManager,
3753
+ TransactionBatcher,
3754
+ WalletError,
3755
+ defaultNetworkSelector,
3756
+ deriveAccount,
3757
+ deriveAccounts,
3758
+ deriveFaucetAccount,
3759
+ formatCFX,
3760
+ formatUnits,
3761
+ generateMnemonic,
3762
+ getChainConfig,
3763
+ getCoreChains,
3764
+ getEvmChains,
3765
+ getMainnetChains,
3766
+ isCoreAddress,
3767
+ isEspaceAddress,
3768
+ logger,
3769
+ parseCFX,
3770
+ parseUnits,
3771
+ validateMnemonic
3772
+ });
3773
+ //# sourceMappingURL=index.cjs.map