genlayer 0.33.1 → 0.34.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.34.0 (2026-02-08)
4
+
5
+ ### Features
6
+
7
+ * add --password flag for non-interactive CLI usage ([#275](https://github.com/yeagerai/genlayer-cli/issues/275)) ([c5fffa6](https://github.com/yeagerai/genlayer-cli/commit/c5fffa6faaf0133ad83dd47279e3383d0a0cbacb))
8
+
3
9
  ## 0.33.1 (2026-02-07)
4
10
 
5
11
  ### Bug Fixes
package/dist/index.js CHANGED
@@ -20078,7 +20078,7 @@ var require_cli_table3 = __commonJS({
20078
20078
  import { program } from "commander";
20079
20079
 
20080
20080
  // package.json
20081
- var version = "0.33.1";
20081
+ var version = "0.34.0";
20082
20082
  var package_default = {
20083
20083
  name: "genlayer",
20084
20084
  version,
@@ -48674,17 +48674,22 @@ var _BaseAction = class _BaseAction extends ConfigFileManager {
48674
48674
  getAddress(keystoreData) {
48675
48675
  return keystoreData.address;
48676
48676
  }
48677
- async createKeypairByName(accountName, overwrite) {
48677
+ async createKeypairByName(accountName, overwrite, passwordInput) {
48678
48678
  const keystorePath = this.getKeystorePath(accountName);
48679
48679
  this.stopSpinner();
48680
48680
  if (existsSync(keystorePath) && !overwrite) {
48681
48681
  this.failSpinner(`Account '${accountName}' already exists. Use '--overwrite' to replace it.`);
48682
48682
  }
48683
48683
  const wallet = ethers.Wallet.createRandom();
48684
- const password = await this.promptPassword("Enter a password to encrypt your keystore (minimum 8 characters):");
48685
- const confirmPassword = await this.promptPassword("Confirm password:");
48686
- if (password !== confirmPassword) {
48687
- this.failSpinner("Passwords do not match");
48684
+ let password;
48685
+ if (passwordInput) {
48686
+ password = passwordInput;
48687
+ } else {
48688
+ password = await this.promptPassword("Enter a password to encrypt your keystore (minimum 8 characters):");
48689
+ const confirmPassword = await this.promptPassword("Confirm password:");
48690
+ if (password !== confirmPassword) {
48691
+ this.failSpinner("Passwords do not match");
48692
+ }
48688
48693
  }
48689
48694
  if (password.length < _BaseAction.MIN_PASSWORD_LENGTH) {
48690
48695
  this.failSpinner(`Password must be at least ${_BaseAction.MIN_PASSWORD_LENGTH} characters long`);
@@ -50011,7 +50016,7 @@ var CreateAccountAction = class extends BaseAction {
50011
50016
  async execute(options) {
50012
50017
  try {
50013
50018
  this.startSpinner(`Creating account '${options.name}'...`);
50014
- await this.createKeypairByName(options.name, options.overwrite);
50019
+ await this.createKeypairByName(options.name, options.overwrite, options.password);
50015
50020
  if (options.setActive !== false) {
50016
50021
  this.setActiveAccount(options.name);
50017
50022
  }
@@ -50216,9 +50221,14 @@ var UnlockAccountAction = class extends BaseAction {
50216
50221
  this.failSpinner("Invalid keystore format.");
50217
50222
  return;
50218
50223
  }
50219
- this.stopSpinner();
50220
50224
  try {
50221
- const password = await this.promptPassword(`Enter password to unlock '${accountName}':`);
50225
+ let password;
50226
+ if (options?.password) {
50227
+ password = options.password;
50228
+ } else {
50229
+ this.stopSpinner();
50230
+ password = await this.promptPassword(`Enter password to unlock '${accountName}':`);
50231
+ }
50222
50232
  const wallet = await ethers4.Wallet.fromEncryptedJson(keystoreJson, password);
50223
50233
  await this.keychainManager.storePrivateKey(accountName, wallet.privateKey);
50224
50234
  this.succeedSpinner(`Account '${accountName}' unlocked! Private key cached in OS keychain.`);
@@ -50308,9 +50318,14 @@ var SendAction = class extends BaseAction {
50308
50318
  if (cachedKey) {
50309
50319
  privateKey = cachedKey;
50310
50320
  } else {
50311
- this.stopSpinner();
50312
- const password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
50313
- this.startSpinner("Preparing transfer...");
50321
+ let password;
50322
+ if (options.password) {
50323
+ password = options.password;
50324
+ } else {
50325
+ this.stopSpinner();
50326
+ password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
50327
+ this.startSpinner("Preparing transfer...");
50328
+ }
50314
50329
  const wallet = await ethers5.Wallet.fromEncryptedJson(keystoreJson, password);
50315
50330
  privateKey = wallet.privateKey;
50316
50331
  }
@@ -50458,7 +50473,7 @@ function initializeAccountCommands(program2) {
50458
50473
  const showAction = new ShowAccountAction();
50459
50474
  await showAction.execute(options);
50460
50475
  });
50461
- accountCommand.command("create").description("Create a new account with encrypted keystore").requiredOption("--name <name>", "Name for the account").option("--overwrite", "Overwrite existing account", false).option("--no-set-active", "Do not set as active account").action(async (options) => {
50476
+ accountCommand.command("create").description("Create a new account with encrypted keystore").requiredOption("--name <name>", "Name for the account").option("--password <password>", "Password for the keystore (skips interactive prompt)").option("--overwrite", "Overwrite existing account", false).option("--no-set-active", "Do not set as active account").action(async (options) => {
50462
50477
  const createAction = new CreateAccountAction();
50463
50478
  await createAction.execute(options);
50464
50479
  });
@@ -50478,11 +50493,11 @@ function initializeAccountCommands(program2) {
50478
50493
  const removeAction = new RemoveAccountAction();
50479
50494
  await removeAction.execute(name, options);
50480
50495
  });
50481
- accountCommand.command("send <to> <amount>").description("Send GEN to an address").option("--rpc <rpcUrl>", "RPC URL for the network").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--account <name>", "Account to send from").action(async (to, amount, options) => {
50496
+ accountCommand.command("send <to> <amount>").description("Send GEN to an address").option("--rpc <rpcUrl>", "RPC URL for the network").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--account <name>", "Account to send from").option("--password <password>", "Password to unlock account (skips interactive prompt)").action(async (to, amount, options) => {
50482
50497
  const sendAction = new SendAction();
50483
- await sendAction.execute({ to, amount, rpc: options.rpc, network: options.network, account: options.account });
50498
+ await sendAction.execute({ to, amount, rpc: options.rpc, network: options.network, account: options.account, password: options.password });
50484
50499
  });
50485
- accountCommand.command("unlock").description("Unlock account by caching private key in OS keychain").option("--account <name>", "Account to unlock").action(async (options) => {
50500
+ accountCommand.command("unlock").description("Unlock account by caching private key in OS keychain").option("--account <name>", "Account to unlock").option("--password <password>", "Password to unlock account (skips interactive prompt)").action(async (options) => {
50486
50501
  const unlockAction = new UnlockAccountAction();
50487
50502
  await unlockAction.execute(options);
50488
50503
  });
@@ -51321,6 +51336,7 @@ var StakingAction = class extends BaseAction {
51321
51336
  constructor() {
51322
51337
  super();
51323
51338
  __publicField(this, "_stakingClient", null);
51339
+ __publicField(this, "_passwordOverride");
51324
51340
  }
51325
51341
  getNetwork(config) {
51326
51342
  if (config.network) {
@@ -51337,6 +51353,9 @@ var StakingAction = class extends BaseAction {
51337
51353
  if (config.account) {
51338
51354
  this.accountOverride = config.account;
51339
51355
  }
51356
+ if (config.password) {
51357
+ this._passwordOverride = config.password;
51358
+ }
51340
51359
  const network = this.getNetwork(config);
51341
51360
  if (config.stakingAddress) {
51342
51361
  network.stakingContract = {
@@ -51401,8 +51420,13 @@ var StakingAction = class extends BaseAction {
51401
51420
  return cachedKey;
51402
51421
  }
51403
51422
  }
51404
- this.stopSpinner();
51405
- const password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
51423
+ let password;
51424
+ if (this._passwordOverride) {
51425
+ password = this._passwordOverride;
51426
+ } else {
51427
+ this.stopSpinner();
51428
+ password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
51429
+ }
51406
51430
  this.startSpinner("Unlocking account...");
51407
51431
  const wallet = await ethers6.Wallet.fromEncryptedJson(keystoreJson, password);
51408
51432
  return wallet.privateKey;
@@ -51431,6 +51455,9 @@ var StakingAction = class extends BaseAction {
51431
51455
  if (config.account) {
51432
51456
  this.accountOverride = config.account;
51433
51457
  }
51458
+ if (config.password) {
51459
+ this._passwordOverride = config.password;
51460
+ }
51434
51461
  const network = this.getNetwork(config);
51435
51462
  const rpcUrl = config.rpc || network.rpcUrls.default.http[0];
51436
51463
  const privateKey = await this.getPrivateKeyForStaking();
@@ -53162,11 +53189,11 @@ function initializeStakingCommands(program2) {
53162
53189
  const wizard = new ValidatorWizardAction();
53163
53190
  await wizard.execute(options);
53164
53191
  });
53165
- staking.command("validator-join").description("Join as a validator by staking tokens").requiredOption("--amount <amount>", "Amount to stake (in wei or with 'eth'/'gen' suffix, e.g., '42000gen')").option("--operator <address>", "Operator address (defaults to signer)").option("--account <name>", "Account to use").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (options) => {
53192
+ staking.command("validator-join").description("Join as a validator by staking tokens").requiredOption("--amount <amount>", "Amount to stake (in wei or with 'eth'/'gen' suffix, e.g., '42000gen')").option("--operator <address>", "Operator address (defaults to signer)").option("--account <name>", "Account to use").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (options) => {
53166
53193
  const action = new ValidatorJoinAction();
53167
53194
  await action.execute(options);
53168
53195
  });
53169
- staking.command("validator-deposit [validator]").description("Make an additional deposit to a validator wallet").option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)").requiredOption("--amount <amount>", "Amount to deposit (in wei or with 'eth'/'gen' suffix)").option("--account <name>", "Account to use (must be validator owner)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53196
+ staking.command("validator-deposit [validator]").description("Make an additional deposit to a validator wallet").option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)").requiredOption("--amount <amount>", "Amount to deposit (in wei or with 'eth'/'gen' suffix)").option("--account <name>", "Account to use (must be validator owner)").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53170
53197
  const validator = validatorArg || options.validator;
53171
53198
  if (!validator) {
53172
53199
  console.error("Error: validator address is required");
@@ -53175,7 +53202,7 @@ function initializeStakingCommands(program2) {
53175
53202
  const action = new ValidatorDepositAction();
53176
53203
  await action.execute({ ...options, validator });
53177
53204
  });
53178
- staking.command("validator-exit [validator]").description("Exit as a validator by withdrawing shares").option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)").requiredOption("--shares <shares>", "Number of shares to withdraw").option("--account <name>", "Account to use (must be validator owner)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53205
+ staking.command("validator-exit [validator]").description("Exit as a validator by withdrawing shares").option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)").requiredOption("--shares <shares>", "Number of shares to withdraw").option("--account <name>", "Account to use (must be validator owner)").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53179
53206
  const validator = validatorArg || options.validator;
53180
53207
  if (!validator) {
53181
53208
  console.error("Error: validator address is required");
@@ -53184,7 +53211,7 @@ function initializeStakingCommands(program2) {
53184
53211
  const action = new ValidatorExitAction();
53185
53212
  await action.execute({ ...options, validator });
53186
53213
  });
53187
- staking.command("validator-claim [validator]").description("Claim validator withdrawals after unbonding period").option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)").option("--account <name>", "Account to use").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53214
+ staking.command("validator-claim [validator]").description("Claim validator withdrawals after unbonding period").option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)").option("--account <name>", "Account to use").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53188
53215
  const validator = validatorArg || options.validator;
53189
53216
  if (!validator) {
53190
53217
  console.error("Error: validator address is required");
@@ -53193,7 +53220,7 @@ function initializeStakingCommands(program2) {
53193
53220
  const action = new ValidatorClaimAction();
53194
53221
  await action.execute({ ...options, validator });
53195
53222
  });
53196
- staking.command("validator-prime [validator]").description("Prime a validator to prepare their stake record for the next epoch").option("--validator <address>", "Validator address to prime (deprecated, use positional arg)").option("--account <name>", "Account to use").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53223
+ staking.command("validator-prime [validator]").description("Prime a validator to prepare their stake record for the next epoch").option("--validator <address>", "Validator address to prime (deprecated, use positional arg)").option("--account <name>", "Account to use").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53197
53224
  const validator = validatorArg || options.validator;
53198
53225
  if (!validator) {
53199
53226
  console.error("Error: validator address is required");
@@ -53202,11 +53229,11 @@ function initializeStakingCommands(program2) {
53202
53229
  const action = new ValidatorPrimeAction();
53203
53230
  await action.execute({ ...options, validator });
53204
53231
  });
53205
- staking.command("prime-all").description("Prime all validators that need priming").option("--account <name>", "Account to use (pays gas)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (options) => {
53232
+ staking.command("prime-all").description("Prime all validators that need priming").option("--account <name>", "Account to use (pays gas)").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (options) => {
53206
53233
  const action = new ValidatorPrimeAction();
53207
53234
  await action.primeAll(options);
53208
53235
  });
53209
- staking.command("set-operator [validator] [operator]").description("Change the operator address for a validator wallet").option("--validator <address>", "Validator wallet address (deprecated, use positional arg)").option("--operator <address>", "New operator address (deprecated, use positional arg)").option("--account <name>", "Account to use (must be validator owner)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, operatorArg, options) => {
53236
+ staking.command("set-operator [validator] [operator]").description("Change the operator address for a validator wallet").option("--validator <address>", "Validator wallet address (deprecated, use positional arg)").option("--operator <address>", "New operator address (deprecated, use positional arg)").option("--account <name>", "Account to use (must be validator owner)").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, operatorArg, options) => {
53210
53237
  const validator = validatorArg || options.validator;
53211
53238
  const operator = operatorArg || options.operator;
53212
53239
  if (!validator || !operator) {
@@ -53216,7 +53243,7 @@ function initializeStakingCommands(program2) {
53216
53243
  const action = new SetOperatorAction();
53217
53244
  await action.execute({ ...options, validator, operator });
53218
53245
  });
53219
- staking.command("set-identity [validator]").description("Set validator identity metadata (moniker, website, socials, etc.)").option("--validator <address>", "Validator wallet address (deprecated, use positional arg)").requiredOption("--moniker <name>", "Validator display name").option("--logo-uri <uri>", "Logo URI").option("--website <url>", "Website URL").option("--description <text>", "Description").option("--email <email>", "Contact email").option("--twitter <handle>", "Twitter handle").option("--telegram <handle>", "Telegram handle").option("--github <handle>", "GitHub handle").option("--extra-cid <cid>", "Extra data as IPFS CID or hex bytes (0x...)").option("--account <name>", "Account to use (must be validator operator)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53246
+ staking.command("set-identity [validator]").description("Set validator identity metadata (moniker, website, socials, etc.)").option("--validator <address>", "Validator wallet address (deprecated, use positional arg)").requiredOption("--moniker <name>", "Validator display name").option("--logo-uri <uri>", "Logo URI").option("--website <url>", "Website URL").option("--description <text>", "Description").option("--email <email>", "Contact email").option("--twitter <handle>", "Twitter handle").option("--telegram <handle>", "Telegram handle").option("--github <handle>", "GitHub handle").option("--extra-cid <cid>", "Extra data as IPFS CID or hex bytes (0x...)").option("--account <name>", "Account to use (must be validator operator)").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").action(async (validatorArg, options) => {
53220
53247
  const validator = validatorArg || options.validator;
53221
53248
  if (!validator) {
53222
53249
  console.error("Error: validator address is required");
@@ -53225,7 +53252,7 @@ function initializeStakingCommands(program2) {
53225
53252
  const action = new SetIdentityAction();
53226
53253
  await action.execute({ ...options, validator });
53227
53254
  });
53228
- staking.command("delegator-join [validator]").description("Join as a delegator by staking with a validator").option("--validator <address>", "Validator address to delegate to (deprecated, use positional arg)").requiredOption("--amount <amount>", "Amount to stake (in wei or with 'eth'/'gen' suffix)").option("--account <name>", "Account to use").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53255
+ staking.command("delegator-join [validator]").description("Join as a delegator by staking with a validator").option("--validator <address>", "Validator address to delegate to (deprecated, use positional arg)").requiredOption("--amount <amount>", "Amount to stake (in wei or with 'eth'/'gen' suffix)").option("--account <name>", "Account to use").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53229
53256
  const validator = validatorArg || options.validator;
53230
53257
  if (!validator) {
53231
53258
  console.error("Error: validator address is required");
@@ -53234,7 +53261,7 @@ function initializeStakingCommands(program2) {
53234
53261
  const action = new DelegatorJoinAction();
53235
53262
  await action.execute({ ...options, validator });
53236
53263
  });
53237
- staking.command("delegator-exit [validator]").description("Exit as a delegator by withdrawing shares from a validator").option("--validator <address>", "Validator address to exit from (deprecated, use positional arg)").requiredOption("--shares <shares>", "Number of shares to withdraw").option("--account <name>", "Account to use").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53264
+ staking.command("delegator-exit [validator]").description("Exit as a delegator by withdrawing shares from a validator").option("--validator <address>", "Validator address to exit from (deprecated, use positional arg)").requiredOption("--shares <shares>", "Number of shares to withdraw").option("--account <name>", "Account to use").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53238
53265
  const validator = validatorArg || options.validator;
53239
53266
  if (!validator) {
53240
53267
  console.error("Error: validator address is required");
@@ -53243,7 +53270,7 @@ function initializeStakingCommands(program2) {
53243
53270
  const action = new DelegatorExitAction();
53244
53271
  await action.execute({ ...options, validator });
53245
53272
  });
53246
- staking.command("delegator-claim [validator]").description("Claim delegator withdrawals after unbonding period").option("--validator <address>", "Validator address (deprecated, use positional arg)").option("--delegator <address>", "Delegator address (defaults to signer)").option("--account <name>", "Account to use").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53273
+ staking.command("delegator-claim [validator]").description("Claim delegator withdrawals after unbonding period").option("--validator <address>", "Validator address (deprecated, use positional arg)").option("--delegator <address>", "Delegator address (defaults to signer)").option("--account <name>", "Account to use").option("--password <password>", "Password to unlock account (skips interactive prompt)").option("--network <network>", "Network to use (localnet, testnet-asimov)").option("--rpc <rpcUrl>", "RPC URL for the network").option("--staking-address <address>", "Staking contract address (overrides chain config)").action(async (validatorArg, options) => {
53247
53274
  const validator = validatorArg || options.validator;
53248
53275
  if (!validator) {
53249
53276
  console.error("Error: validator address is required");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genlayer",
3
- "version": "0.33.1",
3
+ "version": "0.34.0",
4
4
  "description": "GenLayer Command Line Tool",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -4,6 +4,7 @@ export interface CreateAccountOptions {
4
4
  name: string;
5
5
  overwrite: boolean;
6
6
  setActive?: boolean;
7
+ password?: string;
7
8
  }
8
9
 
9
10
  export class CreateAccountAction extends BaseAction {
@@ -14,7 +15,7 @@ export class CreateAccountAction extends BaseAction {
14
15
  async execute(options: CreateAccountOptions): Promise<void> {
15
16
  try {
16
17
  this.startSpinner(`Creating account '${options.name}'...`);
17
- await this.createKeypairByName(options.name, options.overwrite);
18
+ await this.createKeypairByName(options.name, options.overwrite, options.password);
18
19
 
19
20
  if (options.setActive !== false) {
20
21
  this.setActiveAccount(options.name);
@@ -42,6 +42,7 @@ export function initializeAccountCommands(program: Command) {
42
42
  .command("create")
43
43
  .description("Create a new account with encrypted keystore")
44
44
  .requiredOption("--name <name>", "Name for the account")
45
+ .option("--password <password>", "Password for the keystore (skips interactive prompt)")
45
46
  .option("--overwrite", "Overwrite existing account", false)
46
47
  .option("--no-set-active", "Do not set as active account")
47
48
  .action(async (options: CreateAccountOptions) => {
@@ -99,15 +100,17 @@ export function initializeAccountCommands(program: Command) {
99
100
  .option("--rpc <rpcUrl>", "RPC URL for the network")
100
101
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
101
102
  .option("--account <name>", "Account to send from")
102
- .action(async (to: string, amount: string, options: {rpc?: string; network?: string; account?: string}) => {
103
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
104
+ .action(async (to: string, amount: string, options: {rpc?: string; network?: string; account?: string; password?: string}) => {
103
105
  const sendAction = new SendAction();
104
- await sendAction.execute({to, amount, rpc: options.rpc, network: options.network, account: options.account});
106
+ await sendAction.execute({to, amount, rpc: options.rpc, network: options.network, account: options.account, password: options.password});
105
107
  });
106
108
 
107
109
  accountCommand
108
110
  .command("unlock")
109
111
  .description("Unlock account by caching private key in OS keychain")
110
112
  .option("--account <name>", "Account to unlock")
113
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
111
114
  .action(async (options: UnlockAccountOptions) => {
112
115
  const unlockAction = new UnlockAccountAction();
113
116
  await unlockAction.execute(options);
@@ -11,6 +11,7 @@ export interface SendOptions {
11
11
  rpc?: string;
12
12
  network?: string;
13
13
  account?: string;
14
+ password?: string;
14
15
  }
15
16
 
16
17
  export class SendAction extends BaseAction {
@@ -75,9 +76,14 @@ export class SendAction extends BaseAction {
75
76
  if (cachedKey) {
76
77
  privateKey = cachedKey;
77
78
  } else {
78
- this.stopSpinner();
79
- const password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
80
- this.startSpinner("Preparing transfer...");
79
+ let password: string;
80
+ if (options.password) {
81
+ password = options.password;
82
+ } else {
83
+ this.stopSpinner();
84
+ password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
85
+ this.startSpinner("Preparing transfer...");
86
+ }
81
87
  const wallet = await ethers.Wallet.fromEncryptedJson(keystoreJson, password);
82
88
  privateKey = wallet.privateKey;
83
89
  }
@@ -4,6 +4,7 @@ import {ethers} from "ethers";
4
4
 
5
5
  export interface UnlockAccountOptions {
6
6
  account?: string;
7
+ password?: string;
7
8
  }
8
9
 
9
10
  export class UnlockAccountAction extends BaseAction {
@@ -36,10 +37,14 @@ export class UnlockAccountAction extends BaseAction {
36
37
  return;
37
38
  }
38
39
 
39
- this.stopSpinner();
40
-
41
40
  try {
42
- const password = await this.promptPassword(`Enter password to unlock '${accountName}':`);
41
+ let password: string;
42
+ if (options?.password) {
43
+ password = options.password;
44
+ } else {
45
+ this.stopSpinner();
46
+ password = await this.promptPassword(`Enter password to unlock '${accountName}':`);
47
+ }
43
48
  const wallet = await ethers.Wallet.fromEncryptedJson(keystoreJson, password);
44
49
 
45
50
  await this.keychainManager.storePrivateKey(accountName, wallet.privateKey);
@@ -25,10 +25,12 @@ export interface StakingConfig {
25
25
  stakingAddress?: string;
26
26
  network?: string;
27
27
  account?: string;
28
+ password?: string;
28
29
  }
29
30
 
30
31
  export class StakingAction extends BaseAction {
31
32
  private _stakingClient: GenLayerClient<GenLayerChain> | null = null;
33
+ private _passwordOverride: string | undefined;
32
34
 
33
35
  constructor() {
34
36
  super();
@@ -53,6 +55,9 @@ export class StakingAction extends BaseAction {
53
55
  if (config.account) {
54
56
  this.accountOverride = config.account;
55
57
  }
58
+ if (config.password) {
59
+ this._passwordOverride = config.password;
60
+ }
56
61
 
57
62
  const network = this.getNetwork(config);
58
63
 
@@ -140,9 +145,13 @@ export class StakingAction extends BaseAction {
140
145
  }
141
146
  }
142
147
 
143
- // Stop spinner before prompting for password
144
- this.stopSpinner();
145
- const password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
148
+ let password: string;
149
+ if (this._passwordOverride) {
150
+ password = this._passwordOverride;
151
+ } else {
152
+ this.stopSpinner();
153
+ password = await this.promptPassword(`Enter password to unlock account '${accountName}':`);
154
+ }
146
155
  this.startSpinner("Unlocking account...");
147
156
 
148
157
  const wallet = await ethers.Wallet.fromEncryptedJson(keystoreJson, password);
@@ -180,6 +189,9 @@ export class StakingAction extends BaseAction {
180
189
  if (config.account) {
181
190
  this.accountOverride = config.account;
182
191
  }
192
+ if (config.password) {
193
+ this._passwordOverride = config.password;
194
+ }
183
195
 
184
196
  const network = this.getNetwork(config);
185
197
  const rpcUrl = config.rpc || network.rpcUrls.default.http[0];
@@ -37,6 +37,7 @@ export function initializeStakingCommands(program: Command) {
37
37
  .requiredOption("--amount <amount>", "Amount to stake (in wei or with 'eth'/'gen' suffix, e.g., '42000gen')")
38
38
  .option("--operator <address>", "Operator address (defaults to signer)")
39
39
  .option("--account <name>", "Account to use")
40
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
40
41
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
41
42
  .option("--rpc <rpcUrl>", "RPC URL for the network")
42
43
  .option("--staking-address <address>", "Staking contract address (overrides chain config)")
@@ -51,6 +52,7 @@ export function initializeStakingCommands(program: Command) {
51
52
  .option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)")
52
53
  .requiredOption("--amount <amount>", "Amount to deposit (in wei or with 'eth'/'gen' suffix)")
53
54
  .option("--account <name>", "Account to use (must be validator owner)")
55
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
54
56
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
55
57
  .option("--rpc <rpcUrl>", "RPC URL for the network")
56
58
  .action(async (validatorArg: string | undefined, options: ValidatorDepositOptions) => {
@@ -69,6 +71,7 @@ export function initializeStakingCommands(program: Command) {
69
71
  .option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)")
70
72
  .requiredOption("--shares <shares>", "Number of shares to withdraw")
71
73
  .option("--account <name>", "Account to use (must be validator owner)")
74
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
72
75
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
73
76
  .option("--rpc <rpcUrl>", "RPC URL for the network")
74
77
  .action(async (validatorArg: string | undefined, options: ValidatorExitOptions) => {
@@ -86,6 +89,7 @@ export function initializeStakingCommands(program: Command) {
86
89
  .description("Claim validator withdrawals after unbonding period")
87
90
  .option("--validator <address>", "Validator wallet contract address (deprecated, use positional arg)")
88
91
  .option("--account <name>", "Account to use")
92
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
89
93
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
90
94
  .option("--rpc <rpcUrl>", "RPC URL for the network")
91
95
  .action(async (validatorArg: string | undefined, options: ValidatorClaimOptions) => {
@@ -103,6 +107,7 @@ export function initializeStakingCommands(program: Command) {
103
107
  .description("Prime a validator to prepare their stake record for the next epoch")
104
108
  .option("--validator <address>", "Validator address to prime (deprecated, use positional arg)")
105
109
  .option("--account <name>", "Account to use")
110
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
106
111
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
107
112
  .option("--rpc <rpcUrl>", "RPC URL for the network")
108
113
  .option("--staking-address <address>", "Staking contract address (overrides chain config)")
@@ -120,6 +125,7 @@ export function initializeStakingCommands(program: Command) {
120
125
  .command("prime-all")
121
126
  .description("Prime all validators that need priming")
122
127
  .option("--account <name>", "Account to use (pays gas)")
128
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
123
129
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
124
130
  .option("--rpc <rpcUrl>", "RPC URL for the network")
125
131
  .option("--staking-address <address>", "Staking contract address (overrides chain config)")
@@ -134,6 +140,7 @@ export function initializeStakingCommands(program: Command) {
134
140
  .option("--validator <address>", "Validator wallet address (deprecated, use positional arg)")
135
141
  .option("--operator <address>", "New operator address (deprecated, use positional arg)")
136
142
  .option("--account <name>", "Account to use (must be validator owner)")
143
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
137
144
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
138
145
  .option("--rpc <rpcUrl>", "RPC URL for the network")
139
146
  .action(async (validatorArg: string | undefined, operatorArg: string | undefined, options: SetOperatorOptions) => {
@@ -161,6 +168,7 @@ export function initializeStakingCommands(program: Command) {
161
168
  .option("--github <handle>", "GitHub handle")
162
169
  .option("--extra-cid <cid>", "Extra data as IPFS CID or hex bytes (0x...)")
163
170
  .option("--account <name>", "Account to use (must be validator operator)")
171
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
164
172
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
165
173
  .option("--rpc <rpcUrl>", "RPC URL for the network")
166
174
  .action(async (validatorArg: string | undefined, options: SetIdentityOptions) => {
@@ -180,6 +188,7 @@ export function initializeStakingCommands(program: Command) {
180
188
  .option("--validator <address>", "Validator address to delegate to (deprecated, use positional arg)")
181
189
  .requiredOption("--amount <amount>", "Amount to stake (in wei or with 'eth'/'gen' suffix)")
182
190
  .option("--account <name>", "Account to use")
191
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
183
192
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
184
193
  .option("--rpc <rpcUrl>", "RPC URL for the network")
185
194
  .option("--staking-address <address>", "Staking contract address (overrides chain config)")
@@ -199,6 +208,7 @@ export function initializeStakingCommands(program: Command) {
199
208
  .option("--validator <address>", "Validator address to exit from (deprecated, use positional arg)")
200
209
  .requiredOption("--shares <shares>", "Number of shares to withdraw")
201
210
  .option("--account <name>", "Account to use")
211
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
202
212
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
203
213
  .option("--rpc <rpcUrl>", "RPC URL for the network")
204
214
  .option("--staking-address <address>", "Staking contract address (overrides chain config)")
@@ -218,6 +228,7 @@ export function initializeStakingCommands(program: Command) {
218
228
  .option("--validator <address>", "Validator address (deprecated, use positional arg)")
219
229
  .option("--delegator <address>", "Delegator address (defaults to signer)")
220
230
  .option("--account <name>", "Account to use")
231
+ .option("--password <password>", "Password to unlock account (skips interactive prompt)")
221
232
  .option("--network <network>", "Network to use (localnet, testnet-asimov)")
222
233
  .option("--rpc <rpcUrl>", "RPC URL for the network")
223
234
  .option("--staking-address <address>", "Staking contract address (overrides chain config)")
@@ -171,7 +171,7 @@ export class BaseAction extends ConfigFileManager {
171
171
  return keystoreData.address as Address;
172
172
  }
173
173
 
174
- protected async createKeypairByName(accountName: string, overwrite: boolean): Promise<string> {
174
+ protected async createKeypairByName(accountName: string, overwrite: boolean, passwordInput?: string): Promise<string> {
175
175
  const keystorePath = this.getKeystorePath(accountName);
176
176
  this.stopSpinner();
177
177
 
@@ -181,11 +181,15 @@ export class BaseAction extends ConfigFileManager {
181
181
 
182
182
  const wallet = ethers.Wallet.createRandom();
183
183
 
184
- const password = await this.promptPassword("Enter a password to encrypt your keystore (minimum 8 characters):");
185
- const confirmPassword = await this.promptPassword("Confirm password:");
186
-
187
- if (password !== confirmPassword) {
188
- this.failSpinner("Passwords do not match");
184
+ let password: string;
185
+ if (passwordInput) {
186
+ password = passwordInput;
187
+ } else {
188
+ password = await this.promptPassword("Enter a password to encrypt your keystore (minimum 8 characters):");
189
+ const confirmPassword = await this.promptPassword("Confirm password:");
190
+ if (password !== confirmPassword) {
191
+ this.failSpinner("Passwords do not match");
192
+ }
189
193
  }
190
194
 
191
195
  if (password.length < BaseAction.MIN_PASSWORD_LENGTH) {
@@ -38,7 +38,7 @@ describe("CreateAccountAction", () => {
38
38
  await createAction.execute(options);
39
39
 
40
40
  expect(createAction["startSpinner"]).toHaveBeenCalledWith("Creating account 'main'...");
41
- expect(createAction["createKeypairByName"]).toHaveBeenCalledWith("main", false);
41
+ expect(createAction["createKeypairByName"]).toHaveBeenCalledWith("main", false, undefined);
42
42
  expect(createAction["setActiveAccount"]).toHaveBeenCalledWith("main");
43
43
  expect(createAction["succeedSpinner"]).toHaveBeenCalledWith(
44
44
  `Account 'main' created at: ${mockKeystorePath}`,