@cfxdevkit/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +72 -0
  3. package/README.md +257 -0
  4. package/dist/clients/index.cjs +2053 -0
  5. package/dist/clients/index.cjs.map +1 -0
  6. package/dist/clients/index.d.cts +7 -0
  7. package/dist/clients/index.d.ts +7 -0
  8. package/dist/clients/index.js +2043 -0
  9. package/dist/clients/index.js.map +1 -0
  10. package/dist/config/index.cjs +423 -0
  11. package/dist/config/index.cjs.map +1 -0
  12. package/dist/config/index.d.cts +99 -0
  13. package/dist/config/index.d.ts +99 -0
  14. package/dist/config/index.js +380 -0
  15. package/dist/config/index.js.map +1 -0
  16. package/dist/config-BMtaWM0X.d.cts +165 -0
  17. package/dist/config-BMtaWM0X.d.ts +165 -0
  18. package/dist/core-C5qe16RS.d.ts +352 -0
  19. package/dist/core-RZA4aKwj.d.cts +352 -0
  20. package/dist/index-BhCpy6Fz.d.cts +165 -0
  21. package/dist/index-Qz84U9Oq.d.ts +165 -0
  22. package/dist/index.cjs +3773 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.cts +945 -0
  25. package/dist/index.d.ts +945 -0
  26. package/dist/index.js +3730 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/types/index.cjs +44 -0
  29. package/dist/types/index.cjs.map +1 -0
  30. package/dist/types/index.d.cts +5 -0
  31. package/dist/types/index.d.ts +5 -0
  32. package/dist/types/index.js +17 -0
  33. package/dist/types/index.js.map +1 -0
  34. package/dist/utils/index.cjs +83 -0
  35. package/dist/utils/index.cjs.map +1 -0
  36. package/dist/utils/index.d.cts +11 -0
  37. package/dist/utils/index.d.ts +11 -0
  38. package/dist/utils/index.js +56 -0
  39. package/dist/utils/index.js.map +1 -0
  40. package/dist/wallet/index.cjs +852 -0
  41. package/dist/wallet/index.cjs.map +1 -0
  42. package/dist/wallet/index.d.cts +726 -0
  43. package/dist/wallet/index.d.ts +726 -0
  44. package/dist/wallet/index.js +815 -0
  45. package/dist/wallet/index.js.map +1 -0
  46. package/package.json +119 -0
