codecrypto-cli 1.0.13 ā 1.0.15
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 +345 -21
- package/dist/commands/auth.js +1 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/deploy-sc.d.ts.map +1 -1
- package/dist/commands/deploy-sc.js +39 -3
- package/dist/commands/deploy-sc.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +240 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-keys.d.ts +3 -0
- package/dist/commands/generate-keys.d.ts.map +1 -0
- package/dist/commands/generate-keys.js +159 -0
- package/dist/commands/generate-keys.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/commands/auth.ts +1 -1
- package/src/commands/deploy-sc.ts +43 -3
- package/src/commands/doctor.ts +244 -13
- package/src/commands/generate-keys.ts +139 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as os from 'os';
|
|
7
|
+
import { ethers } from 'ethers';
|
|
8
|
+
|
|
9
|
+
interface Account {
|
|
10
|
+
address: string;
|
|
11
|
+
private_key: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface KeysFile {
|
|
15
|
+
mnemonic: string;
|
|
16
|
+
accounts: Account[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const generateKeysCommand = new Command('generate-keys')
|
|
20
|
+
.description('Generate Foundry keys file with mnemonic and derived accounts')
|
|
21
|
+
.option('-m, --mnemonic <mnemonic>', 'Mnemonic phrase (if not provided, a random one will be generated)')
|
|
22
|
+
.option('-n, --count <number>', 'Number of accounts to generate', '10')
|
|
23
|
+
.option('-o, --output <path>', 'Output file path', '~/.foundry/keys.json')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
console.log(chalk.blue('\nš CodeCrypto Foundry Keys Generator\n'));
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// Parse count
|
|
29
|
+
const accountCount = parseInt(options.count, 10);
|
|
30
|
+
if (isNaN(accountCount) || accountCount < 1 || accountCount > 100) {
|
|
31
|
+
console.error(chalk.red('ā Error: Account count must be between 1 and 100'));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Generate or use provided mnemonic
|
|
36
|
+
let mnemonic: string;
|
|
37
|
+
if (options.mnemonic) {
|
|
38
|
+
mnemonic = options.mnemonic.trim();
|
|
39
|
+
// Validate mnemonic
|
|
40
|
+
if (!ethers.Mnemonic.isValidMnemonic(mnemonic)) {
|
|
41
|
+
console.error(chalk.red('ā Error: Invalid mnemonic phrase'));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
// Generate random mnemonic
|
|
46
|
+
const spinner = ora('Generating random mnemonic...').start();
|
|
47
|
+
mnemonic = ethers.Mnemonic.entropyToPhrase(ethers.randomBytes(16));
|
|
48
|
+
spinner.succeed('Random mnemonic generated');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Derive accounts
|
|
52
|
+
const accountsSpinner = ora(`Deriving ${accountCount} account(s) from mnemonic...`).start();
|
|
53
|
+
const accounts: Account[] = [];
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
for (let i = 0; i < accountCount; i++) {
|
|
57
|
+
// Use HDNodeWallet.fromPhrase with the full derivation path
|
|
58
|
+
// This creates a wallet directly from mnemonic at the specified path
|
|
59
|
+
const wallet = ethers.HDNodeWallet.fromPhrase(mnemonic, `m/44'/60'/0'/0/${i}`);
|
|
60
|
+
accounts.push({
|
|
61
|
+
address: wallet.address,
|
|
62
|
+
private_key: wallet.privateKey,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
accountsSpinner.succeed(`Generated ${accountCount} account(s)`);
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
accountsSpinner.fail('Failed to derive accounts');
|
|
69
|
+
console.error(chalk.red(`ā Error: ${error.message}`));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Prepare output data
|
|
74
|
+
const keysData: KeysFile = {
|
|
75
|
+
mnemonic,
|
|
76
|
+
accounts,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Resolve output path
|
|
80
|
+
let outputPath = options.output;
|
|
81
|
+
if (outputPath.startsWith('~')) {
|
|
82
|
+
outputPath = path.join(os.homedir(), outputPath.slice(1));
|
|
83
|
+
}
|
|
84
|
+
outputPath = path.resolve(outputPath);
|
|
85
|
+
|
|
86
|
+
// Create directory if it doesn't exist
|
|
87
|
+
const outputDir = path.dirname(outputPath);
|
|
88
|
+
if (!fs.existsSync(outputDir)) {
|
|
89
|
+
const dirSpinner = ora(`Creating directory: ${outputDir}`).start();
|
|
90
|
+
try {
|
|
91
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
92
|
+
dirSpinner.succeed(`Directory created: ${outputDir}`);
|
|
93
|
+
} catch (error: any) {
|
|
94
|
+
dirSpinner.fail('Failed to create directory');
|
|
95
|
+
console.error(chalk.red(`ā Error: ${error.message}`));
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Write file
|
|
101
|
+
const writeSpinner = ora(`Writing keys to ${outputPath}...`).start();
|
|
102
|
+
try {
|
|
103
|
+
fs.writeFileSync(outputPath, JSON.stringify(keysData, null, 2), 'utf-8');
|
|
104
|
+
writeSpinner.succeed(`Keys saved to ${outputPath}`);
|
|
105
|
+
} catch (error: any) {
|
|
106
|
+
writeSpinner.fail('Failed to write file');
|
|
107
|
+
console.error(chalk.red(`ā Error: ${error.message}`));
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Display summary
|
|
112
|
+
console.log(chalk.green('\nā
Keys generated successfully!\n'));
|
|
113
|
+
console.log(chalk.gray('Summary:'));
|
|
114
|
+
console.log(chalk.white(` Mnemonic: ${chalk.cyan(mnemonic)}`));
|
|
115
|
+
console.log(chalk.white(` Accounts: ${chalk.cyan(accountCount)}`));
|
|
116
|
+
console.log(chalk.white(` Output: ${chalk.cyan(outputPath)}\n`));
|
|
117
|
+
|
|
118
|
+
// Display first few accounts
|
|
119
|
+
console.log(chalk.gray('First 3 accounts:'));
|
|
120
|
+
accounts.slice(0, 3).forEach((account, index) => {
|
|
121
|
+
console.log(chalk.white(` ${index + 1}. ${chalk.cyan(account.address)}`));
|
|
122
|
+
console.log(chalk.gray(` Private Key: ${chalk.dim(account.private_key)}`));
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (accountCount > 3) {
|
|
126
|
+
console.log(chalk.gray(` ... and ${accountCount - 3} more account(s)\n`));
|
|
127
|
+
} else {
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log(chalk.yellow('ā ļø Warning: Keep your mnemonic and private keys secure!'));
|
|
132
|
+
console.log(chalk.yellow(' Never share them or commit them to version control.\n'));
|
|
133
|
+
|
|
134
|
+
} catch (error: any) {
|
|
135
|
+
console.error(chalk.red(`\nā Error: ${error.message}`));
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { deployCommand } from './commands/deploy';
|
|
|
8
8
|
import { deployScCommand } from './commands/deploy-sc';
|
|
9
9
|
import { authCommand } from './commands/auth';
|
|
10
10
|
import { doctorCommand } from './commands/doctor';
|
|
11
|
+
import { generateKeysCommand } from './commands/generate-keys';
|
|
11
12
|
|
|
12
13
|
// Cargar variables de entorno desde ~/.codecrypto/.env si existe
|
|
13
14
|
function loadEnvFile() {
|
|
@@ -55,5 +56,6 @@ program.addCommand(deployCommand);
|
|
|
55
56
|
program.addCommand(deployScCommand);
|
|
56
57
|
program.addCommand(authCommand);
|
|
57
58
|
program.addCommand(doctorCommand);
|
|
59
|
+
program.addCommand(generateKeysCommand);
|
|
58
60
|
|
|
59
61
|
program.parse(process.argv);
|