diff --git a/src/cli/existing_mnemonic.rs b/src/cli/existing_mnemonic.rs index 665d27b..a3ebae6 100644 --- a/src/cli/existing_mnemonic.rs +++ b/src/cli/existing_mnemonic.rs @@ -74,9 +74,22 @@ pub struct ExistingMnemonicSubcommandOpts { /// Deposit amount in ETH. /// For standard validators: exactly 32 ETH. /// For EIP-7251 compounding validators (0x02 withdrawal credentials): 32 to 2048 ETH. - #[arg(long, visible_alias = "deposit_amount", default_value = "32")] + /// Cannot be used together with --deposit-amount-gwei flag. + #[arg( + long, + visible_alias = "deposit_amount", + default_value = "32", + conflicts_with = "deposit_amount_gwei" + )] pub deposit_amount_eth: u64, + /// Deposit amount in Gwei. + /// For standard validators: exactly 32000000000 Gwei (32 ETH). + /// For EIP-7251 compounding validators (0x02 withdrawal credentials): 32000000000 to 2048000000000 Gwei. + /// Cannot be used together with --deposit-amount-eth flag. + #[arg(long, conflicts_with = "deposit_amount_eth")] + pub deposit_amount_gwei: Option, + /// Use EIP-7251 compounding withdrawal credentials (0x02). /// /// When enabled, validators will use 0x02 withdrawal credentials which support @@ -102,6 +115,12 @@ impl ExistingMnemonicSubcommandOpts { .clone() .map(|p| p.as_bytes().to_owned()); + let deposit_amount_gwei = if let Some(gwei) = self.deposit_amount_gwei { + gwei + } else { + self.deposit_amount_eth * 1_000_000_000 // Convert ETH to Gwei + }; + let validators = Validators::new( Some(self.mnemonic.as_bytes()), password, @@ -114,7 +133,7 @@ impl ExistingMnemonicSubcommandOpts { .export( chain, self.withdrawal_credentials.clone(), - self.deposit_amount_eth * 1_000_000_000, // Convert ETH to Gwei + deposit_amount_gwei, self.compounding, self.deposit_cli_version.clone(), self.testnet_config.clone(), diff --git a/src/cli/new_mnemonic.rs b/src/cli/new_mnemonic.rs index e192406..bb15e62 100644 --- a/src/cli/new_mnemonic.rs +++ b/src/cli/new_mnemonic.rs @@ -63,9 +63,22 @@ pub struct NewMnemonicSubcommandOpts { /// Deposit amount in ETH. /// For standard validators: exactly 32 ETH. /// For EIP-7251 compounding validators (0x02 withdrawal credentials): 32 to 2048 ETH. - #[arg(long, visible_alias = "deposit_amount", default_value = "32")] + /// Cannot be used together with --deposit-amount-gwei flag. + #[arg( + long, + visible_alias = "deposit_amount", + default_value = "32", + conflicts_with = "deposit_amount_gwei" + )] pub deposit_amount_eth: u64, + /// Deposit amount in Gwei. + /// For standard validators: exactly 32000000000 Gwei (32 ETH). + /// For EIP-7251 compounding validators (0x02 withdrawal credentials): 32000000000 to 2048000000000 Gwei. + /// Cannot be used together with --deposit-amount-eth flag. + #[arg(long, conflicts_with = "deposit_amount_eth")] + pub deposit_amount_gwei: Option, + /// Use EIP-7251 compounding withdrawal credentials (0x02). /// /// When enabled, validators will use 0x02 withdrawal credentials which support @@ -91,6 +104,12 @@ impl NewMnemonicSubcommandOpts { .clone() .map(|p| p.as_bytes().to_owned()); + let deposit_amount_gwei = if let Some(gwei) = self.deposit_amount_gwei { + gwei + } else { + self.deposit_amount_eth * 1_000_000_000 // Convert ETH to Gwei + }; + let validators = Validators::new( None, password, @@ -103,7 +122,7 @@ impl NewMnemonicSubcommandOpts { .export( chain, self.withdrawal_credentials.clone(), - self.deposit_amount_eth * 1_000_000_000, // Convert ETH to Gwei + deposit_amount_gwei, self.compounding, self.deposit_cli_version.clone(), self.testnet_config.clone(), diff --git a/tests/e2e/new_mnemonic.rs b/tests/e2e/new_mnemonic.rs index 3bffa5a..733c6d9 100644 --- a/tests/e2e/new_mnemonic.rs +++ b/tests/e2e/new_mnemonic.rs @@ -630,3 +630,79 @@ fn parse_kdf_function(keystore: &Keystore) -> String { .unwrap(); kdf_function } + +/* + generate validator with deposit amount specified in gwei +*/ +#[test] +fn test_deposit_amount_gwei() -> Result<(), Box> { + let chain = SupportedNetworks::Sepolia; + let decryption_password = "testtest"; + let num_validators = "1"; + let deposit_amount_gwei = "32000000000"; // 32 ETH in gwei + + let mut cmd = Command::cargo_bin("eth-staking-smith")?; + + cmd.arg("new-mnemonic"); + cmd.arg("--chain"); + cmd.arg(chain.to_string()); + cmd.arg("--keystore_password"); + cmd.arg(decryption_password); + cmd.arg("--num_validators"); + cmd.arg(num_validators); + cmd.arg("--deposit-amount-gwei"); + cmd.arg(deposit_amount_gwei); + + cmd.assert().success(); + + let output = &cmd + .output() + .expect("could not get output from command") + .stdout; + let command_output = std::str::from_utf8(output).expect("could not parse output into string"); + let generated_validator_json: ValidatorExports = + serde_json::from_str(command_output).expect("could not unmarshal command output"); + let generated_deposit_data = generated_validator_json + .deposit_data + .get(0) + .expect("could not get generated deposit data") + .to_owned(); + + // verify the deposit amount is correct + assert_eq!(generated_deposit_data.amount, 32000000000); + + generated_deposit_data + .validate(eth_staking_smith::chain_spec::chain_spec_for_network(&chain).unwrap()); + + Ok(()) +} + +/* + test that deposit-amount-eth and deposit-amount-gwei flags conflict +*/ +#[test] +fn test_conflicting_deposit_flags() -> Result<(), Box> { + let chain = "sepolia"; + let decryption_password = "testtest"; + let num_validators = "1"; + + let mut cmd = Command::cargo_bin("eth-staking-smith")?; + + cmd.arg("new-mnemonic"); + cmd.arg("--chain"); + cmd.arg(chain); + cmd.arg("--keystore_password"); + cmd.arg(decryption_password); + cmd.arg("--num_validators"); + cmd.arg(num_validators); + cmd.arg("--deposit-amount-eth"); + cmd.arg("32"); + cmd.arg("--deposit-amount-gwei"); + cmd.arg("32000000000"); + + cmd.assert() + .failure() + .stderr(predicate::str::contains("cannot be used with")); + + Ok(()) +}