Skip to content

Commit

Permalink
v1.3.0: suffix support added (yerofey#5), probably not stable relea…
Browse files Browse the repository at this point in the history
…se yet
  • Loading branch information
yerofey committed Apr 13, 2022
1 parent 485b82d commit 0120096
Show file tree
Hide file tree
Showing 32 changed files with 205 additions and 88 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ $ cw
# generate random ERC-like wallet with desired prefix
$ cw -p aaa

# generate random BTC wallet (default format: bech32 - bc1...)
# generate random BTC wallet (default format: bech32 - "bc1q...")
$ cw -c BTC

# generate random BTC wallet with desired prefix (case sensitive)
Expand All @@ -32,10 +32,10 @@ $ cw -c BTC -p ABC
# generate random BTC wallet with desired prefix (case insensitive)
$ cw -c BTC -P abc

# generate BTC legacy wallet (1...)
# generate BTC legacy wallet ("1...")
$ cw -c BTC -f legacy

# generate BTC segwit wallet (3...)
# generate BTC segwit wallet ("3...")
$ cw -c BTC -f segwit

# generate BTC bech32 wallet from mnemonic string
Expand Down Expand Up @@ -95,13 +95,15 @@ $ cw -l
* `-l` or `--list`: List all supported cryptocurrencies
* `-m` or `--mnemonic`: Use a bip39 mnemonic phrase (if is set) to generate wallet, or leave it empty to generate new one
* `-n` or `--number`: Specify number of wallets to display (works for HD wallets only, like BTC/LTC/DOGE)
* `-p` or `--prefix`: Specify desired prefix of an wallet address (case sensitive)
* `-P` or `--prefix-ignorecase`: Specify desired prefix of an wallet address (case insensitive)
* `-p` or `--prefix`: Specify desired prefix of an wallet address (**case-sensitive**)
* `-P` or `--prefix-ignorecase`: Specify desired prefix of an wallet address (**case-insensitive**)
* `-s` or `--suffix`: Specify desired suffix of an wallet address (**case-sensitive**)
* `-S` or `--suffix-ignorecase`: Specify desired suffix of an wallet address (**case-insensitive**)
* `-v` or `--version`: Display the version of CW tool

## Highlights
- 24 blockchains supported
- Generate wallet with desired prefix
- 24+ blockchains supported
- Generate wallet with desired prefix/suffix
- Generate wallet from mnemonic
- Generate just a mnemonic
- Works fully offline
Expand Down
2 changes: 2 additions & 0 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ program.option('-m, --mnemonic [mnemonic]', 'Generate wallet from mnemonic strin
program.option('-n, --number <number>', 'Number of wallets to generate (if supported)');
program.option('-p, --prefix <prefix>', 'Desired wallet prefix (case sensitive)');
program.option('-P, --prefix-ignorecase <prefix>', 'Desired wallet prefix (case insensitive)');
program.option('-s, --suffix <suffix>', 'Desired wallet suffix (case sensitive)');
program.option('-S, --suffix-ignorecase <suffix>', 'Desired wallet suffix (case insensitive)');
program.option('-v, --version', 'Display cryptowallet version');
program.parse();

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yerofey/cryptowallet-cli",
"version": "1.2.12",
"version": "1.3.0",
"homepage": "https://github.com/yerofey/cryptowallet-cli",
"author": "Yerofey S. <[email protected]> (https://github.com/yerofey)",
"bin": {
Expand Down
4 changes: 3 additions & 1 deletion src/CW.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ class CW {
mnemonic: '',
number: 1,
prefix: options.prefixIgnorecase || '',
prefixIgnoreCase: options.prefixIgnorecase !== undefined
prefixIgnoreCase: options.prefixIgnorecase !== undefined,
suffix: options.suffixIgnorecase || '',
suffixIgnoreCase: options.suffixIgnorecase !== undefined,
}

for (const key of Object.keys(defaultValues)) {
Expand Down
45 changes: 30 additions & 15 deletions src/Method.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class Method {
log(`😢 ${chalk.yellow('Sorry, ' + coinFullName + ' does not support prefix yet...')}`);
}

if (cw.options.suffix && !cw.suffixFound) {
log(`😢 ${chalk.yellow('Sorry, ' + coinFullName + ' does not support suffix yet...')}`);
}

if (cw.options.mnemonic != '' && cw.wallet.mnemonic == undefined) {
log(`😢 ${chalk.yellow('Sorry, ' + coinFullName + ' does not support mnemonic yet...')}`);
}
Expand All @@ -62,9 +66,19 @@ class Method {
return;
}

log(`✨ ${chalk.green('Done!')} ${chalk.blueBright('Here is your brand new ' + coinFullName + ' wallet' + (cw.prefixFound ? ' with "' + cw.options.prefix + '" prefix' : '') + ':')}\n`);

if (cw.wallet.addresses !== undefined) { // multiple addresses wallet
// prefix, suffix
if (cw.prefixFound && cw.suffixFound) {
log(`✨ ${chalk.green('Done!')} ${chalk.blueBright('Here is your brand new ' + coinFullName + ' wallet with "' + cw.options.prefix + '" prefix and "' + cw.options.suffix + '" suffix:')}\n`);
} else if (cw.prefixFound) {
log(`✨ ${chalk.green('Done!')} ${chalk.blueBright('Here is your brand new ' + coinFullName + ' wallet with "' + cw.options.prefix + '" prefix:')}\n`);
} else if (cw.suffixFound) {
log(`✨ ${chalk.green('Done!')} ${chalk.blueBright('Here is your brand new ' + coinFullName + ' wallet with "' + cw.options.suffix + '" suffix:')}\n`);
} else {
log(`✨ ${chalk.green('Done!')} ${chalk.blueBright('Here is your brand new ' + coinFullName + ' wallet:')}\n`);
}

// result
if (cw.wallet.addresses !== undefined) {
if (cw.wallet.privateExtendedKey) {
log(`🔐 ${cw.wallet.privateExtendedKey}`);
}
Expand All @@ -77,9 +91,21 @@ class Method {
if (cw.wallet.addresses.length > 1) {
log(`🆔 ${item.index}`);
}
if (cw.prefixFound && cw.prefixFoundInWallets.includes(item.address)) {

if (cw.prefixFound && cw.prefixFoundInWallets.includes(item.address) && cw.suffixFound && cw.suffixFoundInWallets.includes(item.address)) {
// highlight found prefix
// log(`👛 ${item.address}`);
const addressCutPrefixLength = cw.row.startsWith.length + cw.options.prefix.length;
const addressFirstPart = item.address.slice(cw.row.startsWith.length, addressCutPrefixLength);
const addressLastPart = item.address.slice(item.address.length - cw.options.suffix.length);
log(`👛 ${cw.row.startsWith}${chalk.magenta(addressFirstPart)}${item.address.substring(cw.row.startsWith.length + addressFirstPart.length, item.address.length - addressLastPart.length)}${chalk.magenta(addressLastPart)}`);
} else if (cw.prefixFound && cw.prefixFoundInWallets.includes(item.address)) {
// highlight found prefix
const addressCutLength = cw.row.startsWith.length + cw.options.prefix.length;
log(`👛 ${cw.row.startsWith}${chalk.magenta(item.address.slice(cw.row.startsWith.length, addressCutLength))}${item.address.slice(addressCutLength)}`);
} else if (cw.suffixFound && cw.suffixFoundInWallets.includes(item.address)) {
// highlight found suffix
log(`👛 ${item.address.slice(0, item.address.length - cw.options.suffix.length)}${chalk.magenta(item.address.slice(item.address.length - cw.options.suffix.length))}`);
} else {
log(`👛 ${item.address}`);
}
Expand All @@ -90,17 +116,6 @@ class Method {
log();
log(`🗂 wallet address path: ${cw.row.path}'/0'/0/ID`);
}
} else { // single address wallet
if (cw.prefixFound) {
const addressCutLength = cw.row.startsWith.length + cw.options.prefix.length;
log(`👛 ${cw.row.startsWith}${chalk.magenta(cw.wallet.address.slice(cw.row.startsWith.length, addressCutLength))}${cw.wallet.address.slice(addressCutLength)}`);
} else {
log(`👛 ${cw.wallet.address}`);
}
log(`🔑 ${cw.wallet.privateKey}`);
if (cw.wallet.mnemonic) {
log(`📄 ${cw.wallet.mnemonic}`);
}
}

if (cw.row.formats !== undefined || cw.row.network == 'EVM' || cw.row.apps || cw.wallet.tested !== undefined) {
Expand Down
122 changes: 92 additions & 30 deletions src/Wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,79 @@ class Wallet {
const row = cw.row;
const options = cw.options;

const prefixBadSymbolsArray = (options.prefix != '' ? options.prefix.split('').filter(char => !RegExp(row.prefixTest, 'g').test(char)) : []);
const badSymbolsArray = (options.prefix != '' ? options.prefix.split('').filter(char => !RegExp(row.prefixTest, 'g').test(char)) : []);
let wallet = {};
let prefixFound = false;
let prefixFoundInWallets = [];
let suffixFound = false;
let suffixFoundInWallets = [];
let onlyPrefix = false;
let onlySuffix = false;
let onlyBoth = false;

if (options.prefix && row.flags.includes('p')) {
if (prefixBadSymbolsArray.length === 0) {
if (options.prefix.length > 1 || 'rareSymbols' in row && RegExp(row.rareSymbols, 'g').test(options.prefix)) {
log(`⏳ Generating wallet with "${options.prefix}" prefix, this might take a while...`);
const prefixFoundInAddress = (address, isIgnoringCase, prefix, symbol) => (!isIgnoringCase && address.startsWith(symbol + '' + prefix) || isIgnoringCase && (address).toUpperCase().startsWith((symbol + '' + prefix).toUpperCase()));
const suffixFoundInAddress = (address, isIgnoringCase, suffix) => (!isIgnoringCase && address.endsWith(suffix) || isIgnoringCase && (address).toUpperCase().endsWith(suffix));

if (options.prefix && row.flags.includes('p') || options.suffix && row.flags.includes('s')) {
if (badSymbolsArray.length === 0) {
if (options.prefix && options.suffix) {
// prefix & suffix
log(`⏳ Generating wallet with "${options.prefix}" prefix and "${options.suffix}" suffix, this for sure will take a while...`);
onlyBoth = true;
} else {
// prefix
if (options.prefix.length > 0 || 'rareSymbols' in row && RegExp(row.rareSymbols, 'g').test(options.prefix)) {
log(`⏳ Generating wallet with "${options.prefix}" prefix, this might take a while...`);
onlyPrefix = true;
}
// suffix
if (options.suffix.length > 0 || 'rareSymbols' in row && RegExp(row.rareSymbols, 'g').test(options.suffix)) {
log(`⏳ Generating wallet with "${options.suffix}" suffix, this might take a while...`);
onlySuffix = true;
}
}

const startsWithSymbols = row.startsWith.split('|');
loop:
while (true) {
wallet = await this.createWallet();
for (let firstSymbol of startsWithSymbols) {
if (wallet.address !== undefined) {
if (!options.prefixIgnoreCase && wallet.address.startsWith(firstSymbol + '' + options.prefix) || options.prefixIgnoreCase && (wallet.address).toUpperCase().startsWith((firstSymbol + '' + options.prefix).toUpperCase())) {
if (wallet.address !== undefined) { // one address
if (onlyPrefix && prefixFoundInAddress(wallet.address, options.prefixIgnoreCase, options.prefix, firstSymbol)) {
prefixFound = true;
break loop;
}
} else if (wallet.addresses !== undefined) {

if (onlySuffix && suffixFoundInAddress(wallet.address, options.suffixIgnoreCase, options.suffix)) {
suffixFound = true;
break loop;
}

if (onlyBoth && prefixFoundInAddress(wallet.address, options.prefixIgnoreCase, options.prefix, firstSymbol) && suffixFoundInAddress(wallet.address, options.suffixIgnoreCase, options.suffix)) {
prefixFound = true;
suffixFound = true;
break loop;
}
} else if (wallet.addresses !== undefined) { // multiple addresses
for (let item of wallet.addresses) {
if (!options.prefixIgnoreCase && (item.address).startsWith(firstSymbol + '' + options.prefix) || options.prefixIgnoreCase && (item.address).toUpperCase().startsWith((firstSymbol + '' + options.prefix).toUpperCase())) {
if (onlyPrefix && prefixFoundInAddress(item.address, options.prefixIgnoreCase, options.prefix, firstSymbol)) {
prefixFound = true;
prefixFoundInWallets.push(item.address);
}

if (onlySuffix && suffixFoundInAddress(item.address, options.suffixIgnoreCase, options.suffix)) {
suffixFound = true;
suffixFoundInWallets.push(item.address);
}

if (onlyBoth && prefixFoundInAddress(item.address, options.prefixIgnoreCase, options.prefix, firstSymbol) && suffixFoundInAddress(item.address, options.suffixIgnoreCase, options.suffix)) {
prefixFound = true;
prefixFoundInWallets.push(item.address);
suffixFound = true;
suffixFoundInWallets.push(item.address);
}
}
if (prefixFound) {
if (onlyPrefix && prefixFound || onlySuffix && suffixFound || onlyBoth && prefixFound && suffixFound) {
break loop;
}
} else {
Expand All @@ -48,12 +93,13 @@ class Wallet {
}
}
} else {
let prefixBadSymbolsString = '';
for (const symbol of prefixBadSymbolsArray) {
prefixBadSymbolsString += '"' + symbol + '", ';
let badSymbolsString = '';
for (const symbol of badSymbolsArray) {
badSymbolsString += '"' + symbol + '", ';
}

log(chalk.red('⛔️ Error: prefix contains non-supported characters (' + prefixBadSymbolsString.substr(0, prefixBadSymbolsString.length - 2) + ')!'));
// TODO: add prefix/suffix own message log
log(chalk.red('⛔️ Error: prefix or suffix contains non-supported characters (' + badSymbolsString.substr(0, badSymbolsString.length - 2) + ')!'));
process.exit(1);
}
} else {
Expand All @@ -63,7 +109,9 @@ class Wallet {
return {
wallet,
prefixFound,
prefixFoundInWallets
prefixFoundInWallets,
suffixFound,
suffixFoundInWallets,
};
}

Expand All @@ -80,7 +128,7 @@ class Wallet {

if (row.length == 0) {
return {
error: 'coin not found'
error: 'coin not found',
}
}

Expand All @@ -92,8 +140,11 @@ class Wallet {

result = Object.assign(result, {
format,
address: wallet.publicAddress,
privateKey: wallet.privateWif,
addresses: [{
index: 0,
address: wallet.publicAddress,
privateKey: wallet.privateWif,
}]
});
} else if (coin == 'BTC') {
const bip39 = require('bip39');
Expand Down Expand Up @@ -175,6 +226,7 @@ class Wallet {
if (number == 1) {
const privateKey = bCrypto.getPrivateKeyFromMnemonic(mnemonic, true, 0);
addresses.push({
index: 0,
address: bCrypto.getAddressFromPrivateKey(privateKey, 'bnb'),
privateKey
});
Expand Down Expand Up @@ -202,7 +254,7 @@ class Wallet {

if (mnemonicString != '' && !bip39.validateMnemonic(mnemonicString)) {
return {
error: 'mnemonic is not valid'
error: 'mnemonic is not valid',
}
}

Expand All @@ -214,8 +266,9 @@ class Wallet {
const account = Account.fromPrivate('0x' + privateKey);

addresses.push({
index: 0,
address: account.address,
privateKey
privateKey,
});
} else {
// TODO: add variable for accountId
Expand All @@ -229,15 +282,15 @@ class Wallet {
addresses.push({
index: walletId,
address: walletAddress,
privateKey
privateKey,
});
}
}

Object.assign(result, {
format: row.format || '',
addresses,
mnemonic
mnemonic,
});
} else if (coin == 'ONE') {
const bip39 = require('bip39');
Expand All @@ -256,9 +309,12 @@ class Wallet {
const account = wallet.getAccount(publicKey);

Object.assign(result, {
address: account.bech32Address,
privateKey: account.privateKey,
mnemonic
addresses: [{
index: 0,
address: account.bech32Address,
privateKey: account.privateKey,
}],
mnemonic,
});
} else if (coin == 'TRX') {
const tronWeb = require('tronweb');
Expand All @@ -267,8 +323,11 @@ class Wallet {
const wallet = await tronWeb.createAccount();

Object.assign(result, {
address: wallet.address.base58,
privateKey: wallet.privateKey
addresses: [{
index: 0,
address: wallet.address.base58,
privateKey: wallet.privateKey
}],
});
} catch (error) {
return {
Expand All @@ -280,8 +339,11 @@ class Wallet {
const wallet = tezos.generateKeysNoSeed();

Object.assign(result, {
address: wallet.pkh,
privateKey: wallet.sk
addresses: [{
index: 0,
address: wallet.pkh,
privateKey: wallet.sk,
}],
});
} else {
return {
Expand All @@ -291,7 +353,7 @@ class Wallet {

if (row.tested !== undefined && row.tested == false) {
Object.assign(result, {
tested: false
tested: false,
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/coins/BCH.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"prefixTest": "(?![0OI])[1-9a-zA-Z]",
"rareSymbols": "[1-9]",
"flags": [
"p"
"p",
"s"
]
}
Loading

0 comments on commit 0120096

Please sign in to comment.