diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 73f97c4d..de1025b3 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -341,7 +341,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { }; // Get the newly created account's keys - let (to_keys, _, _) = ctx + let (to_keys, _, to_identifier) = ctx .wallet() .storage() .user_data @@ -356,7 +356,7 @@ async fn private_transfer_to_owned_account_continuous_run_path() -> Result<()> { to_label: None, to_npk: Some(hex::encode(to_keys.nullifier_public_key.0)), to_vpk: Some(hex::encode(to_keys.viewing_public_key.0)), - to_identifier: 0, + to_identifier, amount: 100, }); diff --git a/integration_tests/tests/token.rs b/integration_tests/tests/token.rs index 5ee25a75..7f270820 100644 --- a/integration_tests/tests/token.rs +++ b/integration_tests/tests/token.rs @@ -1139,7 +1139,7 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { }; // Get keys for foreign mint (claiming path) - let (holder_keys, _, _) = ctx + let (holder_keys, _, holder_identifier) = ctx .wallet() .storage() .user_data @@ -1155,7 +1155,7 @@ async fn token_claiming_path_with_private_accounts() -> Result<()> { holder_label: None, holder_npk: Some(hex::encode(holder_keys.nullifier_public_key.0)), holder_vpk: Some(hex::encode(holder_keys.viewing_public_key.0)), - holder_identifier: 0, + holder_identifier, amount: mint_amount, }; diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 7fb61ca4..db84b066 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -48,6 +48,11 @@ unsafe extern "C" { out_account_id: *mut FfiBytes32, ) -> error::WalletFfiError; + fn wallet_ffi_create_account_private( + handle: *mut WalletHandle, + out_account_id: *mut FfiBytes32, + ) -> error::WalletFfiError; + fn wallet_ffi_create_private_accounts_key( handle: *mut WalletHandle, out_keys: *mut FfiPrivateAccountKeys, @@ -684,14 +689,11 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> { let home = tempfile::tempdir()?; let wallet_ffi_handle = new_wallet_ffi_with_test_context_config(&ctx, home.path())?; - // Create a new receiving key and derive account_id for identifier=0 - let out_account_id: FfiBytes32 = unsafe { - let mut out_keys = FfiPrivateAccountKeys::default(); - wallet_ffi_create_private_accounts_key(wallet_ffi_handle, &raw mut out_keys); - let account_id = nssa::AccountId::from((&out_keys.npk(), 0_u128)); - wallet_ffi_free_private_account_keys(&raw mut out_keys); - (&account_id).into() - }; + // Create a new private account + let mut out_account_id = FfiBytes32::default(); + unsafe { + wallet_ffi_create_account_private(wallet_ffi_handle, &raw mut out_account_id); + } // Call the init function let mut transfer_result = FfiTransferResult::default(); diff --git a/key_protocol/src/key_management/key_tree/mod.rs b/key_protocol/src/key_management/key_tree/mod.rs index 12b953ba..002d1746 100644 --- a/key_protocol/src/key_management/key_tree/mod.rs +++ b/key_protocol/src/key_management/key_tree/mod.rs @@ -533,25 +533,49 @@ mod tests { .key_map .get_mut(&ChainIndex::from_str("/1").unwrap()) .unwrap(); - acc.value.1.push((0, nssa::Account { balance: 2, ..nssa::Account::default() })); + acc.value.1.push(( + 0, + nssa::Account { + balance: 2, + ..nssa::Account::default() + }, + )); let acc = tree .key_map .get_mut(&ChainIndex::from_str("/2").unwrap()) .unwrap(); - acc.value.1.push((0, nssa::Account { balance: 3, ..nssa::Account::default() })); + acc.value.1.push(( + 0, + nssa::Account { + balance: 3, + ..nssa::Account::default() + }, + )); let acc = tree .key_map .get_mut(&ChainIndex::from_str("/0/1").unwrap()) .unwrap(); - acc.value.1.push((0, nssa::Account { balance: 5, ..nssa::Account::default() })); + acc.value.1.push(( + 0, + nssa::Account { + balance: 5, + ..nssa::Account::default() + }, + )); let acc = tree .key_map .get_mut(&ChainIndex::from_str("/1/0").unwrap()) .unwrap(); - acc.value.1.push((0, nssa::Account { balance: 6, ..nssa::Account::default() })); + acc.value.1.push(( + 0, + nssa::Account { + balance: 6, + ..nssa::Account::default() + }, + )); // Update account_id_map for nodes that now have entries for chain_index_str in ["/1", "/2", "/0/1", "/1/0"] { diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 726533eb..065af364 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -174,7 +174,13 @@ mod tests { // /2 let second_chain_index = key_tree_private.generate_new_node_layered().unwrap(); - key_tree_private.key_map.get(&second_chain_index).expect("Node was just inserted").value.0.clone() + key_tree_private + .key_map + .get(&second_chain_index) + .expect("Node was just inserted") + .value + .0 + .clone() } #[test] diff --git a/wallet-ffi/src/account.rs b/wallet-ffi/src/account.rs index ae911870..a928bf92 100644 --- a/wallet-ffi/src/account.rs +++ b/wallet-ffi/src/account.rs @@ -62,6 +62,56 @@ pub unsafe extern "C" fn wallet_ffi_create_account_public( WalletFfiError::Success } +/// Create a new private account, storing a default account entry in local storage. +/// +/// This is the private-account equivalent of `wallet_ffi_create_account_public`. +/// It generates a key node, assigns a random identifier, and inserts a default +/// account record so the account can immediately be used with +/// `wallet_ffi_register_private_account`. +/// +/// # Parameters +/// - `handle`: Valid wallet handle +/// - `out_account_id`: Output pointer for the new account ID (32 bytes) +/// +/// # Returns +/// - `Success` on successful creation +/// - Error code on failure +/// +/// # Safety +/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` +/// - `out_account_id` must be a valid pointer to a `FfiBytes32` struct +#[no_mangle] +pub unsafe extern "C" fn wallet_ffi_create_account_private( + handle: *mut WalletHandle, + out_account_id: *mut FfiBytes32, +) -> WalletFfiError { + let wrapper = match get_wallet(handle) { + Ok(w) => w, + Err(e) => return e, + }; + + if out_account_id.is_null() { + print_error("Null output pointer for account_id"); + return WalletFfiError::NullPointer; + } + + let mut wallet = match wrapper.core.lock() { + Ok(w) => w, + Err(e) => { + print_error(format!("Failed to lock wallet: {e}")); + return WalletFfiError::InternalError; + } + }; + + let (account_id, _chain_index) = wallet.create_new_account_private(None); + + unsafe { + (*out_account_id).data = *account_id.value(); + } + + WalletFfiError::Success +} + /// Create a new private key node. /// /// Returns the nullifier public key (npk) and viewing public key (vpk) to share with diff --git a/wallet-ffi/wallet_ffi.h b/wallet-ffi/wallet_ffi.h index d0bdc60a..dc77cf91 100644 --- a/wallet-ffi/wallet_ffi.h +++ b/wallet-ffi/wallet_ffi.h @@ -242,6 +242,29 @@ typedef struct FfiTransferResult { enum WalletFfiError wallet_ffi_create_account_public(struct WalletHandle *handle, struct FfiBytes32 *out_account_id); +/** + * Create a new private account, storing a default account entry in local storage. + * + * This is the private-account equivalent of `wallet_ffi_create_account_public`. + * It generates a key node, assigns a random identifier, and inserts a default + * account record so the account can immediately be used with + * `wallet_ffi_register_private_account`. + * + * # Parameters + * - `handle`: Valid wallet handle + * - `out_account_id`: Output pointer for the new account ID (32 bytes) + * + * # Returns + * - `Success` on successful creation + * - Error code on failure + * + * # Safety + * - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open` + * - `out_account_id` must be a valid pointer to a `FfiBytes32` struct + */ +enum WalletFfiError wallet_ffi_create_account_private(struct WalletHandle *handle, + struct FfiBytes32 *out_account_id); + /** * Create a new private key node. *