From 434460faf7ff56c8f47dae00781a050f88031ded Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Sat, 9 May 2026 01:40:42 +0700 Subject: [PATCH 1/3] refactor(key-wallet)!: remove `MnemonicWithPassphrase` wallet type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the entire passphrase-as-callback feature: callers can no longer construct a wallet that retains a mnemonic and applies a BIP39 passphrase on-demand. Removed across the workspace: - `WalletType::MnemonicWithPassphrase` variant + Zeroize arm - `Wallet::from_mnemonic_with_passphrase` constructor - `add_account_with_passphrase`, `add_bls_account_with_passphrase`, `add_eddsa_account_with_passphrase` on `Wallet` - `derive_extended_private_key_with_passphrase`, `create_accounts_with_passphrase_from_options`, `create_special_purpose_accounts_with_passphrase`, `needs_passphrase`, and `root_extended_priv_key_with_callback` helpers - `add_managed_*_with_passphrase` on `ManagedAccountOperations` - `passphrase` parameter from `WalletManager::create_wallet_from_mnemonic` and `create_wallet_from_mnemonic_return_serialized_bytes` - `passphrase` parameter from FFI `wallet_create_from_mnemonic*`, `wallet_manager_add_wallet_from_mnemonic*`, `wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes` - All passphrase-only tests (`test_wallet_with_passphrase`, `test_passphrase_edge_cases`, the `passphrase_test` module, FFI `test_passphrase_wallets.rs`, etc.) Breaking change: serialized wallets containing the `MnemonicWithPassphrase` variant can no longer be deserialized, and the FFI `passphrase` parameter is gone — callers must update their code. Co-Authored-By: Claude Opus 4.7 (1M context) --- dash-spv-ffi/src/bin/ffi_cli.rs | 1 - dash-spv-ffi/tests/dashd_sync/context.rs | 8 +- dash-spv-ffi/tests/test_wallet_manager.rs | 1 - dash-spv/src/main.rs | 1 - dash-spv/tests/dashd_sync/setup.rs | 2 +- .../tests/dashd_sync/tests_multi_wallet.rs | 26 +- key-wallet-ffi/examples/check_transaction.c | 3 +- key-wallet-ffi/src/account_collection.rs | 8 - .../src/account_derivation_tests.rs | 21 +- key-wallet-ffi/src/account_tests.rs | 24 +- key-wallet-ffi/src/address_pool.rs | 4 - key-wallet-ffi/src/keys_tests.rs | 72 +---- key-wallet-ffi/src/managed_account.rs | 14 - key-wallet-ffi/src/managed_wallet.rs | 24 +- key-wallet-ffi/src/managed_wallet_tests.rs | 8 +- key-wallet-ffi/src/mnemonic_tests.rs | 6 +- key-wallet-ffi/src/wallet.rs | 26 +- key-wallet-ffi/src/wallet_manager.rs | 21 +- .../src/wallet_manager_serialization_tests.rs | 61 ---- key-wallet-ffi/src/wallet_manager_tests.rs | 28 +- key-wallet-ffi/src/wallet_tests.rs | 53 +--- key-wallet-ffi/tests/debug_wallet_add.rs | 8 +- key-wallet-ffi/tests/integration_test.rs | 16 +- .../tests/test_account_collection.rs | 2 - key-wallet-ffi/tests/test_import_wallet.rs | 2 - .../tests/test_managed_account_collection.rs | 10 - .../tests/test_passphrase_wallets.rs | 201 ------------ .../examples/wallet_creation.rs | 1 - key-wallet-manager/src/lib.rs | 35 +-- key-wallet-manager/src/process_block.rs | 8 +- key-wallet-manager/src/test_helpers.rs | 2 +- key-wallet-manager/tests/integration_test.rs | 3 - .../tests/test_serialized_wallets.rs | 39 --- key-wallet/src/tests/edge_case_tests.rs | 42 --- key-wallet/src/tests/wallet_tests.rs | 35 --- key-wallet/src/wallet/accounts.rs | 183 ----------- key-wallet/src/wallet/helper.rs | 290 +----------------- key-wallet/src/wallet/initialization.rs | 39 --- .../managed_account_operations.rs | 59 ---- .../managed_wallet_info/managed_accounts.rs | 124 +------- key-wallet/src/wallet/mod.rs | 51 --- key-wallet/src/wallet/passphrase_test.rs | 168 ---------- key-wallet/src/wallet/root_extended_keys.rs | 49 --- key-wallet/src/wallet_comprehensive_tests.rs | 28 -- 44 files changed, 57 insertions(+), 1750 deletions(-) delete mode 100644 key-wallet-ffi/tests/test_passphrase_wallets.rs delete mode 100644 key-wallet/src/wallet/passphrase_test.rs diff --git a/dash-spv-ffi/src/bin/ffi_cli.rs b/dash-spv-ffi/src/bin/ffi_cli.rs index 42a766943..bff43c352 100644 --- a/dash-spv-ffi/src/bin/ffi_cli.rs +++ b/dash-spv-ffi/src/bin/ffi_cli.rs @@ -537,7 +537,6 @@ fn main() { let success = wallet_manager_add_wallet_from_mnemonic( wallet_manager as *mut _, mnemonic_c.as_ptr(), - ptr::null(), // no passphrase &mut error, ); diff --git a/dash-spv-ffi/tests/dashd_sync/context.rs b/dash-spv-ffi/tests/dashd_sync/context.rs index be21cfd65..b2bfa6060 100644 --- a/dash-spv-ffi/tests/dashd_sync/context.rs +++ b/dash-spv-ffi/tests/dashd_sync/context.rs @@ -169,16 +169,10 @@ impl FFITestContext { /// Calls FFI wallet functions through raw pointers held by the context. pub(super) unsafe fn add_wallet(&self, mnemonic: &str) -> Vec { let mnemonic_c = CString::new(mnemonic).unwrap(); - let passphrase = CString::new("").unwrap(); let mut error = FFIError::default(); let wm = self.session.wallet_manager as *mut FFIWalletManager; - let success = wallet_manager_add_wallet_from_mnemonic( - wm, - mnemonic_c.as_ptr(), - passphrase.as_ptr(), - &mut error, - ); + let success = wallet_manager_add_wallet_from_mnemonic(wm, mnemonic_c.as_ptr(), &mut error); if !success { let error_msg = if !error.message.is_null() { CStr::from_ptr(error.message).to_str().unwrap_or("Unknown error") diff --git a/dash-spv-ffi/tests/test_wallet_manager.rs b/dash-spv-ffi/tests/test_wallet_manager.rs index dde3af4d6..b6ecb0d7a 100644 --- a/dash-spv-ffi/tests/test_wallet_manager.rs +++ b/dash-spv-ffi/tests/test_wallet_manager.rs @@ -79,7 +79,6 @@ mod tests { let (serialized_wallet, expected_wallet_id) = native_manager .create_wallet_from_mnemonic_return_serialized_bytes( "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - "", 0, WalletAccountCreationOptions::Default, false, diff --git a/dash-spv/src/main.rs b/dash-spv/src/main.rs index b20aaa596..f01eed019 100644 --- a/dash-spv/src/main.rs +++ b/dash-spv/src/main.rs @@ -292,7 +292,6 @@ async fn run() -> Result<(), Box> { let mut wallet_manager = WalletManager::::new(config.network); wallet_manager.create_wallet_from_mnemonic( mnemonic_phrase.as_str(), - "", 0, key_wallet::wallet::initialization::WalletAccountCreationOptions::default(), )?; diff --git a/dash-spv/tests/dashd_sync/setup.rs b/dash-spv/tests/dashd_sync/setup.rs index 7daa736b5..00d31c15d 100644 --- a/dash-spv/tests/dashd_sync/setup.rs +++ b/dash-spv/tests/dashd_sync/setup.rs @@ -372,7 +372,7 @@ pub(super) fn create_test_wallet( ) -> (Arc>>, WalletId) { let mut wallet_manager = WalletManager::::new(network); let wallet_id = wallet_manager - .create_wallet_from_mnemonic(mnemonic, "", 0, test_account_options()) + .create_wallet_from_mnemonic(mnemonic, 0, test_account_options()) .expect("Failed to create wallet from mnemonic"); (Arc::new(RwLock::new(wallet_manager)), wallet_id) } diff --git a/dash-spv/tests/dashd_sync/tests_multi_wallet.rs b/dash-spv/tests/dashd_sync/tests_multi_wallet.rs index cbe029a9d..47ea9f483 100644 --- a/dash-spv/tests/dashd_sync/tests_multi_wallet.rs +++ b/dash-spv/tests/dashd_sync/tests_multi_wallet.rs @@ -84,7 +84,7 @@ async fn test_wallet_added_at_runtime_catches_up() { let w1_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic(&ctx.dashd.wallet.mnemonic, "", 0, test_account_options()) + .create_wallet_from_mnemonic(&ctx.dashd.wallet.mnemonic, 0, test_account_options()) .expect("add pre-funded W1 at runtime") }; wait_for_wallet_synced(client_handle.client.wallet(), &w1_id, initial_height).await; @@ -115,7 +115,7 @@ async fn test_wallet_added_at_runtime_catches_up() { let w2_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic(EMPTY_MNEMONIC, "", initial_height, test_account_options()) + .create_wallet_from_mnemonic(EMPTY_MNEMONIC, initial_height, test_account_options()) .expect("add W2 at runtime") }; @@ -167,12 +167,7 @@ async fn test_wallet_added_at_runtime_catches_up() { let w3_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic( - SECONDARY_MNEMONIC, - "", - future_height, - test_account_options(), - ) + .create_wallet_from_mnemonic(SECONDARY_MNEMONIC, future_height, test_account_options()) .expect("add W3 at runtime") }; @@ -278,18 +273,13 @@ async fn test_runtime_add_shared_block_two_wallets() { let w1_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic(EMPTY_MNEMONIC, "", initial_height, test_account_options()) + .create_wallet_from_mnemonic(EMPTY_MNEMONIC, initial_height, test_account_options()) .expect("add W1 at runtime") }; let w2_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic( - SECONDARY_MNEMONIC, - "", - initial_height, - test_account_options(), - ) + .create_wallet_from_mnemonic(SECONDARY_MNEMONIC, initial_height, test_account_options()) .expect("add W2 at runtime") }; @@ -371,7 +361,7 @@ async fn test_runtime_add_during_initial_sync() { let w1_id = { let mut wallet_guard = wallet.write().await; wallet_guard - .create_wallet_from_mnemonic(&ctx.dashd.wallet.mnemonic, "", 0, test_account_options()) + .create_wallet_from_mnemonic(&ctx.dashd.wallet.mnemonic, 0, test_account_options()) .expect("add W1 before start") }; @@ -423,7 +413,7 @@ async fn test_runtime_add_during_initial_sync() { let w2_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic(EMPTY_MNEMONIC, "", 0, test_account_options()) + .create_wallet_from_mnemonic(EMPTY_MNEMONIC, 0, test_account_options()) .expect("add W2 mid-flight") }; @@ -506,7 +496,7 @@ async fn test_runtime_add_with_tip_advance_during_rescan() { let w2_id = { let mut wallet_guard = client_handle.client.wallet().write().await; wallet_guard - .create_wallet_from_mnemonic(EMPTY_MNEMONIC, "", 0, test_account_options()) + .create_wallet_from_mnemonic(EMPTY_MNEMONIC, 0, test_account_options()) .expect("add W2 at runtime") }; diff --git a/key-wallet-ffi/examples/check_transaction.c b/key-wallet-ffi/examples/check_transaction.c index 1baeaccdc..0426d50cf 100644 --- a/key-wallet-ffi/examples/check_transaction.c +++ b/key-wallet-ffi/examples/check_transaction.c @@ -35,7 +35,6 @@ typedef struct { // External function declarations extern void* wallet_create_from_mnemonic( const char* mnemonic, - const char* passphrase, FFINetwork network, FFIError* error ); @@ -64,7 +63,7 @@ int main() { FFINetwork network = Testnet; // Create wallet - void* wallet = wallet_create_from_mnemonic(mnemonic, NULL, network, &error); + void* wallet = wallet_create_from_mnemonic(mnemonic, network, &error); if (!wallet) { printf("Failed to create wallet: %s\n", error.message); return 1; diff --git a/key-wallet-ffi/src/account_collection.rs b/key-wallet-ffi/src/account_collection.rs index f45c32ab0..912cc4660 100644 --- a/key-wallet-ffi/src/account_collection.rs +++ b/key-wallet-ffi/src/account_collection.rs @@ -1070,7 +1070,6 @@ mod tests { // Create wallet with default accounts let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, ptr::null(), error, @@ -1125,7 +1124,6 @@ mod tests { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &options, error, @@ -1172,7 +1170,6 @@ mod tests { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &options, error, @@ -1243,7 +1240,6 @@ mod tests { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &options, error, @@ -1296,7 +1292,6 @@ mod tests { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &options, error, @@ -1381,7 +1376,6 @@ mod tests { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &options, error, @@ -1468,7 +1462,6 @@ mod tests { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &options, error, @@ -1539,7 +1532,6 @@ mod tests { // Create wallet with default accounts (which should have at least BIP44 account 0) let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, ptr::null(), error, diff --git a/key-wallet-ffi/src/account_derivation_tests.rs b/key-wallet-ffi/src/account_derivation_tests.rs index b380916d2..688560d3a 100644 --- a/key-wallet-ffi/src/account_derivation_tests.rs +++ b/key-wallet-ffi/src/account_derivation_tests.rs @@ -23,12 +23,7 @@ mod tests { // Create wallet on testnet with default accounts let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); assert_eq!(error.code, FFIErrorCode::Success); @@ -122,12 +117,7 @@ mod tests { // Create wallet on testnet with default accounts let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); @@ -177,12 +167,7 @@ mod tests { // Create wallet and get account 0 let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); let account = unsafe { diff --git a/key-wallet-ffi/src/account_tests.rs b/key-wallet-ffi/src/account_tests.rs index 35be6a188..5e90bb34b 100644 --- a/key-wallet-ffi/src/account_tests.rs +++ b/key-wallet-ffi/src/account_tests.rs @@ -30,15 +30,9 @@ mod tests { // Create a wallet with default accounts let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; // Try to get the default account (should exist) @@ -84,15 +78,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; let count = unsafe { wallet_get_account_count(wallet, &mut error) }; @@ -129,15 +117,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); diff --git a/key-wallet-ffi/src/address_pool.rs b/key-wallet-ffi/src/address_pool.rs index 780dc4f23..44ede36eb 100644 --- a/key-wallet-ffi/src/address_pool.rs +++ b/key-wallet-ffi/src/address_pool.rs @@ -977,12 +977,10 @@ mod tests { // Add a wallet with default accounts let mnemonic = CString::new(test_mnemonic).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), &mut error, ); @@ -1076,12 +1074,10 @@ mod tests { // Add a wallet with default accounts let mnemonic = CString::new(test_mnemonic).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), &mut error, ); diff --git a/key-wallet-ffi/src/keys_tests.rs b/key-wallet-ffi/src/keys_tests.rs index 5ae315bc9..4fb6d21ea 100644 --- a/key-wallet-ffi/src/keys_tests.rs +++ b/key-wallet-ffi/src/keys_tests.rs @@ -15,14 +15,8 @@ mod tests { // Create a wallet to get extended keys from let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); assert_eq!(error.code, FFIErrorCode::Success); @@ -107,15 +101,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); @@ -138,15 +126,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); @@ -172,15 +154,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; // Try to derive private key - should now succeed (44'/1'/0'/0/0 for Dash) @@ -218,15 +194,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; // Ensure wallet was created successfully @@ -273,14 +243,8 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); assert_eq!(error.code, FFIErrorCode::Success); @@ -420,15 +384,9 @@ mod tests { // Create a wallet for subsequent tests let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; // Test with null path @@ -554,15 +512,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); @@ -599,15 +551,9 @@ mod tests { // Create a wallet let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; // Test different derivation paths (Dash coin type 5) diff --git a/key-wallet-ffi/src/managed_account.rs b/key-wallet-ffi/src/managed_account.rs index 21f069fde..3ebf703ef 100644 --- a/key-wallet-ffi/src/managed_account.rs +++ b/key-wallet-ffi/src/managed_account.rs @@ -1701,12 +1701,10 @@ mod tests { // Add a wallet with default accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), &mut error, ); @@ -1760,7 +1758,6 @@ mod tests { // Add a wallet with minimal accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut options = FFIWalletAccountCreationOptions::default_options(); options.option_type = FFIAccountCreationOptionType::BIP44AccountsOnly; @@ -1771,7 +1768,6 @@ mod tests { let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), &options, &mut error, ); @@ -1826,7 +1822,6 @@ mod tests { // Add a wallet with multiple accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut options = FFIWalletAccountCreationOptions::default_options(); options.option_type = FFIAccountCreationOptionType::AllAccounts; @@ -1845,7 +1840,6 @@ mod tests { let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), &options, &mut error, ); @@ -1888,12 +1882,10 @@ mod tests { // Add a wallet with default accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), &mut error, ); @@ -2011,12 +2003,10 @@ mod tests { // Add a wallet let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), &mut error, ); @@ -2066,12 +2056,10 @@ mod tests { // Add a wallet with default accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), &mut error, ); @@ -2161,11 +2149,9 @@ mod tests { options.coinjoin_count = coinjoin_indices.len(); let mnemonic2 = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase2 = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic2.as_ptr(), - passphrase2.as_ptr(), &options, &mut error, ); diff --git a/key-wallet-ffi/src/managed_wallet.rs b/key-wallet-ffi/src/managed_wallet.rs index 1a6673c93..8f6c6fd71 100644 --- a/key-wallet-ffi/src/managed_wallet.rs +++ b/key-wallet-ffi/src/managed_wallet.rs @@ -487,15 +487,9 @@ mod tests { // Create a wallet let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet.is_null()); assert_eq!(error.code, FFIErrorCode::Success); @@ -564,15 +558,9 @@ mod tests { // Create a wallet with a known mnemonic let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let wallet_ptr = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet_ptr.is_null()); assert_eq!(error.code, FFIErrorCode::Success); @@ -745,15 +733,9 @@ mod tests { // Create a wallet let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let wallet_ptr = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - &mut error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, &mut error) }; assert!(!wallet_ptr.is_null()); diff --git a/key-wallet-ffi/src/managed_wallet_tests.rs b/key-wallet-ffi/src/managed_wallet_tests.rs index d0e067187..83d8d97ef 100644 --- a/key-wallet-ffi/src/managed_wallet_tests.rs +++ b/key-wallet-ffi/src/managed_wallet_tests.rs @@ -30,14 +30,8 @@ mod tests { assert!(!manager.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); - let added = wallet_manager_add_wallet_from_mnemonic( - manager, - mnemonic.as_ptr(), - passphrase.as_ptr(), - error, - ); + let added = wallet_manager_add_wallet_from_mnemonic(manager, mnemonic.as_ptr(), error); assert!(added); assert_eq!(error.code, FFIErrorCode::Success); diff --git a/key-wallet-ffi/src/mnemonic_tests.rs b/key-wallet-ffi/src/mnemonic_tests.rs index 18ab54af0..5a4dc6b1f 100644 --- a/key-wallet-ffi/src/mnemonic_tests.rs +++ b/key-wallet-ffi/src/mnemonic_tests.rs @@ -606,8 +606,9 @@ mod tests { let mnemonic = unsafe { mnemonic::mnemonic_generate(12, &mut error) }; assert!(!mnemonic.is_null()); + let passphrase = CString::new("").unwrap(); + // Generate seed twice with same passphrase - should be identical - let passphrase = CString::new("test").unwrap(); let mut seed1 = [0u8; 64]; let mut seed_len1 = 0usize; let mut seed2 = [0u8; 64]; @@ -653,6 +654,8 @@ mod tests { assert!(!mnemonic.is_null()); assert_eq!(error.code, FFIErrorCode::Success); + let passphrase = CString::new("").unwrap(); + // Validate let is_valid = unsafe { mnemonic::mnemonic_validate(mnemonic, &mut error) }; assert!(is_valid); @@ -666,7 +669,6 @@ mod tests { // Convert to seed let mut seed = [0u8; 64]; let mut seed_len = 0usize; - let passphrase = CString::new("workflow_test").unwrap(); let success = unsafe { mnemonic::mnemonic_to_seed( diff --git a/key-wallet-ffi/src/wallet.rs b/key-wallet-ffi/src/wallet.rs index b29802747..113cd7902 100644 --- a/key-wallet-ffi/src/wallet.rs +++ b/key-wallet-ffi/src/wallet.rs @@ -23,7 +23,6 @@ use key_wallet::Network; /// # Safety /// /// - `mnemonic` must be a valid pointer to a null-terminated C string -/// - `passphrase` must be a valid pointer to a null-terminated C string or null /// - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null /// - `error` must be a valid pointer to an FFIError structure /// - The caller must ensure all pointers remain valid for the duration of this call @@ -31,7 +30,6 @@ use key_wallet::Network; #[no_mangle] pub unsafe extern "C" fn wallet_create_from_mnemonic_with_options( mnemonic: *const c_char, - passphrase: *const c_char, network: FFINetwork, account_options: *const FFIWalletAccountCreationOptions, error: *mut FFIError, @@ -41,12 +39,6 @@ pub unsafe extern "C" fn wallet_create_from_mnemonic_with_options( let mnemonic = deref_ptr!(mnemonic, error); let mnemonic_str = unwrap_or_return!(CStr::from_ptr(mnemonic).to_str(), error); - let passphrase_str = if passphrase.is_null() { - "" - } else { - unwrap_or_return!(CStr::from_ptr(passphrase).to_str(), error) - }; - let mnemonic = unwrap_or_return!(Mnemonic::from_phrase(mnemonic_str, Language::English), error); let network_rust: Network = network.into(); @@ -56,19 +48,8 @@ pub unsafe extern "C" fn wallet_create_from_mnemonic_with_options( (*account_options).to_wallet_options() }; - let wallet = if passphrase_str.is_empty() { - unwrap_or_return!(Wallet::from_mnemonic(mnemonic, network_rust, creation_options), error) - } else { - unwrap_or_return!( - Wallet::from_mnemonic_with_passphrase( - mnemonic, - passphrase_str.to_string(), - network_rust, - creation_options, - ), - error - ) - }; + let wallet = + unwrap_or_return!(Wallet::from_mnemonic(mnemonic, network_rust, creation_options), error); Box::into_raw(Box::new(FFIWallet::new(wallet))) } @@ -78,20 +59,17 @@ pub unsafe extern "C" fn wallet_create_from_mnemonic_with_options( /// # Safety /// /// - `mnemonic` must be a valid pointer to a null-terminated C string -/// - `passphrase` must be a valid pointer to a null-terminated C string or null /// - `error` must be a valid pointer to an FFIError structure /// - The caller must ensure all pointers remain valid for the duration of this call /// - The returned pointer must be freed with `wallet_free` when no longer needed #[no_mangle] pub unsafe extern "C" fn wallet_create_from_mnemonic( mnemonic: *const c_char, - passphrase: *const c_char, network: FFINetwork, error: *mut FFIError, ) -> *mut FFIWallet { wallet_create_from_mnemonic_with_options( mnemonic, - passphrase, network, ptr::null(), // Use default options error, diff --git a/key-wallet-ffi/src/wallet_manager.rs b/key-wallet-ffi/src/wallet_manager.rs index 05f0ee786..e2736b26b 100644 --- a/key-wallet-ffi/src/wallet_manager.rs +++ b/key-wallet-ffi/src/wallet_manager.rs @@ -120,7 +120,6 @@ pub unsafe extern "C" fn wallet_manager_create( /// /// - `manager` must be a valid pointer to an FFIWalletManager instance /// - `mnemonic` must be a valid pointer to a null-terminated C string -/// - `passphrase` must be a valid pointer to a null-terminated C string or null /// - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null /// - `error` must be a valid pointer to an FFIError structure /// - The caller must ensure all pointers remain valid for the duration of this call @@ -128,18 +127,12 @@ pub unsafe extern "C" fn wallet_manager_create( pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic_with_options( manager: *mut FFIWalletManager, mnemonic: *const c_char, - passphrase: *const c_char, account_options: *const crate::types::FFIWalletAccountCreationOptions, error: *mut FFIError, ) -> bool { let manager_ref = deref_ptr!(manager, error); let mnemonic = deref_ptr!(mnemonic, error); let mnemonic_str = unwrap_or_return!(CStr::from_ptr(mnemonic).to_str(), error); - let passphrase_str = if passphrase.is_null() { - "" - } else { - unwrap_or_return!(CStr::from_ptr(passphrase).to_str(), error) - }; let creation_options = if account_options.is_null() { key_wallet::wallet::initialization::WalletAccountCreationOptions::Default @@ -149,7 +142,7 @@ pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic_with_options( let result = manager_ref.runtime.block_on(async { let mut manager_guard = manager_ref.manager.write().await; - manager_guard.create_wallet_from_mnemonic(mnemonic_str, passphrase_str, 0, creation_options) + manager_guard.create_wallet_from_mnemonic(mnemonic_str, 0, creation_options) }); let _ = unwrap_or_return!(result, error); true @@ -161,20 +154,17 @@ pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic_with_options( /// /// - `manager` must be a valid pointer to an FFIWalletManager instance /// - `mnemonic` must be a valid pointer to a null-terminated C string -/// - `passphrase` must be a valid pointer to a null-terminated C string or null /// - `error` must be a valid pointer to an FFIError structure /// - The caller must ensure all pointers remain valid for the duration of this call #[no_mangle] pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic( manager: *mut FFIWalletManager, mnemonic: *const c_char, - passphrase: *const c_char, error: *mut FFIError, ) -> bool { wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic, - passphrase, ptr::null(), // Use default options error, ) @@ -189,7 +179,6 @@ pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic( /// /// - `manager` must be a valid pointer to an FFIWalletManager instance /// - `mnemonic` must be a valid pointer to a null-terminated C string -/// - `passphrase` must be a valid pointer to a null-terminated C string or null /// - `birth_height` is the block height to start syncing from (0 = sync from genesis) /// - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null /// - `downgrade_to_pubkey_wallet` if true, creates a watch-only or externally signable wallet @@ -202,10 +191,10 @@ pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic( /// - The caller must free the returned wallet_bytes using wallet_manager_free_wallet_bytes() #[cfg(feature = "bincode")] #[no_mangle] +#[allow(clippy::too_many_arguments)] pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager: *mut FFIWalletManager, mnemonic: *const c_char, - passphrase: *const c_char, birth_height: c_uint, account_options: *const crate::types::FFIWalletAccountCreationOptions, downgrade_to_pubkey_wallet: bool, @@ -222,11 +211,6 @@ pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic_return_serializ check_ptr!(wallet_id_out, error); let mnemonic_str = unwrap_or_return!(CStr::from_ptr(mnemonic).to_str(), error); - let passphrase_str = if passphrase.is_null() { - "" - } else { - unwrap_or_return!(CStr::from_ptr(passphrase).to_str(), error) - }; let creation_options = if account_options.is_null() { key_wallet::wallet::initialization::WalletAccountCreationOptions::Default @@ -239,7 +223,6 @@ pub unsafe extern "C" fn wallet_manager_add_wallet_from_mnemonic_return_serializ manager_guard.create_wallet_from_mnemonic_return_serialized_bytes( mnemonic_str, - passphrase_str, birth_height, creation_options, downgrade_to_pubkey_wallet, diff --git a/key-wallet-ffi/src/wallet_manager_serialization_tests.rs b/key-wallet-ffi/src/wallet_manager_serialization_tests.rs index 1e97d8095..df78f06a6 100644 --- a/key-wallet-ffi/src/wallet_manager_serialization_tests.rs +++ b/key-wallet-ffi/src/wallet_manager_serialization_tests.rs @@ -21,7 +21,6 @@ mod tests { assert!(!manager.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -32,7 +31,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, // birth_height ptr::null(), // default account options false, // don't downgrade to pubkey wallet @@ -72,7 +70,6 @@ mod tests { assert!(!manager.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -83,7 +80,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), true, // downgrade to pubkey wallet @@ -120,7 +116,6 @@ mod tests { assert!(!manager.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -131,7 +126,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), true, // downgrade to pubkey wallet @@ -158,54 +152,6 @@ mod tests { } } - #[test] - fn test_create_wallet_with_passphrase() { - let mut error = FFIError::default(); - let error = &mut error as *mut FFIError; - - // Create a wallet manager - let manager = unsafe { wallet_manager::wallet_manager_create(FFINetwork::Testnet, error) }; - assert!(!manager.is_null()); - - let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("test_passphrase").unwrap(); - - let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); - let mut wallet_bytes_len_out: usize = 0; - let mut wallet_id_out = [0u8; 32]; - - // Create wallet with passphrase - let success = unsafe { - wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( - manager, - mnemonic.as_ptr(), - passphrase.as_ptr(), - 0, - ptr::null(), - false, - false, - &mut wallet_bytes_out, - &mut wallet_bytes_len_out, - wallet_id_out.as_mut_ptr(), - error, - ) - }; - - assert!(success, "Failed to create wallet with passphrase"); - assert_eq!(unsafe { (*error).code }, FFIErrorCode::Success); - assert!(!wallet_bytes_out.is_null()); - assert!(wallet_bytes_len_out > 0); - - // Clean up - unsafe { - wallet_manager::wallet_manager_free_wallet_bytes( - wallet_bytes_out, - wallet_bytes_len_out, - ); - wallet_manager::wallet_manager_free(manager); - } - } - #[test] fn test_import_serialized_wallet() { let mut error = FFIError::default(); @@ -216,7 +162,6 @@ mod tests { assert!(!manager1.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -227,7 +172,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager1, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), false, @@ -284,7 +228,6 @@ mod tests { assert!(!manager.is_null()); let invalid_mnemonic = CString::new("invalid mnemonic phrase").unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -294,7 +237,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, invalid_mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), false, @@ -334,7 +276,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, ptr::null(), - ptr::null(), 0, ptr::null(), false, @@ -367,7 +308,6 @@ mod tests { assert!(!manager.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); // Create custom account options (BIP44 accounts only) let bip44_indices = [0u32, 1u32, 2u32]; @@ -396,7 +336,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, &account_options, false, diff --git a/key-wallet-ffi/src/wallet_manager_tests.rs b/key-wallet-ffi/src/wallet_manager_tests.rs index 9cb6ed66f..0719e7871 100644 --- a/key-wallet-ffi/src/wallet_manager_tests.rs +++ b/key-wallet-ffi/src/wallet_manager_tests.rs @@ -48,13 +48,11 @@ mod tests { // Add a wallet from mnemonic let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -90,8 +88,7 @@ mod tests { let success = wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, - mnemonic.as_ptr(), - ptr::null(), // No passphrase + mnemonic.as_ptr(), // No passphrase error, ); if !success { @@ -161,7 +158,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - ptr::null(), error, ) }; @@ -225,7 +221,6 @@ mod tests { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, invalid_mnemonic.as_ptr(), - ptr::null(), error, ) }; @@ -248,13 +243,11 @@ mod tests { // Add a wallet with account count let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -280,12 +273,10 @@ mod tests { // Add a wallet let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -332,12 +323,10 @@ mod tests { // Add wallet let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -410,12 +399,10 @@ mod tests { // Test adding wallet with null manager let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( ptr::null_mut(), mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -474,13 +461,11 @@ mod tests { // Add a wallet from mnemonic let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -593,13 +578,11 @@ mod tests { // Add a wallet from mnemonic let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -748,13 +731,11 @@ mod tests { // Add a wallet from mnemonic let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), error, ) }; @@ -858,7 +839,6 @@ mod tests { // Test basic wallet creation and serialization let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -868,7 +848,6 @@ mod tests { crate::wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, // birth_height ptr::null(), // default account options false, // don't downgrade to pubkey wallet @@ -909,7 +888,6 @@ mod tests { crate::wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager2, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), true, // downgrade to pubkey wallet @@ -979,7 +957,6 @@ mod tests { crate::wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager4, mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), true, // downgrade to pubkey wallet @@ -1018,7 +995,6 @@ mod tests { crate::wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager5, invalid_mnemonic.as_ptr(), - passphrase.as_ptr(), 0, ptr::null(), false, @@ -1054,7 +1030,6 @@ mod tests { assert!(!manager1.is_null()); let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut wallet_bytes_out: *mut u8 = ptr::null_mut(); let mut wallet_bytes_len_out: usize = 0; @@ -1065,7 +1040,6 @@ mod tests { crate::wallet_manager::wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( manager1, mnemonic.as_ptr(), - passphrase.as_ptr(), 100, // birth_height ptr::null(), // default account options false, // don't downgrade to pubkey wallet diff --git a/key-wallet-ffi/src/wallet_tests.rs b/key-wallet-ffi/src/wallet_tests.rs index de13d4aa8..922ec7ea3 100644 --- a/key-wallet-ffi/src/wallet_tests.rs +++ b/key-wallet-ffi/src/wallet_tests.rs @@ -18,15 +18,9 @@ mod wallet_tests { let error = &mut error as *mut FFIError; let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, error) }; assert!(!wallet.is_null()); @@ -104,46 +98,14 @@ mod wallet_tests { } } - #[test] - fn test_wallet_with_passphrase() { - let mut error = FFIError::default(); - let error = &mut error as *mut FFIError; - - let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("test passphrase").unwrap(); - - let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) - }; - - assert!(!wallet.is_null()); - assert_eq!(unsafe { (*error).code }, FFIErrorCode::Success); - - // Clean up - unsafe { - wallet::wallet_free(wallet); - } - } - #[test] fn test_wallet_error_cases() { let mut error = FFIError::default(); let error = &mut error as *mut FFIError; // Test with null mnemonic - let wallet = unsafe { - wallet::wallet_create_from_mnemonic( - ptr::null(), - ptr::null(), - FFINetwork::Testnet, - error, - ) - }; + let wallet = + unsafe { wallet::wallet_create_from_mnemonic(ptr::null(), FFINetwork::Testnet, error) }; assert!(wallet.is_null()); assert_eq!(unsafe { (*error).code }, FFIErrorCode::InvalidInput); @@ -152,7 +114,6 @@ mod wallet_tests { let wallet = unsafe { wallet::wallet_create_from_mnemonic( invalid_mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, error, ) @@ -240,15 +201,9 @@ mod wallet_tests { // Create wallet from mnemonic let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let wallet_with_mnemonic = unsafe { - wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) + wallet::wallet_create_from_mnemonic(mnemonic.as_ptr(), FFINetwork::Testnet, error) }; assert!(!wallet_with_mnemonic.is_null()); diff --git a/key-wallet-ffi/tests/debug_wallet_add.rs b/key-wallet-ffi/tests/debug_wallet_add.rs index dfab07850..3f246860d 100644 --- a/key-wallet-ffi/tests/debug_wallet_add.rs +++ b/key-wallet-ffi/tests/debug_wallet_add.rs @@ -14,16 +14,10 @@ fn test_debug_wallet_add() { println!("Manager created successfully"); let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("pass1").unwrap(); println!("Adding wallet with passphrase 'pass1'"); let success = unsafe { - wallet_manager::wallet_manager_add_wallet_from_mnemonic( - manager, - mnemonic.as_ptr(), - passphrase.as_ptr(), - error, - ) + wallet_manager::wallet_manager_add_wallet_from_mnemonic(manager, mnemonic.as_ptr(), error) }; if !success { diff --git a/key-wallet-ffi/tests/integration_test.rs b/key-wallet-ffi/tests/integration_test.rs index cf3115c41..fedc05231 100644 --- a/key-wallet-ffi/tests/integration_test.rs +++ b/key-wallet-ffi/tests/integration_test.rs @@ -31,13 +31,9 @@ fn test_full_wallet_workflow() { assert!(!manager.is_null()); // 4. Add wallet to manager - let passphrase = CString::new("").unwrap(); let success = unsafe { key_wallet_ffi::wallet_manager::wallet_manager_add_wallet_from_mnemonic( - manager, - mnemonic, - passphrase.as_ptr(), - error, + manager, mnemonic, error, ) }; assert!(success); @@ -89,7 +85,7 @@ fn test_seed_to_wallet_workflow() { // 1. Convert mnemonic to seed let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("test passphrase").unwrap(); + let passphrase = CString::new("").unwrap(); let mut seed = [0u8; 64]; let mut seed_len: usize = 0; @@ -185,7 +181,6 @@ fn test_error_handling() { let wallet = unsafe { key_wallet_ffi::wallet::wallet_create_from_mnemonic( invalid_mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, error, ) @@ -195,12 +190,7 @@ fn test_error_handling() { // 2. Null pointer errors let wallet = unsafe { - key_wallet_ffi::wallet::wallet_create_from_mnemonic( - ptr::null(), - ptr::null(), - FFINetwork::Testnet, - error, - ) + key_wallet_ffi::wallet::wallet_create_from_mnemonic(ptr::null(), FFINetwork::Testnet, error) }; assert!(wallet.is_null()); assert_eq!(unsafe { (*error).code }, FFIErrorCode::InvalidInput); diff --git a/key-wallet-ffi/tests/test_account_collection.rs b/key-wallet-ffi/tests/test_account_collection.rs index ecaf7aa1e..035cb900f 100644 --- a/key-wallet-ffi/tests/test_account_collection.rs +++ b/key-wallet-ffi/tests/test_account_collection.rs @@ -37,7 +37,6 @@ fn test_account_collection_comprehensive() { let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, &account_options, error, @@ -155,7 +154,6 @@ fn test_account_collection_minimal() { // Create wallet with minimal accounts (default) let wallet = wallet_create_from_mnemonic_with_options( mnemonic.as_ptr(), - ptr::null(), FFINetwork::Testnet, ptr::null(), // Use default options test, diff --git a/key-wallet-ffi/tests/test_import_wallet.rs b/key-wallet-ffi/tests/test_import_wallet.rs index b28cdfece..33a4c2103 100644 --- a/key-wallet-ffi/tests/test_import_wallet.rs +++ b/key-wallet-ffi/tests/test_import_wallet.rs @@ -21,12 +21,10 @@ mod tests { // First, create a wallet from mnemonic let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about\0"; - let passphrase = "\0"; let success = wallet_manager_add_wallet_from_mnemonic( manager, mnemonic.as_ptr() as *const c_char, - passphrase.as_ptr() as *const c_char, &mut error, ); assert!(success); diff --git a/key-wallet-ffi/tests/test_managed_account_collection.rs b/key-wallet-ffi/tests/test_managed_account_collection.rs index 7baa8d9b9..9a49aaa65 100644 --- a/key-wallet-ffi/tests/test_managed_account_collection.rs +++ b/key-wallet-ffi/tests/test_managed_account_collection.rs @@ -26,12 +26,10 @@ fn test_managed_account_collection_basic() { // Add a wallet with default accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), // Use default options &mut error, ); @@ -94,7 +92,6 @@ fn test_managed_account_collection_with_special_accounts() { // Create wallet with special accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut options = FFIWalletAccountCreationOptions::default_options(); options.option_type = FFIAccountCreationOptionType::AllAccounts; @@ -130,7 +127,6 @@ fn test_managed_account_collection_with_special_accounts() { let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), &options, &mut error, ); @@ -222,7 +218,6 @@ fn test_managed_account_collection_summary() { // Create wallet with multiple account types let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut options = FFIWalletAccountCreationOptions::default_options(); options.option_type = FFIAccountCreationOptionType::AllAccounts; @@ -249,7 +244,6 @@ fn test_managed_account_collection_summary() { let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), &options, &mut error, ); @@ -303,7 +297,6 @@ fn test_managed_account_collection_summary_data() { // Create wallet with various account types let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let mut options = FFIWalletAccountCreationOptions::default_options(); options.option_type = FFIAccountCreationOptionType::AllAccounts; @@ -337,7 +330,6 @@ fn test_managed_account_collection_summary_data() { let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), &options, &mut error, ); @@ -428,12 +420,10 @@ fn test_managed_account_collection_nonexistent_accounts() { // Create wallet with minimal accounts let mnemonic = CString::new(TEST_MNEMONIC).unwrap(); - let passphrase = CString::new("").unwrap(); let success = wallet_manager_add_wallet_from_mnemonic_with_options( manager, mnemonic.as_ptr(), - passphrase.as_ptr(), ptr::null(), // Default options &mut error, ); diff --git a/key-wallet-ffi/tests/test_passphrase_wallets.rs b/key-wallet-ffi/tests/test_passphrase_wallets.rs deleted file mode 100644 index 1dea85e93..000000000 --- a/key-wallet-ffi/tests/test_passphrase_wallets.rs +++ /dev/null @@ -1,201 +0,0 @@ -//! Tests for wallet creation with passphrase through FFI -//! These tests demonstrate current issues with passphrase handling in the FFI layer - -use dash_network::ffi::FFINetwork; -use key_wallet_ffi::error::{FFIError, FFIErrorCode}; -use std::ffi::CString; - -#[test] -fn test_ffi_wallet_create_from_mnemonic_with_passphrase() { - // This test verifies that wallets with passphrases now work correctly through FFI - - let mut error = FFIError::default(); - let error = &mut error as *mut FFIError; - - let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("my_secure_passphrase").unwrap(); - - // Create wallet with passphrase using default options (which creates account 0) - let wallet = unsafe { - key_wallet_ffi::wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) - }; - - // Wallet should be created successfully - assert!(!wallet.is_null()); - assert_eq!(unsafe { (*error).code }, FFIErrorCode::Success); - - // Since we can't derive addresses directly from wallets anymore, - // verify that the wallet was created successfully - let is_watch_only = unsafe { key_wallet_ffi::wallet::wallet_is_watch_only(wallet, error) }; - assert!(!is_watch_only); - assert_eq!(unsafe { (*error).code }, FFIErrorCode::Success); - - // Get wallet ID to verify it was created - let mut wallet_id = [0u8; 32]; - let success = - unsafe { key_wallet_ffi::wallet::wallet_get_id(wallet, wallet_id.as_mut_ptr(), error) }; - assert!(success); - assert_ne!(wallet_id, [0u8; 32]); - println!("Successfully created passphrase wallet with ID: {:?}", &wallet_id[..8]); - - // Clean up - unsafe { - key_wallet_ffi::wallet::wallet_free(wallet); - } -} - -#[test] -fn test_ffi_wallet_manager_add_wallet_with_passphrase() { - // This test shows the issue when adding a wallet with passphrase to the wallet manager - - let mut error = FFIError::default(); - let error = &mut error as *mut FFIError; - - // Create wallet manager - let manager = unsafe { - key_wallet_ffi::wallet_manager::wallet_manager_create(FFINetwork::Testnet, error) - }; - assert!(!manager.is_null()); - - let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("test_passphrase_123").unwrap(); - - // Add wallet with passphrase to manager - let success = unsafe { - key_wallet_ffi::wallet_manager::wallet_manager_add_wallet_from_mnemonic( - manager, - mnemonic.as_ptr(), - passphrase.as_ptr(), - error, - ) - }; - - // This should succeed after our previous fix - assert!(success); - assert_eq!(unsafe { (*error).code }, FFIErrorCode::Success); - - // Get wallet IDs - let mut wallet_ids_ptr = std::ptr::null_mut(); - let mut count = 0usize; - let success = unsafe { - key_wallet_ffi::wallet_manager::wallet_manager_get_wallet_ids( - manager, - &mut wallet_ids_ptr, - &mut count, - error, - ) - }; - assert!(success); - assert_eq!(count, 1); - - // Clean up - if !wallet_ids_ptr.is_null() && count > 0 { - unsafe { - key_wallet_ffi::wallet_manager::wallet_manager_free_wallet_ids(wallet_ids_ptr, count); - } - } - unsafe { - key_wallet_ffi::wallet_manager::wallet_manager_free(manager); - } -} - -#[test] -fn test_ffi_wallet_with_passphrase_ideal_workflow() { - // This test demonstrates what the ideal workflow should be for wallets with passphrases - - let mut error = FFIError::default(); - let error = &mut error as *mut FFIError; - - let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let passphrase = CString::new("my_passphrase").unwrap(); - - // Create wallet with passphrase - let wallet = unsafe { - key_wallet_ffi::wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) - }; - assert!(!wallet.is_null()); - - // IDEAL: There should be a way to either: - // 1. Automatically create account 0 with the passphrase during wallet creation - // 2. Provide a function to add an account with passphrase: - // wallet_add_account_with_passphrase(wallet, account_type, network, passphrase, error) - // 3. Have a callback mechanism to request the passphrase when needed - - // Since we can't derive addresses directly from wallets anymore, - // just verify the wallet was created - let is_watch_only = unsafe { key_wallet_ffi::wallet::wallet_is_watch_only(wallet, error) }; - assert!(!is_watch_only); - println!("Wallet with passphrase created successfully"); - unsafe { - key_wallet_ffi::wallet::wallet_free(wallet); - } -} - -#[test] -fn test_demonstrate_passphrase_issue_with_account_creation() { - // This test verifies that the passphrase wallet issue has been FIXED - - let mut error = FFIError::default(); - let error = &mut error as *mut FFIError; - - // Create two wallets: one without passphrase, one with - let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - let empty_passphrase = CString::new("").unwrap(); - let actual_passphrase = CString::new("test123").unwrap(); - - // Wallet WITHOUT passphrase - let wallet_no_pass = unsafe { - key_wallet_ffi::wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - empty_passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) - }; - assert!(!wallet_no_pass.is_null()); - - // Wallet WITH passphrase - let wallet_with_pass = unsafe { - key_wallet_ffi::wallet::wallet_create_from_mnemonic( - mnemonic.as_ptr(), - actual_passphrase.as_ptr(), - FFINetwork::Testnet, - error, - ) - }; - assert!(!wallet_with_pass.is_null()); - - // Try to get account count for both wallets - let count_no_pass = - unsafe { key_wallet_ffi::account::wallet_get_account_count(wallet_no_pass, error) }; - - let count_with_pass = - unsafe { key_wallet_ffi::account::wallet_get_account_count(wallet_with_pass, error) }; - - println!("Account count without passphrase: {}", count_no_pass); - println!("Account count with passphrase: {}", count_with_pass); - - // Both wallets should now have accounts created automatically - assert!(count_no_pass > 0, "Wallet without passphrase should have at least one account"); - - // FIXED: The wallet with passphrase should ALSO have accounts now - assert!(count_with_pass > 0, "Wallet with passphrase should now have accounts created"); - - // Verify the accounts are actually different (different derivation due to passphrase) - - // Clean up - unsafe { - key_wallet_ffi::wallet::wallet_free(wallet_no_pass); - key_wallet_ffi::wallet::wallet_free(wallet_with_pass); - } -} diff --git a/key-wallet-manager/examples/wallet_creation.rs b/key-wallet-manager/examples/wallet_creation.rs index beb3f3160..9ba2dad98 100644 --- a/key-wallet-manager/examples/wallet_creation.rs +++ b/key-wallet-manager/examples/wallet_creation.rs @@ -43,7 +43,6 @@ fn main() { let result = manager.create_wallet_from_mnemonic( test_mnemonic, - "", // No passphrase 100_000, key_wallet::wallet::initialization::WalletAccountCreationOptions::Default, ); diff --git a/key-wallet-manager/src/lib.rs b/key-wallet-manager/src/lib.rs index b0be0024e..08bb3b5b4 100644 --- a/key-wallet-manager/src/lib.rs +++ b/key-wallet-manager/src/lib.rs @@ -152,27 +152,14 @@ impl WalletManager { pub fn create_wallet_from_mnemonic( &mut self, mnemonic: &str, - passphrase: &str, birth_height: CoreBlockHeight, account_creation_options: key_wallet::wallet::initialization::WalletAccountCreationOptions, ) -> Result { let mnemonic_obj = Mnemonic::from_phrase(mnemonic, key_wallet::mnemonic::Language::English) .map_err(|e| WalletError::InvalidMnemonic(e.to_string()))?; - // Use appropriate wallet creation method based on whether a passphrase is provided - let wallet = if passphrase.is_empty() { - Wallet::from_mnemonic(mnemonic_obj, self.network, account_creation_options) - .map_err(|e| WalletError::WalletCreation(e.to_string()))? - } else { - // For wallets with passphrase, use the provided options - Wallet::from_mnemonic_with_passphrase( - mnemonic_obj, - passphrase.to_string(), - self.network, - account_creation_options, - ) - .map_err(|e| WalletError::WalletCreation(e.to_string()))? - }; + let wallet = Wallet::from_mnemonic(mnemonic_obj, self.network, account_creation_options) + .map_err(|e| WalletError::WalletCreation(e.to_string()))?; // Compute wallet ID from the wallet's root public key let wallet_id = wallet.compute_wallet_id(); @@ -187,7 +174,6 @@ impl WalletManager { let managed_info = T::from_wallet(&wallet, birth_height); // The wallet already has accounts created according to the provided options - // No need to manually add accounts here since that's handled by from_mnemonic/from_mnemonic_with_passphrase let wallet_mut = wallet.clone(); // Add the account to managed info and generate initial addresses @@ -207,7 +193,6 @@ impl WalletManager { /// /// # Arguments /// * `mnemonic` - The mnemonic phrase - /// * `passphrase` - Optional BIP39 passphrase (empty string for no passphrase) /// * `birth_height` - Birth height for wallet scanning (0 to sync from genesis) /// * `account_creation_options` - Which accounts to create initially /// * `downgrade_to_pubkey_wallet` - If true, creates a wallet without private keys @@ -222,11 +207,9 @@ impl WalletManager { /// When `downgrade_to_pubkey_wallet` is true, the returned wallet contains NO private key material, /// making it safe to use on potentially compromised systems or for creating watch-only wallets. #[cfg(feature = "bincode")] - #[allow(clippy::too_many_arguments)] pub fn create_wallet_from_mnemonic_return_serialized_bytes( &mut self, mnemonic: &str, - passphrase: &str, birth_height: CoreBlockHeight, account_creation_options: key_wallet::wallet::initialization::WalletAccountCreationOptions, downgrade_to_pubkey_wallet: bool, @@ -237,19 +220,9 @@ impl WalletManager { let mnemonic_obj = Mnemonic::from_phrase(mnemonic, key_wallet::mnemonic::Language::English) .map_err(|e| WalletError::InvalidMnemonic(e.to_string()))?; - // Create the initial wallet from mnemonic - let mut wallet = if passphrase.is_empty() { + let mut wallet = Wallet::from_mnemonic(mnemonic_obj, self.network, account_creation_options) - .map_err(|e| WalletError::WalletCreation(e.to_string()))? - } else { - Wallet::from_mnemonic_with_passphrase( - mnemonic_obj, - passphrase.to_string(), - self.network, - account_creation_options, - ) - .map_err(|e| WalletError::WalletCreation(e.to_string()))? - }; + .map_err(|e| WalletError::WalletCreation(e.to_string()))?; // Downgrade to pubkey-only wallet if requested let final_wallet = if downgrade_to_pubkey_wallet { diff --git a/key-wallet-manager/src/process_block.rs b/key-wallet-manager/src/process_block.rs index aac4c16f0..901baba03 100644 --- a/key-wallet-manager/src/process_block.rs +++ b/key-wallet-manager/src/process_block.rs @@ -588,7 +588,6 @@ mod tests { let wallet_id2 = manager .create_wallet_from_mnemonic( &mnemonic2.to_string(), - "", 0, WalletAccountCreationOptions::Default, ) @@ -656,12 +655,7 @@ mod tests { // create_wallet_from_mnemonic bumps let wallet_id = manager - .create_wallet_from_mnemonic( - TEST_MNEMONIC, - "", - 0, - WalletAccountCreationOptions::Default, - ) + .create_wallet_from_mnemonic(TEST_MNEMONIC, 0, WalletAccountCreationOptions::Default) .unwrap(); expected_rev += 1; assert_eq!(manager.monitor_revision(), expected_rev, "after create_wallet_from_mnemonic"); diff --git a/key-wallet-manager/src/test_helpers.rs b/key-wallet-manager/src/test_helpers.rs index f71223961..d262dfd55 100644 --- a/key-wallet-manager/src/test_helpers.rs +++ b/key-wallet-manager/src/test_helpers.rs @@ -22,7 +22,7 @@ pub(crate) fn dummy_instant_lock(txid: Txid) -> InstantLock { pub(crate) fn setup_manager_with_wallet() -> (WalletManager, WalletId, Address) { let mut manager = WalletManager::new(Network::Testnet); let wallet_id = manager - .create_wallet_from_mnemonic(TEST_MNEMONIC, "", 0, WalletAccountCreationOptions::Default) + .create_wallet_from_mnemonic(TEST_MNEMONIC, 0, WalletAccountCreationOptions::Default) .unwrap(); let addresses = manager.monitored_addresses(); assert!(!addresses.is_empty(), "wallet should have monitored addresses"); diff --git a/key-wallet-manager/tests/integration_test.rs b/key-wallet-manager/tests/integration_test.rs index 2eb01b3f3..402f8f3c3 100644 --- a/key-wallet-manager/tests/integration_test.rs +++ b/key-wallet-manager/tests/integration_test.rs @@ -32,7 +32,6 @@ fn test_wallet_manager_from_mnemonic() { // Create a wallet from mnemonic let wallet_result = manager.create_wallet_from_mnemonic( &mnemonic.to_string(), - "", 0, WalletAccountCreationOptions::Default, ); @@ -152,7 +151,6 @@ fn test_block_height_tracking() { let wallet_id1 = manager .create_wallet_from_mnemonic( &mnemonic1.to_string(), - "", 0, WalletAccountCreationOptions::Default, ) @@ -162,7 +160,6 @@ fn test_block_height_tracking() { let wallet_id2 = manager .create_wallet_from_mnemonic( &mnemonic2.to_string(), - "", 5000, WalletAccountCreationOptions::Default, ) diff --git a/key-wallet-manager/tests/test_serialized_wallets.rs b/key-wallet-manager/tests/test_serialized_wallets.rs index b79d5d84b..edcdab694 100644 --- a/key-wallet-manager/tests/test_serialized_wallets.rs +++ b/key-wallet-manager/tests/test_serialized_wallets.rs @@ -16,7 +16,6 @@ mod tests { // Test 1: Create full wallet with private keys let result = manager.create_wallet_from_mnemonic_return_serialized_bytes( test_mnemonic, - "", 100_000, WalletAccountCreationOptions::Default, false, // Don't downgrade @@ -37,7 +36,6 @@ mod tests { let mut manager2 = WalletManager::::new(Network::Testnet); let result = manager2.create_wallet_from_mnemonic_return_serialized_bytes( test_mnemonic, - "", 100_000, WalletAccountCreationOptions::Default, true, // Downgrade to pubkey wallet @@ -55,7 +53,6 @@ mod tests { let mut manager3 = WalletManager::::new(Network::Testnet); let result = manager3.create_wallet_from_mnemonic_return_serialized_bytes( test_mnemonic, - "", 100_000, WalletAccountCreationOptions::Default, true, // Downgrade to pubkey wallet @@ -73,40 +70,4 @@ mod tests { assert!(import_result.is_ok()); assert_eq!(import_result.unwrap(), wallet_id); } - - #[test] - fn test_wallet_with_passphrase() { - let mut manager = WalletManager::::new(Network::Testnet); - - let test_mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; - let passphrase = "test_passphrase"; - - let result = manager.create_wallet_from_mnemonic_return_serialized_bytes( - test_mnemonic, - passphrase, - 0, - WalletAccountCreationOptions::Default, - false, - false, - ); - assert!(result.is_ok()); - let (bytes, wallet_id) = result.unwrap(); - assert!(!bytes.is_empty()); - - // Wallet ID with passphrase should be different - let mut manager2 = WalletManager::::new(Network::Testnet); - let result2 = manager2.create_wallet_from_mnemonic_return_serialized_bytes( - test_mnemonic, - "", // No passphrase - 0, - WalletAccountCreationOptions::Default, - false, - false, - ); - assert!(result2.is_ok()); - let (_bytes2, wallet_id2) = result2.unwrap(); - - // Different wallet IDs because different passphrases - assert_ne!(wallet_id, wallet_id2); - } } diff --git a/key-wallet/src/tests/edge_case_tests.rs b/key-wallet/src/tests/edge_case_tests.rs index a65d0fac1..28e8811c8 100644 --- a/key-wallet/src/tests/edge_case_tests.rs +++ b/key-wallet/src/tests/edge_case_tests.rs @@ -271,48 +271,6 @@ fn test_concurrent_access_simulation() { assert_ne!(wallet.wallet_id, [0u8; 32]); } -#[test] -fn test_passphrase_edge_cases() { - let mnemonic = Mnemonic::from_phrase( - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - Language::English, - ) - .unwrap(); - - // Test with empty passphrase - use regular from_mnemonic for empty passphrase - let wallet1 = Wallet::from_mnemonic( - mnemonic.clone(), - Network::Testnet, - crate::wallet::initialization::WalletAccountCreationOptions::None, - ) - .unwrap(); - - // Test with very long passphrase - let long_passphrase = "a".repeat(1000); - let wallet2 = Wallet::from_mnemonic_with_passphrase( - mnemonic.clone(), - long_passphrase, - Network::Testnet, - crate::wallet::initialization::WalletAccountCreationOptions::None, - ) - .unwrap(); - - // Test with special characters - let special_passphrase = "!@#$%^&*()_+-=[]{}|;':\",./<>?"; - let wallet3 = Wallet::from_mnemonic_with_passphrase( - mnemonic, - special_passphrase.to_string(), - Network::Testnet, - crate::wallet::initialization::WalletAccountCreationOptions::None, - ) - .unwrap(); - - // All wallets should have different IDs due to different passphrases - assert_ne!(wallet1.wallet_id, wallet2.wallet_id); - assert_ne!(wallet2.wallet_id, wallet3.wallet_id); - assert_ne!(wallet1.wallet_id, wallet3.wallet_id); -} - #[test] fn test_derivation_path_depth_limits() { // Test maximum derivation path depth diff --git a/key-wallet/src/tests/wallet_tests.rs b/key-wallet/src/tests/wallet_tests.rs index 3c4546eda..f165030fa 100644 --- a/key-wallet/src/tests/wallet_tests.rs +++ b/key-wallet/src/tests/wallet_tests.rs @@ -148,41 +148,6 @@ fn test_wallet_creation_watch_only() { assert_eq!(wallet.compute_wallet_id(), expected_id); } -#[test] -fn test_wallet_creation_with_passphrase() { - let mnemonic = Mnemonic::from_phrase(TEST_MNEMONIC, Language::English).unwrap(); - let passphrase = "test_passphrase"; - let seed = mnemonic.to_seed(passphrase); - let root_priv_key = RootExtendedPrivKey::new_master(&seed).unwrap(); - let root_pub_key = root_priv_key.to_root_extended_pub_key(); - - let wallet = Wallet::from_mnemonic_with_passphrase( - mnemonic.clone(), - passphrase.to_string(), - Network::Testnet, - crate::wallet::initialization::WalletAccountCreationOptions::None, - ) - .unwrap(); - - // Verify wallet properties - assert!(wallet.has_mnemonic()); - assert!(wallet.needs_passphrase()); - assert!(wallet.can_sign()); // Can sign but needs passphrase - assert!(!wallet.is_watch_only()); - - // Verify mnemonic and public key are stored - match &wallet.wallet_type { - WalletType::MnemonicWithPassphrase { - mnemonic: wallet_mnemonic, - root_extended_public_key, - } => { - assert_eq!(wallet_mnemonic.to_string(), mnemonic.to_string()); - assert_eq!(root_extended_public_key.root_public_key, root_pub_key.root_public_key); - } - _ => panic!("Expected mnemonic with passphrase wallet type"), - } -} - #[test] fn test_wallet_id_computation() { let mnemonic = Mnemonic::from_phrase(TEST_MNEMONIC, Language::English).unwrap(); diff --git a/key-wallet/src/wallet/accounts.rs b/key-wallet/src/wallet/accounts.rs index f6c4041f1..2ff00d229 100644 --- a/key-wallet/src/wallet/accounts.rs +++ b/key-wallet/src/wallet/accounts.rs @@ -63,65 +63,6 @@ impl Wallet { self.accounts.insert(account).map_err(|e| Error::InvalidParameter(e.to_string())) } - /// Add a new account to a wallet that requires a passphrase - /// - /// This function only works with wallets created with a passphrase (MnemonicWithPassphrase type). - /// It will fail if called on other wallet types. - /// - /// # Arguments - /// * `account_type` - The type of account to create - /// * `passphrase` - The passphrase used when creating the wallet - /// - /// # Returns - /// Ok(()) if the account was successfully added - /// - /// # Errors - /// Returns an error if: - /// - The wallet is not a passphrase wallet - /// - The account already exists - /// - The passphrase is incorrect (will fail during derivation) - pub fn add_account_with_passphrase( - &mut self, - account_type: AccountType, - passphrase: &str, - ) -> Result<()> { - // Check that this is a passphrase wallet - match &self.wallet_type { - crate::wallet::WalletType::MnemonicWithPassphrase { mnemonic, .. } => { - // Get a unique wallet ID for this wallet first - let wallet_id = self.get_wallet_id(); - - // Derive the account using the passphrase - let derivation_path = account_type.derivation_path(self.network)?; - - // Generate seed with passphrase - let seed = mnemonic.to_seed(passphrase); - let root_key = super::root_extended_keys::RootExtendedPrivKey::new_master(&seed)?; - let master_key = root_key.to_extended_priv_key(self.network); - let secp = Secp256k1::new(); - let account_xpriv = - master_key.derive_priv(&secp, &derivation_path).map_err(Error::Bip32)?; - - let account = Account::from_xpriv(Some(wallet_id), account_type, account_xpriv, self.network)?; - - // Check if account already exists - if self.accounts.contains_account_type(&account_type) { - return Err(Error::InvalidParameter(format!( - "Account type {:?} already exists for network {:?}", - account_type, self.network - ))); - } - - // Insert into the collection - self.accounts.insert(account) - .map_err(|e| Error::InvalidParameter(e.to_string())) - } - _ => Err(Error::InvalidParameter( - "add_account_with_passphrase can only be used with wallets created with a passphrase".to_string() - )), - } - } - /// Add a new BLS account to the wallet /// /// BLS accounts are used for Platform/masternode operations. @@ -183,68 +124,6 @@ impl Wallet { .map_err(|e| Error::InvalidParameter(e.to_string())) } - /// Add a new BLS account to a wallet that requires a passphrase - /// - /// This function only works with wallets created with a passphrase (MnemonicWithPassphrase type). - /// - /// # Arguments - /// * `account_type` - The type of account (must be ProviderOperatorKeys) - /// * `passphrase` - The passphrase used when creating the wallet - /// - /// # Returns - /// Ok(()) if the account was successfully added - #[cfg(feature = "bls")] - pub fn add_bls_account_with_passphrase( - &mut self, - account_type: AccountType, - passphrase: &str, - ) -> Result<()> { - // Validate account type - if !matches!(account_type, AccountType::ProviderOperatorKeys) { - return Err(Error::InvalidParameter( - "BLS accounts can only be ProviderOperatorKeys".to_string(), - )); - } - - // Check that this is a passphrase wallet - match &self.wallet_type { - crate::wallet::WalletType::MnemonicWithPassphrase { mnemonic, .. } => { - // Get a unique wallet ID for this wallet first - let wallet_id = self.get_wallet_id(); - - // Derive the account using the passphrase - let derivation_path = account_type.derivation_path(self.network)?; - - // Generate seed with passphrase - let seed = mnemonic.to_seed(passphrase); - let root_key = super::root_extended_keys::RootExtendedPrivKey::new_master(&seed)?; - let master_key = root_key.to_extended_priv_key(self.network); - let secp = Secp256k1::new(); - let account_xpriv = - master_key.derive_priv(&secp, &derivation_path).map_err(Error::Bip32)?; - - // Create BLS seed from derived private key - let bls_seed = account_xpriv.private_key.secret_bytes(); - let bls_account = BLSAccount::from_seed(Some(wallet_id.to_vec()), account_type, bls_seed, self.network)?; - - // Check if account already exists - if self.accounts.contains_account_type(&account_type) { - return Err(Error::InvalidParameter(format!( - "Account type {:?} already exists for network {:?}", - account_type, self.network - ))); - } - - // Insert into the collection - self.accounts.insert_bls_account(bls_account) - .map_err(|e| Error::InvalidParameter(e.to_string())) - } - _ => Err(Error::InvalidParameter( - "add_bls_account_with_passphrase can only be used with wallets created with a passphrase".to_string() - )), - } - } - /// Add a new EdDSA account to the wallet /// /// EdDSA accounts are used for Platform operations. @@ -306,68 +185,6 @@ impl Wallet { .map_err(|e| Error::InvalidParameter(e.to_string())) } - /// Add a new EdDSA account to a wallet that requires a passphrase - /// - /// This function only works with wallets created with a passphrase (MnemonicWithPassphrase type). - /// - /// # Arguments - /// * `account_type` - The type of account (must be ProviderPlatformKeys) - /// * `passphrase` - The passphrase used when creating the wallet - /// - /// # Returns - /// Ok(()) if the account was successfully added - #[cfg(feature = "eddsa")] - pub fn add_eddsa_account_with_passphrase( - &mut self, - account_type: AccountType, - passphrase: &str, - ) -> Result<()> { - // Validate account type - if !matches!(account_type, AccountType::ProviderPlatformKeys) { - return Err(Error::InvalidParameter( - "EdDSA accounts can only be ProviderPlatformKeys".to_string(), - )); - } - - // Check that this is a passphrase wallet - match &self.wallet_type { - crate::wallet::WalletType::MnemonicWithPassphrase { mnemonic, .. } => { - // Get a unique wallet ID for this wallet first - let wallet_id = self.get_wallet_id(); - - // Derive the account using the passphrase - let derivation_path = account_type.derivation_path(self.network)?; - - // Generate seed with passphrase - let seed = mnemonic.to_seed(passphrase); - let root_key = super::root_extended_keys::RootExtendedPrivKey::new_master(&seed)?; - let master_key = root_key.to_extended_priv_key(self.network); - let secp = Secp256k1::new(); - let account_xpriv = - master_key.derive_priv(&secp, &derivation_path).map_err(Error::Bip32)?; - - // Create Ed25519 seed from derived private key - let ed25519_seed = account_xpriv.private_key.secret_bytes(); - let eddsa_account = EdDSAAccount::from_seed(Some(wallet_id.to_vec()), account_type, ed25519_seed, self.network)?; - - // Check if account already exists - if self.accounts.contains_account_type(&account_type) { - return Err(Error::InvalidParameter(format!( - "Account type {:?} already exists for network {:?}", - account_type, self.network - ))); - } - - // Insert into the collection - self.accounts.insert_eddsa_account(eddsa_account) - .map_err(|e| Error::InvalidParameter(e.to_string())) - } - _ => Err(Error::InvalidParameter( - "add_eddsa_account_with_passphrase can only be used with wallets created with a passphrase".to_string() - )), - } - } - /// Get the wallet ID for this wallet fn get_wallet_id(&self) -> [u8; 32] { self.wallet_id diff --git a/key-wallet/src/wallet/helper.rs b/key-wallet/src/wallet/helper.rs index a67e58185..ff38fce23 100644 --- a/key-wallet/src/wallet/helper.rs +++ b/key-wallet/src/wallet/helper.rs @@ -78,10 +78,7 @@ impl Wallet { /// Check if wallet has a mnemonic pub fn has_mnemonic(&self) -> bool { - matches!( - self.wallet_type, - WalletType::Mnemonic { .. } | WalletType::MnemonicWithPassphrase { .. } - ) + matches!(self.wallet_type, WalletType::Mnemonic { .. }) } /// Check if wallet is watch-only @@ -99,11 +96,6 @@ impl Wallet { !matches!(self.wallet_type, WalletType::WatchOnly) } - /// Check if wallet needs a passphrase for signing - pub fn needs_passphrase(&self) -> bool { - matches!(self.wallet_type, WalletType::MnemonicWithPassphrase { .. }) - } - /// Check if wallet has a seed pub fn has_seed(&self) -> bool { matches!(self.wallet_type, WalletType::Seed { .. } | WalletType::Mnemonic { .. }) @@ -114,11 +106,6 @@ impl Wallet { &mut self, options: WalletAccountCreationOptions, ) -> Result<()> { - if matches!(self.wallet_type, WalletType::MnemonicWithPassphrase { .. }) { - return Err(Error::InvalidParameter( - "create_accounts_from_options can not be used on wallets with a mnemonic and a passphrase".to_string() - )); - } match options { WalletAccountCreationOptions::Default => { // Create default BIP32 account 0 @@ -314,212 +301,6 @@ impl Wallet { Ok(()) } - /// Create accounts based on the provided creation options with passphrase - pub fn create_accounts_with_passphrase_from_options( - &mut self, - options: WalletAccountCreationOptions, - passphrase: &str, - ) -> Result<()> { - if !matches!(self.wallet_type, WalletType::MnemonicWithPassphrase { .. }) { - return Err(Error::InvalidParameter( - "create_accounts_with_passphrase_from_options can only be used with wallets created with a passphrase".to_string() - )); - } - match options { - WalletAccountCreationOptions::Default => { - // Create default BIP32 account 0 - self.add_account_with_passphrase( - AccountType::Standard { - index: 0, - standard_account_type: StandardAccountType::BIP32Account, - }, - passphrase, - )?; - - // Create default BIP44 account 0 - self.add_account_with_passphrase( - AccountType::Standard { - index: 0, - standard_account_type: StandardAccountType::BIP44Account, - }, - passphrase, - )?; - - // Create default CoinJoin account 0 - self.add_account_with_passphrase( - AccountType::CoinJoin { - index: 0, - }, - passphrase, - )?; - - // Create all special purpose accounts - self.create_special_purpose_accounts_with_passphrase(passphrase)?; - - // Create default PlatformPayment account (account=0, key_class=0) - self.add_account_with_passphrase( - AccountType::PlatformPayment { - account: 0, - key_class: 0, - }, - passphrase, - )?; - } - - WalletAccountCreationOptions::AllAccounts( - bip44_indices, - bip32_indices, - coinjoin_indices, - top_up_accounts, - platform_payment_specs, - ) => { - // Create specified BIP44 accounts - for index in bip44_indices { - self.add_account_with_passphrase( - AccountType::Standard { - index, - standard_account_type: StandardAccountType::BIP44Account, - }, - passphrase, - )?; - } - - // Create specified BIP32 accounts - for index in bip32_indices { - self.add_account_with_passphrase( - AccountType::Standard { - index, - standard_account_type: StandardAccountType::BIP32Account, - }, - passphrase, - )?; - } - - // Create specified CoinJoin accounts - for index in coinjoin_indices { - self.add_account_with_passphrase( - AccountType::CoinJoin { - index, - }, - passphrase, - )?; - } - - // Create specified IdentityTopUp accounts - for registration_index in top_up_accounts { - self.add_account_with_passphrase( - AccountType::IdentityTopUp { - registration_index, - }, - passphrase, - )?; - } - - // Create specified PlatformPayment accounts - for spec in platform_payment_specs { - self.add_account_with_passphrase( - AccountType::PlatformPayment { - account: spec.account, - key_class: spec.key_class, - }, - passphrase, - )?; - } - - // Create all special purpose accounts - self.create_special_purpose_accounts_with_passphrase(passphrase)?; - } - - WalletAccountCreationOptions::BIP44AccountsOnly(bip44_indices) => { - // Create BIP44 account 0 if not exists - for index in bip44_indices { - self.add_account_with_passphrase( - AccountType::Standard { - index, - standard_account_type: StandardAccountType::BIP44Account, - }, - passphrase, - )?; - } - } - - WalletAccountCreationOptions::SpecificAccounts( - bip44_indices, - bip32_indices, - coinjoin_indices, - topup_indices, - platform_payment_specs, - special_accounts, - ) => { - // Create specified BIP44 accounts - for index in bip44_indices { - self.add_account_with_passphrase( - AccountType::Standard { - index, - standard_account_type: StandardAccountType::BIP44Account, - }, - passphrase, - )?; - } - - // Create specified BIP32 accounts - for index in bip32_indices { - self.add_account_with_passphrase( - AccountType::Standard { - index, - standard_account_type: StandardAccountType::BIP32Account, - }, - passphrase, - )?; - } - - // Create specified CoinJoin accounts - for index in coinjoin_indices { - self.add_account_with_passphrase( - AccountType::CoinJoin { - index, - }, - passphrase, - )?; - } - - // Create identity top-up accounts - for registration_index in topup_indices { - self.add_account_with_passphrase( - AccountType::IdentityTopUp { - registration_index, - }, - passphrase, - )?; - } - - // Create specified PlatformPayment accounts - for spec in platform_payment_specs { - self.add_account_with_passphrase( - AccountType::PlatformPayment { - account: spec.account, - key_class: spec.key_class, - }, - passphrase, - )?; - } - - // Create any additional special accounts if provided - if let Some(special_types) = special_accounts { - for account_type in special_types { - self.add_account_with_passphrase(account_type, passphrase)?; - } - } - } - - WalletAccountCreationOptions::None => { - // Don't create any accounts - useful for tests - } - } - - Ok(()) - } - /// Create all special purpose accounts fn create_special_purpose_accounts(&mut self) -> Result<()> { // Identity registration account @@ -548,70 +329,27 @@ impl Wallet { Ok(()) } - /// Create all special purpose accounts - fn create_special_purpose_accounts_with_passphrase(&mut self, passphrase: &str) -> Result<()> { - // Identity registration account - self.add_account_with_passphrase(AccountType::IdentityRegistration, passphrase)?; - - // Identity invitation account - self.add_account_with_passphrase(AccountType::IdentityInvitation, passphrase)?; - - // Identity top-up not bound to identity - self.add_account_with_passphrase(AccountType::IdentityTopUpNotBoundToIdentity, passphrase)?; - - // Asset lock address top-up - self.add_account_with_passphrase(AccountType::AssetLockAddressTopUp, passphrase)?; - - // Asset lock shielded address top-up - self.add_account_with_passphrase(AccountType::AssetLockShieldedAddressTopUp, passphrase)?; - - // Provider keys accounts - self.add_account_with_passphrase(AccountType::ProviderVotingKeys, passphrase)?; - self.add_account_with_passphrase(AccountType::ProviderOwnerKeys, passphrase)?; - #[cfg(feature = "bls")] - self.add_bls_account_with_passphrase(AccountType::ProviderOperatorKeys, passphrase)?; - #[cfg(feature = "eddsa")] - self.add_eddsa_account_with_passphrase(AccountType::ProviderPlatformKeys, passphrase)?; - - Ok(()) - } - /// Derive an extended private key at a specific derivation path /// /// This will return the extended private key for the given derivation path. /// Only works for wallets that have access to the private keys (not watch-only). - /// For MnemonicWithPassphrase wallets, you must provide the passphrase. /// /// # Arguments /// * `path` - The derivation path (e.g., "m/44'/5'/0'/0/0") - /// * `passphrase` - Optional passphrase for MnemonicWithPassphrase wallets /// /// # Returns /// The extended private key, or an error if the wallet is watch-only or path is invalid - pub fn derive_extended_private_key_with_passphrase( + pub fn derive_extended_private_key( &self, path: &crate::DerivationPath, - passphrase: Option<&str>, ) -> Result { - use crate::bip32::ExtendedPrivKey; use secp256k1::Secp256k1; - // Get the master private key based on wallet type let master = match &self.wallet_type { WalletType::Mnemonic { root_extended_private_key, .. } => root_extended_private_key.to_extended_priv_key(self.network), - WalletType::MnemonicWithPassphrase { - mnemonic, - .. - } => { - let pass = passphrase.ok_or(Error::InvalidParameter( - "Passphrase required for this wallet type".to_string(), - ))?; - let seed = mnemonic.to_seed(pass); - ExtendedPrivKey::new_master(self.network, &seed)? - } WalletType::Seed { root_extended_private_key, .. @@ -624,34 +362,14 @@ impl Wallet { } }; - // Derive the private key at the specified path let secp = Secp256k1::new(); master.derive_priv(&secp, path).map_err(|e| e.into()) } - /// Derive an extended private key at a specific derivation path - /// - /// This will return the extended private key for the given derivation path. - /// Only works for wallets that have access to the private keys (not watch-only). - /// For MnemonicWithPassphrase wallets, this will fail. - /// - /// # Arguments - /// * `path` - The derivation path (e.g., "m/44'/5'/0'/0/0") - /// - /// # Returns - /// The extended private key, or an error if the wallet is watch-only or path is invalid - pub fn derive_extended_private_key( - &self, - path: &crate::DerivationPath, - ) -> Result { - self.derive_extended_private_key_with_passphrase(path, None) - } - /// Derive a private key at a specific derivation path /// /// This will return the private key (SecretKey) for the given derivation path. /// Only works for wallets that have access to the private keys (not watch-only). - /// For MnemonicWithPassphrase wallets, this will fail. /// /// # Arguments /// * `path` - The derivation path (e.g., "m/44'/5'/0'/0/0") @@ -667,7 +385,6 @@ impl Wallet { /// /// This will return the private key in WIF format for the given derivation path. /// Only works for wallets that have access to the private keys (not watch-only). - /// For MnemonicWithPassphrase wallets, this will fail. /// /// # Arguments /// * `path` - The derivation path (e.g., "m/44'/5'/0'/0/0") @@ -691,9 +408,6 @@ impl Wallet { /// /// # Behavior by wallet type /// * `Mnemonic`, `Seed`, `ExtendedPrivKey`: works for both hardened and non-hardened paths. - /// * `MnemonicWithPassphrase`: works for non-hardened paths only (hardened paths require - /// the passphrase to reconstruct the root private key; use - /// [`Wallet::derive_extended_private_key_with_passphrase`] for those). /// * `WatchOnly` / `ExternalSignable`: **cannot derive from the root at all** — these /// unit variants carry no root key material. Hardened paths fail because there's no /// private key on hand, and non-hardened paths fail because there's no root xpub diff --git a/key-wallet/src/wallet/initialization.rs b/key-wallet/src/wallet/initialization.rs index a46cdc95c..c0fd7cd6e 100644 --- a/key-wallet/src/wallet/initialization.rs +++ b/key-wallet/src/wallet/initialization.rs @@ -145,10 +145,6 @@ impl Wallet { | WalletType::ExtendedPrivKey(root_extended_private_key) => { root_extended_private_key.to_root_extended_pub_key() } - WalletType::MnemonicWithPassphrase { - root_extended_public_key, - .. - } => root_extended_public_key.clone(), WalletType::ExternalSignable | WalletType::WatchOnly => { panic!( "Wallet::from_wallet_type cannot be used with WalletType::WatchOnly or \ @@ -241,41 +237,6 @@ impl Wallet { Ok(wallet) } - /// Create a wallet from a mnemonic phrase with passphrase - /// The passphrase is used only to derive the master public key, then discarded - /// - /// # Arguments - /// * `mnemonic` - The mnemonic phrase - /// * `passphrase` - The BIP39 passphrase - /// * `network` - Network to create accounts for - /// * `account_creation_options` - Specifies which accounts to create during initialization - pub fn from_mnemonic_with_passphrase( - mnemonic: Mnemonic, - passphrase: String, - network: Network, - account_creation_options: WalletAccountCreationOptions, - ) -> Result { - let seed = mnemonic.to_seed(&passphrase); - let root_extended_private_key = RootExtendedPrivKey::new_master(&seed)?; - let root_extended_public_key = root_extended_private_key.to_root_extended_pub_key(); - - // Store only mnemonic and public key, not the passphrase or private key - let mut wallet = Self::from_wallet_type( - network, - WalletType::MnemonicWithPassphrase { - mnemonic, - root_extended_public_key, - }, - ); - - wallet.create_accounts_with_passphrase_from_options( - account_creation_options.clone(), - passphrase.as_str(), - )?; - - Ok(wallet) - } - /// Create a watch-only or externally signable wallet from an extended public key. /// /// This is a thin adapter that hashes `master_xpub` into a stable wallet id diff --git a/key-wallet/src/wallet/managed_wallet_info/managed_account_operations.rs b/key-wallet/src/wallet/managed_wallet_info/managed_account_operations.rs index b59ca1e47..41a4ccf6f 100644 --- a/key-wallet/src/wallet/managed_wallet_info/managed_account_operations.rs +++ b/key-wallet/src/wallet/managed_wallet_info/managed_account_operations.rs @@ -21,25 +21,6 @@ pub trait ManagedAccountOperations { /// Ok(()) if the managed account was successfully added fn add_managed_account(&mut self, wallet: &Wallet, account_type: AccountType) -> Result<()>; - /// Add a new managed account with passphrase verification - /// - /// This function verifies the passphrase and creates a ManagedAccount. - /// It only works with wallets created with a passphrase. - /// - /// # Arguments - /// * `wallet` - The wallet containing the account (must be MnemonicWithPassphrase type) - /// * `account_type` - The type of account to manage - /// * `passphrase` - The passphrase to verify - /// - /// # Returns - /// Ok(()) if the managed account was successfully added - fn add_managed_account_with_passphrase( - &mut self, - wallet: &Wallet, - account_type: AccountType, - passphrase: &str, - ) -> Result<()>; - /// Create and add a managed account directly with extended public key /// /// This allows creating a managed account without requiring it to exist in the wallet first. @@ -71,26 +52,6 @@ pub trait ManagedAccountOperations { fn add_managed_bls_account(&mut self, wallet: &Wallet, account_type: AccountType) -> Result<()>; - /// Add a new managed BLS account with passphrase verification - /// - /// This function verifies the passphrase and creates a managed BLS account. - /// It only works with wallets created with a passphrase. - /// - /// # Arguments - /// * `wallet` - The wallet containing the BLS account (must be MnemonicWithPassphrase type) - /// * `account_type` - The type of account (must be ProviderOperatorKeys) - /// * `passphrase` - The passphrase to verify - /// - /// # Returns - /// Ok(()) if the managed BLS account was successfully added - #[cfg(feature = "bls")] - fn add_managed_bls_account_with_passphrase( - &mut self, - wallet: &Wallet, - account_type: AccountType, - passphrase: &str, - ) -> Result<()>; - /// Create and add a managed BLS account directly with BLS public key /// /// This allows creating a managed BLS account without requiring it to exist in the wallet first. @@ -125,26 +86,6 @@ pub trait ManagedAccountOperations { account_type: AccountType, ) -> Result<()>; - /// Add a new managed EdDSA account with passphrase verification - /// - /// This function verifies the passphrase and creates a managed EdDSA account. - /// It only works with wallets created with a passphrase. - /// - /// # Arguments - /// * `wallet` - The wallet containing the EdDSA account (must be MnemonicWithPassphrase type) - /// * `account_type` - The type of account (must be ProviderPlatformKeys) - /// * `passphrase` - The passphrase to verify - /// - /// # Returns - /// Ok(()) if the managed EdDSA account was successfully added - #[cfg(feature = "eddsa")] - fn add_managed_eddsa_account_with_passphrase( - &mut self, - wallet: &Wallet, - account_type: AccountType, - passphrase: &str, - ) -> Result<()>; - /// Create and add a managed EdDSA account directly with Ed25519 public key /// /// This allows creating a managed EdDSA account without requiring it to exist in the wallet first. diff --git a/key-wallet/src/wallet/managed_wallet_info/managed_accounts.rs b/key-wallet/src/wallet/managed_wallet_info/managed_accounts.rs index c4b097ef7..40610e6d2 100644 --- a/key-wallet/src/wallet/managed_wallet_info/managed_accounts.rs +++ b/key-wallet/src/wallet/managed_wallet_info/managed_accounts.rs @@ -10,9 +10,10 @@ use crate::account::EdDSAAccount; use crate::account::{Account, AccountType, ManagedCoreFundsAccount}; use crate::bip32::ExtendedPubKey; use crate::error::{Error, Result}; +#[cfg(any(feature = "bls", feature = "eddsa"))] use crate::managed_account::managed_account_trait::ManagedAccountTrait; use crate::managed_account::{ManagedCoreKeysAccount, OwnedManagedCoreAccount}; -use crate::wallet::{Wallet, WalletType}; +use crate::wallet::Wallet; /// Wrap an [`Account`] as the right [`OwnedManagedCoreAccount`] variant for /// its [`AccountType`] — funds-bearing for Standard / CoinJoin / DashPay, @@ -80,49 +81,6 @@ impl ManagedAccountOperations for ManagedWalletInfo { Ok(()) } - /// Add a new managed account with passphrase verification - /// - /// This function verifies the passphrase and creates a ManagedAccount. - /// It only works with wallets created with a passphrase. - /// - /// # Arguments - /// * `wallet` - The wallet containing the account (must be MnemonicWithPassphrase type) - /// * `account_type` - The type of account to manage - /// * `passphrase` - The passphrase to verify - /// - /// # Returns - /// Ok(()) if the managed account was successfully added - fn add_managed_account_with_passphrase( - &mut self, - wallet: &Wallet, - account_type: AccountType, - passphrase: &str, - ) -> Result<()> { - // Verify this is a passphrase wallet - match &wallet.wallet_type { - WalletType::MnemonicWithPassphrase { mnemonic, root_extended_public_key: wallet_pub } => { - // Verify the passphrase by deriving and comparing - let seed = mnemonic.to_seed(passphrase); - let root_key = crate::wallet::root_extended_keys::RootExtendedPrivKey::new_master(&seed)?; - - // Compare with wallet's stored public key - let derived_pub = root_key.to_root_extended_pub_key(); - - if derived_pub.root_public_key != wallet_pub.root_public_key { - return Err(Error::InvalidParameter( - "Invalid passphrase".to_string() - )); - } - - // Passphrase is valid, proceed with adding the managed account - self.add_managed_account(wallet, account_type) - } - _ => Err(Error::InvalidParameter( - "add_managed_account_with_passphrase can only be used with wallets created with a passphrase".to_string() - )), - } - } - fn add_managed_account_from_xpub( &mut self, account_type: AccountType, @@ -200,45 +158,6 @@ impl ManagedAccountOperations for ManagedWalletInfo { Ok(()) } - #[cfg(feature = "bls")] - fn add_managed_bls_account_with_passphrase( - &mut self, - wallet: &Wallet, - account_type: AccountType, - passphrase: &str, - ) -> Result<()> { - // Validate account type - if !matches!(account_type, AccountType::ProviderOperatorKeys) { - return Err(Error::InvalidParameter( - "BLS accounts can only be ProviderOperatorKeys".to_string(), - )); - } - - // Verify this is a passphrase wallet - match &wallet.wallet_type { - WalletType::MnemonicWithPassphrase { mnemonic, root_extended_public_key: wallet_pub } => { - // Verify the passphrase by deriving and comparing - let seed = mnemonic.to_seed(passphrase); - let root_key = crate::wallet::root_extended_keys::RootExtendedPrivKey::new_master(&seed)?; - - // Compare with wallet's stored public key - let derived_pub = root_key.to_root_extended_pub_key(); - - if derived_pub.root_public_key != wallet_pub.root_public_key { - return Err(Error::InvalidParameter( - "Invalid passphrase".to_string() - )); - } - - // Passphrase is valid, proceed with adding the managed BLS account - self.add_managed_bls_account(wallet, account_type) - } - _ => Err(Error::InvalidParameter( - "add_managed_bls_account_with_passphrase can only be used with wallets created with a passphrase".to_string() - )), - } - } - #[cfg(feature = "bls")] fn add_managed_bls_account_from_public_key( &mut self, @@ -318,45 +237,6 @@ impl ManagedAccountOperations for ManagedWalletInfo { Ok(()) } - #[cfg(feature = "eddsa")] - fn add_managed_eddsa_account_with_passphrase( - &mut self, - wallet: &Wallet, - account_type: AccountType, - passphrase: &str, - ) -> Result<()> { - // Validate account type - if !matches!(account_type, AccountType::ProviderPlatformKeys) { - return Err(Error::InvalidParameter( - "EdDSA accounts can only be ProviderPlatformKeys".to_string(), - )); - } - - // Verify this is a passphrase wallet - match &wallet.wallet_type { - WalletType::MnemonicWithPassphrase { mnemonic, root_extended_public_key: wallet_pub } => { - // Verify the passphrase by deriving and comparing - let seed = mnemonic.to_seed(passphrase); - let root_key = crate::wallet::root_extended_keys::RootExtendedPrivKey::new_master(&seed)?; - - // Compare with wallet's stored public key - let derived_pub = root_key.to_root_extended_pub_key(); - - if derived_pub.root_public_key != wallet_pub.root_public_key { - return Err(Error::InvalidParameter( - "Invalid passphrase".to_string() - )); - } - - // Passphrase is valid, proceed with adding the managed EdDSA account - self.add_managed_eddsa_account(wallet, account_type) - } - _ => Err(Error::InvalidParameter( - "add_managed_eddsa_account_with_passphrase can only be used with wallets created with a passphrase".to_string() - )), - } - } - #[cfg(feature = "eddsa")] fn add_managed_eddsa_account_from_public_key( &mut self, diff --git a/key-wallet/src/wallet/mod.rs b/key-wallet/src/wallet/mod.rs index 1b70a95ee..779e254a4 100644 --- a/key-wallet/src/wallet/mod.rs +++ b/key-wallet/src/wallet/mod.rs @@ -40,12 +40,6 @@ pub enum WalletType { mnemonic: Mnemonic, root_extended_private_key: RootExtendedPrivKey, }, - /// Mnemonic wallet with BIP39 passphrase (passphrase requested via callback when needed) - MnemonicWithPassphrase { - mnemonic: Mnemonic, - /// Extended public key derived with the passphrase (for address generation) - root_extended_public_key: RootExtendedPubKey, - }, /// Wallet from seed bytes Seed { seed: Seed, @@ -173,15 +167,6 @@ impl Zeroize for Wallet { root_extended_private_key.zeroize(); // Note: root_extended_private_key.root_private_key (SecretKey) doesn't implement Zeroize } - WalletType::MnemonicWithPassphrase { - mnemonic, - root_extended_public_key, - } => { - // Zeroize the mnemonic - mnemonic.zeroize(); - // Zeroize the public key structure (best effort) - root_extended_public_key.zeroize(); - } WalletType::Seed { seed, root_extended_private_key, @@ -206,9 +191,6 @@ impl Zeroize for Wallet { } } -#[cfg(test)] -mod passphrase_test; - #[cfg(test)] mod tests { use super::*; @@ -480,39 +462,6 @@ mod tests { assert_eq!(watch_only_account.extended_public_key(), account_xpub); } - // ✓ Test wallet with passphrase (from BIP39 tests) - #[test] - fn test_wallet_with_passphrase() { - let mnemonic = Mnemonic::from_phrase( - "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - Language::English, - ).unwrap(); - - let network = Network::Testnet; - - // Create wallet without passphrase - use regular from_mnemonic for empty passphrase - let wallet1 = Wallet::from_mnemonic( - mnemonic.clone(), - network, - initialization::WalletAccountCreationOptions::Default, - ) - .unwrap(); - - // Create wallet with passphrase "TREZOR" - let wallet2 = Wallet::from_mnemonic_with_passphrase( - mnemonic, - "TREZOR".to_string(), - network, - initialization::WalletAccountCreationOptions::None, - ) - .unwrap(); - - // Different passphrases should generate different root keys - let root_xpub1 = wallet1.root_extended_pub_key().unwrap(); - let root_xpub2 = wallet2.root_extended_pub_key().unwrap(); - assert_ne!(root_xpub1.root_public_key, root_xpub2.root_public_key); - } - // ✓ Test account retrieval and management #[test] fn test_account_management() { diff --git a/key-wallet/src/wallet/passphrase_test.rs b/key-wallet/src/wallet/passphrase_test.rs deleted file mode 100644 index c40348014..000000000 --- a/key-wallet/src/wallet/passphrase_test.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! Tests for wallet creation with passphrase -//! These tests demonstrate current issues with passphrase handling - -#[cfg(test)] -mod tests { - use crate::account::StandardAccountType; - use crate::mnemonic::{Language, Mnemonic}; - use crate::wallet::initialization::WalletAccountCreationOptions; - use crate::{AccountType, Network, Wallet}; - - #[test] - fn test_wallet_from_mnemonic_with_passphrase_account_creation() { - // This test demonstrates the issue with creating accounts for wallets with passphrases - - let mnemonic_str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; - let mnemonic = Mnemonic::from_phrase(mnemonic_str, Language::English).unwrap(); - let passphrase = "my_secure_passphrase"; - let network = Network::Testnet; - - // Create a wallet with passphrase - let wallet = Wallet::from_mnemonic_with_passphrase( - mnemonic.clone(), - passphrase.to_string(), - network, - WalletAccountCreationOptions::None, - ) - .expect("Should create wallet with passphrase"); - - // Verify wallet was created - // We can't easily check the wallet type from outside, but we know it's created - - // Try to get account 0 - should not exist yet - assert!(wallet.get_bip44_account(0).is_none()); - - // Try to add account 0 without providing passphrase - // THIS WILL FAIL because the wallet needs the passphrase to derive accounts - let mut wallet_mut = wallet.clone(); - let account_type = AccountType::Standard { - index: 0, - standard_account_type: StandardAccountType::BIP44Account, - }; - - // This should fail with an error about needing the passphrase - let result = wallet_mut.add_account(account_type, None); - - // EXPECTED: This will fail because we can't derive the account without the passphrase - assert!(result.is_err()); - - if let Err(e) = result { - println!("Expected error when adding account without passphrase: {}", e); - // The error should mention needing a passphrase - assert!( - e.to_string().contains("passphrase") - || e.to_string().contains("Mnemonic with passphrase") - ); - } - } - - #[test] - fn test_wallet_with_passphrase_cannot_derive_keys() { - // This test shows that wallets with passphrases can't derive private keys - // without the passphrase being provided - - let mnemonic_str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; - let mnemonic = Mnemonic::from_phrase(mnemonic_str, Language::English).unwrap(); - let passphrase = "test_passphrase_123"; - let network = Network::Testnet; - - // Create wallet with passphrase - let wallet = Wallet::from_mnemonic_with_passphrase( - mnemonic, - passphrase.to_string(), - network, - WalletAccountCreationOptions::None, - ) - .expect("Should create wallet"); - - // Try to get the root extended private key - // THIS WILL FAIL because passphrase is needed - let root_key_result = wallet.root_extended_priv_key(); - - assert!(root_key_result.is_err()); - - if let Err(e) = root_key_result { - println!("Expected error when getting root key without passphrase: {}", e); - // Should indicate that passphrase is required - assert!( - e.to_string().contains("passphrase") - || e.to_string().contains("Mnemonic with passphrase") - ); - } - } - - #[test] - fn test_add_account_with_passphrase() { - // This test demonstrates the new add_account_with_passphrase function - - let mnemonic_str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; - let mnemonic = Mnemonic::from_phrase(mnemonic_str, Language::English).unwrap(); - let passphrase = "my_passphrase"; - let network = Network::Testnet; - - // Create wallet with passphrase - let mut wallet = Wallet::from_mnemonic_with_passphrase( - mnemonic, - passphrase.to_string(), - network, - WalletAccountCreationOptions::None, - ) - .expect("Should create wallet"); - - // Verify no accounts exist initially - assert!(wallet.get_bip44_account(0).is_none()); - - // Add account using the new function with the correct passphrase - let account_type = AccountType::Standard { - index: 0, - standard_account_type: StandardAccountType::BIP44Account, - }; - - let result = wallet.add_account_with_passphrase(account_type, passphrase); - assert!(result.is_ok(), "Should successfully add account with correct passphrase"); - - // Verify account was added - assert!(wallet.get_bip44_account(0).is_some()); - - // Try to add the same account again - should fail - let duplicate_result = wallet.add_account_with_passphrase(account_type, passphrase); - assert!(duplicate_result.is_err()); - assert!(duplicate_result.unwrap_err().to_string().contains("already exists")); - - // Add a second account - let account_type_2 = AccountType::Standard { - index: 1, - standard_account_type: StandardAccountType::BIP44Account, - }; - let result2 = wallet.add_account_with_passphrase(account_type_2, passphrase); - assert!(result2.is_ok()); - assert!(wallet.get_bip44_account(1).is_some()); - } - - #[test] - fn test_add_account_with_passphrase_wrong_wallet_type() { - // Test that add_account_with_passphrase fails on non-passphrase wallets - - let mnemonic_str = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; - let mnemonic = Mnemonic::from_phrase(mnemonic_str, Language::English).unwrap(); - let network = Network::Testnet; - - // Create regular wallet WITHOUT passphrase - let mut wallet = - Wallet::from_mnemonic(mnemonic, network, WalletAccountCreationOptions::Default) - .expect("Should create wallet"); - - // Try to use add_account_with_passphrase - should fail - let account_type = AccountType::Standard { - index: 10, - standard_account_type: StandardAccountType::BIP44Account, - }; - - let result = wallet.add_account_with_passphrase(account_type, "some_passphrase"); - assert!(result.is_err()); - assert!(result - .unwrap_err() - .to_string() - .contains("can only be used with wallets created with a passphrase")); - } -} diff --git a/key-wallet/src/wallet/root_extended_keys.rs b/key-wallet/src/wallet/root_extended_keys.rs index 4ef0a8f20..a08fab2ce 100644 --- a/key-wallet/src/wallet/root_extended_keys.rs +++ b/key-wallet/src/wallet/root_extended_keys.rs @@ -364,10 +364,6 @@ impl Wallet { root_extended_private_key, .. } => Ok(root_extended_private_key.to_root_extended_pub_key()), - WalletType::MnemonicWithPassphrase { - root_extended_public_key, - .. - } => Ok(root_extended_public_key.clone()), WalletType::Seed { root_extended_private_key, .. @@ -391,10 +387,6 @@ impl Wallet { root_extended_private_key, .. } => Ok(Cow::Owned(root_extended_private_key.to_root_extended_pub_key())), - WalletType::MnemonicWithPassphrase { - root_extended_public_key, - .. - } => Ok(Cow::Borrowed(root_extended_public_key)), WalletType::Seed { root_extended_private_key, .. @@ -418,11 +410,6 @@ impl Wallet { root_extended_private_key, .. } => Ok(root_extended_private_key), - WalletType::MnemonicWithPassphrase { - .. - } => Err(Error::InvalidParameter( - "Mnemonic with passphrase requires passphrase to derive private key".into(), - )), WalletType::Seed { root_extended_private_key, .. @@ -436,40 +423,4 @@ impl Wallet { } } } - - /// Get the root extended private key with passphrase callback for MnemonicWithPassphrase - pub fn root_extended_priv_key_with_callback( - &self, - passphrase_callback: F, - ) -> crate::Result - where - F: FnOnce() -> Result, - { - match &self.wallet_type { - WalletType::Mnemonic { - root_extended_private_key, - .. - } => Ok(root_extended_private_key.clone()), - WalletType::MnemonicWithPassphrase { - mnemonic, - .. - } => { - // Request passphrase via callback - let passphrase = passphrase_callback()?; - let seed = mnemonic.to_seed(&passphrase); - Ok(RootExtendedPrivKey::new_master(&seed)?) - } - WalletType::Seed { - root_extended_private_key, - .. - } => Ok(root_extended_private_key.clone()), - WalletType::ExtendedPrivKey(key) => Ok(key.clone()), - WalletType::ExternalSignable => { - Err(Error::InvalidParameter("External signable wallet has no private key".into())) - } - WalletType::WatchOnly => { - Err(Error::InvalidParameter("Watch-only wallet has no private key".into())) - } - } - } } diff --git a/key-wallet/src/wallet_comprehensive_tests.rs b/key-wallet/src/wallet_comprehensive_tests.rs index 93fd65d29..80bc14a6a 100644 --- a/key-wallet/src/wallet_comprehensive_tests.rs +++ b/key-wallet/src/wallet_comprehensive_tests.rs @@ -146,34 +146,6 @@ mod tests { assert_eq!(wallet.wallet_id, watch_only.wallet_id); } - #[test] - fn test_wallet_with_passphrase() { - let mnemonic = Mnemonic::from_phrase(TEST_MNEMONIC, Language::English).unwrap(); - - // Create wallet without passphrase - use regular from_mnemonic for empty passphrase - let wallet1 = Wallet::from_mnemonic( - mnemonic.clone(), - Network::Testnet, - crate::wallet::initialization::WalletAccountCreationOptions::Default, - ) - .unwrap(); - - // Create wallet with passphrase - let wallet2 = Wallet::from_mnemonic_with_passphrase( - mnemonic, - "TREZOR".to_string(), - Network::Testnet, - crate::wallet::initialization::WalletAccountCreationOptions::None, - ) - .unwrap(); - - // Different passphrases should generate different root keys - let root_xpub1 = wallet1.root_extended_pub_key().unwrap(); - let root_xpub2 = wallet2.root_extended_pub_key().unwrap(); - - assert_ne!(root_xpub1.root_public_key, root_xpub2.root_public_key); - } - // ============================================================================ // TODO: Advanced tests need to be reimplemented with ManagedAccount // ============================================================================ From 790def6b24bc643f4643e9e60d05655b96fb66e9 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Sat, 9 May 2026 01:49:04 +0700 Subject: [PATCH 2/3] docs(key-wallet-ffi): regenerate FFI_API.md after passphrase removal Auto-generated docs were stale after removing the `passphrase` parameter from `wallet_create_from_mnemonic*` and `wallet_manager_add_wallet_from_mnemonic*`. Co-Authored-By: Claude Opus 4.7 (1M context) --- key-wallet-ffi/FFI_API.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/key-wallet-ffi/FFI_API.md b/key-wallet-ffi/FFI_API.md index 9fd0cd37e..9b9885165 100644 --- a/key-wallet-ffi/FFI_API.md +++ b/key-wallet-ffi/FFI_API.md @@ -449,14 +449,14 @@ Free a managed platform account result's error message (if any) Note: This does #### `wallet_manager_add_wallet_from_mnemonic` ```c -wallet_manager_add_wallet_from_mnemonic(manager: *mut FFIWalletManager, mnemonic: *const c_char, passphrase: *const c_char, error: *mut FFIError,) -> bool +wallet_manager_add_wallet_from_mnemonic(manager: *mut FFIWalletManager, mnemonic: *const c_char, error: *mut FFIError,) -> bool ``` **Description:** -Add a wallet from mnemonic to the manager (backward compatibility) # Safety - `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call +Add a wallet from mnemonic to the manager (backward compatibility) # Safety - `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call **Safety:** -- `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call +- `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call **Module:** `wallet_manager` @@ -465,7 +465,7 @@ Add a wallet from mnemonic to the manager (backward compatibility) # Safety - #### `wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes` ```c -wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes(manager: *mut FFIWalletManager, mnemonic: *const c_char, passphrase: *const c_char, birth_height: c_uint, account_options: *const crate::types::FFIWalletAccountCreationOptions, downgrade_to_pubkey_wallet: bool, allow_external_signing: bool, wallet_bytes_out: *mut *mut u8, wallet_bytes_len_out: *mut usize, wallet_id_out: *mut u8, error: *mut FFIError,) -> bool +wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes(manager: *mut FFIWalletManager, mnemonic: *const c_char, birth_height: c_uint, account_options: *const crate::types::FFIWalletAccountCreationOptions, downgrade_to_pubkey_wallet: bool, allow_external_signing: bool, wallet_bytes_out: *mut *mut u8, wallet_bytes_len_out: *mut usize, wallet_id_out: *mut u8, error: *mut FFIError,) -> bool ``` **Module:** `wallet_manager` @@ -475,14 +475,14 @@ wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes(manager: *mut FF #### `wallet_manager_add_wallet_from_mnemonic_with_options` ```c -wallet_manager_add_wallet_from_mnemonic_with_options(manager: *mut FFIWalletManager, mnemonic: *const c_char, passphrase: *const c_char, account_options: *const crate::types::FFIWalletAccountCreationOptions, error: *mut FFIError,) -> bool +wallet_manager_add_wallet_from_mnemonic_with_options(manager: *mut FFIWalletManager, mnemonic: *const c_char, account_options: *const crate::types::FFIWalletAccountCreationOptions, error: *mut FFIError,) -> bool ``` **Description:** -Add a wallet from mnemonic to the manager with options # Safety - `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call +Add a wallet from mnemonic to the manager with options # Safety - `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call **Safety:** -- `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call +- `manager` must be a valid pointer to an FFIWalletManager instance - `mnemonic` must be a valid pointer to a null-terminated C string - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call **Module:** `wallet_manager` @@ -1333,14 +1333,14 @@ Check if a transaction belongs to the wallet using ManagedWalletInfo # Safety #### `wallet_create_from_mnemonic` ```c -wallet_create_from_mnemonic(mnemonic: *const c_char, passphrase: *const c_char, network: FFINetwork, error: *mut FFIError,) -> *mut FFIWallet +wallet_create_from_mnemonic(mnemonic: *const c_char, network: FFINetwork, error: *mut FFIError,) -> *mut FFIWallet ``` **Description:** -Create a new wallet from mnemonic (backward compatibility - single network) # Safety - `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed +Create a new wallet from mnemonic (backward compatibility - single network) # Safety - `mnemonic` must be a valid pointer to a null-terminated C string - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed **Safety:** -- `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed +- `mnemonic` must be a valid pointer to a null-terminated C string - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed **Module:** `wallet` @@ -1349,14 +1349,14 @@ Create a new wallet from mnemonic (backward compatibility - single network) # S #### `wallet_create_from_mnemonic_with_options` ```c -wallet_create_from_mnemonic_with_options(mnemonic: *const c_char, passphrase: *const c_char, network: FFINetwork, account_options: *const FFIWalletAccountCreationOptions, error: *mut FFIError,) -> *mut FFIWallet +wallet_create_from_mnemonic_with_options(mnemonic: *const c_char, network: FFINetwork, account_options: *const FFIWalletAccountCreationOptions, error: *mut FFIError,) -> *mut FFIWallet ``` **Description:** -Create a new wallet from mnemonic with options # Safety - `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed +Create a new wallet from mnemonic with options # Safety - `mnemonic` must be a valid pointer to a null-terminated C string - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed **Safety:** -- `mnemonic` must be a valid pointer to a null-terminated C string - `passphrase` must be a valid pointer to a null-terminated C string or null - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed +- `mnemonic` must be a valid pointer to a null-terminated C string - `account_options` must be a valid pointer to FFIWalletAccountCreationOptions or null - `error` must be a valid pointer to an FFIError structure - The caller must ensure all pointers remain valid for the duration of this call - The returned pointer must be freed with `wallet_free` when no longer needed **Module:** `wallet` From aab0e0b5ccda07abdf0a043bac1cc7dba32f2e65 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Sat, 9 May 2026 01:51:10 +0700 Subject: [PATCH 3/3] refactor: address review comments after passphrase removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Distinguish ExternalSignable from WatchOnly in derive_extended_private_key error path so callers see why each variant rejects the request. - Drop the stale "passphrase 'pass1'" debug prints in debug_wallet_add.rs that no longer reflect what the test does. - Remove the obsolete bug-comment and "// No passphrase" annotation in wallet_manager_tests.rs — the bug and the parameter both no longer exist. Co-Authored-By: Claude Opus 4.7 (1M context) --- key-wallet-ffi/src/wallet_manager_tests.rs | 6 ++---- key-wallet-ffi/tests/debug_wallet_add.rs | 4 ++-- key-wallet/src/wallet/helper.rs | 7 ++++++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/key-wallet-ffi/src/wallet_manager_tests.rs b/key-wallet-ffi/src/wallet_manager_tests.rs index 0719e7871..76abf7e48 100644 --- a/key-wallet-ffi/src/wallet_manager_tests.rs +++ b/key-wallet-ffi/src/wallet_manager_tests.rs @@ -78,9 +78,7 @@ mod tests { let manager = unsafe { wallet_manager::wallet_manager_create(FFINetwork::Testnet, error) }; assert!(!manager.is_null()); - // Add multiple wallets - // Note: We use different mnemonics instead of different passphrases - // because the library has a bug with passphrase wallets (see line 140-146 in wallet_manager/mod.rs) + // Use distinct mnemonics so each wallet has a unique ID. let mnemonics = [TEST_MNEMONIC, TEST_MNEMONIC_2, TEST_MNEMONIC_3]; unsafe { for (i, mnemonic_str) in mnemonics.iter().enumerate() { @@ -88,7 +86,7 @@ mod tests { let success = wallet_manager::wallet_manager_add_wallet_from_mnemonic( manager, - mnemonic.as_ptr(), // No passphrase + mnemonic.as_ptr(), error, ); if !success { diff --git a/key-wallet-ffi/tests/debug_wallet_add.rs b/key-wallet-ffi/tests/debug_wallet_add.rs index 3f246860d..901d9523b 100644 --- a/key-wallet-ffi/tests/debug_wallet_add.rs +++ b/key-wallet-ffi/tests/debug_wallet_add.rs @@ -15,7 +15,7 @@ fn test_debug_wallet_add() { let mnemonic = CString::new("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about").unwrap(); - println!("Adding wallet with passphrase 'pass1'"); + println!("Adding wallet from mnemonic"); let success = unsafe { wallet_manager::wallet_manager_add_wallet_from_mnemonic(manager, mnemonic.as_ptr(), error) }; @@ -29,7 +29,7 @@ fn test_debug_wallet_add() { } } } else { - println!("Successfully added wallet with passphrase"); + println!("Successfully added wallet from mnemonic"); } assert!(success); diff --git a/key-wallet/src/wallet/helper.rs b/key-wallet/src/wallet/helper.rs index ff38fce23..c5a519ed4 100644 --- a/key-wallet/src/wallet/helper.rs +++ b/key-wallet/src/wallet/helper.rs @@ -355,7 +355,12 @@ impl Wallet { .. } => root_extended_private_key.to_extended_priv_key(self.network), WalletType::ExtendedPrivKey(root_priv) => root_priv.to_extended_priv_key(self.network), - WalletType::ExternalSignable | WalletType::WatchOnly => { + WalletType::ExternalSignable => { + return Err(Error::InvalidParameter( + "External signable wallet has no private key".to_string(), + )); + } + WalletType::WatchOnly => { return Err(Error::InvalidParameter( "Cannot derive private keys from watch-only wallet".to_string(), ));