@yerofey/cryptowallet-cli 1.39.0 → 1.41.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.
package/README.md CHANGED
@@ -41,6 +41,20 @@ $ yarn global add @yerofey/cryptowallet-cli
41
41
  $ bun add -g @yerofey/cryptowallet-cli
42
42
  ```
43
43
 
44
+ ## Install (on a server)
45
+
46
+ > Recommended for generating a wallet with long prefixes/suffixes or generating a lot of wallets at once
47
+
48
+ You can rent a VDS/VPS on [aeza.net](https://aeza.net/?ref=439099) for an hour or a day and run [this](https://gist.github.com/yerofey/c1cbf80bdfacfad668f53d595f890c44) one-liner to install `cw` tool:
49
+
50
+ ```bash
51
+ # install `cw` tool on a server with all dependencies
52
+ bash <(curl -sL https://gist.githubusercontent.com/yerofey/c1cbf80bdfacfad668f53d595f890c44/raw/376e310ed260ca54fec83b04d4d78d7587b83d78/install-cw.sh)
53
+
54
+ # run `cw` tool
55
+ cw
56
+ ```
57
+
44
58
  ## Usage
45
59
 
46
60
  ```bash
@@ -125,11 +139,13 @@ $ cw -l
125
139
  - `EVM` (Ethereum, Base, or any EVM L1/L2/L3, etc.) **default**
126
140
  - `BTC` (Bitcoin) [legacy, segwit, bech32, taproot]
127
141
  - `ETH` (Ethereum)
142
+ - `XRP` (Ripple) **Beta**
143
+ - `BNB` (BNB) [BEP2, BEP20, ERC20]
128
144
  - `SOL` (Solana)
129
- - `BNB` (Binance Coin) [BEP2, BEP20, ERC20]
130
- - `BSC` (Binance Smart Chain)
145
+ - `ADA` (Cardano)
131
146
  - `DOGE` (Dogecoin) [legacy, segwit, bech32]
132
147
  - `TRX` (Tron)
148
+ - `XLM` (Stellar)
133
149
  - `SUI` (Sui)
134
150
  - `TON` (The Open Network) [W5, V2-V5, simple]
135
151
  - `LTC` (Litecoin) [legacy, segwit, bech32]
@@ -252,9 +268,11 @@ Each chain JSON file is structured to provide essential information about the bl
252
268
  - `network`: The type of network or protocol the blockchain follows (e.g., EVM for Ethereum-compatible chains).
253
269
  - `startsWith`: The set of characters that the wallet address typically starts with.
254
270
  - `prefixTest`: A regular expression pattern that tests for valid characters that can appear in the prefix of a wallet address.
271
+ - `rareSymbols`: (Optional) A regular expression pattern that tests for rare symbols that can appear in the wallet address.
255
272
  - `apps`: An array of supported wallet applications that can be used with the generated addresses.
256
273
  - `flags`: An array of supported features for the wallet generation. Common flags include `m` for mnemonic support, `n` for generating multiple wallets, `p` for prefix support, and `s` for suffix support.
257
274
  - `formats`: (Optional) An object defining multiple wallet formats if the blockchain supports more than one format. Each format should specify its unique properties.
275
+ - `beta`: (Optional) A boolean value indicating if the chain is in beta testing. If set to `true`, the chain will be marked as beta in the list of supported chains.
258
276
 
259
277
  By following this structure, the `cw` tool can understand and support wallet generation for a wide array of blockchains.
260
278
 
package/cli.js CHANGED
@@ -26,6 +26,7 @@ const isDev = process.env.NODE_ENV === 'development';
26
26
 
27
27
  // check if there is a need for multi-threading
28
28
  const isMultiThreaded =
29
+ !options.mnemonic ||
29
30
  options.prefix ||
30
31
  options.suffix ||
31
32
  options['suffix-sensitive'] ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yerofey/cryptowallet-cli",
3
- "version": "1.39.0",
3
+ "version": "1.41.0",
4
4
  "description": "Crypto wallet generator CLI tool",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/yerofey/cryptowallet-cli",
@@ -28,7 +28,7 @@
28
28
  "address": "CWsbNQRxNzAasLd2zfwkEkbBZXKxfoxva14pe8wawUju"
29
29
  },