@@ -0,0 +1,852 @@
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/wallet/index.ts
21
+ var wallet_exports = {};
22
+ __export(wallet_exports, {
23
+ BatcherError: () => BatcherError,
24
+ COIN_TYPES: () => COIN_TYPES,
25
+ CORE_NETWORK_IDS: () => CORE_NETWORK_IDS,
26
+ EmbeddedWalletError: () => EmbeddedWalletError,
27
+ EmbeddedWalletManager: () => EmbeddedWalletManager,
28
+ SessionKeyError: () => SessionKeyError,
29
+ SessionKeyManager: () => SessionKeyManager,
30
+ TransactionBatcher: () => TransactionBatcher,
31
+ WalletError: () => WalletError,
32
+ deriveAccount: () => deriveAccount,
33
+ deriveAccounts: () => deriveAccounts,
34
+ deriveFaucetAccount: () => deriveFaucetAccount,
35
+ generateMnemonic: () => generateMnemonic,
36
+ getDerivationPath: () => getDerivationPath,
37
+ validateMnemonic: () => validateMnemonic
38
+ });
39
+ module.exports = __toCommonJS(wallet_exports);
40
+
41
+ // src/wallet/types/index.ts
42
+ var WalletError = class extends Error {
43
+ constructor(message, code, context) {
44
+ super(message);
45
+ this.code = code;
46
+ this.context = context;
47
+ this.name = "WalletError";
48
+ }
49
+ };
50
+ var SessionKeyError = class extends WalletError {
51
+ constructor(message, context) {
52
+ super(message, "SESSION_KEY_ERROR", context);
53
+ this.name = "SessionKeyError";
54
+ }
55
+ };
56
+ var BatcherError = class extends WalletError {
57
+ constructor(message, context) {
58
+ super(message, "BATCHER_ERROR", context);
59
+ this.name = "BatcherError";
60
+ }
61
+ };
62
+ var EmbeddedWalletError = class extends WalletError {
63
+ constructor(message, context) {
64
+ super(message, "EMBEDDED_WALLET_ERROR", context);
65
+ this.name = "EmbeddedWalletError";
66
+ }
67
+ };
68
+
69
+ // src/wallet/batching/batcher.ts
70
+ var TransactionBatcher = class {
71
+ coreBatch = [];
72
+ evmBatch = [];
73
+ autoExecuteTimer = null;
74
+ options;
75
+ constructor(options = {}) {
76
+ this.options = {
77
+ maxBatchSize: options.maxBatchSize || 10,
78
+ autoExecuteTimeout: options.autoExecuteTimeout || 0,
79
+ // 0 = disabled
80
+ minGasPrice: options.minGasPrice || 0n
81
+ };
82
+ }
83
+ /**
84
+ * Add transaction to batch
85
+ *
86
+ * @param tx - Transaction to add
87
+ * @returns Transaction ID
88
+ */
89
+ addTransaction(tx) {
90
+ const transaction = {
91
+ id: `tx_${Date.now()}_${Math.random().toString(36).substring(7)}`,
92
+ ...tx,
93
+ addedAt: /* @__PURE__ */ new Date()
94
+ };
95
+ const batch = tx.chain === "core" ? this.coreBatch : this.evmBatch;
96
+ batch.push(transaction);
97
+ if (this.options.autoExecuteTimeout > 0 && batch.length === 1) {
98
+ this.startAutoExecuteTimer(tx.chain);
99
+ }
100
+ if (batch.length >= this.options.maxBatchSize) {
101
+ console.log(
102
+ `Batch for ${tx.chain} is full (${batch.length} transactions)`
103
+ );
104
+ }
105
+ return transaction.id;
106
+ }
107
+ /**
108
+ * Remove transaction from batch
109
+ *
110
+ * @param transactionId - Transaction ID
111
+ * @param chain - Chain type
112
+ * @returns true if removed, false if not found
113
+ */
114
+ removeTransaction(transactionId, chain) {
115
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
116
+ const index = batch.findIndex((tx) => tx.id === transactionId);
117
+ if (index !== -1) {
118
+ batch.splice(index, 1);
119
+ return true;
120
+ }
121
+ return false;
122
+ }
123
+ /**
124
+ * Get pending transactions for a chain
125
+ *
126
+ * @param chain - Chain type
127
+ * @returns Array of pending transactions
128
+ */
129
+ getPendingTransactions(chain) {
130
+ return chain === "core" ? [...this.coreBatch] : [...this.evmBatch];
131
+ }
132
+ /**
133
+ * Get batch statistics
134
+ *
135
+ * @param chain - Chain type
136
+ * @returns Batch statistics
137
+ */
138
+ getBatchStats(chain) {
139
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
140
+ return {
141
+ count: batch.length,
142
+ totalValue: batch.reduce((sum, tx) => sum + (tx.value || 0n), 0n),
143
+ avgGasLimit: batch.length > 0 ? batch.reduce((sum, tx) => sum + (tx.gasLimit || 0n), 0n) / BigInt(batch.length) : 0n,
144
+ oldestTransaction: batch[0]?.addedAt
145
+ };
146
+ }
147
+ /**
148
+ * Execute batch of transactions
149
+ *
150
+ * Note: This is a simplified implementation. In production, you would:
151
+ * - Use multicall contracts for actual batching
152
+ * - Handle gas estimation
153
+ * - Implement retry logic
154
+ * - Support different batching strategies (sequential, parallel, etc.)
155
+ *
156
+ * @param chain - Chain to execute on
157
+ * @param signer - Function to sign and send transactions
158
+ * @returns Batch execution result
159
+ */
160
+ async executeBatch(chain, signer) {
161
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
162
+ if (batch.length === 0) {
163
+ throw new BatcherError("No transactions in batch", { chain });
164
+ }
165
+ this.stopAutoExecuteTimer();
166
+ const batchId = `batch_${Date.now()}_${Math.random().toString(36).substring(7)}`;
167
+ const transactionHashes = [];
168
+ let successCount = 0;
169
+ let failureCount = 0;
170
+ let totalGasUsed = 0n;
171
+ for (const tx of batch) {
172
+ try {
173
+ if (signer) {
174
+ const hash = await signer(tx);
175
+ transactionHashes.push(hash);
176
+ successCount++;
177
+ totalGasUsed += tx.gasLimit || 21000n;
178
+ } else {
179
+ const hash = `0x${Array.from(
180
+ { length: 64 },
181
+ () => Math.floor(Math.random() * 16).toString(16)
182
+ ).join("")}`;
183
+ transactionHashes.push(hash);
184
+ successCount++;
185
+ totalGasUsed += tx.gasLimit || 21000n;
186
+ }
187
+ } catch (error) {
188
+ failureCount++;
189
+ console.error(`Transaction ${tx.id} failed:`, error);
190
+ }
191
+ }
192
+ if (chain === "core") {
193
+ this.coreBatch = [];
194
+ } else {
195
+ this.evmBatch = [];
196
+ }
197
+ return {
198
+ batchId,
199
+ transactionHashes,
200
+ successCount,
201
+ failureCount,
202
+ executedAt: /* @__PURE__ */ new Date(),
203
+ totalGasUsed,
204
+ chain
205
+ };
206
+ }
207
+ /**
208
+ * Clear all pending transactions
209
+ *
210
+ * @param chain - Chain to clear, or undefined to clear both
211
+ */
212
+ clearBatch(chain) {
213
+ if (chain === "core" || chain === void 0) {
214
+ this.coreBatch = [];
215
+ }
216
+ if (chain === "evm" || chain === void 0) {
217
+ this.evmBatch = [];
218
+ }
219
+ this.stopAutoExecuteTimer();
220
+ }
221
+ /**
222
+ * Start auto-execute timer
223
+ */
224
+ startAutoExecuteTimer(chain) {
225
+ if (this.options.autoExecuteTimeout <= 0) return;
226
+ this.stopAutoExecuteTimer();
227
+ this.autoExecuteTimer = setTimeout(() => {
228
+ const batch = chain === "core" ? this.coreBatch : this.evmBatch;
229
+ if (batch.length > 0) {
230
+ console.log(
231
+ `Auto-executing batch for ${chain} (${batch.length} transactions)`
232
+ );
233
+ }
234
+ }, this.options.autoExecuteTimeout);
235
+ }
236
+ /**
237
+ * Stop auto-execute timer
238
+ */
239
+ stopAutoExecuteTimer() {
240
+ if (this.autoExecuteTimer) {
241
+ clearTimeout(this.autoExecuteTimer);
242
+ this.autoExecuteTimer = null;
243
+ }
244
+ }
245
+ /**
246
+ * Get batcher configuration
247
+ */
248
+ getOptions() {
249
+ return { ...this.options };
250
+ }
251
+ /**
252
+ * Update batcher configuration
253
+ */
254
+ updateOptions(options) {
255
+ this.options = {
256
+ ...this.options,
257
+ ...options
258
+ };
259
+ if (options.autoExecuteTimeout !== void 0) {
260
+ this.stopAutoExecuteTimer();
261
+ if (this.coreBatch.length > 0) {
262
+ this.startAutoExecuteTimer("core");
263
+ }
264
+ if (this.evmBatch.length > 0) {
265
+ this.startAutoExecuteTimer("evm");
266
+ }
267
+ }
268
+ }
269
+ };
270
+
271
+ // src/wallet/derivation.ts
272
+ var import_bip32 = require("@scure/bip32");
273
+ var import_bip39 = require("@scure/bip39");
274
+ var import_english = require("@scure/bip39/wordlists/english.js");
275
+ var import_accounts = require("cive/accounts");
276
+ var import_viem = require("viem");
277
+ var import_accounts2 = require("viem/accounts");
278
+
279
+ // src/wallet/types.ts
280
+ var COIN_TYPES = {
281
+ /** Conflux Core Space - registered coin type 503 */
282
+ CONFLUX: 503,
283
+ /** Ethereum/eSpace - standard coin type 60 */
284
+ ETHEREUM: 60
285
+ };
286
+ var CORE_NETWORK_IDS = {
287
+ /** Local development network */
288
+ LOCAL: 2029,
289
+ /** Testnet */
290
+ TESTNET: 1,
291
+ /** Mainnet */
292
+ MAINNET: 1029
293
+ };
294
+
295
+ // src/wallet/derivation.ts
296
+ function generateMnemonic(strength = 128) {
297
+ return (0, import_bip39.generateMnemonic)(import_english.wordlist, strength);
298
+ }
299
+ function validateMnemonic(mnemonic) {
300
+ const normalizedMnemonic = mnemonic.trim().toLowerCase();
301
+ const words = normalizedMnemonic.split(/\s+/);
302
+ const wordCount = words.length;
303
+ if (wordCount !== 12 && wordCount !== 24) {
304
+ return {
305
+ valid: false,
306
+ wordCount,
307
+ error: `Invalid word count: ${wordCount}. Must be 12 or 24.`
308
+ };
309
+ }
310
+ const valid = (0, import_bip39.validateMnemonic)(normalizedMnemonic, import_english.wordlist);
311
+ return {
312
+ valid,
313
+ wordCount,
314
+ error: valid ? void 0 : "Invalid mnemonic: checksum verification failed"
315
+ };
316
+ }
317
+ function deriveAccounts(mnemonic, options) {
318
+ const {
319
+ count,
320
+ startIndex = 0,
321
+ coreNetworkId = CORE_NETWORK_IDS.LOCAL,
322
+ accountType = "standard"
323
+ } = options;
324
+ const validation = validateMnemonic(mnemonic);
325
+ if (!validation.valid) {
326
+ throw new Error(`Invalid mnemonic: ${validation.error}`);
327
+ }
328
+ const normalizedMnemonic = mnemonic.trim().toLowerCase();
329
+ const seed = (0, import_bip39.mnemonicToSeedSync)(normalizedMnemonic);
330
+ const masterKey = import_bip32.HDKey.fromMasterSeed(seed);
331
+ const accounts = [];
332
+ const accountTypeIndex = accountType === "standard" ? 0 : 1;
333
+ for (let i = startIndex; i < startIndex + count; i++) {
334
+ const corePath = `m/44'/${COIN_TYPES.CONFLUX}'/${accountTypeIndex}'/0/${i}`;
335
+ const coreKey = masterKey.derive(corePath);
336
+ const evmPath = `m/44'/${COIN_TYPES.ETHEREUM}'/${accountTypeIndex}'/0/${i}`;
337
+ const evmKey = masterKey.derive(evmPath);
338
+ if (!coreKey.privateKey || !evmKey.privateKey) {
339
+ throw new Error(`Failed to derive keys at index ${i}`);
340
+ }
341
+ const corePrivateKey = (0, import_viem.bytesToHex)(coreKey.privateKey);
342
+ const evmPrivateKey = (0, import_viem.bytesToHex)(evmKey.privateKey);
343
+ const coreAccount = (0, import_accounts.privateKeyToAccount)(corePrivateKey, {
344
+ networkId: coreNetworkId
345
+ });
346
+ const evmAccount = (0, import_accounts2.privateKeyToAccount)(evmPrivateKey);
347
+ accounts.push({
348
+ index: i,
349
+ coreAddress: coreAccount.address,
350
+ evmAddress: evmAccount.address,
351
+ corePrivateKey,
352
+ evmPrivateKey,
353
+ paths: {
354
+ core: corePath,
355
+ evm: evmPath
356
+ }
357
+ });
358
+ }
359
+ return accounts;
360
+ }
361
+ function deriveAccount(mnemonic, index, coreNetworkId = CORE_NETWORK_IDS.LOCAL, accountType = "standard") {
362
+ const accounts = deriveAccounts(mnemonic, {
363
+ count: 1,
364
+ startIndex: index,
365
+ coreNetworkId,
366
+ accountType
367
+ });
368
+ return accounts[0];
369
+ }
370
+ function deriveFaucetAccount(mnemonic, coreNetworkId = CORE_NETWORK_IDS.LOCAL) {
371
+ return deriveAccount(mnemonic, 0, coreNetworkId, "mining");
372
+ }
373
+ function getDerivationPath(coinType, index, accountType = "standard") {
374
+ const accountTypeIndex = accountType === "standard" ? 0 : 1;
375
+ return `m/44'/${coinType}'/${accountTypeIndex}'/0/${index}`;
376
+ }
377
+
378
+ // src/wallet/embedded/custody.ts
379
+ var import_accounts3 = require("viem/accounts");
380
+ var EmbeddedWalletManager = class {
381
+ wallets = /* @__PURE__ */ new Map();
382
+ options;
383
+ constructor(options = {}) {
384
+ this.options = {
385
+ algorithm: options.algorithm || "aes-256-gcm",
386
+ iterations: options.iterations || 1e5,
387
+ autoCreate: options.autoCreate !== false
388
+ // Default true
389
+ };
390
+ }
391
+ /**
392
+ * Create a new embedded wallet for a user
393
+ *
394
+ * @param userId - User identifier
395
+ * @param password - Encryption password
396
+ * @returns Created wallet (without private key)
397
+ */
398
+ async createWallet(userId, password) {
399
+ if (this.wallets.has(userId)) {
400
+ throw new EmbeddedWalletError("Wallet already exists", { userId });
401
+ }
402
+ const privateKey = (0, import_accounts3.generatePrivateKey)();
403
+ const account = (0, import_accounts3.privateKeyToAccount)(privateKey);
404
+ const { encrypted, iv, salt } = await this.encryptPrivateKey(
405
+ privateKey,
406
+ password
407
+ );
408
+ const evmAddress = account.address;
409
+ const coreAddress = `cfx:${evmAddress.slice(2)}`;
410
+ const wallet = {
411
+ userId,
412
+ coreAddress,
413
+ evmAddress,
414
+ encryptedPrivateKey: encrypted,
415
+ encryption: {
416
+ algorithm: this.options.algorithm,
417
+ iv,
418
+ salt
419
+ },
420
+ createdAt: /* @__PURE__ */ new Date(),
421
+ lastAccessedAt: /* @__PURE__ */ new Date(),
422
+ isActive: true
423
+ };
424
+ this.wallets.set(userId, wallet);
425
+ const { encryptedPrivateKey: _, ...publicWallet } = wallet;
426
+ return publicWallet;
427
+ }
428
+ /**
429
+ * Get wallet info (without private key)
430
+ *
431
+ * @param userId - User identifier
432
+ * @returns Wallet info or undefined
433
+ */
434
+ getWallet(userId) {
435
+ const wallet = this.wallets.get(userId);
436
+ if (!wallet) return void 0;
437
+ wallet.lastAccessedAt = /* @__PURE__ */ new Date();
438
+ const { encryptedPrivateKey: _, ...publicWallet } = wallet;
439
+ return publicWallet;
440
+ }
441
+ /**
442
+ * Check if user has a wallet
443
+ *
444
+ * @param userId - User identifier
445
+ * @returns true if wallet exists
446
+ */
447
+ hasWallet(userId) {
448
+ return this.wallets.has(userId);
449
+ }
450
+ /**
451
+ * Sign transaction with user's embedded wallet
452
+ *
453
+ * @param userId - User identifier
454
+ * @param password - Decryption password
455
+ * @param request - Transaction request
456
+ * @returns Signed transaction
457
+ */
458
+ async signTransaction(userId, password, request) {
459
+ const wallet = this.wallets.get(userId);
460
+ if (!wallet) {
461
+ throw new EmbeddedWalletError("Wallet not found", { userId });
462
+ }
463
+ if (!wallet.isActive) {
464
+ throw new EmbeddedWalletError("Wallet is not active", { userId });
465
+ }
466
+ const privateKey = await this.decryptPrivateKey(
467
+ wallet.encryptedPrivateKey,
468
+ password,
469
+ wallet.encryption.iv,
470
+ wallet.encryption.salt
471
+ );
472
+ const account = (0, import_accounts3.privateKeyToAccount)(privateKey);
473
+ wallet.lastAccessedAt = /* @__PURE__ */ new Date();
474
+ const serialized = JSON.stringify({
475
+ from: account.address,
476
+ ...request,
477
+ value: request.value?.toString(),
478
+ gasLimit: request.gasLimit?.toString(),
479
+ gasPrice: request.gasPrice?.toString()
480
+ });
481
+ const signature = await account.signMessage({
482
+ message: serialized
483
+ });
484
+ return {
485
+ rawTransaction: signature,
486
+ hash: `0x${Array.from(
487
+ { length: 64 },
488
+ () => Math.floor(Math.random() * 16).toString(16)
489
+ ).join("")}`,
490
+ from: account.address,
491
+ chain: request.chain
492
+ };
493
+ }
494
+ /**
495
+ * Export wallet for user backup
496
+ *
497
+ * @param userId - User identifier
498
+ * @param password - Encryption password
499
+ * @returns Encrypted wallet export
500
+ */
501
+ async exportWallet(userId, password) {
502
+ const wallet = this.wallets.get(userId);
503
+ if (!wallet) {
504
+ throw new EmbeddedWalletError("Wallet not found", { userId });
505
+ }
506
+ const exportData = JSON.stringify({
507
+ coreAddress: wallet.coreAddress,
508
+ evmAddress: wallet.evmAddress,
509
+ encryptedPrivateKey: wallet.encryptedPrivateKey,
510
+ encryption: wallet.encryption
511
+ });
512
+ const { encrypted, iv, salt } = await this.encryptPrivateKey(
513
+ exportData,
514
+ password
515
+ );
516
+ return {
517
+ userId,
518
+ encryptedData: encrypted,
519
+ encryption: {
520
+ algorithm: this.options.algorithm,
521
+ iv,
522
+ salt
523
+ },
524
+ exportedAt: /* @__PURE__ */ new Date()
525
+ };
526
+ }
527
+ /**
528
+ * Deactivate wallet
529
+ *
530
+ * @param userId - User identifier
531
+ */
532
+ deactivateWallet(userId) {
533
+ const wallet = this.wallets.get(userId);
534
+ if (wallet) {
535
+ wallet.isActive = false;
536
+ }
537
+ }
538
+ /**
539
+ * Delete wallet permanently
540
+ *
541
+ * WARNING: This operation cannot be undone
542
+ *
543
+ * @param userId - User identifier
544
+ * @returns true if deleted, false if not found
545
+ */
546
+ deleteWallet(userId) {
547
+ return this.wallets.delete(userId);
548
+ }
549
+ /**
550
+ * List all wallets (without private keys)
551
+ *
552
+ * @returns Array of wallet info
553
+ */
554
+ listWallets() {
555
+ return Array.from(this.wallets.values()).map((wallet) => {
556
+ const { encryptedPrivateKey: _, ...publicWallet } = wallet;
557
+ return publicWallet;
558
+ });
559
+ }
560
+ /**
561
+ * Get wallet statistics
562
+ *
563
+ * @returns Wallet statistics
564
+ */
565
+ getStats() {
566
+ const all = Array.from(this.wallets.values());
567
+ const active = all.filter((w) => w.isActive);
568
+ return {
569
+ total: all.length,
570
+ active: active.length,
571
+ inactive: all.length - active.length
572
+ };
573
+ }
574
+ /**
575
+ * Encrypt private key
576
+ *
577
+ * NOTE: Simplified implementation for demonstration
578
+ * Production should use proper encryption (node:crypto, @noble/ciphers, etc.)
579
+ */
580
+ async encryptPrivateKey(data, password) {
581
+ const iv = Array.from(
582
+ { length: 16 },
583
+ () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
584
+ ).join("");
585
+ const salt = Array.from(
586
+ { length: 32 },
587
+ () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
588
+ ).join("");
589
+ const mockEncrypted = Buffer.from(
590
+ JSON.stringify({ data, password, iv, salt })
591
+ ).toString("base64");
592
+ return {
593
+ encrypted: mockEncrypted,
594
+ iv,
595
+ salt
596
+ };
597
+ }
598
+ /**
599
+ * Decrypt private key
600
+ *
601
+ * NOTE: Simplified implementation for demonstration
602
+ */
603
+ async decryptPrivateKey(encrypted, password, _iv, _salt) {
604
+ try {
605
+ const decoded = JSON.parse(
606
+ Buffer.from(encrypted, "base64").toString("utf-8")
607
+ );
608
+ if (decoded.password !== password) {
609
+ throw new Error("Invalid password");
610
+ }
611
+ return decoded.data;
612
+ } catch (error) {
613
+ throw new EmbeddedWalletError("Failed to decrypt private key", {
614
+ error: error instanceof Error ? error.message : "Unknown error"
615
+ });
616
+ }
617
+ }
618
+ };
619
+
620
+ // src/wallet/session-keys/manager.ts
621
+ var import_accounts4 = require("viem/accounts");
622
+ var SessionKeyManager = class {
623
+ sessionKeys = /* @__PURE__ */ new Map();
624
+ /**
625
+ * Generate a new session key
626
+ *
627
+ * @param parentAddress - Parent wallet address
628
+ * @param options - Session key configuration
629
+ * @returns Created session key
630
+ */
631
+ generateSessionKey(parentAddress, options) {
632
+ const privateKey = `0x${Array.from(
633
+ { length: 64 },
634
+ () => Math.floor(Math.random() * 16).toString(16)
635
+ ).join("")}`;
636
+ const account = (0, import_accounts4.privateKeyToAccount)(privateKey);
637
+ const ttl = options.ttl || 3600;
638
+ const now = /* @__PURE__ */ new Date();
639
+ const expiresAt = new Date(now.getTime() + ttl * 1e3);
640
+ const sessionKey = {
641
+ id: `sk_${Date.now()}_${Math.random().toString(36).substring(7)}`,
642
+ privateKey,
643
+ address: account.address,
644
+ parentAddress,
645
+ ttl,
646
+ expiresAt,
647
+ permissions: options.permissions || {},
648
+ createdAt: now,
649
+ isActive: true,
650
+ chain: options.chain
651
+ };
652
+ this.sessionKeys.set(sessionKey.id, sessionKey);
653
+ return sessionKey;
654
+ }
655
+ /**
656
+ * Get session key by ID
657
+ *
658
+ * @param sessionKeyId - Session key identifier
659
+ * @returns Session key or undefined
660
+ */
661
+ getSessionKey(sessionKeyId) {
662
+ const sessionKey = this.sessionKeys.get(sessionKeyId);
663
+ if (sessionKey && /* @__PURE__ */ new Date() > sessionKey.expiresAt) {
664
+ sessionKey.isActive = false;
665
+ }
666
+ return sessionKey;
667
+ }
668
+ /**
669
+ * Revoke a session key
670
+ *
671
+ * @param sessionKeyId - Session key identifier
672
+ */
673
+ revokeSessionKey(sessionKeyId) {
674
+ const sessionKey = this.sessionKeys.get(sessionKeyId);
675
+ if (sessionKey) {
676
+ sessionKey.isActive = false;
677
+ }
678
+ }
679
+ /**
680
+ * List all session keys for a parent address
681
+ *
682
+ * @param parentAddress - Parent wallet address
683
+ * @returns Array of session keys
684
+ */
685
+ listSessionKeys(parentAddress) {
686
+ return Array.from(this.sessionKeys.values()).filter(
687
+ (sk) => sk.parentAddress.toLowerCase() === parentAddress.toLowerCase()
688
+ );
689
+ }
690
+ /**
691
+ * List active session keys for a parent address
692
+ *
693
+ * @param parentAddress - Parent wallet address
694
+ * @returns Array of active session keys
695
+ */
696
+ listActiveSessionKeys(parentAddress) {
697
+ return this.listSessionKeys(parentAddress).filter(
698
+ (sk) => sk.isActive && /* @__PURE__ */ new Date() <= sk.expiresAt
699
+ );
700
+ }
701
+ /**
702
+ * Validate transaction against session key permissions
703
+ *
704
+ * @param sessionKey - Session key
705
+ * @param request - Transaction request
706
+ * @throws SessionKeyError if validation fails
707
+ */
708
+ validateTransaction(sessionKey, request) {
709
+ if (!sessionKey.isActive) {
710
+ throw new SessionKeyError("Session key is not active", {
711
+ sessionKeyId: sessionKey.id
712
+ });
713
+ }
714
+ if (/* @__PURE__ */ new Date() > sessionKey.expiresAt) {
715
+ throw new SessionKeyError("Session key has expired", {
716
+ sessionKeyId: sessionKey.id,
717
+ expiresAt: sessionKey.expiresAt
718
+ });
719
+ }
720
+ if (request.chain !== sessionKey.chain) {
721
+ throw new SessionKeyError("Chain mismatch", {
722
+ sessionKeyId: sessionKey.id,
723
+ allowedChain: sessionKey.chain,
724
+ requestedChain: request.chain
725
+ });
726
+ }
727
+ const { permissions } = sessionKey;
728
+ if (permissions.maxValue && request.value && request.value > permissions.maxValue) {
729
+ throw new SessionKeyError("Transaction value exceeds maximum", {
730
+ sessionKeyId: sessionKey.id,
731
+ maxValue: permissions.maxValue.toString(),
732
+ requestedValue: request.value.toString()
733
+ });
734
+ }
735
+ if (permissions.contracts && permissions.contracts.length > 0) {
736
+ const isWhitelisted = permissions.contracts.some(
737
+ (addr) => addr.toLowerCase() === request.to.toLowerCase()
738
+ );
739
+ if (!isWhitelisted) {
740
+ throw new SessionKeyError("Contract not whitelisted", {
741
+ sessionKeyId: sessionKey.id,
742
+ whitelistedContracts: permissions.contracts,
743
+ requestedContract: request.to
744
+ });
745
+ }
746
+ }
747
+ if (permissions.operations && permissions.operations.length > 0 && request.data) {
748
+ const selector = request.data.slice(0, 10);
749
+ const isAllowed = permissions.operations.some(
750
+ (op) => op.toLowerCase() === selector.toLowerCase()
751
+ );
752
+ if (!isAllowed) {
753
+ throw new SessionKeyError("Operation not allowed", {
754
+ sessionKeyId: sessionKey.id,
755
+ allowedOperations: permissions.operations,
756
+ requestedOperation: selector
757
+ });
758
+ }
759
+ }
760
+ }
761
+ /**
762
+ * Sign transaction with session key
763
+ *
764
+ * @param sessionKeyId - Session key identifier
765
+ * @param request - Transaction request
766
+ * @returns Signed transaction
767
+ * @throws SessionKeyError if session key is invalid or transaction violates permissions
768
+ */
769
+ async signWithSessionKey(sessionKeyId, request) {
770
+ const sessionKey = this.sessionKeys.get(sessionKeyId);
771
+ if (!sessionKey) {
772
+ throw new SessionKeyError("Session key not found", { sessionKeyId });
773
+ }
774
+ this.validateTransaction(sessionKey, request);
775
+ const account = (0, import_accounts4.privateKeyToAccount)(sessionKey.privateKey);
776
+ const serialized = JSON.stringify({
777
+ from: account.address,
778
+ to: request.to,
779
+ value: request.value?.toString(),
780
+ data: request.data,
781
+ gasLimit: request.gasLimit?.toString(),
782
+ gasPrice: request.gasPrice?.toString(),
783
+ nonce: request.nonce,
784
+ chain: request.chain
785
+ });
786
+ const signature = await account.signMessage({
787
+ message: serialized
788
+ });
789
+ return {
790
+ rawTransaction: signature,
791
+ hash: `0x${Array.from(
792
+ { length: 64 },
793
+ () => Math.floor(Math.random() * 16).toString(16)
794
+ ).join("")}`,
795
+ from: account.address,
796
+ chain: request.chain
797
+ };
798
+ }
799
+ /**
800
+ * Clean up expired session keys
801
+ *
802
+ * @returns Number of removed session keys
803
+ */
804
+ cleanupExpired() {
805
+ const now = /* @__PURE__ */ new Date();
806
+ let removed = 0;
807
+ for (const [id, sessionKey] of this.sessionKeys.entries()) {
808
+ if (now > sessionKey.expiresAt) {
809
+ this.sessionKeys.delete(id);
810
+ removed++;
811
+ }
812
+ }
813
+ return removed;
814
+ }
815
+ /**
816
+ * Get session key statistics
817
+ *
818
+ * @returns Statistics about session keys
819
+ */
820
+ getStats() {
821
+ const all = Array.from(this.sessionKeys.values());
822
+ const active = all.filter(
823
+ (sk) => sk.isActive && /* @__PURE__ */ new Date() <= sk.expiresAt
824
+ );
825
+ const expired = all.filter((sk) => /* @__PURE__ */ new Date() > sk.expiresAt);
826
+ return {
827
+ total: all.length,
828
+ active: active.length,
829
+ expired: expired.length,
830
+ inactive: all.length - active.length - expired.length
831
+ };
832
+ }
833
+ };
834
+ // Annotate the CommonJS export names for ESM import in node:
835
+ 0 && (module.exports = {
836
+ BatcherError,
837
+ COIN_TYPES,
838
+ CORE_NETWORK_IDS,
839
+ EmbeddedWalletError,
840
+ EmbeddedWalletManager,
841
+ SessionKeyError,
842
+ SessionKeyManager,
843
+ TransactionBatcher,
844
+ WalletError,
845
+ deriveAccount,
846
+ deriveAccounts,
847
+ deriveFaucetAccount,
848
+ generateMnemonic,
849
+ getDerivationPath,
850
+ validateMnemonic
851
+ });
852
+ //# sourceMappingURL=index.cjs.map