@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 +20 -2
- package/cli.js +1 -0
- package/package.json +12 -4
- package/src/Method.js +111 -28
- package/src/Wallet.js +238 -6
- package/src/chains/ADA.json +10 -0
- package/src/chains/ETH.json +1 -1
- package/src/chains/EVM.json +1 -1
- package/src/chains/SOL.json +1 -1
- package/src/chains/TON.json +9 -6
- package/src/chains/XLM.json +9 -0
- package/src/chains/XRP.json +10 -0
- package/src/chains/BSC.json +0 -8
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
|
-
- `
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yerofey/cryptowallet-cli",
|
|
3
|
-
"version": "1.
|
|
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": "
|
|
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${
|
|
58
|
-
|
|
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
|
-
'
|
|
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(
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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('
|
|
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
|
|
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: '
|
|
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: '
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
+
}
|
package/src/chains/ETH.json
CHANGED
package/src/chains/EVM.json
CHANGED
package/src/chains/SOL.json
CHANGED
package/src/chains/TON.json
CHANGED
|
@@ -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
|
}
|