30
30
  {
31
- "type": "usdt",
31
+ "type": "trx",
32
32
  "address": "TCW9eaRWjpivZvnZ5DwgbWxPRpoZNWbuPe"
33
33
  },
34
34
  {
@@ -86,6 +86,9 @@
86
86
  "sui-wallet",
87
87
  "ton",
88
88
  "the-open-network",
89
+ "cardano",
90
+ "ripple",
91
+ "stellar",
89
92
  "base",
90
93
  "litecoin",
91
94
  "ltc",
@@ -109,6 +112,7 @@
109
112
  ],
110
113
  "dependencies": {
111
114
  "@binance-chain/javascript-sdk": "^4.2.2",
115
+ "@emurgo/cardano-serialization-lib-nodejs": "^14.1.1",
112
116
  "@harmony-js/account": "^0.1.58",
113
117
  "@mysten/sui": "^1.18.0",
114
118
  "@solana/web3.js": "^1.98.0",
@@ -118,10 +122,11 @@
118
122
  "@yerofey/dogecoin-bip84": "^0.0.5",
119
123
  "@yerofey/litecoin-bip84": "^0.0.5",
120
124
  "bigint-buffer": "^1.1.5",
121
- "bip39": "3.1.0",
125
+ "bip39": "^3.1.0",
122
126
  "bip84": "^0.2.9",
123
127
  "bip86": "^0.0.4",
124
128
  "bs58": "^6.0.0",
129
+ "cardano-wallet-js": "^1.4.0",
125
130
  "chalk": "5.4.1",
126
131
  "clipboardy": "^4.0.0",
127
132
  "coininfo": "5.2.1",
@@ -136,9 +141,12 @@
136
141
  "ethereum-cryptography": "^3.1.0",
137
142
  "ethereum-mnemonic-privatekey-utils": "1.0.5",
138
143
  "qrcode-terminal": "^0.12.0",
144
+ "ripple-keypairs": "^2.0.0",
145
+ "stellar-hd-wallet": "^0.0.10",
139
146
  "tezos-sign": "1.4.1",
140
147
  "tonweb": "^0.0.66",
141
- "tronweb": "^6.0.1"
148
+ "tronweb": "^6.0.1",
149
+ "xrpl": "^4.2.0"
142
150
  },
