@@ -6,7 +6,7 @@ import type { LogFn } from '@aztec/foundation/log';
66import type { AztecAddress } from '@aztec/stdlib/aztec-address' ;
77
88import { wordlist } from '@scure/bip39/wordlists/english.js' ;
9- import { writeFile } from 'fs/promises' ;
9+ import { readFile , writeFile } from 'fs/promises' ;
1010import { basename , dirname , join } from 'path' ;
1111import { createPublicClient , fallback , http } from 'viem' ;
1212import { generateMnemonic , mnemonicToAccount } from 'viem/accounts' ;
@@ -42,6 +42,7 @@ export type NewValidatorKeystoreOptions = {
4242 ikm ?: string ;
4343 blsPath ?: string ;
4444 password ?: string ;
45+ passwordFile ?: string ;
4546 encryptedKeystoreDir ?: string ;
4647 json ?: boolean ;
4748 feeRecipient : AztecAddress ;
@@ -53,6 +54,41 @@ export type NewValidatorKeystoreOptions = {
5354 l1ChainId ?: number ;
5455} ;
5556
57+ function validatePassword ( password : string , source : string ) : string {
58+ if ( password . length === 0 ) {
59+ throw new Error ( `${ source } cannot be empty` ) ;
60+ }
61+ return password ;
62+ }
63+
64+ function stripOneTrailingNewline ( password : string ) : string {
65+ if ( password . endsWith ( '\n' ) ) {
66+ password = password . slice ( 0 , - 1 ) ;
67+ }
68+ if ( password . endsWith ( '\r' ) ) {
69+ password = password . slice ( 0 , - 1 ) ;
70+ }
71+ return password ;
72+ }
73+
74+ async function resolvePassword ( options : Pick < NewValidatorKeystoreOptions , 'password' | 'passwordFile' > ) {
75+ if ( options . password !== undefined && options . passwordFile !== undefined ) {
76+ throw new Error ( '--password and --password-file cannot be used together' ) ;
77+ }
78+ if ( options . password !== undefined ) {
79+ return validatePassword ( options . password , '--password' ) ;
80+ }
81+ if ( options . passwordFile !== undefined ) {
82+ if ( options . passwordFile . length === 0 ) {
83+ throw new Error ( '--password-file cannot be empty' ) ;
84+ }
85+ const password = stripOneTrailingNewline ( await readFile ( options . passwordFile , 'utf-8' ) ) ;
86+ return validatePassword ( password , '--password-file' ) ;
87+ }
88+
89+ return undefined ;
90+ }
91+
5692export async function newValidatorKeystore ( options : NewValidatorKeystoreOptions , log : LogFn ) {
5793 // validate bls-path inputs before proceeding with key generation
5894 validateBlsPathOptions ( options ) ;
@@ -78,17 +114,20 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
78114 blsPath,
79115 ikm,
80116 mnemonic : _mnemonic ,
81- password,
117+ password : passwordOption ,
118+ passwordFile,
82119 encryptedKeystoreDir,
83120 stakerOutput,
84121 gseAddress,
85122 l1RpcUrls,
86123 l1ChainId,
87124 } = options ;
88125
126+ const password = await resolvePassword ( { password : passwordOption , passwordFile } ) ;
127+ const shouldEncryptKeystores = password !== undefined ;
89128 const mnemonic = _mnemonic ?? generateMnemonic ( wordlist ) ;
90129
91- if ( ! _mnemonic && ! json ) {
130+ if ( ! _mnemonic && ! json && ! shouldEncryptKeystores ) {
92131 log ( 'No mnemonic provided, generating new one...' ) ;
93132 log ( `Using new mnemonic:` ) ;
94133 log ( '' ) ;
@@ -115,7 +154,7 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
115154 } ) ;
116155
117156 // If password provided, write ETH JSON V3 and BLS BN254 keystores and replace plaintext
118- if ( password !== undefined ) {
157+ if ( shouldEncryptKeystores ) {
119158 const encryptedKeystoreOutDir =
120159 encryptedKeystoreDir && encryptedKeystoreDir . length > 0 ? encryptedKeystoreDir : keystoreOutDir ;
121160 await writeEthJsonV3ToFile ( validators , { outDir : encryptedKeystoreOutDir , password } ) ;
@@ -160,7 +199,7 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
160199 }
161200 }
162201
163- const outputData = ! _mnemonic ? { ...keystore , generatedMnemonic : mnemonic } : keystore ;
202+ const outputData = ! _mnemonic && ! shouldEncryptKeystores ? { ...keystore , generatedMnemonic : mnemonic } : keystore ;
164203
165204 // Handle JSON output
166205 if ( json ) {
0 commit comments