@yerofey/cryptowallet-cli 1.38.2 → 1.39.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/LICENSE +1 -1
- package/README.md +6 -9
- package/cli.js +135 -105
- package/package.json +2 -1
- package/src/Method.js +2 -2
- package/src/Wallet.js +4 -2
- package/src/chains/BNB.json +2 -2
- package/src/chains/BSC.json +1 -1
- package/src/chains/ETC.json +1 -1
- package/src/chains/ETH.json +1 -1
- package/src/chains/EVM.json +1 -1
- package/src/options.js +0 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://npmjs.com/@yerofey/cryptowallet-cli)
|
|
5
5
|
[](https://npmjs.com/package/@yerofey/cryptowallet-cli)
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> cw: crypto wallet generator CLI tool
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
@@ -44,7 +44,7 @@ $ bun add -g @yerofey/cryptowallet-cli
|
|
|
44
44
|
## Usage
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
# generate random EVM-compatible wallet (for Ethereum,
|
|
47
|
+
# generate random EVM-compatible wallet (for Ethereum, Base, and any L1/L2/L3 EVM-compatible chain, etc.)
|
|
48
48
|
$ cw
|
|
49
49
|
|
|
50
50
|
# generate random wallet and copy the mnemonic to the clipboard
|
|
@@ -56,9 +56,6 @@ $ cw -c btc
|
|
|
56
56
|
# generate random mnemonic string (12 words) to import in any wallet app
|
|
57
57
|
$ cw -m
|
|
58
58
|
|
|
59
|
-
# generate random wallet faster (use all available CPU cores)
|
|
60
|
-
$ cw -t
|
|
61
|
-
|
|
62
59
|
# generate random mnemonic string of a specific length (12, 15, 18, 21 or 24 words)
|
|
63
60
|
$ cw -m 12
|
|
64
61
|
$ cw -m 15
|
|
@@ -125,7 +122,7 @@ $ cw -l
|
|
|
125
122
|
|
|
126
123
|
## Blockchains & tickers supported
|
|
127
124
|
|
|
128
|
-
- `EVM` (Ethereum, Base,
|
|
125
|
+
- `EVM` (Ethereum, Base, or any EVM L1/L2/L3, etc.) **default**
|
|
129
126
|
- `BTC` (Bitcoin) [legacy, segwit, bech32, taproot]
|
|
130
127
|
- `ETH` (Ethereum)
|
|
131
128
|
- `SOL` (Solana)
|
|
@@ -156,11 +153,11 @@ $ cw -l
|
|
|
156
153
|
- `NBT` (NIX Bridge Token)
|
|
157
154
|
- `PLS` (PulseChain)
|
|
158
155
|
|
|
159
|
-
*all other cryptos that are tokens in the ecosystems like Ethereum, Binance Smart Chain
|
|
156
|
+
*all other cryptos that are tokens in the ecosystems like Ethereum, Base, Binance Smart Chain and others chains are supported as well (L1/L2/L3, etc.)*
|
|
160
157
|
|
|
161
158
|
## Options
|
|
162
159
|
|
|
163
|
-
- `-
|
|
160
|
+
- `-c` or `--chain`: Specify the chain/coin ticker to generate a wallet for
|
|
164
161
|
- `-C` or `--copy`: Copy the generated mnemonic to the clipboard
|
|
165
162
|
- `-D` or `--csv`: Save output into CSV file with custom or default name ("`cw-output.csv`") - this is a shorthand for `-o csv -F filename`
|
|
166
163
|
- `-f` or `--format`: Specify the blockchain wallet format (for BTC: legacy, segwit, bech32)
|
|
@@ -181,7 +178,7 @@ $ cw -l
|
|
|
181
178
|
- `-S` or `--suffix-sensitive`: Specify desired suffix for the wallet address (**case-sensitive**)
|
|
182
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)
|
|
183
180
|
- `-q` or `--qr`: Display QR code with the generated wallet address (works only without `-n` argument)
|
|
184
|
-
- `-v` or `--version`: Display current version of
|
|
181
|
+
- `-v` or `--version`: Display current version of `cw` tool
|
|
185
182
|
|
|
186
183
|
**Currently not necessary options:**
|
|
187
184
|
|
package/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
import { config } from 'dotenv';
|
|
4
5
|
import os from 'node:os';
|
|
5
6
|
import {
|
|
6
7
|
Worker,
|
|
@@ -14,9 +15,37 @@ import { exit, log, supportedChains } from './src/utils.js';
|
|
|
14
15
|
import Method from './src/Method.js';
|
|
15
16
|
import chalk from 'chalk';
|
|
16
17
|
|
|
18
|
+
// load environment variables
|
|
19
|
+
config();
|
|
20
|
+
|
|
17
21
|
// get the current file path
|
|
18
22
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
23
|
|
|
24
|
+
// check if the app is running in development mode
|
|
25
|
+
const isDev = process.env.NODE_ENV === 'development';
|
|
26
|
+
|
|
27
|
+
// check if there is a need for multi-threading
|
|
28
|
+
const isMultiThreaded =
|
|
29
|
+
options.prefix ||
|
|
30
|
+
options.suffix ||
|
|
31
|
+
options['suffix-sensitive'] ||
|
|
32
|
+
options['prefix-sensitive'] ||
|
|
33
|
+
options.threads ||
|
|
34
|
+
isMainThread ||
|
|
35
|
+
workerData ||
|
|
36
|
+
false;
|
|
37
|
+
|
|
38
|
+
// check if the mnemonic string is requested (not provided)
|
|
39
|
+
const isMnemonicString =
|
|
40
|
+
options.mnemonic &&
|
|
41
|
+
(options.mnemonic === true ||
|
|
42
|
+
options.mnemonic === '' ||
|
|
43
|
+
options.mnemonic.split(' ').length === 1);
|
|
44
|
+
|
|
45
|
+
// check if the wallet generation is enabled
|
|
46
|
+
const isWalletGeneration =
|
|
47
|
+
!isMnemonicString && !options.list && !options.version && !options.donate;
|
|
48
|
+
|
|
20
49
|
// show all supported chains
|
|
21
50
|
if (options.list) {
|
|
22
51
|
(async () => {
|
|
@@ -25,13 +54,8 @@ if (options.list) {
|
|
|
25
54
|
})();
|
|
26
55
|
}
|
|
27
56
|
|
|
28
|
-
// generate mnemonic string
|
|
29
|
-
if (
|
|
30
|
-
options.mnemonic &&
|
|
31
|
-
(options.mnemonic === true ||
|
|
32
|
-
options.mnemonic === '' ||
|
|
33
|
-
options.mnemonic.split(' ').length === 1)
|
|
34
|
-
) {
|
|
57
|
+
// generate mnemonic string (12/15/18/21/24 words)
|
|
58
|
+
if (isMnemonicString) {
|
|
35
59
|
(async () => {
|
|
36
60
|
new Method('mnemonic').init({
|
|
37
61
|
mnemonic: options.mnemonic,
|
|
@@ -63,7 +87,6 @@ if (!supportedChains.includes(chain)) {
|
|
|
63
87
|
log(chalk.red('⛔️ Error: this chain is not supported!'));
|
|
64
88
|
exit(1);
|
|
65
89
|
}
|
|
66
|
-
options.b = chain; // ensure the chain is passed to the Method class
|
|
67
90
|
|
|
68
91
|
// multi-threads mode (only for suffix, prefix, number)
|
|
69
92
|
const allMachineThreads = os.cpus().length;
|
|
@@ -79,112 +102,119 @@ if (inputThreads > availableThreads) {
|
|
|
79
102
|
numThreads = inputThreads;
|
|
80
103
|
}
|
|
81
104
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
sharedArray[0] = 0; // 0 - not found, 1 - found
|
|
105
|
-
|
|
106
|
-
for (let i = 0; i < numThreads; i++) {
|
|
107
|
-
const worker = new Worker(__filename, {
|
|
108
|
-
workerData: {
|
|
109
|
-
workerId: i,
|
|
110
|
-
totalWorkers: numThreads,
|
|
111
|
-
chain,
|
|
112
|
-
options: JSON.parse(JSON.stringify(options)),
|
|
113
|
-
sharedBuffer,
|
|
114
|
-
},
|
|
115
|
-
stdout: true, // enable capturing stdout
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// pipe worker stdout to main process
|
|
119
|
-
worker.stdout.on('data', (data) => {
|
|
120
|
-
if (Atomics.load(sharedArray, 0) === 0) {
|
|
121
|
-
process.stdout.write(data); // forward stdout to main process
|
|
122
|
-
|
|
123
|
-
return data;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
105
|
+
// wallet generation
|
|
106
|
+
if (isMultiThreaded && isWalletGeneration) {
|
|
107
|
+
if (isMainThread) {
|
|
108
|
+
if (numThreads === 1) {
|
|
109
|
+
console.log(
|
|
110
|
+
chalk.cyan(
|
|
111
|
+
'🐢 Using only 1 thread to generate a wallet, this might take a while...'
|
|
112
|
+
),
|
|
113
|
+
chalk.gray(
|
|
114
|
+
`(pass "-t ${availableThreads}" to use all available threads)`
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
} else {
|
|
118
|
+
console.log(
|
|
119
|
+
chalk.cyan(
|
|
120
|
+
`⚡ Using ${numThreads}/${allMachineThreads} threads to generate a wallet...`
|
|
121
|
+
),
|
|
122
|
+
chalk.gray(
|
|
123
|
+
`(pass "-t ${availableThreads}" to use all available threads)`
|
|
124
|
+
)
|
|
125
|
+
);
|
|
126
|
+
}
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const workers = [];
|
|
129
|
+
|
|
130
|
+
// create a shared buffer to communicate between workers
|
|
131
|
+
const sharedBuffer = new SharedArrayBuffer(4); // 4 bytes for the flag
|
|
132
|
+
const sharedArray = new Int32Array(sharedBuffer);
|
|
133
|
+
sharedArray[0] = 0; // 0 - not found, 1 - found
|
|
134
|
+
|
|
135
|
+
for (let i = 0; i < numThreads; i++) {
|
|
136
|
+
const worker = new Worker(__filename, {
|
|
137
|
+
workerData: {
|
|
138
|
+
workerId: i,
|
|
139
|
+
totalWorkers: numThreads,
|
|
140
|
+
chain,
|
|
141
|
+
options: JSON.parse(JSON.stringify(options)),
|
|
142
|
+
sharedBuffer,
|
|
143
|
+
},
|
|
144
|
+
stdout: true, // enable capturing stdout
|
|
145
|
+
});
|
|
131
146
|
|
|
132
|
-
|
|
133
|
-
|
|
147
|
+
// pipe worker stdout to main process
|
|
148
|
+
worker.stdout.on('data', (data) => {
|
|
149
|
+
if (Atomics.load(sharedArray, 0) === 0) {
|
|
150
|
+
process.stdout.write(data); // forward stdout to main process
|
|
134
151
|
|
|
135
|
-
|
|
136
|
-
|
|
152
|
+
return data;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
137
155
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
156
|
+
worker.on('message', (message) => {
|
|
157
|
+
if (Atomics.load(sharedArray, 0) === 0) {
|
|
158
|
+
// set the shared flag to 1 to stop all workers
|
|
159
|
+
Atomics.store(sharedArray, 0, 1);
|
|
141
160
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
);
|
|
161
|
+
// print the log output from the worker
|
|
162
|
+
process.stdout.write(message.log);
|
|
145
163
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
} else {
|
|
149
|
-
// worker thread (multi-threaded mode)
|
|
150
|
-
(async () => {
|
|
151
|
-
try {
|
|
152
|
-
// read shared flag before starting work
|
|
153
|
-
const sharedArray = new Int32Array(workerData.sharedBuffer);
|
|
154
|
-
if (Atomics.load(sharedArray, 0) === 1) {
|
|
155
|
-
process.exit(0); // exit early if a wallet has already been found
|
|
156
|
-
}
|
|
164
|
+
// terminate all workers
|
|
165
|
+
workers.forEach((w) => w.terminate());
|
|
157
166
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
b: workerData.chain,
|
|
161
|
-
chain: workerData.chain,
|
|
162
|
-
options: workerData.options,
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
163
169
|
});
|
|
164
170
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
process.stdout.write = (chunk, encoding, callback) => {
|
|
169
|
-
logOutput += chunk.toString();
|
|
170
|
-
if (callback) callback();
|
|
171
|
-
};
|
|
171
|
+
worker.on('error', (err) =>
|
|
172
|
+
console.error(`❌ Worker error: ${err.message}`)
|
|
173
|
+
);
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
await method.init();
|
|
175
|
-
|
|
176
|
-
// restore stdout
|
|
177
|
-
process.stdout.write = originalWrite;
|
|
178
|
-
|
|
179
|
-
// check the shared flag again before sending the result
|
|
180
|
-
if (Atomics.load(sharedArray, 0) === 1) {
|
|
181
|
-
process.exit(0);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// send the log output to the main thread
|
|
185
|
-
parentPort.postMessage({ log: logOutput });
|
|
186
|
-
} catch (err) {
|
|
187
|
-
console.error(`Worker ${workerData.workerId} failed: ${err.message}`);
|
|
175
|
+
workers.push(worker);
|
|
188
176
|
}
|
|
189
|
-
}
|
|
177
|
+
} else {
|
|
178
|
+
// worker thread
|
|
179
|
+
(async () => {
|
|
180
|
+
try {
|
|
181
|
+
// read shared flag before starting work
|
|
182
|
+
const sharedArray = new Int32Array(workerData.sharedBuffer);
|
|
183
|
+
if (Atomics.load(sharedArray, 0) === 1) {
|
|
184
|
+
process.exit(0); // exit early if a wallet has already been found
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// create a new Method instance
|
|
188
|
+
const method = new Method('wallet', {
|
|
189
|
+
b: workerData.chain,
|
|
190
|
+
chain: workerData.chain,
|
|
191
|
+
options: workerData.options,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// capture stdout logs in a buffer
|
|
195
|
+
let logOutput = '';
|
|
196
|
+
const originalWrite = process.stdout.write;
|
|
197
|
+
process.stdout.write = (chunk, encoding, callback) => {
|
|
198
|
+
logOutput += chunk.toString();
|
|
199
|
+
if (callback) callback();
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// print the wallet to stdout
|
|
203
|
+
await method.init();
|
|
204
|
+
|
|
205
|
+
// restore stdout
|
|
206
|
+
process.stdout.write = originalWrite;
|
|
207
|
+
|
|
208
|
+
// check the shared flag again before sending the result
|
|
209
|
+
if (Atomics.load(sharedArray, 0) === 1) {
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// send the log output to the main thread
|
|
214
|
+
parentPort.postMessage({ log: logOutput });
|
|
215
|
+
} catch (err) {
|
|
216
|
+
console.error(`Worker ${workerData.workerId} failed: ${err.message}`);
|
|
217
|
+
}
|
|
218
|
+
})();
|
|
219
|
+
}
|
|
190
220
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yerofey/cryptowallet-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.39.0",
|
|
4
4
|
"description": "Crypto wallet generator CLI tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/yerofey/cryptowallet-cli",
|
|
@@ -133,6 +133,7 @@
|
|
|
133
133
|
"ed25519-hd-key": "^1.3.0",
|
|
134
134
|
"eth-lib": "0.1.29",
|
|
135
135
|
"ethereum-bip84": "0.0.3",
|
|
136
|
+
"ethereum-cryptography": "^3.1.0",
|
|
136
137
|
"ethereum-mnemonic-privatekey-utils": "1.0.5",
|
|
137
138
|
"qrcode-terminal": "^0.12.0",
|
|
138
139
|
"tezos-sign": "1.4.1",
|
package/src/Method.js
CHANGED
|
@@ -544,8 +544,8 @@ class Method {
|
|
|
544
544
|
// network
|
|
545
545
|
if (cw.row.network == 'EVM' || false) {
|
|
546
546
|
log(
|
|
547
|
-
|
|
548
|
-
'🆒 You can use this wallet for Ethereum,
|
|
547
|
+
blue(
|
|
548
|
+
'🆒 You can use this wallet for Ethereum, Base or any other L1/L2/L3 chain (EVM compatible)'
|
|
549
549
|
)
|
|
550
550
|
);
|
|
551
551
|
}
|
package/src/Wallet.js
CHANGED
|
@@ -398,7 +398,8 @@ class Wallet {
|
|
|
398
398
|
const mnemonic = mnemonicString || generateMnemonicString(mnemonicLength);
|
|
399
399
|
const privateKey = pkutils.getPrivateKeyFromMnemonic(mnemonic);
|
|
400
400
|
|
|
401
|
-
|
|
401
|
+
const numberIsSupported = row.flags.includes('n') || false;
|
|
402
|
+
if (!numberIsSupported || number == 1) {
|
|
402
403
|
const account = Account.fromPrivate('0x' + privateKey);
|
|
403
404
|
|
|
404
405
|
addresses.push({
|
|
@@ -407,6 +408,7 @@ class Wallet {
|
|
|
407
408
|
privateKey,
|
|
408
409
|
});
|
|
409
410
|
} else {
|
|
411
|
+
// ! known issue: "Cannot read properties of undefined (reading 'fromBase58')"
|
|
410
412
|
// TODO: add variable for accountId
|
|
411
413
|
const root = new fromMnemonicEthereum(mnemonic, '');
|
|
412
414
|
const child = root.deriveAccount(0);
|
|
@@ -619,7 +621,7 @@ class Wallet {
|
|
|
619
621
|
addresses: addresses,
|
|
620
622
|
mnemonic: mnemonicString,
|
|
621
623
|
});
|
|
622
|
-
} else if (chain == 'TRX') {
|
|
624
|
+
} else if (chain == 'TRX' || row.network == 'TRON') {
|
|
623
625
|
try {
|
|
624
626
|
// Validate mnemonic
|
|
625
627
|
if (mnemonicString !== '' && !bip39.validateMnemonic(mnemonicString)) {
|
package/src/chains/BNB.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"startsWith": "0x",
|
|
16
16
|
"prefixTest": "[0-9a-fA-F]",
|
|
17
17
|
"apps": ["metamask", "trustwallet", "binance-chain-wallet"],
|
|
18
|
-
"flags": ["f", "m", "
|
|
18
|
+
"flags": ["f", "m", "p", "s"]
|
|
19
19
|
},
|
|
20
20
|
"ERC20": {
|
|
21
21
|
"format": "ERC20",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"startsWith": "0x",
|
|
24
24
|
"prefixTest": "[0-9a-f]",
|
|
25
25
|
"apps": ["metamask", "trustwallet", "binance-chain-wallet"],
|
|
26
|
-
"flags": ["f", "m", "
|
|
26
|
+
"flags": ["f", "m", "p", "s"]
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
package/src/chains/BSC.json
CHANGED
package/src/chains/ETC.json
CHANGED
package/src/chains/ETH.json
CHANGED
package/src/chains/EVM.json
CHANGED
package/src/options.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { program } from 'commander';
|
|
2
2
|
|
|
3
|
-
program.option('-b <ticker>', 'Wallet for specific blockchain', 'EVM');
|
|
4
3
|
program.option('-c, --chain <ticker>', 'Wallet for specific blockchain', 'EVM');
|
|
5
4
|
program.option('-C, --copy', 'Copy the result to the clipboard');
|
|
6
5
|
program.option('-D, --csv [filename]', 'Save result into CSV file');
|