143
151
  "devDependencies": {
144
152
  "ava": "^6.2.0",
package/src/Method.js CHANGED
@@ -54,10 +54,9 @@ class Method {
54
54
  for (const val of supportedChains) {
55
55
  // eslint-disable-next-line no-undef
56
56
  const data = await loadJson(
57
- `${path.dirname(import.meta.url)}${path.sep}chains${path.sep}${val}.json`.replace(
58
- 'file://',
59
- ''
60
- )
57
+ `${path.dirname(import.meta.url)}${path.sep}chains${
58
+ path.sep
59
+ }${val}.json`.replace('file://', '')
61
60
  );
62
61
 
63
62
  let title = data.title || '';
@@ -99,7 +98,7 @@ class Method {
99
98
  log();
100
99
  log(
101
100
  greenBright(
102
- '⬇️ You can import it into your favorite wallet app or use it to generate a wallet with "-m" flag'
101
+ '💾 You can import it into your favorite wallet app or use it to generate a wallet with "-m" flag'
103
102
  )
104
103
  );
105
104
 
@@ -159,7 +158,7 @@ class Method {
159
158
  return;
160
159
  }
161
160
 
162
- let linesCount = 0;
161
+ let linesCount = 0; // count of lines to add empty line before the next message
163
162
  const outputFormats = ['csv'];
164
163
  const displayAsText =
165
164
  cw.options.output === undefined ||
@@ -231,7 +230,9 @@ class Method {
231
230
  );
232
231
  } else {
233
232
  // not supported for multiple wallets
234
- log(`ℹ️ It's not supported to display QR code for multiple wallets yet`);
233
+ log(
234
+ `ℹ️ It's not supported to display QR code for multiple wallets yet`
235
+ );
235
236
  log();
236
237
  }
237
238
  }
@@ -247,24 +248,58 @@ class Method {
247
248
  linesCount += 1;
248
249
  }
249
250
 
251
+ // wallets
250
252
  if (displayAsText) {
253
+ // show all addresses if flag is set or if prefix or suffix is not found
254
+ let showAllAddresses = cw.options.number !== undefined;
255
+ if (cw.suffixFound) {
256
+ showAllAddresses = false;
257
+ }
258
+ if (cw.prefixFound) {
259
+ showAllAddresses = false;
260
+ }
261
+ // show private key only for the first wallet or the one that matches the prefix or/and suffix
262
+ let showPrivateKey = false;
263
+ // add empty line before the next message
264
+ let emptyLineAdded = false;
251
265
  // display addresses
252
266
  let index = 0;
253
267
  for (const item of cw.wallet.addresses) {
254
268
  if (cw.wallet.addresses.length > 1) {
255
- log();
256
-
257
269
  // Display index
258
- if (item.index !== undefined) {
270
+ if (
271
+ item.index !== undefined &&
272
+ (showAllAddresses ||
273
+ (!showAllAddresses && index == 0) ||
274
+ cw.prefixFoundInWallets.includes(item.address) ||
275
+ cw.suffixFoundInWallets.includes(item.address))
276
+ ) {
277
+ log();
259
278
  log(`🆔 ${item.index}`);
279
+ emptyLineAdded = true;
280
+ }
281
+
282
+ if (item.breakLine !== undefined && item.breakLine) {
283
+ log();
284
+ emptyLineAdded = true;
260
285
  }
261
286
 
287
+ // TODO: fix situation with TON and multiple wallets labels (there are no spaces between them)
288
+
262
289
  // Display address details
263
290
  if (item.title) {
291
+ if (!emptyLineAdded) {
292
+ log();
293
+ emptyLineAdded = true;
294
+ }
264
295
  log(`🏷 ${item.title}`);
265
296
  }
266
297
  }
267
298
 
299
+ // in multi-wallets mode, hide private key for all wallets except the first one and the one that matches the prefix or/and suffix
300
+ showPrivateKey = false;
301
+
302
+ // highlight prefix and suffix
268
303
  if (
269
304
  cw.prefixFound &&
270
305
  cw.prefixFoundInWallets.includes(item.address) &&
@@ -317,6 +352,7 @@ class Method {
317
352
  log(`👛 ${item.address}`);
318
353
  }
319
354
  matchingWalletsIndexes.push(index);
355
+ showPrivateKey = true;
320
356
  } else if (
321
357
  cw.prefixFound &&
322
358
  cw.prefixFoundInWallets.includes(item.address)
@@ -363,6 +399,7 @@ class Method {
363
399
  log(`👛 ${item.address}`);
364
400
  }
365
401
  matchingWalletsIndexes.push(index);
402
+ showPrivateKey = true;
366
403
  } else if (
367
404
  cw.suffixFound &&
368
405
  cw.suffixFoundInWallets.includes(item.address)
@@ -386,10 +423,23 @@ class Method {
386
423
  log(`👛 ${item.address}`);
387
424
  }
388
425
  matchingWalletsIndexes.push(index);
426
+ showPrivateKey = true;
389
427
  } else {
390
- log(`👛 ${item.address}`);
428
+ if (showAllAddresses || (!showAllAddresses && index == 0) || item.show !== undefined && item.show) {
429
+ log(`👛 ${item.address}`);
430
+ }
431
+ }
432
+ // display public key or xpubkey (if exists)
433
+ if (item.publicKey !== undefined || item.xpubKey !== undefined) {
434
+ log(`🗝️ ${item.publicKey ?? item.xpubKey}`);
391
435
  }
392
- if (item.privateKey !== undefined) {
436
+ // display private key
437
+ if (
438
+ item.privateKey !== undefined &&
439
+ (showAllAddresses ||
440
+ (!showAllAddresses && index == 0) ||
441
+ showPrivateKey)
442
+ ) {
393
443
  log(`🔑 ${item.privateKey}`);
394
444
  }
395
445
  // copy to clipboard if flag is set
@@ -414,6 +464,16 @@ class Method {
414
464
  )
415
465
  );
416
466
  }
467
+
468
+ // beta
469
+ if (cw.row.beta !== undefined && cw.row.beta) {
470
+ log();
471
+ log(
472
+ yellow(
473
+ '🔶 This wallet generation method is in Beta - not all features are available and not everything was tested yet'
474
+ )
475
+ );
476
+ }
417
477
  } else {
418
478
  outputData.wallets = cw.wallet.addresses;
419
479
  }
@@ -483,21 +543,21 @@ class Method {
483
543
  }
484
544
 
485
545
  // matching wallets
486
- if (
487
- cw.options.number &&
488
- cw.options.number > 1 &&
489
- matchingWalletsIndexes.length > 0
490
- ) {
491
- const foundCount = matchingWalletsIndexes.length;
492
- const foundMany = foundCount !== 1;
493
- log(
494
- cyan(
495
- `🔍 Found ${foundCount} matching wallet${
496
- foundMany ? 's' : ''
497
- }: 🆔 ${matchingWalletsIndexes.join(',')}`
498
- )
499
- );
500
- }
546
+ // if (
547
+ // cw.options.number &&
548
+ // cw.options.number > 1 &&
549
+ // matchingWalletsIndexes.length > 0
550
+ // ) {
551
+ // const foundCount = matchingWalletsIndexes.length;
552
+ // const foundMany = foundCount !== 1;
553
+ // log(
554
+ // cyan(
555
+ // `🔍 Found ${foundCount} matching wallet${
556
+ // foundMany ? 's' : ''
557
+ // }: 🆔 ${matchingWalletsIndexes.join(',')}`
558
+ // )
559
+ // );
560
+ // }
501
561
 
502
562
  // attempts
503
563
  if (cw.attempts !== undefined && cw.attempts > 1 && cw.options.geek) {
@@ -553,15 +613,37 @@ class Method {
553
613
  // apps
554
614
  if (cw.row.apps !== undefined) {
555
615
  let apps = {
616
+ backpack: 'Backpack',
617
+ bitget: 'Bitget Wallet',
556
618
  coinbase: 'Coinbase Wallet',
619
+ daedalus: 'Daedalus',
620
+ eternl: 'Eternl',
621
+ jupiter: 'Jupiter',
622
+ keplr: 'Keplr',
623
+ ledger: 'Ledger',
624
+ lobstr: 'Lobstr',
625
+ magiceden: 'Magic Eden',
557
626
  metamask: 'MetaMask',
627
+ mytonwallet: 'MyTonWallet',
628
+ nami: 'Nami Wallet',
629
+ okx: 'OKX Wallet',
630
+ osmwallet: 'OsmWallet',
558
631
  phantom: 'Phantom',
632
+ plug: 'Plug',
633
+ rabet: 'Rabet',
634
+ rainbow: 'Rainbow',
635
+ solar: 'Solar',
636
+ stellarx: 'StellarX',
559
637
  suiet: 'Suiet',
560
638
  suiwallet: 'Sui Wallet',
561
639
  tonhub: 'Tonhub',
562
640
  tonkeeper: 'Tonkeeper',
563
641
  tronlink: 'TronLink',
564
642
  trustwallet: 'Trust Wallet',
643
+ uniswap: 'Uniswap',
644
+ vespr: 'VESPR',
645
+ xumm: 'Xumm',
646
+ yoroi: 'Yoroi',
565
647
  'harmony-chrome-ext': 'Harmony Chrome Extension Wallet',
566
648
  'binance-chain-wallet': 'Binance Chain Wallet',
567
649
  };
@@ -578,7 +660,7 @@ class Method {
578
660
  appsString +=
579
661
  ' and any other wallet app (either using mnemonic or private key)';
580
662
  }
581
- log(greenBright('⬇️ You can import this wallet into ' + appsString));
663
+ log(greenBright('💾 You can import this wallet into ' + appsString));
582
664
  }
583
665
 
584
666
  // donation
@@ -604,6 +686,7 @@ class Method {
604
686
  - BTC: bc1qcwamquntxshqsjcra6vryftrfd9z57j02g3ywq
605
687
  - ETH: 0xe3e3ed78d9f8A935a9a0fCE2a7305F2f5DBabAD8
606
688
  - SOL: CWsbNQRxNzAasLd2zfwkEkbBZXKxfoxva14pe8wawUju
689
+ - SUI: 0x1b27883fefacd14a19df37f2fc2e9fa1ccbf03823413f5edc315c164ef90a4f3
607
690
  - TON: UQCWDwqtvC_jml2hSf8laNQu4chYVCbHBpkbKbyDdxzM7Ma0
608
691
  - DOGE: DMAkWQKx1H6ESG3beDBssn5mAAZcwkrYVh
609
692
 
package/src/Wallet.js CHANGED
@@ -37,6 +37,14 @@ import {
37
37
  } from '@ton/crypto';
38
38
  import { WalletContractV5R1 } from '@ton/ton';
39
39
  import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
40
+ import rippleKeypairs from 'ripple-keypairs';
41
+ import {
42
+ Wallet as RippleWallet,
43
+ classicAddressToXAddress as RippleClassicAddressToXAddress,
44
+ } from 'xrpl';
45
+ import StellarHDWallet from 'stellar-hd-wallet';
46
+ import { Seed as CardanoSeed } from 'cardano-wallet-js';
47
+ import CardanoWasm from '@emurgo/cardano-serialization-lib-nodejs';
40
48
 
41
49
  config();
42
50
 
@@ -262,7 +270,7 @@ class Wallet {
262
270
 
263
271
  if (row.length == 0) {
264
272
  return {
265
- error: 'this blockchain is not found',
273
+ error: 'this coin or chain is not found',
266
274
  };
267
275
  }
268
276
 
@@ -279,6 +287,119 @@ class Wallet {
279
287
  },
280
288
  ],
281
289
  });
290
+ } else if (chain == 'ADA') {
291
+ try {
292
+ // Validate mnemonic
293
+ if (mnemonicString !== '' && !bip39.validateMnemonic(mnemonicString)) {
294
+ return {
295
+ error: 'mnemonic is not valid',
296
+ };
297
+ }
298
+
299
+ // Generate a 24-word mnemonic (recommended for Shelley wallets)
300
+ const mnemonic = mnemonicString || CardanoSeed.generateRecoveryPhrase();
301
+
302
+ // Convert mnemonic to a 512-bit seed
303
+ const entropy = bip39.mnemonicToEntropy(mnemonic);
304
+
305
+ // Generate root key from entropy
306
+ const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
307
+ Buffer.from(entropy, 'hex'), // correct entropy input
308
+ Buffer.from('') // empty password
309
+ );
310
+
311
+ // Derive the account key (BIP44: m/1852'/1815'/0')
312
+ const accountKey = rootKey
313
+ .derive(1852 | 0x80000000) // Purpose
314
+ .derive(1815 | 0x80000000) // Coin type (ADA)
315
+ .derive(0 | 0x80000000); // First account
316
+
317
+ const generateCardanoAddress = (chainType, index) => {
318
+ const addressKey = accountKey
319
+ .derive(chainType)
320
+ .derive(index)
321
+ .to_public()
322
+ .to_raw_key()
323
+ .hash();
324
+ const paymentCredential =
325
+ CardanoWasm.Credential.from_keyhash(addressKey);
326
+ const stakeKey = accountKey
327
+ .derive(2)
328
+ .derive(0)
329
+ .to_public()
330
+ .to_raw_key()
331
+ .hash();
332
+ const stakeCredential = CardanoWasm.Credential.from_keyhash(stakeKey);
333
+ return CardanoWasm.BaseAddress.new(
334
+ CardanoWasm.NetworkInfo.mainnet().network_id(),
335
+ paymentCredential,
336
+ stakeCredential
337
+ )
338
+ .to_address()
339
+ .to_bech32();
340
+ };
341
+
342
+ const utxoPubKey = accountKey
343
+ .derive(0) // external
344
+ .derive(0)
345
+ .to_public();
346
+ const stakeKey = accountKey
347
+ .derive(2) // chimeric
348
+ .derive(0)
349
+ .to_public();
350
+
351
+ const baseAddr = CardanoWasm.BaseAddress.new(
352
+ CardanoWasm.NetworkInfo.mainnet().network_id(),
353
+ CardanoWasm.Credential.from_keyhash(utxoPubKey.to_raw_key().hash()),
354
+ CardanoWasm.Credential.from_keyhash(stakeKey.to_raw_key().hash())
355
+ );
356
+
357
+ // bootstrap address - byron-era addresses with no staking rights
358
+ const byronAddr = CardanoWasm.ByronAddress.icarus_from_key(
359
+ utxoPubKey, // Ae2* style icarus address
360
+ CardanoWasm.NetworkInfo.mainnet().protocol_magic()
361
+ );
362
+
363
+ // Generate Staking Key Hash (BIP44: m/1852'/1815'/0'/2/0)
364
+ const stakingKey = accountKey
365
+ .derive(2)
366
+ .derive(0)
367
+ .to_public()
368
+ .to_raw_key()
369
+ .hash();
370
+ const stakingKeyHash = Buffer.from(stakingKey.to_bytes()).toString(
371
+ 'hex'
372
+ );
373
+
374
+ // Return wallet details
375
+ Object.assign(result, {
376
+ addresses: [
377
+ {
378
+ title: 'Shelley-era base address',
379
+ address: baseAddr.to_address().to_bech32(),
380
+ // publicKey: utxoPubKey.to_bech32(),
381
+ privateKey: rootKey.to_bech32(),
382
+ },
383
+ {
384
+ title: 'Byron-era bootstrap address (old style)',
385
+ address: byronAddr.to_base58(),
386
+ breakLine: true,
387
+ show: true,
388
+ },
389
+ {
390
+ title: 'Staking key hash',
391
+ address: stakingKeyHash,
392
+ breakLine: true,
393
+ show: true,
394
+ },
395
+ ],
396
+ mnemonic,
397
+ });
398
+ } catch (error) {
399
+ return {
400
+ error: `Failed to generate ADA wallet: ${error.message} (${error})`,
401
+ };
402
+ }
282
403
  } else if (chain == 'BTC') {
283
404
  // Validate mnemonic
284
405
  if (mnemonicString != '' && !bip39.validateMnemonic(mnemonicString)) {
@@ -571,16 +692,19 @@ class Wallet {
571
692
  // when UQ was implemented (non-bounceable addresses)
572
693
  const nonBounceableAddress = address.toString(true, true, false);
573
694
  addresses.push({
574
- title: 'V4R2 (UQ): best for wallets (non-bounceable)',
695
+ title: 'v4R2 (UQ): best for wallets (non-bounceable)',
575
696
  address: nonBounceableAddress,
576
697
  });
577
698
  const bouncableAddress = address.toString(true, true, true);
578
699
  addresses.push({
579
- title: 'V4R2 (EQ): best for smart contracts (bounceable)',
700
+ title: 'v4R2 (EQ): best for smart contracts (bounceable)',
580
701
  address: bouncableAddress,
702
+ breakLine: true,
703
+ show: true,
581
704
  });
582
705
  } else {
583
706
  addresses.push({
707
+ title: _tonwebFormat,
584
708
  address: address.toString(true, true, true),
585
709
  });
586
710
  }
@@ -602,7 +726,7 @@ class Wallet {
602
726
  testOnly: false,
603
727
  });
604
728
  addresses.push({
605
- title: 'W5 (V5R1) [UQ]: best for wallets (non-bounceable)',
729
+ title: 'W5 - v5R1 (UQ): best for wallets (non-bounceable)',
606
730
  address: nonBounceableV5Address,
607
731
  });
608
732
  const bouncableAddressV5 = v5Address.toString({
@@ -611,8 +735,10 @@ class Wallet {
611
735
  testOnly: false,
612
736
  });
613
737
  addresses.push({
614
- title: 'W5 (V5R1) [EQ]: best for smart contracts (bounceable)',
738
+ title: 'W5 - v5R1 (EQ): best for smart contracts (bounceable)',
615
739
  address: bouncableAddressV5,
740
+ breakLine: true,
741
+ show: true,
616
742
  });
617
743
  break;
618
744
  }
@@ -651,6 +777,105 @@ class Wallet {
651
777
  error: `Failed to generate TRX wallet: ${error.message} (${error})`,
652
778
  };
653
779
  }
780
+ } else if (chain == 'XLM') {
781
+ try {
782
+ // Validate mnemonic
783
+ if (mnemonicString !== '' && !bip39.validateMnemonic(mnemonicString)) {
784
+ return {
785
+ error: 'mnemonic is not valid',
786
+ };
787
+ }
788
+
789
+ // Generate mnemonic if not provided
790
+ const mnemonic =
791
+ mnemonicString ||
792
+ StellarHDWallet.generateMnemonic({ entropyBits: 128 });
793
+ // Create a Stellar HD Wallet from the mnemonic
794
+ const wallet = StellarHDWallet.fromMnemonic(mnemonic);
795
+
796
+ // Get the first account (Trust Wallet, Ledger, etc. use `m/44'/148'/0'`)
797
+ const publicKey = wallet.getPublicKey(0);
798
+ const secretKey = wallet.getSecret(0);
799
+ // const keypair = wallet.getKeypair(0); // Full keypair object
800
+ // const rawKey = wallet.derive(`m/44'/148'/0'`).toString('hex');
801
+
802
+ // Return wallet details
803
+ Object.assign(result, {
804
+ addresses: [
805
+ {
806
+ index: 0,
807
+ address: publicKey,
808
+ privateKey: secretKey,
809
+ },
810
+ ],
811
+ mnemonic,
812
+ });
813
+ } catch (error) {
814
+ return {
815
+ error: `Failed to generate XLM wallet: ${error.message} (${error})`,
816
+ };
817
+ }
818
+ } else if (chain == 'XRP') {
819
+ try {
820
+ // Validate mnemonic
821
+ if (mnemonicString !== '' && !bip39.validateMnemonic(mnemonicString)) {
822
+ return {
823
+ error: 'mnemonic is not valid',
824
+ };
825
+ }
826
+
827
+ // Generate a 12-word mnemonic (or use provided one)
828
+ const mnemonic = mnemonicString || bip39.generateMnemonic(128);
829
+
830
+ // Convert mnemonic to a 512-bit seed
831
+ const seed = bip39.mnemonicToSeedSync(mnemonic, '');
832
+
833
+ // Extract 16 bytes from the seed (XRP entropy requirement)
834
+ const entropy = seed.slice(0, 16);
835
+
836
+ // Encode the entropy as a Base58-encoded XRP seed
837
+ const base58Seed = rippleKeypairs.generateSeed({
838
+ entropy,
839
+ algorithm: 'ecdsa-secp256k1',
840
+ });
841
+
842
+ // Generate a wallet from the seed
843
+ const wallet = RippleWallet.fromSeed(base58Seed, {
844
+ algorithm: 'secp256k1',
845
+ });
846
+ // console.log('wallet', wallet);
847
+
848
+ // dev
849
+ // const masterKey = rippleKeypairs.deriveKeypair(base58Seed, {
850
+ // algorithm: 'ecdsa-secp256k1',
851
+ // accountIndex: 0,
852
+ // });
853
+ // const address = rippleKeypairs.deriveAddress(masterKey.publicKey);
854
+ // console.log('masterKey', masterKey);
855
+ // console.log('address', address);
856
+
857
+ // Return wallet details
858
+ Object.assign(result, {
859
+ addresses: [
860
+ {
861
+ title: 'Classic',
862
+ address: wallet.address,
863
+ privateKey: wallet.privateKey,
864
+ },
865
+ {
866
+ title: 'X-address',
867
+ address: RippleClassicAddressToXAddress(wallet.address, false, false),
868
+ breakLine: true,
869
+ show: true,
870
+ },
871
+ ],
872
+ mnemonic,
873
+ });
874
+ } catch (error) {
875
+ return {
876
+ error: `Failed to generate XRP wallet: ${error.message} (${error})`,
877
+ };
878
+ }
654
879
  } else if (chain == 'XTZ') {
655
880
  // TODO: generate wallet from mnemonic
656
881
  const wallet = tezos.generateKeysNoSeed();
@@ -667,7 +892,7 @@ class Wallet {
667
892
  } else {
668
893
  return {
669
894
  error:
670
- 'your desired blockchain is not supported yet, please open an issue on GitHub: https://github.com/yerofey/cryptowallet-cli/issues',
895
+ 'your desired coin/chain is not supported yet, please open an issue on GitHub: https://github.com/yerofey/cryptowallet-cli/issues',
671
896
  };
672
897
  }
673
898
 
@@ -678,6 +903,13 @@ class Wallet {
678
903
  });
679
904
  }
