@cfxdevkit/services 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.
@@ -0,0 +1,566 @@
1
+ import { Address } from 'viem';
2
+
3
+ /**
4
+ * Encryption service using AES-256-GCM
5
+ *
6
+ * Security specifications:
7
+ * - Algorithm: AES-256-GCM (authenticated encryption)
8
+ * - Key derivation: PBKDF2-SHA256 with 100,000 iterations
9
+ * - Salt: 32 bytes (random, stored in keystore)
10
+ * - IV: 12 bytes (random per encryption, prepended to ciphertext)
11
+ * - Format: base64(IV + EncryptedData + AuthTag)
12
+ */
13
+ declare class EncryptionService {
14
+ private constructor();
15
+ private static readonly ITERATIONS;
16
+ private static readonly KEY_LENGTH;
17
+ private static readonly SALT_LENGTH;
18
+ private static readonly IV_LENGTH;
19
+ /**
20
+ * Generate a random salt for key derivation
21
+ */
22
+ static generateSalt(): Buffer;
23
+ /**
24
+ * Derive encryption key from password using PBKDF2
25
+ */
26
+ static deriveKey(password: string, salt: Buffer): Promise<CryptoKey>;
27
+ /**
28
+ * Encrypt plaintext with password
29
+ *
30
+ * @param plaintext - String to encrypt
31
+ * @param password - Encryption password
32
+ * @param salt - Salt for key derivation
33
+ * @returns Base64-encoded ciphertext with prepended IV
34
+ */
35
+ static encrypt(plaintext: string, password: string, salt: Buffer): Promise<string>;
36
+ /**
37
+ * Decrypt ciphertext with password
38
+ *
39
+ * @param ciphertext - Base64-encoded ciphertext with prepended IV
40
+ * @param password - Encryption password
41
+ * @param salt - Salt for key derivation
42
+ * @returns Decrypted plaintext
43
+ * @throws Error if decryption fails (wrong password or corrupted data)
44
+ */
45
+ static decrypt(ciphertext: string, password: string, salt: Buffer): Promise<string>;
46
+ /**
47
+ * Encrypt an object (serializes to JSON first)
48
+ */
49
+ static encryptObject<T>(obj: T, password: string, salt: Buffer): Promise<string>;
50
+ /**
51
+ * Decrypt to an object (parses JSON after decryption)
52
+ */
53
+ static decryptObject<T>(ciphertext: string, password: string, salt: Buffer): Promise<T>;
54
+ /**
55
+ * Hash a string with SHA-256 (for config integrity checks)
56
+ */
57
+ static hash(data: string): Promise<string>;
58
+ /**
59
+ * Verify password strength (basic validation)
60
+ */
61
+ static validatePasswordStrength(password: string): {
62
+ valid: boolean;
63
+ errors: string[];
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Keystore Version 2 Schema
69
+ *
70
+ * Breaking changes from v1:
71
+ * - adminPrivateKey removed (admins identified by wallet address only)
72
+ * - Multiple admin addresses supported
73
+ * - Per-mnemonic node configuration
74
+ * - Derived keys cached and encrypted
75
+ * - Immutable node configuration
76
+ */
77
+ /**
78
+ * Main keystore file structure
79
+ */
80
+ interface KeystoreV2 {
81
+ version: 2;
82
+ setupCompleted: boolean;
83
+ setupCompletedAt?: string;
84
+ adminAddresses: string[];
85
+ encryptionEnabled: boolean;
86
+ encryptionSalt?: string;
87
+ mnemonics: MnemonicEntry[];
88
+ activeIndex: number;
89
+ }
90
+ /**
91
+ * Individual mnemonic entry with node configuration
92
+ */
93
+ interface MnemonicEntry {
94
+ id: string;
95
+ label: string;
96
+ type: 'plaintext' | 'encrypted';
97
+ mnemonic: string;
98
+ createdAt: string;
99
+ nodeConfig: NodeConfig;
100
+ derivedKeys: DerivedKeys;
101
+ }
102
+ /**
103
+ * Node configuration bound to a mnemonic
104
+ * Immutable once blockchain data exists
105
+ */
106
+ interface NodeConfig {
107
+ accountsCount: number;
108
+ chainId: number;
109
+ evmChainId: number;
110
+ miningAuthor: 'auto' | string;
111
+ immutable: boolean;
112
+ configHash: string;
113
+ createdAt: string;
114
+ }
115
+ /**
116
+ * Derived account keys (genesis + faucet)
117
+ * Encrypted if keystore encryption enabled
118
+ */
119
+ interface DerivedKeys {
120
+ type: 'plaintext' | 'encrypted';
121
+ genesisAccounts: DerivedAccount[] | string;
122
+ faucetAccount: DerivedAccount | string;
123
+ }
124
+ /**
125
+ * Single derived account with addresses and private keys for both chains
126
+ */
127
+ interface DerivedAccount {
128
+ index: number;
129
+ core: string;
130
+ evm: string;
131
+ privateKey: string;
132
+ evmPrivateKey: string;
133
+ address?: string;
134
+ path?: string;
135
+ network?: 'core' | 'espace';
136
+ }
137
+ /**
138
+ * Summary of a mnemonic (without sensitive data)
139
+ */
140
+ interface MnemonicSummary {
141
+ id: string;
142
+ label: string;
143
+ type: 'plaintext' | 'encrypted';
144
+ isActive: boolean;
145
+ createdAt: string;
146
+ nodeConfig: NodeConfig;
147
+ dataDir: string;
148
+ dataSize: string;
149
+ }
150
+ /**
151
+ * Setup data for initial configuration
152
+ */
153
+ interface SetupData {
154
+ adminAddress: string;
155
+ mnemonic: string;
156
+ mnemonicLabel: string;
157
+ nodeConfig: {
158
+ accountsCount: number;
159
+ chainId: number;
160
+ evmChainId: number;
161
+ miningAuthor?: string;
162
+ };
163
+ encryption?: {
164
+ enabled: boolean;
165
+ password?: string;
166
+ };
167
+ }
168
+ /**
169
+ * Data for adding a new mnemonic
170
+ */
171
+ interface AddMnemonicData {
172
+ mnemonic: string;
173
+ label: string;
174
+ nodeConfig: {
175
+ accountsCount: number;
176
+ chainId: number;
177
+ evmChainId: number;
178
+ miningAuthor?: string;
179
+ };
180
+ setAsActive?: boolean;
181
+ }
182
+ /**
183
+ * Validation result
184
+ */
185
+ interface ValidationResult {
186
+ valid: boolean;
187
+ errors: string[];
188
+ warnings?: string[];
189
+ }
190
+ /**
191
+ * Node configuration modification check result
192
+ */
193
+ interface ConfigModificationCheck {
194
+ canModify: boolean;
195
+ reason?: string;
196
+ dataDir?: string;
197
+ lockFile?: string;
198
+ }
199
+
200
+ declare class KeystoreLockedError extends Error {
201
+ constructor(message?: string);
202
+ }
203
+ /**
204
+ * KeystoreService V2
205
+ */
206
+ declare class KeystoreService {
207
+ private keystorePath;
208
+ private keystore;
209
+ private currentPassword;
210
+ constructor(keystorePath?: string);
211
+ private requireKeystore;
212
+ private requireEncryptionSalt;
213
+ private requirePassword;
214
+ /**
215
+ * Initialize keystore (load from disk or create empty)
216
+ */
217
+ initialize(): Promise<void>;
218
+ /**
219
+ * Load keystore from disk
220
+ */
221
+ private loadKeystore;
222
+ /**
223
+ * Save keystore to disk
224
+ */
225
+ private saveKeystore;
226
+ /**
227
+ * Check if initial setup is completed
228
+ */
229
+ isSetupCompleted(): Promise<boolean>;
230
+ /**
231
+ * Complete initial setup
232
+ */
233
+ completeSetup(data: SetupData): Promise<void>;
234
+ /**
235
+ * Get all admin addresses
236
+ */
237
+ getAdminAddresses(): Promise<string[]>;
238
+ /**
239
+ * Add admin address
240
+ */
241
+ addAdminAddress(address: string): Promise<void>;
242
+ /**
243
+ * Remove admin address
244
+ */
245
+ removeAdminAddress(address: string, currentAdmin: string): Promise<void>;
246
+ /**
247
+ * Check if address is admin
248
+ */
249
+ isAdmin(address: string): boolean;
250
+ /**
251
+ * Get active mnemonic entry
252
+ */
253
+ getActiveMnemonic(): Promise<MnemonicEntry>;
254
+ /**
255
+ * Get mnemonic by ID
256
+ */
257
+ getMnemonic(id: string): Promise<MnemonicEntry>;
258
+ /**
259
+ * List all mnemonics (summary only)
260
+ */
261
+ listMnemonics(): Promise<MnemonicSummary[]>;
262
+ /**
263
+ * Add new mnemonic
264
+ */
265
+ addMnemonic(data: AddMnemonicData): Promise<MnemonicEntry>;
266
+ /**
267
+ * Update mnemonic label
268
+ */
269
+ updateMnemonicLabel(id: string, label: string): Promise<void>;
270
+ /**
271
+ * Switch active mnemonic
272
+ */
273
+ switchActiveMnemonic(id: string): Promise<void>;
274
+ /**
275
+ * Delete mnemonic and its data
276
+ */
277
+ deleteMnemonic(id: string, deleteData?: boolean): Promise<void>;
278
+ /**
279
+ * Get node configuration for a mnemonic
280
+ */
281
+ getNodeConfig(mnemonicId: string): Promise<NodeConfig>;
282
+ /**
283
+ * Check if node configuration can be modified
284
+ */
285
+ canModifyNodeConfig(mnemonicId: string): Promise<ConfigModificationCheck>;
286
+ /**
287
+ * Update node configuration
288
+ */
289
+ updateNodeConfig(mnemonicId: string, config: Partial<NodeConfig>): Promise<void>;
290
+ /**
291
+ * Delete blockchain data directory
292
+ */
293
+ deleteNodeData(mnemonicId: string): Promise<{
294
+ deletedDir: string;
295
+ dataSize: string;
296
+ }>;
297
+ /**
298
+ * Check if keystore is locked
299
+ */
300
+ isLocked(): boolean;
301
+ /**
302
+ * Check if encryption is enabled for the keystore
303
+ */
304
+ isEncryptionEnabled(): boolean;
305
+ /**
306
+ * Unlock keystore with password
307
+ */
308
+ unlockKeystore(password: string): Promise<void>;
309
+ /**
310
+ * Lock keystore (clear password from memory)
311
+ */
312
+ lockKeystore(): Promise<void>;
313
+ /**
314
+ * Get decrypted mnemonic
315
+ */
316
+ getDecryptedMnemonic(mnemonicId: string): Promise<string>;
317
+ /**
318
+ * Get genesis accounts for a mnemonic
319
+ */
320
+ deriveGenesisAccounts(mnemonicId: string): Promise<DerivedAccount[]>;
321
+ /**
322
+ * Get faucet account for a mnemonic
323
+ */
324
+ deriveFaucetAccount(mnemonicId: string): Promise<DerivedAccount>;
325
+ /**
326
+ * Derive accounts from mnemonic (HD wallet derivation)
327
+ * Returns accounts with both Core and eSpace private keys
328
+ * Uses @cfxdevkit/core/wallet for derivation
329
+ */
330
+ deriveAccountsFromMnemonic(mnemonic: string, _network: 'core' | 'espace', // Kept for API compatibility, both keys are always derived
331
+ count: number, startIndex?: number, chainIdOverride?: number): Promise<DerivedAccount[]>;
332
+ /**
333
+ * Get data directory for active mnemonic
334
+ */
335
+ getDataDir(): Promise<string>;
336
+ /**
337
+ * Get data directory for specific mnemonic
338
+ */
339
+ private getDataDirForMnemonic;
340
+ /**
341
+ * Get mnemonic hash (for display)
342
+ */
343
+ getMnemonicHash(): Promise<string>;
344
+ /**
345
+ * Get active mnemonic label
346
+ */
347
+ getActiveLabel(): string;
348
+ /**
349
+ * Get active mnemonic index
350
+ */
351
+ getActiveIndex(): number;
352
+ /**
353
+ * Generate new BIP-39 mnemonic
354
+ * Uses @cfxdevkit/core/wallet for generation
355
+ */
356
+ generateMnemonic(): string;
357
+ /**
358
+ * Validate mnemonic format
359
+ * Uses @cfxdevkit/core/wallet for validation
360
+ */
361
+ validateMnemonic(mnemonic: string): boolean;
362
+ /**
363
+ * Ensure keystore is loaded
364
+ */
365
+ private ensureKeystoreLoaded;
366
+ /**
367
+ * Create a mnemonic entry with node config and derived keys
368
+ */
369
+ private createMnemonicEntry;
370
+ /**
371
+ * Calculate config hash for integrity check
372
+ */
373
+ private calculateConfigHash;
374
+ /**
375
+ * Get data directory size (human-readable)
376
+ */
377
+ private getDataDirSize;
378
+ }
379
+ /**
380
+ * Get singleton KeystoreService instance
381
+ */
382
+ declare function getKeystoreService(): KeystoreService;
383
+
384
+ interface SwapQuoteParams {
385
+ tokenIn: Address;
386
+ tokenOut: Address;
387
+ amountIn: string;
388
+ slippage?: number;
389
+ network?: 'testnet' | 'mainnet';
390
+ }
391
+ interface SwapExecuteParams extends SwapQuoteParams {
392
+ account: number;
393
+ deadline?: number;
394
+ }
395
+ interface SwapQuote {
396
+ amountIn: string;
397
+ amountOut: string;
398
+ amountOutMin: string;
399
+ path: Address[];
400
+ priceImpact: string;
401
+ slippage: number;
402
+ }
403
+ interface SwapResult {
404
+ hash: string;
405
+ amountIn: string;
406
+ amountOut: string;
407
+ path: Address[];
408
+ }
409
+ /**
410
+ * Minimal interface for the devkit dependency used by SwapService.
411
+ * Only the methods actually consumed by this service are listed.
412
+ */
413
+ interface SwapDevKit {
414
+ getAccounts(): Record<number, {
415
+ privateKey: string;
416
+ evmAddress: string;
417
+ }>;
418
+ }
419
+ declare class SwapService {
420
+ private devkit;
421
+ constructor(devkit: SwapDevKit);
422
+ /**
423
+ * Get swap contracts for network
424
+ */
425
+ private getContracts;
426
+ /**
427
+ * Get token info
428
+ */
429
+ getToken(symbol: string, network?: 'testnet' | 'mainnet'): {
430
+ readonly address: Address;
431
+ readonly symbol: "WCFX";
432
+ readonly name: "Wrapped CFX";
433
+ readonly decimals: 18;
434
+ } | {
435
+ readonly address: Address;
436
+ readonly symbol: "USDT";
437
+ readonly name: "Tether USD";
438
+ readonly decimals: 18;
439
+ } | {
440
+ readonly address: Address;
441
+ readonly symbol: "USDC";
442
+ readonly name: "USD Coin";
443
+ readonly decimals: 18;
444
+ };
445
+ /**
446
+ * List available tokens
447
+ */
448
+ listTokens(network?: 'testnet' | 'mainnet'): ({
449
+ readonly address: Address;
450
+ readonly symbol: "WCFX";
451
+ readonly name: "Wrapped CFX";
452
+ readonly decimals: 18;
453
+ } | {
454
+ readonly address: Address;
455
+ readonly symbol: "USDT";
456
+ readonly name: "Tether USD";
457
+ readonly decimals: 18;
458
+ } | {
459
+ readonly address: Address;
460
+ readonly symbol: "USDC";
461
+ readonly name: "USD Coin";
462
+ readonly decimals: 18;
463
+ })[];
464
+ /**
465
+ * Get swap quote
466
+ */
467
+ getQuote(params: SwapQuoteParams): Promise<SwapQuote>;
468
+ /**
469
+ * Execute swap
470
+ */
471
+ executeSwap(params: SwapExecuteParams): Promise<SwapResult>;
472
+ /**
473
+ * Get Swappi router ABI
474
+ */
475
+ getRouterABI(): readonly [{
476
+ readonly inputs: readonly [{
477
+ readonly name: "amountIn";
478
+ readonly type: "uint256";
479
+ }, {
480
+ readonly name: "amountOutMin";
481
+ readonly type: "uint256";
482
+ }, {
483
+ readonly name: "path";
484
+ readonly type: "address[]";
485
+ }, {
486
+ readonly name: "to";
487
+ readonly type: "address";
488
+ }, {
489
+ readonly name: "deadline";
490
+ readonly type: "uint256";
491
+ }];
492
+ readonly name: "swapExactTokensForTokens";
493
+ readonly outputs: readonly [{
494
+ readonly name: "amounts";
495
+ readonly type: "uint256[]";
496
+ }];
497
+ readonly stateMutability: "nonpayable";
498
+ readonly type: "function";
499
+ }, {
500
+ readonly inputs: readonly [{
501
+ readonly name: "amountOut";
502
+ readonly type: "uint256";
503
+ }, {
504
+ readonly name: "amountInMax";
505
+ readonly type: "uint256";
506
+ }, {
507
+ readonly name: "path";
508
+ readonly type: "address[]";
509
+ }, {
510
+ readonly name: "to";
511
+ readonly type: "address";
512
+ }, {
513
+ readonly name: "deadline";
514
+ readonly type: "uint256";
515
+ }];
516
+ readonly name: "swapTokensForExactTokens";
517
+ readonly outputs: readonly [{
518
+ readonly name: "amounts";
519
+ readonly type: "uint256[]";
520
+ }];
521
+ readonly stateMutability: "nonpayable";
522
+ readonly type: "function";
523
+ }, {
524
+ readonly inputs: readonly [{
525
+ readonly name: "amountIn";
526
+ readonly type: "uint256";
527
+ }, {
528
+ readonly name: "path";
529
+ readonly type: "address[]";
530
+ }];
531
+ readonly name: "getAmountsOut";
532
+ readonly outputs: readonly [{
533
+ readonly name: "amounts";
534
+ readonly type: "uint256[]";
535
+ }];
536
+ readonly stateMutability: "view";
537
+ readonly type: "function";
538
+ }, {
539
+ readonly inputs: readonly [{
540
+ readonly name: "amountOut";
541
+ readonly type: "uint256";
542
+ }, {
543
+ readonly name: "path";
544
+ readonly type: "address[]";
545
+ }];
546
+ readonly name: "getAmountsIn";
547
+ readonly outputs: readonly [{
548
+ readonly name: "amounts";
549
+ readonly type: "uint256[]";
550
+ }];
551
+ readonly stateMutability: "view";
552
+ readonly type: "function";
553
+ }];
554
+ /**
555
+ * Get Swappi contract addresses
556
+ */
557
+ getContractAddresses(network?: 'testnet' | 'mainnet'): {
558
+ readonly FACTORY: Address;
559
+ readonly ROUTER: Address;
560
+ } | {
561
+ readonly FACTORY: Address;
562
+ readonly ROUTER: Address;
563
+ };
564
+ }
565
+
566
+ export { type AddMnemonicData, type ConfigModificationCheck, type DerivedAccount, type DerivedKeys, EncryptionService, KeystoreLockedError, KeystoreService, type KeystoreV2, type MnemonicEntry, type MnemonicSummary, type NodeConfig, type SetupData, type SwapExecuteParams, type SwapQuote, type SwapQuoteParams, type SwapResult, SwapService, type ValidationResult, getKeystoreService };