@yerofey/cryptowallet-cli 1.36.3 → 1.37.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 +9 -3
- package/cli.js +158 -23
- package/package.json +1 -1
- package/src/Method.js +0 -12
- package/src/options.js +6 -5
package/README.md
CHANGED
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
- [x] Generate brand new crypto wallet address (offline)
|
|
14
14
|
- [x] Generate wallet address with prefix (string at the start): [`-p`] (case-insensitive) or [`-P`] (case-sensitive)
|
|
15
15
|
- [x] Generate wallet address with suffix (string at the end): [`-s`] (case-insensitive) or [`-S`] (case-sensitive)
|
|
16
|
-
- [x] Generate wallet with different formats (for Bitcoin:
|
|
16
|
+
- [x] Generate wallet with different formats (for Bitcoin: `legacy`, `segwit`, `bech32`, `taproot`; for BNB: `bep2`, `bep20`, `erc20`; for TON: `w5` and all previous ones): [`-f`]
|
|
17
17
|
- [x] Generate wallet from your desired mnemonic string: [`-m`]
|
|
18
18
|
- [x] Generate mnemonic string: [`-m`] or [`-m 12`] or [`-m 15`] or [`-m 18`] or [`-m 21`] or [`-m 24`]
|
|
19
|
+
- [x] Use multiple threads (cores) for faster generation [`-t`]
|
|
19
20
|
- [x] Generate a lot of wallets at once: [`-n`]
|
|
20
21
|
- [x] Save result into a CSV file: [`--csv`]
|
|
21
22
|
- [x] Copy the generated mnemonic to the clipboard: [`-C` or `--copy`]
|
|
@@ -43,12 +44,18 @@ $ yarn global add @yerofey/cryptowallet-cli
|
|
|
43
44
|
# generate random EVM-compatible wallet (for Ethereum, Polygon, any L1/L2 EVM-compatible chain, etc.)
|
|
44
45
|
$ cw
|
|
45
46
|
|
|
47
|
+
# generate random wallet and copy the mnemonic to the clipboard
|
|
48
|
+
$ cw -C
|
|
49
|
+
|
|
46
50
|
# generate random BTC wallet (default format: bech32 - "bc1q...")
|
|
47
51
|
$ cw -c btc
|
|
48
52
|
|
|
49
53
|
# generate random mnemonic string (12 words) to import in any wallet app
|
|
50
54
|
$ cw -m
|
|
51
55
|
|
|
56
|
+
# generate random wallet faster (use all available CPU cores)
|
|
57
|
+
$ cw -t
|
|
58
|
+
|
|
52
59
|
# generate random mnemonic string of a specific length (12, 15, 18, 21 or 24 words)
|
|
53
60
|
$ cw -m 12
|
|
54
61
|
$ cw -m 15
|
|
@@ -169,6 +176,7 @@ $ cw -l
|
|
|
169
176
|
- `-P` or `--prefix-sensitive`: Specify desired prefix of the wallet address (**case-sensitive**)
|
|
170
177
|
- `-s` or `--suffix`: Specify desired suffix for the wallet address (**case-insensitive**)
|
|
171
178
|
- `-S` or `--suffix-sensitive`: Specify desired suffix for the wallet address (**case-sensitive**)
|
|
179
|
+
- `-t` or `--threads`: Use multiple threads (cores) for faster generation (default: half of the available cores), or pass `0` to use all available cores (not recommended for laptops)
|
|
172
180
|
- `-q` or `--qr`: Display QR code with the generated wallet address (works only without `-n` argument)
|
|
173
181
|
- `-v` or `--version`: Display current version of CW tool
|
|
174
182
|
|
|
@@ -188,8 +196,6 @@ $ cw -l
|
|
|
188
196
|
- [x] v22.x ✅
|
|
189
197
|
- [x] v23.x ✅
|
|
190
198
|
|
|
191
|
-
*tested on Ubuntu 22.04 & Mac M1*
|
|
192
|
-
|
|
193
199
|
## TODO
|
|
194
200
|
|
|
195
201
|
- [ ] SegWit Bech32 wallet address support for all Bitcoin forks
|
package/cli.js
CHANGED
|
@@ -1,41 +1,176 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import {
|
|
6
|
+
Worker,
|
|
7
|
+
isMainThread,
|
|
8
|
+
parentPort,
|
|
9
|
+
workerData,
|
|
10
|
+
} from 'node:worker_threads';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
4
12
|
import chalk from 'chalk';
|
|
5
13
|
import { options } from './src/options.js';
|
|
6
14
|
import { log, supportedChains } from './src/utils.js';
|
|
7
15
|
import Method from './src/Method.js';
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
// get the current file path
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
|
|
20
|
+
if (options.list !== undefined) {
|
|
21
|
+
(async () => {
|
|
11
22
|
return new Method('list').init();
|
|
12
|
-
}
|
|
23
|
+
})();
|
|
24
|
+
}
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
// generate mnemonic string if no argument is passed or only the mnemonic length is passed
|
|
27
|
+
if (
|
|
28
|
+
options.mnemonic &&
|
|
29
|
+
(options.mnemonic === true ||
|
|
30
|
+
options.mnemonic === '' ||
|
|
31
|
+
options.mnemonic.split(' ').length === 1)
|
|
32
|
+
) {
|
|
33
|
+
(async () => {
|
|
34
|
+
return new Method('mnemonic').init({
|
|
35
|
+
mnemonic: options.mnemonic,
|
|
36
|
+
copy: options?.copy || false,
|
|
37
|
+
});
|
|
38
|
+
})();
|
|
39
|
+
}
|
|
23
40
|
|
|
24
|
-
|
|
41
|
+
if (options.version) {
|
|
42
|
+
(async () => {
|
|
25
43
|
return new Method('version').init();
|
|
26
|
-
}
|
|
44
|
+
})();
|
|
45
|
+
}
|
|
27
46
|
|
|
28
|
-
|
|
47
|
+
if (options.donate) {
|
|
48
|
+
(async () => {
|
|
29
49
|
return new Method('donate').init();
|
|
50
|
+
})();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const chain = (options.chain.toUpperCase() || 'EVM').trim();
|
|
54
|
+
if (!supportedChains.includes(chain)) {
|
|
55
|
+
log(chalk.red('⛔️ Error: this chain is not supported!'));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
options.b = chain; // ensure the chain is passed to the Method class
|
|
59
|
+
|
|
60
|
+
// multi-threads mode (only for suffix, prefix, number)
|
|
61
|
+
const allMachineThreads = os.cpus().length;
|
|
62
|
+
const availableThreads = os.cpus().length - 1; // leave 1 core for the main thread
|
|
63
|
+
const defaultThreads = os.cpus().length / 2; // use half of the available threads
|
|
64
|
+
const inputThreads = parseInt(options.threads || 1, 10); // default to 1 thread
|
|
65
|
+
let numThreads = defaultThreads; // default to half of the available threads
|
|
66
|
+
if (inputThreads > availableThreads) {
|
|
67
|
+
numThreads = defaultThreads;
|
|
68
|
+
} else if (inputThreads <= 0) {
|
|
69
|
+
numThreads = availableThreads;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (isMainThread) {
|
|
73
|
+
if (numThreads === 1) {
|
|
74
|
+
console.log(
|
|
75
|
+
chalk.green(
|
|
76
|
+
'🐢 Using only 1 thread to generate a wallet, this might take a while...'
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
} else {
|
|
80
|
+
console.log(
|
|
81
|
+
chalk.green(`🏎️💨 Using ${numThreads}/${allMachineThreads} threads to generate a wallet...`)
|
|
82
|
+
);
|
|
30
83
|
}
|
|
31
84
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
85
|
+
const workers = [];
|
|
86
|
+
|
|
87
|
+
// create a shared buffer to communicate between workers
|
|
88
|
+
const sharedBuffer = new SharedArrayBuffer(4); // 4 bytes for the flag
|
|
89
|
+
const sharedArray = new Int32Array(sharedBuffer);
|
|
90
|
+
sharedArray[0] = 0; // 0 - not found, 1 - found
|
|
91
|
+
|
|
92
|
+
for (let i = 0; i < numThreads; i++) {
|
|
93
|
+
const worker = new Worker(__filename, {
|
|
94
|
+
workerData: {
|
|
95
|
+
workerId: i,
|
|
96
|
+
totalWorkers: numThreads,
|
|
97
|
+
chain,
|
|
98
|
+
options: JSON.parse(JSON.stringify(options)),
|
|
99
|
+
sharedBuffer,
|
|
100
|
+
},
|
|
101
|
+
stdout: true, // enable capturing stdout
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// pipe worker stdout to main process
|
|
105
|
+
worker.stdout.on('data', (data) => {
|
|
106
|
+
if (Atomics.load(sharedArray, 0) === 0) {
|
|
107
|
+
process.stdout.write(data); // forward stdout to main process
|
|
108
|
+
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
worker.on('message', (message) => {
|
|
114
|
+
if (Atomics.load(sharedArray, 0) === 0) {
|
|
115
|
+
// set the shared flag to 1 to stop all workers
|
|
116
|
+
Atomics.store(sharedArray, 0, 1);
|
|
117
|
+
|
|
118
|
+
// print the log output from the worker
|
|
119
|
+
process.stdout.write(message.log);
|
|
120
|
+
|
|
121
|
+
// terminate all workers
|
|
122
|
+
workers.forEach((w) => w.terminate());
|
|
123
|
+
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
worker.on('error', (err) =>
|
|
129
|
+
console.error(`❌ Worker error: ${err.message}`)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
workers.push(worker);
|
|
38
133
|
}
|
|
134
|
+
} else {
|
|
135
|
+
// worker thread (multi-threaded mode)
|
|
136
|
+
(async () => {
|
|
137
|
+
try {
|
|
138
|
+
// read shared flag before starting work
|
|
139
|
+
const sharedArray = new Int32Array(workerData.sharedBuffer);
|
|
140
|
+
if (Atomics.load(sharedArray, 0) === 1) {
|
|
141
|
+
process.exit(0); // exit early if a wallet has already been found
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// create a new Method instance
|
|
145
|
+
const method = new Method('wallet', {
|
|
146
|
+
b: workerData.chain,
|
|
147
|
+
chain: workerData.chain,
|
|
148
|
+
options: workerData.options,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// capture stdout logs in a buffer
|
|
152
|
+
let logOutput = '';
|
|
153
|
+
const originalWrite = process.stdout.write;
|
|
154
|
+
process.stdout.write = (chunk, encoding, callback) => {
|
|
155
|
+
logOutput += chunk.toString();
|
|
156
|
+
if (callback) callback();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// print the wallet to stdout
|
|
160
|
+
await method.init();
|
|
161
|
+
|
|
162
|
+
// restore stdout
|
|
163
|
+
process.stdout.write = originalWrite;
|
|
164
|
+
|
|
165
|
+
// check the shared flag again before sending the result
|
|
166
|
+
if (Atomics.load(sharedArray, 0) === 1) {
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
39
169
|
|
|
40
|
-
|
|
41
|
-
})
|
|
170
|
+
// send the log output to the main thread
|
|
171
|
+
parentPort.postMessage({ log: logOutput });
|
|
172
|
+
} catch (err) {
|
|
173
|
+
console.error(`Worker ${workerData.workerId} failed: ${err.message}`);
|
|
174
|
+
}
|
|
175
|
+
})();
|
|
176
|
+
}
|
package/package.json
CHANGED
package/src/Method.js
CHANGED
|
@@ -312,10 +312,6 @@ class Method {
|
|
|
312
312
|
addressHighlightedPart
|
|
313
313
|
)}${addressLastPart}${magenta(addressHighlightedSuffix)}`
|
|
314
314
|
);
|
|
315
|
-
// DEBUG
|
|
316
|
-
if (IS_DEV) {
|
|
317
|
-
log(`___ ${item.address}`);
|
|
318
|
-
}
|
|
319
315
|
} else {
|
|
320
316
|
log(`👛 ${item.address}`);
|
|
321
317
|
}
|
|
@@ -362,10 +358,6 @@ class Method {
|
|
|
362
358
|
addressHighlightedPart
|
|
363
359
|
)}${addressLastPart}`
|
|
364
360
|
);
|
|
365
|
-
// DEBUG
|
|
366
|
-
if (IS_DEV) {
|
|
367
|
-
log(`___ ${item.address}`);
|
|
368
|
-
}
|
|
369
361
|
} else {
|
|
370
362
|
log(`👛 ${item.address}`);
|
|
371
363
|
}
|
|
@@ -389,10 +381,6 @@ class Method {
|
|
|
389
381
|
log(
|
|
390
382
|
`👛 ${addressFirstPart}${magenta(addressHighlightedSuffix)}`
|
|
391
383
|
);
|
|
392
|
-
// DEBUG
|
|
393
|
-
if (IS_DEV) {
|
|
394
|
-
log(`___ ${item.address}`);
|
|
395
|
-
}
|
|
396
384
|
} else {
|
|
397
385
|
log(`👛 ${item.address}`);
|
|
398
386
|
}
|
package/src/options.js
CHANGED
|
@@ -3,10 +3,7 @@ import { program } from 'commander';
|
|
|
3
3
|
program.option('-b <ticker>', 'Wallet for specific blockchain', 'EVM');
|
|
4
4
|
program.option('-c, --chain <ticker>', 'Wallet for specific blockchain', 'EVM');
|
|
5
5
|
program.option('-C, --copy', 'Copy the result to the clipboard');
|
|
6
|
-
program.option(
|
|
7
|
-
'-D, --csv [filename]',
|
|
8
|
-
'Save result into CSV file'
|
|
9
|
-
);
|
|
6
|
+
program.option('-D, --csv [filename]', 'Save result into CSV file');
|
|
10
7
|
program.option(
|
|
11
8
|
'-f, --format <format>',
|
|
12
9
|
'Wallet format type (for cryptos with multiple wallet formats)'
|
|
@@ -37,8 +34,12 @@ program.option(
|
|
|
37
34
|
'-S, --suffix-sensitive <suffix>',
|
|
38
35
|
'Desired wallet suffix (case-sensitive)'
|
|
39
36
|
);
|
|
37
|
+
program.option(
|
|
38
|
+
'-t, --threads <threads>',
|
|
39
|
+
'Number of threads (cores) to use for wallet generation'
|
|
40
|
+
);
|
|
40
41
|
program.option('-v, --version', 'Display cryptowallet version');
|
|
41
|
-
program.option('
|
|
42
|
+
program.option('--donate', 'Donate to the project');
|
|
42
43
|
program.parse();
|
|
43
44
|
|
|
44
45
|
export const options = program.opts();
|