680
905
 
906
+ // Add beta flag if needed
907
+ if (row.beta !== undefined && row.beta == true) {
908
+ Object.assign(result, {
909
+ beta: true,
910
+ });
911
+ }
912
+
681
913
  return result;
682
914
  }
683
915
  }
@@ -0,0 +1,10 @@
1
+ {
2
+ "title": "Cardano",
3
+ "startsWith": "addr1q",
4
+ "prefixTest": "[a-z0-9]",
5
+ "rareSymbols": "[a-z]",
6
+ "path": "m/1852'/1815'/0'/0/0",
7
+ "purpose": "1852'",
8
+ "apps": ["trustwallet", "vespr", "eternl", "nami", "yoroi", "daedalus", "ledger"],
9
+ "flags": ["m", "p", "s"]
10
+ }
@@ -3,6 +3,6 @@
3
3
  "network": "EVM",
4
4
  "startsWith": "0x",
5
5
  "prefixTest": "[0-9a-fA-F]",
6
- "apps": ["metamask", "trustwallet"],
6
+ "apps": ["metamask", "trustwallet", "phantom", "ledger"],
7
7
  "flags": ["m", "p", "s"]
8
8
  }
@@ -3,6 +3,6 @@
3
3
  "network": "EVM",
4
4
  "startsWith": "0x",
