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