5
5
  "prefixTest": "[0-9a-fA-F]",
6
- "apps": ["metamask", "trustwallet"],
6
+ "apps": ["metamask", "trustwallet", "phantom", "ledger"],
7
7
  "flags": ["m", "p", "s"]
8
8
  }
@@ -3,6 +3,6 @@
3
3
  "network": "SVM",
4
4
  "startsWith": "",
5
5
  "prefixTest": "[1-9a-zA-Z]",
6
- "apps": ["phantom", "trustwallet"],
6
+ "apps": ["phantom", "jupiter", "trustwallet"],
7
7
  "flags": ["m", "n", "p", "s"]
8
8
  }
@@ -65,7 +65,8 @@
65
65
  "prefixTest": "[0-9a-zA-Z-_]",
66
66
  "rareSymbols": "[0-9]",
67
67
  "apps": ["tonkeeper", "tonhub", "trustwallet"],
68
- "flags": ["m", "p", "s"]
68
+ "flags": ["m", "p", "s"],
69
+ "requiresActivation": true
69
70
  },
70
71
  "V4R2": {
71
72
  "format": "V4R2",
@@ -73,7 +74,8 @@
73
74
  "prefixTest": "[0-9a-zA-Z-_]",
74
75
  "rareSymbols": "[0-9]",
75
76
  "apps": ["tonkeeper", "tonhub", "trustwallet"],
76
- "flags": ["m", "p", "s"]
77
+ "flags": ["m", "p", "s"],
78
+ "requiresActivation": true
77
79
  },
78
80
  "V5R1": {
79
81
  "format": "V5R1",
@@ -81,7 +83,8 @@
81
83
  "prefixTest": "[0-9a-zA-Z-_]",
82
84
  "rareSymbols": "[0-9]",
83
85
  "apps": ["tonkeeper", "tonhub", "trustwallet"],
84
- "flags": ["m", "p", "s"]
86
+ "flags": ["m", "p", "s"],
87
+ "requiresActivation": true
85
88
  },
86
89
  "W5": {
87
90
  "comment": "This is the same as V5R1",
@@ -90,8 +93,8 @@
90
93
  "prefixTest": "[0-9a-zA-Z-_]",
91
94
  "rareSymbols": "[0-9]",
92
95
  "apps": ["tonkeeper", "tonhub", "trustwallet"],
93
- "flags": ["m", "p", "s"]
96
+ "flags": ["m", "p", "s"],
97
+ "requiresActivation": true
94
98
  }
95
- },
96
- "requiresActivation": true
99
+ }
97
100
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "title": "Stellar",
3
+ "startsWith": "G",
4
+ "prefixTest": "[A-Z2-7]",
5
+ "strictCase": "upper",
6
+ "addressChars": 56,
7
+ "apps": ["trustwallet", "rabet", "lobstr", "solar", "stellarx", "ledger"],
8
+ "flags": ["m", "p", "s"]
9
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "title": "XRP Ledger: Ripple",
3
+ "startsWith": "r",
4
+ "prefixTest": "[a-km-zA-HJ-NP-Z1-9]",
5
+ "path": "m/44'/144'/0'/0/0",
6
+ "purpose": "44'",
7
+ "apps": ["xumm", "osmwallet", "ledger"],
8
+ "flags": ["m", "p", "s"],
9
+ "beta": true
10
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "title": "Binance Smart Chain",
3
- "network": "EVM",
4
- "startsWith": "0x",
5
- "prefixTest": "[0-9a-fA-F]",
6
- "apps": ["metamask", "trustwallet"],
7
- "flags": ["m", "p", "s"]
8
- }