diff --git a/Cargo.lock b/Cargo.lock index 8175c47b77a..759abe8d08a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1491,6 +1491,7 @@ dependencies = [ "async-trait", "bincode 1.3.3", "blsful", + "chrono", "clap", "dashcore", "dashcore_hashes", @@ -1501,12 +1502,14 @@ dependencies = [ "key-wallet-manager", "log", "rand 0.8.5", + "rayon", "serde", "serde_json", "thiserror 1.0.69", "tokio", "tokio-util", "tracing", + "tracing-appender", "tracing-subscriber", ] @@ -6846,6 +6849,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +dependencies = [ + "crossbeam-channel", + "thiserror 2.0.17", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" diff --git a/packages/rs-platform-wallet-ffi/src/platform_wallet_info.rs b/packages/rs-platform-wallet-ffi/src/platform_wallet_info.rs index 49211d074e8..5e0e41df327 100644 --- a/packages/rs-platform-wallet-ffi/src/platform_wallet_info.rs +++ b/packages/rs-platform-wallet-ffi/src/platform_wallet_info.rs @@ -1,13 +1,15 @@ use crate::error::*; use crate::handle::*; -use crate::types::*; +use crate::types::Network; use key_wallet::wallet::initialization::WalletAccountCreationOptions; +use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface; use platform_wallet::platform_wallet_info::PlatformWalletInfo; use std::os::raw::{c_char, c_uchar}; /// Create a new PlatformWalletInfo from seed bytes #[no_mangle] pub extern "C" fn platform_wallet_info_create_from_seed( + network: Network, seed_bytes: *const c_uchar, seed_len: usize, out_handle: *mut Handle, @@ -44,10 +46,10 @@ pub extern "C" fn platform_wallet_info_create_from_seed( let mut seed_array = [0u8; 64]; seed_array.copy_from_slice(seed_slice); - // Create wallet from seed - use empty network list, accounts can be added later + // Create wallet from seed let wallet = match key_wallet::Wallet::from_seed_bytes( seed_array, - &[], // No networks initially + network, WalletAccountCreationOptions::None, // No accounts initially ) { Ok(w) => w, @@ -64,14 +66,8 @@ pub extern "C" fn platform_wallet_info_create_from_seed( } }; - // Create ManagedWalletInfo from the wallet - let wallet_info = key_wallet::wallet::ManagedWalletInfo::from_wallet(&wallet); - - // Create PlatformWalletInfo wrapping the ManagedWalletInfo - let platform_wallet = PlatformWalletInfo { - wallet_info, - identity_managers: std::collections::BTreeMap::new(), - }; + // Create PlatformWalletInfo from the wallet + let platform_wallet = PlatformWalletInfo::from_wallet(&wallet); // Store in handle storage let handle = WALLET_INFO_STORAGE.insert(platform_wallet); @@ -83,6 +79,7 @@ pub extern "C" fn platform_wallet_info_create_from_seed( /// Create a new PlatformWalletInfo from mnemonic #[no_mangle] pub extern "C" fn platform_wallet_info_create_from_mnemonic( + network: Network, mnemonic: *const c_char, passphrase: *const c_char, out_handle: *mut Handle, @@ -155,7 +152,7 @@ pub extern "C" fn platform_wallet_info_create_from_mnemonic( match key_wallet::Wallet::from_mnemonic_with_passphrase( mnemonic_obj, pass.to_string(), - &[], // No networks initially + network, WalletAccountCreationOptions::None, // No accounts initially ) { Ok(w) => w, @@ -177,7 +174,7 @@ pub extern "C" fn platform_wallet_info_create_from_mnemonic( } else { match key_wallet::Wallet::from_mnemonic( mnemonic_obj, - &[], // No networks initially + network, WalletAccountCreationOptions::None, // No accounts initially ) { Ok(w) => w, @@ -195,14 +192,8 @@ pub extern "C" fn platform_wallet_info_create_from_mnemonic( } }; - // Create ManagedWalletInfo from the wallet - let wallet_info = key_wallet::wallet::ManagedWalletInfo::from_wallet(&wallet); - - // Create PlatformWalletInfo wrapping the ManagedWalletInfo - let platform_wallet = PlatformWalletInfo { - wallet_info, - identity_managers: std::collections::BTreeMap::new(), - }; + // Create PlatformWalletInfo from the wallet + let platform_wallet = PlatformWalletInfo::from_wallet(&wallet); // Store in handle storage let handle = WALLET_INFO_STORAGE.insert(platform_wallet); @@ -211,11 +202,10 @@ pub extern "C" fn platform_wallet_info_create_from_mnemonic( PlatformWalletFFIResult::Success } -/// Get the identity manager for a specific network +/// Get the identity manager #[no_mangle] pub extern "C" fn platform_wallet_info_get_identity_manager( wallet_handle: Handle, - network: NetworkType, out_handle: *mut Handle, out_error: *mut PlatformWalletFFIError, ) -> PlatformWalletFFIResult { @@ -233,23 +223,9 @@ pub extern "C" fn platform_wallet_info_get_identity_manager( WALLET_INFO_STORAGE .with_item(wallet_handle, |wallet_info| { - let dash_network = network.to_dash_network(); - - if let Some(manager) = wallet_info.identity_managers.get(&dash_network) { - let handle = IDENTITY_MANAGER_STORAGE.insert(manager.clone()); - unsafe { *out_handle = handle }; - PlatformWalletFFIResult::Success - } else { - if !out_error.is_null() { - unsafe { - *out_error = PlatformWalletFFIError::new( - PlatformWalletFFIResult::ErrorInvalidNetwork, - format!("No identity manager for network: {:?}", network), - ); - } - } - PlatformWalletFFIResult::ErrorInvalidNetwork - } + let handle = IDENTITY_MANAGER_STORAGE.insert(wallet_info.identity_manager.clone()); + unsafe { *out_handle = handle }; + PlatformWalletFFIResult::Success }) .unwrap_or_else(|| { if !out_error.is_null() { @@ -264,11 +240,10 @@ pub extern "C" fn platform_wallet_info_get_identity_manager( }) } -/// Add or update identity manager for a network +/// Set the identity manager #[no_mangle] pub extern "C" fn platform_wallet_info_set_identity_manager( wallet_handle: Handle, - network: NetworkType, manager_handle: Handle, out_error: *mut PlatformWalletFFIError, ) -> PlatformWalletFFIResult { @@ -292,8 +267,7 @@ pub extern "C" fn platform_wallet_info_set_identity_manager( WALLET_INFO_STORAGE .with_item_mut(wallet_handle, |wallet_info| { - let dash_network = network.to_dash_network(); - wallet_info.identity_managers.insert(dash_network, manager); + wallet_info.identity_manager = manager; PlatformWalletFFIResult::Success }) .unwrap_or_else(|| { @@ -353,6 +327,7 @@ pub extern "C" fn platform_wallet_info_destroy(wallet_handle: Handle) -> Platfor #[cfg(test)] mod tests { + use crate::platform_wallet_string_free; use super::*; #[test] @@ -362,6 +337,7 @@ mod tests { let mut error = PlatformWalletFFIError::success(); let result = platform_wallet_info_create_from_seed( + Network::Testnet, seed.as_ptr(), seed.len(), &mut handle, @@ -385,6 +361,7 @@ mod tests { let mut error = PlatformWalletFFIError::success(); let result = platform_wallet_info_create_from_mnemonic( + Network::Testnet, mnemonic.as_ptr(), std::ptr::null(), &mut handle, @@ -405,7 +382,7 @@ mod tests { let mut handle: Handle = NULL_HANDLE; let mut error = PlatformWalletFFIError::success(); - platform_wallet_info_create_from_seed(seed.as_ptr(), seed.len(), &mut handle, &mut error); + platform_wallet_info_create_from_seed(Network::Testnet, seed.as_ptr(), seed.len(), &mut handle, &mut error); let mut json_ptr: *mut c_char = std::ptr::null_mut(); let result = platform_wallet_info_to_json(handle, &mut json_ptr, &mut error); diff --git a/packages/rs-platform-wallet-ffi/src/types.rs b/packages/rs-platform-wallet-ffi/src/types.rs index c838f21b486..8f7cd1442b7 100644 --- a/packages/rs-platform-wallet-ffi/src/types.rs +++ b/packages/rs-platform-wallet-ffi/src/types.rs @@ -1,35 +1,6 @@ use std::os::raw::{c_char, c_uchar}; -/// Network types -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum NetworkType { - Mainnet = 0, - Testnet = 1, - Devnet = 2, - Regtest = 3, -} - -impl NetworkType { - pub fn to_dash_network(&self) -> dashcore::Network { - match self { - NetworkType::Mainnet => dashcore::Network::Dash, - NetworkType::Testnet => dashcore::Network::Testnet, - NetworkType::Devnet => dashcore::Network::Devnet, - NetworkType::Regtest => dashcore::Network::Regtest, - } - } - - pub fn from_dash_network(network: dashcore::Network) -> Self { - match network { - dashcore::Network::Dash => NetworkType::Mainnet, - dashcore::Network::Testnet => NetworkType::Testnet, - dashcore::Network::Devnet => NetworkType::Devnet, - dashcore::Network::Regtest => NetworkType::Regtest, - _ => NetworkType::Mainnet, - } - } -} +pub use dashcore::Network; /// Identifier (32 bytes) #[repr(C)] @@ -155,22 +126,6 @@ pub extern "C" fn platform_wallet_string_free(s: *mut c_char) { mod tests { use super::*; - #[test] - fn test_network_type_conversion() { - assert_eq!( - NetworkType::Mainnet.to_dash_network(), - dashcore::Network::Dash - ); - assert_eq!( - NetworkType::Testnet.to_dash_network(), - dashcore::Network::Testnet - ); - assert_eq!( - NetworkType::from_dash_network(dashcore::Network::Testnet), - NetworkType::Testnet - ); - } - #[test] fn test_identifier_bytes_from_slice() { let bytes = [0u8; 32]; diff --git a/packages/rs-platform-wallet-ffi/tests/integration_tests.rs b/packages/rs-platform-wallet-ffi/tests/integration_tests.rs index 58407eeaddb..ed4bbaed0b5 100644 --- a/packages/rs-platform-wallet-ffi/tests/integration_tests.rs +++ b/packages/rs-platform-wallet-ffi/tests/integration_tests.rs @@ -20,7 +20,7 @@ fn test_wallet_creation_and_destruction() { let mut error = PlatformWalletFFIError::success(); let result = - platform_wallet_info_create_from_seed(seed.as_ptr(), seed.len(), &mut handle, &mut error); + platform_wallet_info_create_from_seed(Network::Testnet, seed.as_ptr(), seed.len(), &mut handle, &mut error); assert_eq!(result, PlatformWalletFFIResult::Success); assert_ne!(handle, NULL_HANDLE); @@ -43,6 +43,7 @@ fn test_wallet_from_mnemonic() { let mut error = PlatformWalletFFIError::success(); let result = platform_wallet_info_create_from_mnemonic( + Network::Testnet, mnemonic.as_ptr(), std::ptr::null(), &mut handle, @@ -179,7 +180,7 @@ fn test_serialization() { let mut handle: Handle = NULL_HANDLE; let mut error = PlatformWalletFFIError::success(); - platform_wallet_info_create_from_seed(seed.as_ptr(), seed.len(), &mut handle, &mut error); + platform_wallet_info_create_from_seed(Network::Testnet, seed.as_ptr(), seed.len(), &mut handle, &mut error); // Serialize to JSON - function not yet implemented // let mut json_ptr: *mut std::os::raw::c_char = std::ptr::null_mut(); @@ -237,6 +238,7 @@ fn test_error_handling() { // Try to create wallet with null pointer let result = platform_wallet_info_create_from_seed( + Network::Testnet, std::ptr::null(), 0, std::ptr::null_mut(), @@ -260,6 +262,7 @@ fn test_full_workflow() { let mut wallet_handle: Handle = NULL_HANDLE; let result = platform_wallet_info_create_from_mnemonic( + Network::Testnet, mnemonic.as_ptr(), std::ptr::null(), &mut wallet_handle, @@ -290,10 +293,8 @@ fn test_full_workflow() { identity_manager_set_primary_identity(manager_handle, id_bytes, &mut error); // Set identity manager on wallet - let network = NetworkType::Testnet; let result = platform_wallet_info_set_identity_manager( wallet_handle, - network, manager_handle, &mut error, ); @@ -303,7 +304,6 @@ fn test_full_workflow() { let mut retrieved_manager_handle: Handle = NULL_HANDLE; let result = platform_wallet_info_get_identity_manager( wallet_handle, - network, &mut retrieved_manager_handle, &mut error, ); diff --git a/packages/rs-platform-wallet/examples/basic_usage.rs b/packages/rs-platform-wallet/examples/basic_usage.rs index 11e61302fa5..aef8c8afdc2 100644 --- a/packages/rs-platform-wallet/examples/basic_usage.rs +++ b/packages/rs-platform-wallet/examples/basic_usage.rs @@ -20,7 +20,7 @@ fn main() -> Result<(), PlatformWalletError> { println!( "Total identities on {:?}: {}", network, - platform_wallet.identities(network).len() + platform_wallet.identities().len() ); // The platform wallet can be used with WalletManager (requires "manager" feature) diff --git a/packages/rs-platform-wallet/src/error.rs b/packages/rs-platform-wallet/src/error.rs index 0aede4246b0..6f406f2922c 100644 --- a/packages/rs-platform-wallet/src/error.rs +++ b/packages/rs-platform-wallet/src/error.rs @@ -18,10 +18,7 @@ pub enum PlatformWalletError { #[error("Contact request not found: {0}")] ContactRequestNotFound(Identifier), - - #[error("No accounts found for network: {0:?}")] - NoAccountsForNetwork(Network), - + #[error( "DashPay receiving account already exists for identity {identity} with contact {contact} on network {network:?} (account index {account_index})" )] diff --git a/packages/rs-platform-wallet/src/lib.rs b/packages/rs-platform-wallet/src/lib.rs index f9bdf6f8eae..80eee325ddc 100644 --- a/packages/rs-platform-wallet/src/lib.rs +++ b/packages/rs-platform-wallet/src/lib.rs @@ -8,3 +8,15 @@ pub mod contact_request; pub mod crypto; pub mod error; pub mod established_contact; +pub mod identity_manager; +pub mod managed_identity; +pub mod platform_wallet_info; + +// Re-export main types at crate root +pub use block_time::BlockTime; +pub use contact_request::ContactRequest; +pub use error::PlatformWalletError; +pub use established_contact::EstablishedContact; +pub use identity_manager::IdentityManager; +pub use managed_identity::ManagedIdentity; +pub use platform_wallet_info::PlatformWalletInfo; diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/accessors.rs b/packages/rs-platform-wallet/src/platform_wallet_info/accessors.rs index a25acfde9b3..d1dd635661e 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/accessors.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/accessors.rs @@ -4,63 +4,53 @@ use crate::ManagedIdentity; use dpp::identifier::Identifier; use dpp::identity::Identity; use indexmap::IndexMap; -use key_wallet::Network; impl PlatformWalletInfo { - /// Get all identities associated with this wallet for a specific network - pub fn identities(&self, network: Network) -> IndexMap { - self.identity_manager(network) - .map(|manager| manager.identities()) - .unwrap_or_default() + /// Get all identities associated with this wallet + pub fn identities(&self) -> IndexMap { + self.identity_manager().identities() } - /// Get direct access to managed identities for a specific network + /// Get direct access to managed identities pub fn managed_identities( &self, - network: Network, - ) -> Option<&IndexMap> { - self.identity_manager(network) - .map(|manager| &manager.identities) + ) -> &IndexMap { + &self.identity_manager().identities } - /// Add an identity to this wallet for a specific network + /// Add an identity to this wallet pub fn add_identity( &mut self, - network: Network, identity: Identity, ) -> Result<(), PlatformWalletError> { - self.identity_manager_mut(network).add_identity(identity) + self.identity_manager_mut().add_identity(identity) } - /// Get a specific identity by ID for a specific network - pub fn identity(&self, network: Network, identity_id: &Identifier) -> Option<&Identity> { - self.identity_manager(network) - .and_then(|manager| manager.identity(identity_id)) + /// Get a specific identity by ID + pub fn identity(&self, identity_id: &Identifier) -> Option<&Identity> { + self.identity_manager().identity(identity_id) } - /// Remove an identity from this wallet for a specific network + /// Remove an identity from this wallet pub fn remove_identity( &mut self, - network: Network, identity_id: &Identifier, ) -> Result { - self.identity_manager_mut(network) + self.identity_manager_mut() .remove_identity(identity_id) } - /// Get the primary identity for a specific network (if set) - pub fn primary_identity(&self, network: Network) -> Option<&Identity> { - self.identity_manager(network) - .and_then(|manager| manager.primary_identity()) + /// Get the primary identity (if set) + pub fn primary_identity(&self) -> Option<&Identity> { + self.identity_manager().primary_identity() } - /// Set the primary identity for a specific network + /// Set the primary identity pub fn set_primary_identity( &mut self, - network: Network, identity_id: Identifier, ) -> Result<(), PlatformWalletError> { - self.identity_manager_mut(network) + self.identity_manager_mut() .set_primary_identity(identity_id) } } diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/contact_requests.rs b/packages/rs-platform-wallet/src/platform_wallet_info/contact_requests.rs index e90b301743e..bccb3e8f167 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/contact_requests.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/contact_requests.rs @@ -16,7 +16,6 @@ use key_wallet::account::AccountType; use key_wallet::bip32::ExtendedPubKey; use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface; use key_wallet::wallet::managed_wallet_info::ManagedAccountOperations; -use key_wallet::Network; use key_wallet::Wallet; use dpp::document::DocumentV0Getters; @@ -24,19 +23,17 @@ use dpp::identity::signer::Signer; use dpp::identity::IdentityPublicKey; impl PlatformWalletInfo { - /// Add a sent contact request for a specific identity on a specific network + /// Add a sent contact request for a specific identity /// If there's already an incoming request from the recipient, automatically establish the contact pub(crate) fn add_sent_contact_request( &mut self, wallet: &mut Wallet, account_index: u32, - network: Network, identity_id: &Identifier, request: ContactRequest, ) -> Result<(), PlatformWalletError> { if self - .identity_manager(network) - .and_then(|manager| manager.managed_identity(identity_id)) + .identity_manager().managed_identity(identity_id) .is_none() { return Err(PlatformWalletError::IdentityNotFound(*identity_id)); @@ -59,29 +56,27 @@ impl PlatformWalletInfo { }; let wallet_has_account = wallet - .accounts - .get(&network) - .and_then(|collection| collection.account_of_type(account_type)) + .accounts.account_of_type(account_type) .is_some(); if wallet_has_account { return Err(PlatformWalletError::DashpayReceivingAccountAlreadyExists { identity: *identity_id, contact: Identifier::from(friend_identity_id), - network, + network: self.network(), account_index, }); } if !wallet_has_account { - let account_path = account_type.derivation_path(network).map_err(|err| { + let account_path = account_type.derivation_path(self.network()).map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to derive DashPay receiving account path: {err}" )) })?; let account_xpub = wallet - .derive_extended_public_key(network, &account_path) + .derive_extended_public_key(&account_path) .map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to derive DashPay receiving account xpub: {err}" @@ -89,7 +84,7 @@ impl PlatformWalletInfo { })?; wallet - .add_account(account_type, network, Some(account_xpub)) + .add_account(account_type, Some(account_xpub)) .map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to add DashPay receiving account to wallet: {err}" @@ -99,22 +94,21 @@ impl PlatformWalletInfo { let managed_has_account = self .wallet_info - .accounts(network) - .and_then(|collection| collection.dashpay_receival_accounts.get(&account_key)) + .accounts().dashpay_receival_accounts.get(&account_key) .is_some(); if managed_has_account { return Err(PlatformWalletError::DashpayReceivingAccountAlreadyExists { identity: *identity_id, contact: Identifier::from(friend_identity_id), - network, + network: self.network(), account_index, }); } if !managed_has_account { self.wallet_info - .add_managed_account(wallet, account_type, network) + .add_managed_account(wallet, account_type) .map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to add managed DashPay receiving account: {err}" @@ -124,8 +118,7 @@ impl PlatformWalletInfo { let managed_account_collection = self .wallet_info - .accounts_mut(network) - .ok_or(PlatformWalletError::NoAccountsForNetwork(network))?; + .accounts_mut(); let managed_account = managed_account_collection .dashpay_receival_accounts @@ -138,7 +131,7 @@ impl PlatformWalletInfo { managed_account.metadata.last_used = Some(request_created_at); - self.identity_manager_mut(network) + self.identity_manager_mut() .managed_identity_mut(identity_id) .ok_or(PlatformWalletError::IdentityNotFound(*identity_id))? .add_sent_contact_request(request); @@ -146,19 +139,17 @@ impl PlatformWalletInfo { Ok(()) } - /// Add an incoming contact request for a specific identity on a specific network + /// Add an incoming contact request for a specific identity /// If there's already a sent request to the sender, automatically establish the contact pub(crate) fn add_incoming_contact_request( &mut self, wallet: &mut Wallet, - network: Network, identity_id: &Identifier, friend_identity: &Identity, request: ContactRequest, ) -> Result<(), PlatformWalletError> { if self - .identity_manager(network) - .and_then(|manager| manager.managed_identity(identity_id)) + .identity_manager().managed_identity(identity_id) .is_none() { return Err(PlatformWalletError::IdentityNotFound(*identity_id)); @@ -186,8 +177,7 @@ impl PlatformWalletInfo { } if self - .identity_manager(network) - .and_then(|manager| manager.managed_identity(identity_id)) + .identity_manager().managed_identity(identity_id) .and_then(|managed| { managed .identity @@ -221,16 +211,14 @@ impl PlatformWalletInfo { }; let wallet_has_account = wallet - .accounts - .get(&network) - .and_then(|collection| collection.account_of_type(account_type)) + .accounts.account_of_type(account_type) .is_some(); if wallet_has_account { return Err(PlatformWalletError::DashpayExternalAccountAlreadyExists { identity: *identity_id, contact: friend_identity_identifier, - network, + network: self.network(), account_index, }); } @@ -242,7 +230,7 @@ impl PlatformWalletInfo { })?; wallet - .add_account(account_type, network, Some(account_xpub)) + .add_account(account_type, Some(account_xpub)) .map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to add DashPay external account to wallet: {err}" @@ -251,21 +239,20 @@ impl PlatformWalletInfo { let managed_has_account = self .wallet_info - .accounts(network) - .and_then(|collection| collection.dashpay_external_accounts.get(&account_key)) + .accounts().dashpay_external_accounts.get(&account_key) .is_some(); if managed_has_account { return Err(PlatformWalletError::DashpayExternalAccountAlreadyExists { identity: *identity_id, contact: friend_identity_identifier, - network, + network: self.network(), account_index, }); } self.wallet_info - .add_managed_account(wallet, account_type, network) + .add_managed_account(wallet, account_type) .map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to add managed DashPay external account: {err}" @@ -274,8 +261,7 @@ impl PlatformWalletInfo { let managed_account_collection = self .wallet_info - .accounts_mut(network) - .ok_or(PlatformWalletError::NoAccountsForNetwork(network))?; + .accounts_mut(); let managed_account = managed_account_collection .dashpay_external_accounts @@ -288,7 +274,7 @@ impl PlatformWalletInfo { managed_account.metadata.last_used = Some(request_created_at); - self.identity_manager_mut(network) + self.identity_manager_mut() .managed_identity_mut(identity_id) .ok_or(PlatformWalletError::IdentityNotFound(*identity_id))? .add_incoming_contact_request(request); @@ -306,7 +292,6 @@ impl PlatformWalletInfo { /// # Arguments /// /// * `wallet` - The wallet to use for account derivation - /// * `network` - The network to operate on /// * `sender_identity` - The sender's identity /// * `recipient_identity` - The recipient's identity /// * `sender_key_index` - Optional index of sender's encryption key (if None, uses first encryption key) @@ -323,7 +308,6 @@ impl PlatformWalletInfo { pub async fn send_contact_request( &mut self, wallet: &mut Wallet, - network: Network, sender_identity: &Identity, recipient_identity: &Identity, sender_key_index: Option, @@ -335,7 +319,7 @@ impl PlatformWalletInfo { ecdh_provider: dash_sdk::platform::dashpay::EcdhProvider, ) -> Result<(Identifier, Identifier), PlatformWalletError> where - S: Signer, + S: Signer, F: FnOnce(&IdentityPublicKey, u32) -> Fut, Fut: std::future::Future>, G: FnOnce(&dashcore::secp256k1::PublicKey) -> Gut, @@ -382,8 +366,7 @@ impl PlatformWalletInfo { // Get SDK from identity manager let sdk = self - .identity_manager(network) - .and_then(|manager| manager.sdk.as_ref()) + .identity_manager().sdk.as_ref() .ok_or_else(|| { PlatformWalletError::InvalidIdentityData( "SDK not configured in identity manager".to_string(), @@ -412,14 +395,14 @@ impl PlatformWalletInfo { }; // Derive the account path and xpub - let account_path = account_type.derivation_path(network).map_err(|err| { + let account_path = account_type.derivation_path(self.network()).map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to derive DashPay receiving account path: {err}" )) })?; let account_xpub = wallet - .derive_extended_public_key(network, &account_path) + .derive_extended_public_key(&account_path) .map_err(|err| { PlatformWalletError::InvalidIdentityData(format!( "Failed to derive DashPay receiving account xpub: {err}" @@ -462,7 +445,6 @@ impl PlatformWalletInfo { self.add_sent_contact_request( wallet, account_index, - network, &sender_identity_id, contact_request, )?; @@ -470,16 +452,15 @@ impl PlatformWalletInfo { Ok((result.document.id(), result.recipient_id)) } - /// Accept an incoming contact request and establish the contact on a specific network + /// Accept an incoming contact request and establish the contact /// Returns the established contact if successful pub fn accept_incoming_request( &mut self, - network: Network, identity_id: &Identifier, sender_id: &Identifier, ) -> Result { let managed_identity = self - .identity_manager_mut(network) + .identity_manager_mut() .managed_identity_mut(identity_id) .ok_or(PlatformWalletError::IdentityNotFound(*identity_id))?; @@ -508,7 +489,7 @@ mod tests { let xpub_str = "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"; let xpub = xpub_str.parse::().unwrap(); let root_xpub = RootExtendedPubKey::from_extended_pub_key(&xpub); - Wallet::from_wallet_type(key_wallet::wallet::WalletType::WatchOnly(root_xpub)) + Wallet::from_wallet_type(Network::Testnet, key_wallet::wallet::WalletType::WatchOnly(root_xpub)) } fn create_test_identity(id_bytes: [u8; 32]) -> Identity { @@ -556,13 +537,12 @@ mod tests { #[test] fn test_accept_incoming_request_identity_not_found() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); - let network = Network::Testnet; + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let identity_id = Identifier::from([1u8; 32]); let sender_id = Identifier::from([2u8; 32]); // Try to accept request for non-existent identity - let result = platform_wallet.accept_incoming_request(network, &identity_id, &sender_id); + let result = platform_wallet.accept_incoming_request(&identity_id, &sender_id); assert!(result.is_err()); assert!(matches!( @@ -573,20 +553,19 @@ mod tests { #[test] fn test_accept_incoming_request_contact_not_found() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); - let network = Network::Testnet; + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let identity_id = Identifier::from([1u8; 32]); let sender_id = Identifier::from([2u8; 32]); // Create and add identity let identity = create_test_identity([1u8; 32]); platform_wallet - .identity_manager_mut(network) + .identity_manager_mut() .add_identity(identity) .unwrap(); // Try to accept request that doesn't exist - let result = platform_wallet.accept_incoming_request(network, &identity_id, &sender_id); + let result = platform_wallet.accept_incoming_request(&identity_id, &sender_id); assert!(result.is_err()); assert!(matches!( @@ -597,9 +576,8 @@ mod tests { #[test] fn test_error_identity_not_found_for_sent_request() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let mut wallet = create_dummy_wallet(); - let network = Network::Testnet; let identity_id = Identifier::from([1u8; 32]); let recipient_id = Identifier::from([2u8; 32]); @@ -609,7 +587,6 @@ mod tests { let result = platform_wallet.add_sent_contact_request( &mut wallet, 0, - network, &identity_id, request, ); @@ -623,9 +600,8 @@ mod tests { #[test] fn test_error_identity_not_found_for_incoming_request() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let mut wallet = create_dummy_wallet(); - let network = Network::Testnet; let identity_id = Identifier::from([1u8; 32]); let friend_id = Identifier::from([2u8; 32]); @@ -635,7 +611,6 @@ mod tests { // Try to add incoming request for non-existent identity let result = platform_wallet.add_incoming_contact_request( &mut wallet, - network, &identity_id, &friend_identity, request, @@ -650,9 +625,8 @@ mod tests { #[test] fn test_error_sender_mismatch_for_incoming_request() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let mut wallet = create_dummy_wallet(); - let network = Network::Testnet; let identity_id = Identifier::from([1u8; 32]); let friend_id = Identifier::from([2u8; 32]); let wrong_id = Identifier::from([3u8; 32]); @@ -660,7 +634,7 @@ mod tests { // Create and add our identity let identity = create_test_identity([1u8; 32]); platform_wallet - .identity_manager_mut(network) + .identity_manager_mut() .add_identity(identity) .unwrap(); @@ -673,7 +647,6 @@ mod tests { // Try to add incoming request with mismatched sender let result = platform_wallet.add_incoming_contact_request( &mut wallet, - network, &identity_id, &friend_identity, request, @@ -688,16 +661,15 @@ mod tests { #[test] fn test_error_missing_encryption_key_in_sender() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let mut wallet = create_dummy_wallet(); - let network = Network::Testnet; let identity_id = Identifier::from([1u8; 32]); let friend_id = Identifier::from([2u8; 32]); // Create and add our identity let identity = create_test_identity([1u8; 32]); platform_wallet - .identity_manager_mut(network) + .identity_manager_mut() .add_identity(identity) .unwrap(); @@ -717,7 +689,6 @@ mod tests { // Try to add incoming request let result = platform_wallet.add_incoming_contact_request( &mut wallet, - network, &identity_id, &friend_identity, request, @@ -732,16 +703,15 @@ mod tests { #[test] fn test_error_wrong_key_purpose_in_sender() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let mut wallet = create_dummy_wallet(); - let network = Network::Testnet; let identity_id = Identifier::from([1u8; 32]); let friend_id = Identifier::from([2u8; 32]); // Create and add our identity let identity = create_test_identity([1u8; 32]); platform_wallet - .identity_manager_mut(network) + .identity_manager_mut() .add_identity(identity) .unwrap(); @@ -772,7 +742,6 @@ mod tests { // Try to add incoming request let result = platform_wallet.add_incoming_contact_request( &mut wallet, - network, &identity_id, &friend_identity, request, @@ -787,9 +756,8 @@ mod tests { #[test] fn test_error_missing_recipient_encryption_key() { - let mut platform_wallet = PlatformWalletInfo::new([1u8; 32], "Test Wallet".to_string()); + let mut platform_wallet = PlatformWalletInfo::new(Network::Testnet, [1u8; 32], "Test Wallet".to_string()); let mut wallet = create_dummy_wallet(); - let network = Network::Testnet; let identity_id = Identifier::from([1u8; 32]); let friend_id = Identifier::from([2u8; 32]); @@ -802,7 +770,7 @@ mod tests { }; let identity = Identity::V0(identity_v0); platform_wallet - .identity_manager_mut(network) + .identity_manager_mut() .add_identity(identity) .unwrap(); @@ -813,7 +781,6 @@ mod tests { // Try to add incoming request let result = platform_wallet.add_incoming_contact_request( &mut wallet, - network, &identity_id, &friend_identity, request, diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/managed_account_operations.rs b/packages/rs-platform-wallet/src/platform_wallet_info/managed_account_operations.rs index e5c1c6d63d9..2659107be87 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/managed_account_operations.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/managed_account_operations.rs @@ -1,5 +1,4 @@ use crate::platform_wallet_info::PlatformWalletInfo; -use dashcore::Network; use key_wallet::wallet::managed_wallet_info::ManagedAccountOperations; use key_wallet::{AccountType, ExtendedPubKey, Wallet}; @@ -9,23 +8,20 @@ impl ManagedAccountOperations for PlatformWalletInfo { &mut self, wallet: &Wallet, account_type: AccountType, - network: Network, ) -> key_wallet::Result<()> { self.wallet_info - .add_managed_account(wallet, account_type, network) + .add_managed_account(wallet, account_type) } fn add_managed_account_with_passphrase( &mut self, wallet: &Wallet, account_type: AccountType, - network: Network, passphrase: &str, ) -> key_wallet::Result<()> { self.wallet_info.add_managed_account_with_passphrase( wallet, account_type, - network, passphrase, ) } @@ -33,11 +29,10 @@ impl ManagedAccountOperations for PlatformWalletInfo { fn add_managed_account_from_xpub( &mut self, account_type: AccountType, - network: Network, account_xpub: ExtendedPubKey, ) -> key_wallet::Result<()> { self.wallet_info - .add_managed_account_from_xpub(account_type, network, account_xpub) + .add_managed_account_from_xpub(account_type, account_xpub) } #[cfg(feature = "bls")] @@ -45,10 +40,9 @@ impl ManagedAccountOperations for PlatformWalletInfo { &mut self, wallet: &Wallet, account_type: AccountType, - network: Network, ) -> key_wallet::Result<()> { self.wallet_info - .add_managed_bls_account(wallet, account_type, network) + .add_managed_bls_account(wallet, account_type) } #[cfg(feature = "bls")] @@ -56,13 +50,11 @@ impl ManagedAccountOperations for PlatformWalletInfo { &mut self, wallet: &Wallet, account_type: AccountType, - network: Network, passphrase: &str, ) -> key_wallet::Result<()> { self.wallet_info.add_managed_bls_account_with_passphrase( wallet, account_type, - network, passphrase, ) } @@ -71,12 +63,10 @@ impl ManagedAccountOperations for PlatformWalletInfo { fn add_managed_bls_account_from_public_key( &mut self, account_type: AccountType, - network: Network, bls_public_key: [u8; 48], ) -> key_wallet::Result<()> { self.wallet_info.add_managed_bls_account_from_public_key( account_type, - network, bls_public_key, ) } @@ -86,10 +76,9 @@ impl ManagedAccountOperations for PlatformWalletInfo { &mut self, wallet: &Wallet, account_type: AccountType, - network: Network, ) -> key_wallet::Result<()> { self.wallet_info - .add_managed_eddsa_account(wallet, account_type, network) + .add_managed_eddsa_account(wallet, account_type) } #[cfg(feature = "eddsa")] @@ -97,13 +86,11 @@ impl ManagedAccountOperations for PlatformWalletInfo { &mut self, wallet: &Wallet, account_type: AccountType, - network: Network, passphrase: &str, ) -> key_wallet::Result<()> { self.wallet_info.add_managed_eddsa_account_with_passphrase( wallet, account_type, - network, passphrase, ) } @@ -112,12 +99,10 @@ impl ManagedAccountOperations for PlatformWalletInfo { fn add_managed_eddsa_account_from_public_key( &mut self, account_type: AccountType, - network: Network, ed25519_public_key: [u8; 32], ) -> key_wallet::Result<()> { self.wallet_info.add_managed_eddsa_account_from_public_key( account_type, - network, ed25519_public_key, ) } diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs b/packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs index ac4113f18a1..93e5fe436ed 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/matured_transactions.rs @@ -9,7 +9,7 @@ use dashcore::transaction::special_transaction::TransactionPayload; use dpp::prelude::Identifier; use key_wallet::wallet::immature_transaction::ImmatureTransaction; use key_wallet::Network; - +use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface; #[allow(unused_imports)] use crate::ContactRequest; @@ -23,7 +23,6 @@ impl PlatformWalletInfo { /// # Arguments /// /// * `wallet` - The wallet to derive authentication keys from - /// * `network` - The network to operate on /// * `tx` - The asset lock transaction /// /// # Returns @@ -32,7 +31,6 @@ impl PlatformWalletInfo { pub async fn fetch_identity_and_contacts_for_asset_lock( &mut self, wallet: &key_wallet::Wallet, - network: Network, tx: &dashcore::Transaction, ) -> Result, PlatformWalletError> { use dashcore::hashes::Hash; @@ -60,7 +58,6 @@ impl PlatformWalletInfo { let result = self .fetch_contact_requests_for_identities_after_asset_locks( wallet, - network, &[immature_tx], ) .await?; @@ -77,7 +74,6 @@ impl PlatformWalletInfo { /// # Arguments /// /// * `wallet` - The wallet to derive authentication keys from - /// * `network` - The network to operate on /// * `asset_lock_transactions` - List of asset lock transactions from pending_asset_locks /// /// # Returns @@ -86,7 +82,6 @@ impl PlatformWalletInfo { pub async fn fetch_contact_requests_for_identities_after_asset_locks( &mut self, wallet: &key_wallet::Wallet, - network: Network, asset_lock_transactions: &[ImmatureTransaction], ) -> Result, PlatformWalletError> { use dash_sdk::platform::types::identity::PublicKeyHash; @@ -102,8 +97,7 @@ impl PlatformWalletInfo { // Get SDK from identity manager let sdk = self - .identity_manager(network) - .and_then(|manager| manager.sdk.as_ref()) + .identity_manager().sdk.as_ref() .ok_or_else(|| { PlatformWalletError::InvalidIdentityData( "SDK not configured in identity manager".to_string(), @@ -122,7 +116,7 @@ impl PlatformWalletInfo { IDENTITY_AUTHENTICATION_PATH_MAINNET, IDENTITY_AUTHENTICATION_PATH_TESTNET, }; - let base_path = match network { + let base_path = match self.network() { Network::Dash => IDENTITY_AUTHENTICATION_PATH_MAINNET, Network::Testnet => IDENTITY_AUTHENTICATION_PATH_TESTNET, _ => { @@ -145,7 +139,7 @@ impl PlatformWalletInfo { // Derive the extended private key at this path let auth_key = wallet - .derive_extended_private_key(network, &full_path) + .derive_extended_private_key(&full_path) .map_err(|e| { PlatformWalletError::InvalidIdentityData(format!( "Failed to derive authentication key: {}", @@ -172,11 +166,9 @@ impl PlatformWalletInfo { // Add identity to manager if not already present if !self - .identity_manager(network) - .map(|mgr| mgr.identities().contains_key(&identity_id)) - .unwrap_or(false) + .identity_manager().identities().contains_key(&identity_id) { - self.identity_manager_mut(network) + self.identity_manager_mut() .add_identity(identity.clone())?; } @@ -192,7 +184,7 @@ impl PlatformWalletInfo { if let Ok(contact_request) = parse_contact_request_document(&doc) { // Add to managed identity if let Some(managed_identity) = self - .identity_manager_mut(network) + .identity_manager_mut() .managed_identity_mut(&identity_id) { managed_identity.add_sent_contact_request(contact_request); @@ -207,7 +199,7 @@ impl PlatformWalletInfo { if let Ok(contact_request) = parse_contact_request_document(&doc) { // Add to managed identity if let Some(managed_identity) = self - .identity_manager_mut(network) + .identity_manager_mut() .managed_identity_mut(&identity_id) { managed_identity diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/mod.rs b/packages/rs-platform-wallet/src/platform_wallet_info/mod.rs index a28000ea942..4291ed00081 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/mod.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/mod.rs @@ -1,7 +1,6 @@ use crate::IdentityManager; use key_wallet::wallet::ManagedWalletInfo; use key_wallet::Network; -use std::collections::BTreeMap; use std::fmt; mod accessors; @@ -17,29 +16,27 @@ pub struct PlatformWalletInfo { /// The underlying managed wallet info pub wallet_info: ManagedWalletInfo, - /// Identity managers for each network - pub identity_managers: BTreeMap, + /// Identity manager + pub identity_manager: IdentityManager, } impl PlatformWalletInfo { - /// Create a new platform wallet info - pub fn new(wallet_id: [u8; 32], name: String) -> Self { + /// Create a new platform wallet info for a specific network + pub fn new(network: Network, wallet_id: [u8; 32], name: String) -> Self { Self { - wallet_info: ManagedWalletInfo::with_name(wallet_id, name), - identity_managers: BTreeMap::new(), + wallet_info: ManagedWalletInfo::with_name(network, wallet_id, name), + identity_manager: IdentityManager::new(), } } - /// Get or create an identity manager for a specific network - fn identity_manager_mut(&mut self, network: Network) -> &mut IdentityManager { - self.identity_managers - .entry(network) - .or_insert_with(IdentityManager::new) + /// Get or create an identity manager + fn identity_manager_mut(&mut self) -> &mut IdentityManager { + &mut self.identity_manager } - /// Get an identity manager for a specific network (if it exists) - fn identity_manager(&self, network: Network) -> Option<&IdentityManager> { - self.identity_managers.get(&network) + /// Get an identity manager (if it exists) + fn identity_manager(&self) -> &IdentityManager { + &self.identity_manager } } @@ -47,7 +44,7 @@ impl fmt::Debug for PlatformWalletInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PlatformWalletInfo") .field("wallet_info", &self.wallet_info) - .field("identity_managers", &self.identity_managers) + .field("identity_manager", &self.identity_manager) .finish() } } @@ -61,10 +58,10 @@ mod tests { #[test] fn test_platform_wallet_creation() { let wallet_id = [1u8; 32]; - let wallet = PlatformWalletInfo::new(wallet_id, "Test Platform Wallet".to_string()); + let wallet = PlatformWalletInfo::new(Network::Testnet, wallet_id, "Test Platform Wallet".to_string()); assert_eq!(wallet.wallet_id(), wallet_id); assert_eq!(wallet.name(), Some("Test Platform Wallet")); - assert_eq!(wallet.identities(Network::Testnet).len(), 0); + assert_eq!(wallet.identities().len(), 0); } } diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs b/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs index 00b494d1c2f..24919950a1e 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/wallet_info_interface.rs @@ -11,24 +11,30 @@ use key_wallet::wallet::managed_wallet_info::transaction_building::{ use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface; use key_wallet::wallet::ManagedWalletInfo; use key_wallet::{Utxo, Wallet, WalletBalance}; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeSet; +use dpp::prelude::CoreBlockHeight; +use crate::IdentityManager; /// Implement WalletInfoInterface for PlatformWalletInfo impl WalletInfoInterface for PlatformWalletInfo { fn from_wallet(wallet: &Wallet) -> Self { Self { wallet_info: ManagedWalletInfo::from_wallet(wallet), - identity_managers: BTreeMap::new(), + identity_manager: IdentityManager::new(), } } fn from_wallet_with_name(wallet: &Wallet, name: String) -> Self { Self { wallet_info: ManagedWalletInfo::from_wallet_with_name(wallet, name), - identity_managers: BTreeMap::new(), + identity_manager: IdentityManager::new(), } } + fn network(&self) -> Network { + self.wallet_info.network() + } + fn wallet_id(&self) -> [u8; 32] { self.wallet_info.wallet_id() } @@ -49,11 +55,11 @@ impl WalletInfoInterface for PlatformWalletInfo { self.wallet_info.set_description(description) } - fn birth_height(&self) -> Option { + fn birth_height(&self) -> CoreBlockHeight { self.wallet_info.birth_height() } - fn set_birth_height(&mut self, height: Option) { + fn set_birth_height(&mut self, height: CoreBlockHeight) { self.wallet_info.set_birth_height(height) } @@ -69,8 +75,8 @@ impl WalletInfoInterface for PlatformWalletInfo { self.wallet_info.update_last_synced(timestamp) } - fn monitored_addresses(&self, network: Network) -> Vec { - self.wallet_info.monitored_addresses(network) + fn monitored_addresses(&self) -> Vec { + self.wallet_info.monitored_addresses() } fn utxos(&self) -> BTreeSet<&Utxo> { @@ -97,40 +103,38 @@ impl WalletInfoInterface for PlatformWalletInfo { self.wallet_info.transaction_history() } - fn accounts_mut(&mut self, network: Network) -> Option<&mut ManagedAccountCollection> { - self.wallet_info.accounts_mut(network) + fn accounts_mut(&mut self) -> &mut ManagedAccountCollection { + self.wallet_info.accounts_mut() } - fn accounts(&self, network: Network) -> Option<&ManagedAccountCollection> { - self.wallet_info.accounts(network) + fn accounts(&self) -> &ManagedAccountCollection { + self.wallet_info.accounts() } fn process_matured_transactions( &mut self, - network: Network, current_height: u32, ) -> Vec { self.wallet_info - .process_matured_transactions(network, current_height) + .process_matured_transactions(current_height) } - fn add_immature_transaction(&mut self, network: Network, tx: ImmatureTransaction) { + fn add_immature_transaction(&mut self, tx: ImmatureTransaction) { // Delegate to the underlying wallet_info - self.wallet_info.add_immature_transaction(network, tx) + self.wallet_info.add_immature_transaction(tx) } - fn immature_transactions(&self, network: Network) -> Option<&ImmatureTransactionCollection> { - self.wallet_info.immature_transactions(network) + fn immature_transactions(&self) -> &ImmatureTransactionCollection { + self.wallet_info.immature_transactions() } - fn network_immature_balance(&self, network: Network) -> u64 { - self.wallet_info.network_immature_balance(network) + fn immature_balance(&self) -> u64 { + self.wallet_info.immature_balance() } fn create_unsigned_payment_transaction( &mut self, wallet: &Wallet, - network: Network, account_index: u32, account_type_pref: Option, recipients: Vec<(Address, u64)>, @@ -139,7 +143,6 @@ impl WalletInfoInterface for PlatformWalletInfo { ) -> Result { self.wallet_info.create_unsigned_payment_transaction( wallet, - network, account_index, account_type_pref, recipients, @@ -148,9 +151,9 @@ impl WalletInfoInterface for PlatformWalletInfo { ) } - fn update_chain_height(&mut self, network: Network, current_height: u32) { + fn update_chain_height(&mut self, current_height: u32) { // Delegate to the underlying wallet_info self.wallet_info - .update_chain_height(network, current_height) + .update_chain_height(current_height) } } diff --git a/packages/rs-platform-wallet/src/platform_wallet_info/wallet_transaction_checker.rs b/packages/rs-platform-wallet/src/platform_wallet_info/wallet_transaction_checker.rs index d19507fae1f..848339dde2f 100644 --- a/packages/rs-platform-wallet/src/platform_wallet_info/wallet_transaction_checker.rs +++ b/packages/rs-platform-wallet/src/platform_wallet_info/wallet_transaction_checker.rs @@ -1,6 +1,6 @@ use crate::platform_wallet_info::PlatformWalletInfo; use async_trait::async_trait; -use dashcore::{Network, Transaction}; +use dashcore::Transaction; use key_wallet::transaction_checking::{ TransactionCheckResult, TransactionContext, WalletTransactionChecker, }; @@ -12,7 +12,6 @@ impl WalletTransactionChecker for PlatformWalletInfo { async fn check_transaction( &mut self, tx: &Transaction, - network: Network, context: TransactionContext, wallet: &mut Wallet, update_state: bool, @@ -20,7 +19,7 @@ impl WalletTransactionChecker for PlatformWalletInfo { // Check transaction with underlying wallet info let result = self .wallet_info - .check_transaction(tx, network, context, wallet, update_state) + .check_transaction(tx, context, wallet, update_state) .await; // If the transaction is relevant, and it's an asset lock, automatically fetch identities @@ -31,16 +30,14 @@ impl WalletTransactionChecker for PlatformWalletInfo { &tx.special_transaction_payload, Some(TransactionPayload::AssetLockPayloadType(_)) ) { - // Check if we have an SDK configured for this network - if let Some(identity_manager) = self.identity_managers.get(&network) { - if identity_manager.sdk.is_some() { - // Call the identity fetching logic - if let Err(e) = self - .fetch_identity_and_contacts_for_asset_lock(wallet, network, tx) - .await - { - eprintln!("Failed to fetch identity for asset lock: {}", e); - } + // Check if we have an SDK configured + if self.identity_manager().sdk.is_some() { + // Call the identity fetching logic + if let Err(e) = self + .fetch_identity_and_contacts_for_asset_lock(wallet, tx) + .await + { + eprintln!("Failed to fetch identity for asset lock: {}", e); } } } diff --git a/packages/rs-sdk-ffi/build_ios.sh b/packages/rs-sdk-ffi/build_ios.sh index 6a01b36ffac..5216bba567c 100755 --- a/packages/rs-sdk-ffi/build_ios.sh +++ b/packages/rs-sdk-ffi/build_ios.sh @@ -323,6 +323,7 @@ fi # Build dash-spv-ffi from local rust-dashcore for device and simulator RUST_DASHCORE_PATH="$PROJECT_ROOT/../rust-dashcore" SPV_CRATE_PATH="$RUST_DASHCORE_PATH/dash-spv-ffi" +SPV_TARGET_PATH="$RUST_DASHCORE_PATH/target" if [ -d "$SPV_CRATE_PATH" ]; then echo -e "${GREEN}Building dash-spv-ffi (local rust-dashcore)${NC}" pushd "$SPV_CRATE_PATH" >/dev/null @@ -377,11 +378,11 @@ if [ "$BUILD_ARCH" != "x86" ]; then mkdir -p "$OUTPUT_DIR/device" cp "$PROJECT_ROOT/target/aarch64-apple-ios/release/librs_sdk_ffi.a" "$OUTPUT_DIR/device/" # Merge with dash-spv-ffi device lib if available - if [ -f "$SPV_CRATE_PATH/target/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then + if [ -f "$SPV_TARGET_PATH/aarch64-apple-ios/release/libdash_spv_ffi.a" ]; then echo -e "${GREEN}Merging device libs (rs-sdk-ffi + dash-spv-ffi)${NC}" libtool -static -o "$OUTPUT_DIR/device/libDashSDKFFI_combined.a" \ "$OUTPUT_DIR/device/librs_sdk_ffi.a" \ - "$SPV_CRATE_PATH/target/aarch64-apple-ios/release/libdash_spv_ffi.a" + "$SPV_TARGET_PATH/aarch64-apple-ios/release/libdash_spv_ffi.a" COMBINED_DEVICE_LIB=1 fi fi @@ -445,10 +446,10 @@ fi if [ -f "$OUTPUT_DIR/simulator/librs_sdk_ffi.a" ]; then # Try to merge with SPV sim lib if it exists SIM_SPV_LIB="" - if [ -f "$SPV_CRATE_PATH/target/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then - SIM_SPV_LIB="$SPV_CRATE_PATH/target/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" - elif [ -f "$SPV_CRATE_PATH/target/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then - SIM_SPV_LIB="$SPV_CRATE_PATH/target/x86_64-apple-ios/release/libdash_spv_ffi.a" + if [ -f "$SPV_TARGET_PATH/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" ]; then + SIM_SPV_LIB="$SPV_TARGET_PATH/aarch64-apple-ios-sim/release/libdash_spv_ffi.a" + elif [ -f "$SPV_TARGET_PATH/x86_64-apple-ios/release/libdash_spv_ffi.a" ]; then + SIM_SPV_LIB="$SPV_TARGET_PATH/x86_64-apple-ios/release/libdash_spv_ffi.a" fi if [ -n "$SIM_SPV_LIB" ]; then echo -e "${GREEN}Merging simulator libs (rs-sdk-ffi + dash-spv-ffi)${NC}" diff --git a/packages/rs-sdk-ffi/src/dashpay/contact_request.rs b/packages/rs-sdk-ffi/src/dashpay/contact_request.rs index 8cfa2714dd7..71079e27c6f 100644 --- a/packages/rs-sdk-ffi/src/dashpay/contact_request.rs +++ b/packages/rs-sdk-ffi/src/dashpay/contact_request.rs @@ -69,7 +69,7 @@ async fn create_contact_request_with_private_key( .await } -async fn send_contact_request_with_shared_secret( +async fn send_contact_request_with_shared_secret>( sdk: &Sdk, send_input: SendContactRequestInput, shared_secret: [u8; 32], @@ -95,7 +95,7 @@ async fn send_contact_request_with_shared_secret( +async fn send_contact_request_with_private_key>( sdk: &Sdk, send_input: SendContactRequestInput, private_key: SecretKey, diff --git a/packages/rs-sdk-ffi/src/lib.rs b/packages/rs-sdk-ffi/src/lib.rs index b1bb2c9428f..f90fffea477 100644 --- a/packages/rs-sdk-ffi/src/lib.rs +++ b/packages/rs-sdk-ffi/src/lib.rs @@ -142,7 +142,6 @@ pub use platform_wallet_ffi::{ Handle, IdentifierArray, IdentifierBytes, - NetworkType, PlatformWalletFFIError, PlatformWalletFFIResult, NULL_HANDLE, diff --git a/packages/rs-sdk-ffi/src/platform_wallet_types.rs b/packages/rs-sdk-ffi/src/platform_wallet_types.rs index 6c08fb0558b..e6664cef2b7 100644 --- a/packages/rs-sdk-ffi/src/platform_wallet_types.rs +++ b/packages/rs-sdk-ffi/src/platform_wallet_types.rs @@ -1,6 +1,6 @@ // Re-export Platform Wallet FFI types for cbindgen to pick up pub use platform_wallet_ffi::{ - BlockTime, Handle, IdentifierArray, IdentifierBytes, NetworkType, PlatformWalletFFIError, + BlockTime, Handle, IdentifierArray, IdentifierBytes, PlatformWalletFFIError, PlatformWalletFFIResult, NULL_HANDLE, }; diff --git a/packages/rs-sdk-trusted-context-provider/src/provider.rs b/packages/rs-sdk-trusted-context-provider/src/provider.rs index 43e137400d5..2e54a84afc5 100644 --- a/packages/rs-sdk-trusted-context-provider/src/provider.rs +++ b/packages/rs-sdk-trusted-context-provider/src/provider.rs @@ -84,7 +84,7 @@ struct MasternodeDiscoveryResponse { impl TrustedHttpContextProvider { /// Verify that a URL's domain resolves - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(not(target_arch = "wasm32"), not(target_os = "ios")))] fn verify_domain_resolves(url: &str) -> Result<(), TrustedContextProviderError> { let parsed_url = Url::parse(url).map_err(|e| { TrustedContextProviderError::NetworkError(format!("Invalid URL: {}", e)) diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index b6990667d81..1ee37405777 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -152,6 +152,9 @@ core_key_wallet_bip38 = ["dpp/core_key_wallet_bip_38"] core_spv = ["dpp/core_spv"] core_rpc_client = ["dpp/core_rpc_client"] +# Platform wallet support +wallet = ["core_key_wallet_manager", "core_key_wallet",] + [[example]] name = "read_contract" diff --git a/packages/rs-sdk/src/platform/dashpay/contact_request.rs b/packages/rs-sdk/src/platform/dashpay/contact_request.rs index 5b3d8b8db4c..9c131977023 100644 --- a/packages/rs-sdk/src/platform/dashpay/contact_request.rs +++ b/packages/rs-sdk/src/platform/dashpay/contact_request.rs @@ -114,7 +114,7 @@ pub struct ContactRequestResult { } /// Input for sending a contact request to the platform -pub struct SendContactRequestInput { +pub struct SendContactRequestInput> { /// The contact request input data pub contact_request: ContactRequestInput, /// The identity public key to use for signing @@ -375,7 +375,7 @@ impl Sdk { /// Returns an error if: /// - Document creation fails (including ECDH encryption) /// - State transition submission fails - pub async fn send_contact_request( + pub async fn send_contact_request, F, Fut, G, Gut, H, Hut>( &self, input: SendContactRequestInput, ecdh_provider: EcdhProvider, diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift index 73d33dbe084..5d0612aa333 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Services/WalletService.swift @@ -210,7 +210,7 @@ public class WalletService: ObservableObject { private func currentDisplayBaseline() -> Int { let stored = Int(baseSyncHeightUI) if stored > 0 { return stored } - return Int(computeNetworkBaselineSyncFromHeight(for: currentNetwork)) + return Int(computeNetworkBaselineSyncFromHeight()) } private init() {} @@ -252,7 +252,7 @@ public class WalletService: ObservableObject { let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("SPV").path // Determine baseline from stored per-wallet per-network sync-from heights let baseline: UInt32 = await MainActor.run { - self.computeNetworkBaselineSyncFromHeight(for: net) + self.computeNetworkBaselineSyncFromHeight() } SDKLogger.log("[SPV][Baseline] Using baseline startFromHeight=\(baseline) on \(net.rawValue) during initialize()", minimumLevel: .high) @@ -331,7 +331,7 @@ public class WalletService: ObservableObject { // MARK: - Wallet Management - public func createWallet(label: String, mnemonic: String? = nil, pin: String = "1234", network: AppNetwork? = nil, networks: [AppNetwork]? = nil, isImport: Bool = false) async throws -> HDWallet { + public func createWallet(label: String, mnemonic: String? = nil, pin: String = "1234", isImport: Bool = false) async throws -> HDWallet { print("=== WalletService.createWallet START ===") print("Label: \(label)") print("Has mnemonic: \(mnemonic != nil)") @@ -347,14 +347,10 @@ public class WalletService: ObservableObject { do { // Create wallet using our refactored WalletManager that wraps FFI print("WalletManager available, creating wallet...") - let walletNetwork = network ?? currentNetwork - let dashNetwork = walletNetwork // Already a DashNetwork let wallet = try await walletManager.createWallet( label: label, - network: dashNetwork, mnemonic: mnemonic, pin: pin, - networks: networks, isImport: isImport ) @@ -370,27 +366,26 @@ public class WalletService: ObservableObject { let isImported = isImport if isImported { // Imported wallet: use fixed per-network baselines - wallet.syncFromMainnet = 730_000 - wallet.syncFromTestnet = 0 - wallet.syncFromDevnet = 0 + wallet.syncBaseHeight = currentNetwork == .mainnet ? 730_000 : 0; } else { - // New wallet: per selected network, use the latest checkpoint height of that chain - let nets = networks ?? [walletNetwork] - for n in nets { - switch n { - case .mainnet: - let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 0)) ?? 0 - print("[WalletService] New wallet baseline mainnet checkpoint=\(cp)") - wallet.syncFromMainnet = Int(cp) - case .testnet: - let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 1)) ?? 0 - print("[WalletService] New wallet baseline testnet checkpoint=\(cp)") - wallet.syncFromTestnet = Int(cp) - case .devnet: - let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 2)) ?? 0 - print("[WalletService] New wallet baseline devnet checkpoint=\(cp)") - wallet.syncFromDevnet = Int(cp) - } + // New wallet: use the latest checkpoint height of that chain + switch currentNetwork { + case .mainnet: + let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 0)) ?? 0 + print("[WalletService] New wallet baseline mainnet checkpoint=\(cp)") + wallet.syncBaseHeight = Int(cp) + case .testnet: + let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 1)) ?? 0 + print("[WalletService] New wallet baseline testnet checkpoint=\(cp)") + wallet.syncBaseHeight = Int(cp) + case .regtest: + let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 2)) ?? 0 + print("[WalletService] New wallet baseline regtest checkpoint=\(cp)") + wallet.syncBaseHeight = Int(cp) + case .devnet: + let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 3)) ?? 0 + print("[WalletService] New wallet baseline devnet checkpoint=\(cp)") + wallet.syncBaseHeight = Int(cp) } } @@ -474,12 +469,12 @@ public class WalletService: ObservableObject { } // Compute baseline from all wallets on the active network and apply before starting - let baseline: UInt32 = computeNetworkBaselineSyncFromHeight(for: currentNetwork) + let baseline: UInt32 = computeNetworkBaselineSyncFromHeight() do { try spvClient.setStartFromHeight(baseline) print("[SPV][Baseline] StartFromHeight applied=\(baseline) for \(currentNetwork.rawValue) before startSync()") // Also print per-wallet values for debugging - logPerWalletSyncFromHeights(for: currentNetwork) + logPerWalletSyncFromHeights() } catch { print("[SPV][Config] Failed to set StartFromHeight: \(error)") } @@ -543,7 +538,7 @@ public class WalletService: ObservableObject { client.stopSync() - let baseline = Int(computeNetworkBaselineSyncFromHeight(for: currentNetwork)) + let baseline = Int(computeNetworkBaselineSyncFromHeight()) let checkpoint = client.getLatestCheckpointHeight() let statsAfter = client.getStats() ?? statsBefore applyInitialSyncState( @@ -619,7 +614,7 @@ public class WalletService: ObservableObject { masternodeProgress = 0 transactionProgress = 0 - let baseline = Int(computeNetworkBaselineSyncFromHeight(for: currentNetwork)) + let baseline = Int(computeNetworkBaselineSyncFromHeight()) applyInitialSyncState(baseline: baseline, tip: nil, checkpoint: nil, snapshot: nil) latestHeaderHeight = 0 @@ -1060,33 +1055,22 @@ extension WalletService { /// Compute the baseline start-from height across all wallets enabled on the given network. /// Defaults: mainnet=730_000, testnet=0, devnet=0 when no wallets are present. @MainActor - func computeNetworkBaselineSyncFromHeight(for network: AppNetwork) -> UInt32 { + func computeNetworkBaselineSyncFromHeight() -> UInt32 { let defaults: [AppNetwork: Int] = [.mainnet: 730_000, .testnet: 0, .devnet: 0] guard let ctx = modelContainer?.mainContext else { - return UInt32(defaults[network] ?? 0) + return UInt32(defaults[currentNetwork] ?? 0) } let wallets: [HDWallet] = (try? ctx.fetch(FetchDescriptor())) ?? [] // Filter to wallets that include this network - let filtered = wallets.filter { w in - switch network { - case .mainnet: return (w.networks & 1) != 0 - case .testnet: return (w.networks & 2) != 0 - case .devnet: return (w.networks & 8) != 0 - } - } - let perWalletHeights: [Int] = filtered.map { w in - switch network { - case .mainnet: return max(0, w.syncFromMainnet) - case .testnet: return max(0, w.syncFromTestnet) - case .devnet: return max(0, w.syncFromDevnet) - } + let perWalletHeights: [Int] = wallets.map { w in + w.syncBaseHeight } if let minValue = perWalletHeights.min() { return UInt32(minValue) } - return UInt32(defaults[network] ?? 0) + return UInt32(defaults[currentNetwork] ?? 0) } /// Combine the persisted sync snapshot (if available) with the logical baseline so the UI reflects @@ -1214,23 +1198,14 @@ extension WalletService { /// Print a concise list of per-wallet sync-from heights for debugging purposes. @MainActor - func logPerWalletSyncFromHeights(for network: AppNetwork) { + func logPerWalletSyncFromHeights() { guard let ctx = modelContainer?.mainContext else { return } let wallets: [HDWallet] = (try? ctx.fetch(FetchDescriptor())) ?? [] let items: [(String, Int)] = wallets.compactMap { w in - // Show only wallets on this network - let enabled: Bool - let h: Int - switch network { - case .mainnet: enabled = (w.networks & 1) != 0; h = w.syncFromMainnet - case .testnet: enabled = (w.networks & 2) != 0; h = w.syncFromTestnet - case .devnet: enabled = (w.networks & 8) != 0; h = w.syncFromDevnet - } - guard enabled else { return nil } - return (w.id.uuidString.prefix(8).description, max(0, h)) + return (w.id.uuidString.prefix(8).description, max(0, w.syncBaseHeight)) } let summary = items.map { "\($0.0):\($0.1)" }.joined(separator: ", ") - print("[SPV][Baseline] Per-wallet sync-from heights for \(network.rawValue): [\(summary)]") + print("[SPV][Baseline] Per-wallet sync-from heights: [\(summary)]") } } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift index 735d93ad602..a2ccd23d35f 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/CoreWalletManager.swift @@ -56,7 +56,7 @@ public class CoreWalletManager: ObservableObject { } // MARK: - Wallet Management - func createWallet(label: String, network: AppNetwork, mnemonic: String? = nil, pin: String, networks: [AppNetwork]? = nil, isImport: Bool = false) async throws -> HDWallet { + func createWallet(label: String, mnemonic: String? = nil, pin: String, isImport: Bool = false) async throws -> HDWallet { print("WalletManager.createWallet called") isLoading = true defer { isLoading = false } @@ -85,28 +85,24 @@ public class CoreWalletManager: ObservableObject { let walletId: Data let serializedBytes: Data do { - let selectedNetworks = networks ?? [network] - let keyWalletNetworks = selectedNetworks.map { $0.toKeyWalletNetwork() } - // Calculate birthHeight based on wallet type // For imported wallets: use 730k for mainnet, 0 for test/devnets (need to sync from genesis) // For new wallets: use 0 to signal "use latest checkpoint" (FFI interprets 0 as None) let birthHeight: UInt32 if isImport { // Imported wallet should sync from a reasonable historical point - birthHeight = network == .mainnet ? 730_000 : 1 // Use 1 instead of 0 to avoid "latest checkpoint" interpretation + birthHeight = sdkWalletManager.network == .mainnet ? 730_000 : 1 // Use 1 instead of 0 to avoid "latest checkpoint" interpretation } else { // New wallet: pass 0 to use latest checkpoint (FFI converts 0 -> None -> latest) birthHeight = 0 } - print("Creating wallet with birthHeight: \(birthHeight) (isImport: \(isImport), network: \(network))") + print("Creating wallet with birthHeight: \(birthHeight) (isImport: \(isImport)") // Add wallet using SDK's WalletManager with combined network bitfield and serialize let result = try sdkWalletManager.addWalletAndSerialize( mnemonic: finalMnemonic, passphrase: nil, - networks: keyWalletNetworks, birthHeight: birthHeight, accountOptions: .default, downgradeToPublicKeyWallet: false, @@ -120,9 +116,10 @@ public class CoreWalletManager: ObservableObject { print("Failed to add wallet: \(error)") throw WalletError.walletError("Failed to add wallet: \(error.localizedDescription)") } - + // Create HDWallet model for SwiftUI - let wallet = HDWallet(label: label, network: network, isImported: isImport) + let appNetwork = AppNetwork(network: sdkWalletManager.network) + let wallet = HDWallet(label: label, network: appNetwork, isImported: isImport) wallet.walletId = walletId // Persist serialized wallet bytes for restoration on next launch @@ -147,44 +144,30 @@ public class CoreWalletManager: ObservableObject { // Sync complete wallet state from Rust managed info try await syncWalletFromManagedInfo(for: wallet) - // If multiple networks were specified, set the bitfield accordingly - if let networks = networks { - var bitfield: UInt32 = 0 - for n in networks { - switch n { - case .mainnet: bitfield |= 1 - case .testnet: bitfield |= 2 - case .devnet: bitfield |= 8 - } - } - wallet.networks = bitfield - } - // Set per-network sync-from heights // These are used by WalletService.computeNetworkBaselineSyncFromHeight() // to determine the SPV sync starting point across all wallets if isImport { // Imported wallet: use fixed per-network baselines - wallet.syncFromMainnet = 730_000 - wallet.syncFromTestnet = 1 // Use 1 instead of 0 to avoid conflicts - wallet.syncFromDevnet = 1 + wallet.syncBaseHeight = sdkWalletManager.network == .mainnet ? 730_000 : 1; } else { - // New wallet: use the latest checkpoint height for each enabled network - let nets = networks ?? [network] - for n in nets { - switch n { - case .mainnet: - if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 0)) { - wallet.syncFromMainnet = Int(cp) - } - case .testnet: - if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 1)) { - wallet.syncFromTestnet = Int(cp) - } - case .devnet: - if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 2)) { - wallet.syncFromDevnet = Int(cp) - } + // New wallet: use the latest checkpoint height + switch sdkWalletManager.network { + case .mainnet: + if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 0)) { + wallet.syncBaseHeight = Int(cp) + } + case .testnet: + if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 1)) { + wallet.syncBaseHeight = Int(cp) + } + case .devnet: + if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 2)) { + wallet.syncBaseHeight = Int(cp) + } + case .regtest: + if let cp = SPVClient.latestCheckpointHeight(forNetwork: .init(rawValue: 3)) { + wallet.syncBaseHeight = Int(cp) } } } @@ -199,7 +182,7 @@ public class CoreWalletManager: ObservableObject { } func importWallet(label: String, network: AppNetwork, mnemonic: String, pin: String) async throws -> HDWallet { - let wallet = try await createWallet(label: label, network: network, mnemonic: mnemonic, pin: pin) + let wallet = try await createWallet(label: label, mnemonic: mnemonic, pin: pin) wallet.isImported = true try modelContainer.mainContext.save() return wallet @@ -213,8 +196,7 @@ public class CoreWalletManager: ObservableObject { /// Sync wallet data using SwiftDashSDK wrappers (no direct FFI in app) private func syncWalletFromManagedInfo(for wallet: HDWallet) async throws { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let network = wallet.dashNetwork.toKeyWalletNetwork() - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: network) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) for account in wallet.accounts { if let managed = collection.getBIP44Account(at: account.accountNumber) { @@ -285,11 +267,12 @@ public class CoreWalletManager: ObservableObject { return try storage.retrieveSeedWithBiometric() } - func createWatchOnlyWallet(label: String, network: AppNetwork, extendedPublicKey: String) async throws -> HDWallet { + func createWatchOnlyWallet(label: String, extendedPublicKey: String) async throws -> HDWallet { isLoading = true defer { isLoading = false } - let wallet = HDWallet(label: label, network: network, isWatchOnly: true) + let appNetwork = AppNetwork(network: sdkWalletManager.network) + let wallet = HDWallet(label: label, network: appNetwork, isWatchOnly: true) // Create account with extended public key let account = wallet.createAccount(at: 0) @@ -332,12 +315,9 @@ public class CoreWalletManager: ObservableObject { throw WalletError.walletError("Wallet ID not available") } - let network = wallet.dashNetwork.toKeyWalletNetwork() - // Get managed account let managedAccount = try sdkWalletManager.getManagedAccount( walletId: walletId, - network: network, accountIndex: accountIndex, accountType: .standardBIP44 ) @@ -357,8 +337,7 @@ public class CoreWalletManager: ObservableObject { /// - Returns: Detailed account information public func getAccountDetails(for wallet: HDWallet, accountInfo: AccountInfo) async throws -> AccountDetailInfo { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let network = wallet.dashNetwork.toKeyWalletNetwork() - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: network) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) // Resolve managed account from category and optional index var managed: ManagedAccount? @@ -386,8 +365,10 @@ public class CoreWalletManager: ObservableObject { case .providerPlatformKeys: managed = collection.getProviderPlatformKeysAccount() } - - let derivationPath = derivationPath(for: accountInfo.category, index: accountInfo.index, network: wallet.dashNetwork) + + let appNetwork = AppNetwork(network: sdkWalletManager.network) + + let derivationPath = derivationPath(for: accountInfo.category, index: accountInfo.index, network: appNetwork) var externalDetails: [AddressDetail] = [] var internalDetails: [AddressDetail] = [] var ffiType = FFIAccountType(rawValue: 0) @@ -430,14 +411,13 @@ public class CoreWalletManager: ObservableObject { /// Derive a private key as WIF from seed using a specific path (deferred to SDK) public func derivePrivateKeyAsWIF(for wallet: HDWallet, accountInfo: AccountInfo, addressIndex: UInt32) async throws -> String { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let net = wallet.dashNetwork // Obtain a non-owning Wallet wrapper from manager - guard let sdkWallet = try sdkWalletManager.getWallet(id: walletId, network: net.toKeyWalletNetwork()) else { + guard let sdkWallet = try sdkWalletManager.getWallet(id: walletId) else { throw WalletError.walletError("Wallet not found in manager") } // Map category to AccountType and master path root - let coinType = (net == .testnet) ? "1'" : "5'" + let coinType = (sdkWalletManager.network == .testnet) ? "1'" : "5'" let mapping: (AccountType, UInt32, String)? = { switch accountInfo.category { case .providerVotingKeys: @@ -510,14 +490,12 @@ public class CoreWalletManager: ObservableObject { /// Get all accounts for a wallet from the FFI wallet manager /// - Parameters: /// - wallet: The wallet model - /// - network: Optional network override; defaults to wallet.dashNetwork /// - Returns: Account information including balances and address counts - public func getAccounts(for wallet: HDWallet, network: AppNetwork? = nil) async throws -> [AccountInfo] { + public func getAccounts(for wallet: HDWallet) async throws -> [AccountInfo] { guard let walletId = wallet.walletId else { throw WalletError.walletError("Wallet ID not available") } - let effectiveNetwork = (network ?? wallet.dashNetwork).toKeyWalletNetwork() let collection: ManagedAccountCollection do { - collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: effectiveNetwork) + collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) } catch let err as KeyWalletError { // If the managed wallet info isn't found (e.g., after fresh start), try restoring from serialized bytes if case .notFound = err, let bytes = wallet.serializedWalletBytes { @@ -525,7 +503,7 @@ public class CoreWalletManager: ObservableObject { let restoredId = try sdkWalletManager.importWallet(from: bytes) if wallet.walletId != restoredId { wallet.walletId = restoredId } // Retry once after import - collection = try sdkWalletManager.getManagedAccountCollection(walletId: wallet.walletId!, network: effectiveNetwork) + collection = try sdkWalletManager.getManagedAccountCollection(walletId: wallet.walletId!) } catch { throw err } @@ -686,7 +664,7 @@ public class CoreWalletManager: ObservableObject { // Get balance via SDK wrappers do { - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: wallet.dashNetwork.toKeyWalletNetwork()) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) if let managed = collection.getBIP44Account(at: account.accountNumber) { if let bal = try? managed.getBalance() { account.confirmedBalance = bal.confirmed @@ -704,10 +682,8 @@ public class CoreWalletManager: ObservableObject { func syncWalletStateFromRust(for wallet: HDWallet) async { guard let walletId = wallet.walletId else { return } - let network = wallet.dashNetwork.toKeyWalletNetwork() - do { - let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId, network: network) + let collection = try sdkWalletManager.getManagedAccountCollection(walletId: walletId) // Sync all accounts for account in wallet.accounts { @@ -776,20 +752,6 @@ public class CoreWalletManager: ObservableObject { // Restore each wallet to the FFI wallet manager for wallet in wallets { - // Migrate networks field if not set (for existing wallets) - if wallet.networks == 0 { - // Set networks based on the wallet's current network - switch wallet.dashNetwork { - case .mainnet: - wallet.networks = 1 << 0 // DASH_FLAG - case .testnet: - wallet.networks = 1 << 1 // TESTNET_FLAG - case .devnet: - wallet.networks = 8 // DEVNET - } - print("Migrated networks field for wallet '\(wallet.label)' to \(wallet.networks)") - } - if let walletBytes = wallet.serializedWalletBytes { do { // Restore wallet to FFI and update the wallet ID diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/HDWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/HDWallet.swift index 70c74f3e6ea..5f5b7e53ed8 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/HDWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/HDWallet.swift @@ -30,17 +30,11 @@ public final class HDWallet: HDWalletModels { // Sync progress (0.0 to 1.0) public var syncProgress: Double - - // Networks bitfield - tracks which networks this wallet is available on - // Uses FFINetworks values: DASH(mainnet)=1, TESTNET=2, DEVNET=8 - public var networks: UInt32 - // Per-network sync-from heights (absolute block heights) - // These indicate the starting block to sync from for each network. + // Network sync-from height (absolute block heights) + // This indicates the starting block to sync from. // 0 means start from genesis. - public var syncFromMainnet: Int = 0 - public var syncFromTestnet: Int = 0 - public var syncFromDevnet: Int = 0 + public var syncBaseHeight: Int = 0 init(label: String, network: AppNetwork, isWatchOnly: Bool = false, isImported: Bool = false) { self.id = UUID() @@ -53,20 +47,8 @@ public final class HDWallet: HDWalletModels { self.syncProgress = 0.0 self.isImported = isImported - // Initialize networks bitfield based on the initial network - switch network { - case .mainnet: - self.networks = 1 // DASH - case .testnet: - self.networks = 2 // TESTNET - case .devnet: - self.networks = 8 // DEVNET - } - - // Default sync-from values (will be overridden by WalletService on creation) - self.syncFromMainnet = 0 - self.syncFromTestnet = 0 - self.syncFromDevnet = 0 + // Default value (will be overridden by WalletService on creation) + self.syncBaseHeight = 0 } public var dashNetwork: AppNetwork { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/TransactionService.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/TransactionService.swift index b7cf6e975eb..4db33071d6c 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/TransactionService.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Core/Wallet/TransactionService.swift @@ -39,7 +39,7 @@ class TransactionService: ObservableObject { ) async throws -> BuiltTransaction { // Route to SDK transaction builder (stubbed for now) guard let wallet = walletManager.currentWallet else { throw TransactionError.invalidState } - let builder = SwiftDashSDK.SDKTransactionBuilder(network: wallet.dashNetwork.sdkNetwork, feePerKB: feePerKB) + let builder = SwiftDashSDK.SDKTransactionBuilder(feePerKB: feePerKB) // TODO: integrate coin selection + key derivation via SDK and add inputs/outputs _ = builder // silence unused throw TransactionError.notSupported("Transaction building is not yet wired to SwiftDashSDK") diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift index 40fa890a227..49c51242b91 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Account.swift @@ -30,7 +30,7 @@ public class Account { var error = FFIError() // Derive master extended private key for this account root let masterPtr = masterPath.withCString { pathCStr in - wallet_derive_extended_private_key(wallet.ffiHandle, wallet.network.ffiValue, pathCStr, &error) + wallet_derive_extended_private_key(wallet.ffiHandle, pathCStr, &error) } defer { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift index e1e51609fad..1bab94efa4a 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/KeyWalletTypes.swift @@ -3,32 +3,6 @@ import DashSDKFFI // MARK: - Network Types -/// Helper to create FFINetworks bitmap from multiple networks -public struct NetworkSet { - public let networks: Set - - public init(_ networks: KeyWalletNetwork...) { - self.networks = Set(networks) - } - - public init(_ networks: [KeyWalletNetwork]) { - self.networks = Set(networks) - } - - public var ffiNetworks: FFINetworks { - var bitmap: UInt32 = 0 - for network in networks { - switch network { - case .mainnet: bitmap |= (1 << 0) // DASH_FLAG - case .testnet: bitmap |= (1 << 1) // TESTNET_FLAG - case .regtest: bitmap |= (1 << 2) // REGTEST_FLAG - case .devnet: bitmap |= (1 << 3) // DEVNET_FLAG - } - } - return FFINetworks(rawValue: bitmap) - } -} - /// Network type for Dash networks public enum KeyWalletNetwork: UInt32 { case mainnet = 0 // DASH diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift index 6598c01b8f0..ade4ef9c613 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/ManagedWallet.swift @@ -4,13 +4,10 @@ import DashSDKFFI /// Swift wrapper for managed wallet with address pool management and transaction checking public class ManagedWallet { private let handle: UnsafeMutablePointer - private let network: KeyWalletNetwork /// Create a managed wallet wrapper from a regular wallet /// - Parameter wallet: The wallet to manage public init(wallet: Wallet) throws { - self.network = wallet.network - var error = FFIError() guard let managedPointer = wallet_create_managed_wallet(wallet.ffiHandle, &error) else { defer { @@ -43,7 +40,7 @@ public class ManagedWallet { } let addressPtr = managed_wallet_get_next_bip44_receive_address( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, &error) + infoHandle, wallet.ffiHandle, accountIndex, &error) defer { if error.message != nil { @@ -74,7 +71,7 @@ public class ManagedWallet { } let addressPtr = managed_wallet_get_next_bip44_change_address( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, &error) + infoHandle, wallet.ffiHandle, accountIndex, &error) defer { if error.message != nil { @@ -114,7 +111,7 @@ public class ManagedWallet { } let success = managed_wallet_get_bip_44_external_address_range( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, + infoHandle, wallet.ffiHandle, accountIndex, startIndex, endIndex, &addressesPtr, &count, &error) defer { @@ -162,7 +159,7 @@ public class ManagedWallet { } let success = managed_wallet_get_bip_44_internal_address_range( - infoHandle, wallet.ffiHandle, network.ffiValue, accountIndex, + infoHandle, wallet.ffiHandle, accountIndex, startIndex, endIndex, &addressesPtr, &count, &error) defer { @@ -202,7 +199,7 @@ public class ManagedWallet { var ffiInfo = FFIAddressPoolInfo() let success = managed_wallet_get_address_pool_info( - handle, network.ffiValue, accountType.ffiValue, accountIndex, + handle, accountType.ffiValue, accountIndex, poolType.ffiValue, &ffiInfo, &error) defer { @@ -229,7 +226,7 @@ public class ManagedWallet { var error = FFIError() let success = managed_wallet_set_gap_limit( - handle, network.ffiValue, accountType.ffiValue, accountIndex, + handle, accountType.ffiValue, accountIndex, poolType.ffiValue, gapLimit, &error) defer { @@ -257,7 +254,7 @@ public class ManagedWallet { var error = FFIError() let success = managed_wallet_generate_addresses_to_index( - handle, wallet.ffiHandle, network.ffiValue, accountType.ffiValue, + handle, wallet.ffiHandle, accountType.ffiValue, accountIndex, poolType.ffiValue, targetIndex, &error) defer { @@ -277,7 +274,7 @@ public class ManagedWallet { var error = FFIError() let success = address.withCString { addressCStr in - managed_wallet_mark_address_used(handle, network.ffiValue, addressCStr, &error) + managed_wallet_mark_address_used(handle, addressCStr, &error) } defer { @@ -320,14 +317,14 @@ public class ManagedWallet { let hashPtr = hashBytes.bindMemory(to: UInt8.self).baseAddress return managed_wallet_check_transaction( - handle, wallet.ffiHandle, network.ffiValue, + handle, wallet.ffiHandle, txPtr, transactionData.count, context.ffiValue, blockHeight, hashPtr, UInt64(timestamp), updateState, &result, &error) } } else { return managed_wallet_check_transaction( - handle, wallet.ffiHandle, network.ffiValue, + handle, wallet.ffiHandle, txPtr, transactionData.count, context.ffiValue, blockHeight, nil, UInt64(timestamp), updateState, &result, &error) @@ -396,7 +393,7 @@ public class ManagedWallet { var count: size_t = 0 let success = managed_wallet_get_utxos( - infoHandle, network.ffiValue, &utxosPtr, &count, &error) + infoHandle, &utxosPtr, &count, &error) defer { if error.message != nil { diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift index dea3b136737..90931f831ed 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Transaction.swift @@ -46,7 +46,6 @@ public class Transaction { let success = ffiOutputs.withUnsafeBufferPointer { outputsPtr in wallet_build_transaction( wallet.ffiHandle, - NetworkSet(wallet.network).ffiNetworks, accountIndex, outputsPtr.baseAddress, outputs.count, @@ -93,7 +92,6 @@ public class Transaction { let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress return wallet_sign_transaction( wallet.ffiHandle, - NetworkSet(wallet.network).ffiNetworks, txPtr, transactionData.count, &signedTxPtr, &signedLen, &error) } @@ -146,7 +144,6 @@ public class Transaction { return wallet_check_transaction( wallet.ffiHandle, - wallet.network.ffiValue, txPtr, transactionData.count, context.ffiValue, blockHeight, hashPtr, timestamp, updateState, &result, &error) @@ -154,7 +151,6 @@ public class Transaction { } else { return wallet_check_transaction( wallet.ffiHandle, - wallet.network.ffiValue, txPtr, transactionData.count, context.ffiValue, blockHeight, nil, timestamp, updateState, &result, &error) @@ -201,4 +197,4 @@ public class Transaction { return classification } -} \ No newline at end of file +} diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift index b79500dbd09..53e71635b89 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/Wallet.swift @@ -4,7 +4,6 @@ import DashSDKFFI /// Swift wrapper for a Dash wallet with HD key derivation public class Wallet { private let handle: UnsafeMutablePointer - internal let network: KeyWalletNetwork private let ownsHandle: Bool // MARK: - Static Methods @@ -33,7 +32,6 @@ public class Wallet { public init(mnemonic: String, passphrase: String? = nil, network: KeyWalletNetwork = .mainnet, accountOptions: AccountCreationOption = .default) throws { - self.network = network var error = FFIError() let walletPtr: UnsafeMutablePointer? @@ -50,7 +48,7 @@ public class Wallet { wallet_create_from_mnemonic_with_options( mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, + network.ffiValue, &options, &error ) @@ -59,7 +57,7 @@ public class Wallet { return wallet_create_from_mnemonic_with_options( mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, + network.ffiValue, &options, &error ) @@ -73,7 +71,7 @@ public class Wallet { wallet_create_from_mnemonic( mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, + network.ffiValue, &error ) } @@ -81,7 +79,7 @@ public class Wallet { return wallet_create_from_mnemonic( mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, + network.ffiValue, &error ) } @@ -109,7 +107,6 @@ public class Wallet { /// - accountOptions: Account creation options public init(seed: Data, network: KeyWalletNetwork = .mainnet, accountOptions: AccountCreationOption = .default) throws { - self.network = network self.ownsHandle = true var error = FFIError() @@ -121,7 +118,7 @@ public class Wallet { return wallet_create_from_seed_with_options( seedPtr, seed.count, - NetworkSet(network).ffiNetworks, + network.ffiValue, &options, &error ) @@ -129,7 +126,7 @@ public class Wallet { return wallet_create_from_seed( seedPtr, seed.count, - NetworkSet(network).ffiNetworks, + network.ffiValue, &error ) } @@ -153,14 +150,12 @@ public class Wallet { /// - xpub: The extended public key string /// - network: The network type public init(xpub: String, network: KeyWalletNetwork = .mainnet) throws { - self.network = network - // Create an empty wallet first (no accounts) var error = FFIError() var options = AccountCreationOption.noAccounts.toFFIOptions() // Create a random wallet with no accounts - let walletPtr = wallet_create_random_with_options(NetworkSet(network).ffiNetworks, &options, &error) + let walletPtr = wallet_create_random_with_options(network.ffiValue, &options, &error) defer { if error.message != nil { @@ -196,9 +191,9 @@ public class Wallet { if case .specificAccounts = accountOptions { var options = accountOptions.toFFIOptions() - walletPtr = wallet_create_random_with_options(NetworkSet(network).ffiNetworks, &options, &error) + walletPtr = wallet_create_random_with_options(network.ffiValue, &options, &error) } else { - walletPtr = wallet_create_random(NetworkSet(network).ffiNetworks, &error) + walletPtr = wallet_create_random(network.ffiValue, &error) } defer { @@ -219,7 +214,6 @@ public class Wallet { /// Private initializer for internal use (takes ownership) private init(handle: UnsafeMutablePointer, network: KeyWalletNetwork) { self.handle = handle - self.network = network self.ownsHandle = true } @@ -286,7 +280,7 @@ public class Wallet { /// - index: The account index /// - Returns: An account handle public func getAccount(type: AccountType, index: UInt32 = 0) throws -> Account { - let result = wallet_get_account(handle, network.ffiValue, index, type.ffiValue) + let result = wallet_get_account(handle, index, type.ffiValue) defer { if result.error_message != nil { @@ -312,7 +306,7 @@ public class Wallet { /// - Returns: An account handle public func getTopUpAccount(registrationIndex: UInt32) throws -> Account { let result = wallet_get_top_up_account_with_registration_index( - handle, network.ffiValue, registrationIndex) + handle, registrationIndex) defer { if result.error_message != nil { @@ -345,11 +339,11 @@ public class Wallet { if let xpub = xpub { result = xpub.withCString { xpubCStr in wallet_add_account_with_string_xpub( - handle, network.ffiValue, type.ffiValue, index, xpubCStr) + handle, type.ffiValue, index, xpubCStr) } } else { result = wallet_add_account( - handle, network.ffiValue, type.ffiValue, index) + handle, type.ffiValue, index) } defer { @@ -374,7 +368,7 @@ public class Wallet { /// Get the number of accounts in the wallet public var accountCount: UInt32 { var error = FFIError() - let count = wallet_get_account_count(handle, network.ffiValue, &error) + let count = wallet_get_account_count(handle, &error) defer { if error.message != nil { @@ -408,7 +402,7 @@ public class Wallet { /// - Returns: The extended public key string public func getAccountXpub(accountIndex: UInt32) throws -> String { var error = FFIError() - let xpubPtr = wallet_get_account_xpub(handle, network.ffiValue, accountIndex, &error) + let xpubPtr = wallet_get_account_xpub(handle, accountIndex, &error) defer { if error.message != nil { @@ -435,7 +429,7 @@ public class Wallet { } var error = FFIError() - let xprivPtr = wallet_get_account_xpriv(handle, network.ffiValue, accountIndex, &error) + let xprivPtr = wallet_get_account_xpriv(handle, accountIndex, &error) defer { if error.message != nil { @@ -463,7 +457,7 @@ public class Wallet { var error = FFIError() let wifPtr = path.withCString { pathCStr in - wallet_derive_private_key_as_wif(handle, network.ffiValue, pathCStr, &error) + wallet_derive_private_key_as_wif(handle, pathCStr, &error) } defer { @@ -488,7 +482,7 @@ public class Wallet { public func derivePublicKey(path: String) throws -> String { var error = FFIError() let hexPtr = path.withCString { pathCStr in - wallet_derive_public_key_as_hex(handle, network.ffiValue, pathCStr, &error) + wallet_derive_public_key_as_hex(handle, pathCStr, &error) } defer { @@ -515,11 +509,10 @@ public class Wallet { /// Get a collection of all accounts in this wallet /// - Parameter network: The network type /// - Returns: The account collection - public func getAccountCollection(network: KeyWalletNetwork? = nil) throws -> AccountCollection { - let targetNetwork = network ?? self.network + public func getAccountCollection() throws -> AccountCollection { var error = FFIError() - guard let collectionHandle = wallet_get_account_collection(handle, targetNetwork.ffiValue, &error) else { + guard let collectionHandle = wallet_get_account_collection(handle, &error) else { defer { if error.message != nil { error_message_free(error.message) @@ -534,9 +527,8 @@ public class Wallet { internal var ffiHandle: UnsafeMutablePointer { handle } // Non-owning initializer for wallets obtained from WalletManager - public init(nonOwningHandle handle: UnsafeRawPointer, network: KeyWalletNetwork) { + public init(nonOwningHandle handle: UnsafeRawPointer) { self.handle = UnsafeMutablePointer(mutating: handle.bindMemory(to: FFIWallet.self, capacity: 1)) - self.network = network self.ownsHandle = false } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift index 34aa3b1a367..01e0fa3df22 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/KeyWallet/WalletManager.swift @@ -4,13 +4,14 @@ import DashSDKFFI /// Swift wrapper for wallet manager that manages multiple wallets public class WalletManager { private let handle: UnsafeMutablePointer + internal let network: KeyWalletNetwork private let ownsHandle: Bool /// Create a new standalone wallet manager /// Note: Consider using init(fromSPVClient:) instead if you have an SPV client - public init() throws { + public init(network: KeyWalletNetwork = .mainnet,) throws { var error = FFIError() - guard let managerHandle = wallet_manager_create(&error) else { + guard let managerHandle = wallet_manager_create(network.ffiValue, &error) else { defer { if error.message != nil { error_message_free(error.message) @@ -20,6 +21,7 @@ public class WalletManager { } self.handle = managerHandle + self.network = network self.ownsHandle = true } @@ -30,14 +32,47 @@ public class WalletManager { throw KeyWalletError.walletError("Failed to get wallet manager from SPV client") } + var error = FFIError() + var network = FFINetwork(rawValue: 0) + wallet_manager_network(managerHandle, &error, &network); + + defer { + if error.message != nil { + error_message_free(error.message) + } + } + + // Check if there was an error + if error.code != FFIErrorCode(rawValue: 0) { + throw KeyWalletError(ffiError: error) + } + self.handle = managerHandle + self.network = KeyWalletNetwork(ffiNetwork: network) self.ownsHandle = true } /// Create a wallet manager wrapper from an existing handle (does not own the handle) /// - Parameter handle: The FFI wallet manager handle - internal init(handle: UnsafeMutablePointer) { + internal init(handle: UnsafeMutablePointer) throws { + + var error = FFIError() + var network = FFINetwork(rawValue: 0) + wallet_manager_network(handle, &error, &network); + + defer { + if error.message != nil { + error_message_free(error.message) + } + } + + // Check if there was an error + if error.code != FFIErrorCode(rawValue: 0) { + throw KeyWalletError(ffiError: error) + } + self.handle = handle + self.network = KeyWalletNetwork(ffiNetwork: network) self.ownsHandle = false } @@ -53,12 +88,10 @@ public class WalletManager { /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase - /// - network: The network type /// - accountOptions: Account creation options /// - Returns: The wallet ID @discardableResult public func addWallet(mnemonic: String, passphrase: String? = nil, - network: KeyWalletNetwork = .mainnet, accountOptions: AccountCreationOption = .default) throws -> Data { var error = FFIError() @@ -70,24 +103,24 @@ public class WalletManager { return passphrase.withCString { passphraseCStr in wallet_manager_add_wallet_from_mnemonic_with_options( handle, mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, &options, &error) + &options, &error) } } else { return wallet_manager_add_wallet_from_mnemonic_with_options( handle, mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, &options, &error) + &options, &error) } } else { if let passphrase = passphrase { return passphrase.withCString { passphraseCStr in wallet_manager_add_wallet_from_mnemonic( handle, mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, &error) + &error) } } else { return wallet_manager_add_wallet_from_mnemonic( handle, mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, &error) + &error) } } } @@ -105,62 +138,6 @@ public class WalletManager { // Get the wallet IDs to return the newly added wallet ID return try getWalletIds().last ?? Data() } - - /// Add a wallet from mnemonic for multiple networks (bitfield) - /// - Parameters: - /// - mnemonic: The mnemonic phrase - /// - passphrase: Optional BIP39 passphrase - /// - networks: Networks to enable for this wallet - /// - accountOptions: Account creation options - /// - Returns: The wallet ID - @discardableResult - public func addWallet(mnemonic: String, passphrase: String? = nil, - networks: [KeyWalletNetwork], - accountOptions: AccountCreationOption = .default) throws -> Data { - var error = FFIError() - let networkSet = NetworkSet(networks) - - let success = mnemonic.withCString { mnemonicCStr in - if case .specificAccounts = accountOptions { - var options = accountOptions.toFFIOptions() - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic_with_options( - handle, mnemonicCStr, passphraseCStr, - networkSet.ffiNetworks, &options, &error) - } - } else { - return wallet_manager_add_wallet_from_mnemonic_with_options( - handle, mnemonicCStr, nil, - networkSet.ffiNetworks, &options, &error) - } - } else { - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic( - handle, mnemonicCStr, passphraseCStr, - networkSet.ffiNetworks, &error) - } - } else { - return wallet_manager_add_wallet_from_mnemonic( - handle, mnemonicCStr, nil, - networkSet.ffiNetworks, &error) - } - } - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - } - - guard success else { - throw KeyWalletError(ffiError: error) - } - - return try getWalletIds().last ?? Data() - } /// Get all wallet IDs /// - Returns: Array of wallet IDs (32-byte Data objects) @@ -197,7 +174,7 @@ public class WalletManager { /// Get a wallet by ID /// - Parameter walletId: The wallet ID (32 bytes) /// - Returns: The wallet if found - public func getWallet(id walletId: Data, network: KeyWalletNetwork) throws -> Wallet? { + public func getWallet(id walletId: Data) throws -> Wallet? { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } @@ -218,7 +195,7 @@ public class WalletManager { throw KeyWalletError(ffiError: error) } // Wrap as non-owning wallet; the manager retains ownership - let wallet = Wallet(nonOwningHandle: UnsafeRawPointer(ptr), network: network) + let wallet = Wallet(nonOwningHandle: UnsafeRawPointer(ptr)) return wallet } @@ -248,11 +225,9 @@ public class WalletManager { /// Get next receive address for a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type /// - accountIndex: The account index /// - Returns: The next receive address - public func getReceiveAddress(walletId: Data, network: KeyWalletNetwork = .mainnet, - accountIndex: UInt32 = 0) throws -> String { + public func getReceiveAddress(walletId: Data, accountIndex: UInt32 = 0) throws -> String { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } @@ -291,7 +266,7 @@ public class WalletManager { // Now get the receive address let addressPtr = managed_wallet_get_next_bip44_receive_address( - managedInfo, wallet, network.ffiValue, accountIndex, &error) + managedInfo, wallet, accountIndex, &error) defer { if error.message != nil { @@ -312,11 +287,9 @@ public class WalletManager { /// Get next change address for a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type /// - accountIndex: The account index /// - Returns: The next change address - public func getChangeAddress(walletId: Data, network: KeyWalletNetwork = .mainnet, - accountIndex: UInt32 = 0) throws -> String { + public func getChangeAddress(walletId: Data, accountIndex: UInt32 = 0) throws -> String { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } @@ -355,7 +328,7 @@ public class WalletManager { // Now get the change address let addressPtr = managed_wallet_get_next_bip44_change_address( - managedInfo, wallet, network.ffiValue, accountIndex, &error) + managedInfo, wallet, accountIndex, &error) defer { if error.message != nil { @@ -412,13 +385,11 @@ public class WalletManager { /// Process a transaction through all wallets /// - Parameters: /// - transactionData: The transaction bytes - /// - network: The network type /// - contextDetails: Transaction context details /// - updateStateIfFound: Whether to update wallet state if transaction is relevant /// - Returns: True if transaction was relevant to at least one wallet @discardableResult public func processTransaction(_ transactionData: Data, - network: KeyWalletNetwork = .mainnet, contextDetails: TransactionContextDetails, updateStateIfFound: Bool = true) throws -> Bool { var error = FFIError() @@ -428,7 +399,7 @@ public class WalletManager { let txPtr = txBytes.bindMemory(to: UInt8.self).baseAddress return wallet_manager_process_transaction( handle, txPtr, transactionData.count, - network.ffiValue, &ffiContext, + &ffiContext, updateStateIfFound, &error) } @@ -450,11 +421,10 @@ public class WalletManager { /// Update the current block height for a network /// - Parameters: /// - height: The new block height - /// - network: The network type - public func updateHeight(_ height: UInt32, network: KeyWalletNetwork = .mainnet) throws { + public func updateHeight(_ height: UInt32) throws { var error = FFIError() - let success = wallet_manager_update_height(handle, network.ffiValue, height, &error) + let success = wallet_manager_update_height(handle, height, &error) defer { if error.message != nil { @@ -470,10 +440,10 @@ public class WalletManager { /// Get the current block height for a network /// - Parameter network: The network type /// - Returns: The current block height - public func currentHeight(network: KeyWalletNetwork = .mainnet) throws -> UInt32 { + public func currentHeight() throws -> UInt32 { var error = FFIError() - let height = wallet_manager_current_height(handle, network.ffiValue, &error) + let height = wallet_manager_current_height(handle, &error) defer { if error.message != nil { @@ -494,20 +464,17 @@ public class WalletManager { /// Get a managed account from a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type /// - accountIndex: The account index /// - accountType: The type of account to get /// - Returns: The managed account - public func getManagedAccount(walletId: Data, network: KeyWalletNetwork = .mainnet, - accountIndex: UInt32, accountType: AccountType) throws -> ManagedAccount { + public func getManagedAccount(walletId: Data, accountIndex: UInt32, accountType: AccountType) throws -> ManagedAccount { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } var result = walletId.withUnsafeBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress - return managed_wallet_get_account(handle, idPtr, network.ffiValue, - accountIndex, accountType.ffiValue) + return managed_wallet_get_account(handle, idPtr, accountIndex, accountType.ffiValue) } defer { @@ -527,11 +494,9 @@ public class WalletManager { /// Get a managed top-up account with a specific registration index /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type /// - registrationIndex: The registration index /// - Returns: The managed account - public func getManagedTopUpAccount(walletId: Data, network: KeyWalletNetwork = .mainnet, - registrationIndex: UInt32) throws -> ManagedAccount { + public func getManagedTopUpAccount(walletId: Data, registrationIndex: UInt32) throws -> ManagedAccount { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } @@ -539,7 +504,7 @@ public class WalletManager { var result = walletId.withUnsafeBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress return managed_wallet_get_top_up_account_with_registration_index( - handle, idPtr, network.ffiValue, registrationIndex) + handle, idPtr, registrationIndex) } defer { @@ -559,9 +524,8 @@ public class WalletManager { /// Get a collection of all managed accounts for a wallet /// - Parameters: /// - walletId: The wallet ID - /// - network: The network type /// - Returns: The managed account collection - public func getManagedAccountCollection(walletId: Data, network: KeyWalletNetwork = .mainnet) throws -> ManagedAccountCollection { + public func getManagedAccountCollection(walletId: Data) throws -> ManagedAccountCollection { guard walletId.count == 32 else { throw KeyWalletError.invalidInput("Wallet ID must be exactly 32 bytes") } @@ -570,7 +534,7 @@ public class WalletManager { let collectionHandle = walletId.withUnsafeBytes { idBytes in let idPtr = idBytes.bindMemory(to: UInt8.self).baseAddress - return managed_wallet_get_account_collection(handle, idPtr, network.ffiValue, &error) + return managed_wallet_get_account_collection(handle, idPtr, &error) } defer { @@ -594,7 +558,6 @@ public class WalletManager { /// - Parameters: /// - mnemonic: The mnemonic phrase /// - passphrase: Optional BIP39 passphrase - /// - network: The network type /// - birthHeight: Optional birth height for wallet /// - accountOptions: Account creation options /// - downgradeToPublicKeyWallet: If true, creates a watch-only or externally signable wallet @@ -603,7 +566,6 @@ public class WalletManager { public func addWalletAndSerialize( mnemonic: String, passphrase: String? = nil, - network: KeyWalletNetwork = .mainnet, birthHeight: UInt32 = 0, accountOptions: AccountCreationOption = .default, downgradeToPublicKeyWallet: Bool = false, @@ -623,7 +585,6 @@ public class WalletManager { handle, mnemonicCStr, passphraseCStr, - NetworkSet(network).ffiNetworks, birthHeight, &options, downgradeToPublicKeyWallet, @@ -639,7 +600,6 @@ public class WalletManager { handle, mnemonicCStr, nil, - NetworkSet(network).ffiNetworks, birthHeight, &options, downgradeToPublicKeyWallet, @@ -672,89 +632,6 @@ public class WalletManager { return (walletId: walletIdData, serializedWallet: serializedData) } - - /// Add a wallet from mnemonic for multiple networks and return serialized bytes - /// - Parameters: - /// - mnemonic: The mnemonic phrase - /// - passphrase: Optional BIP39 passphrase - /// - networks: Networks to enable for this wallet - /// - birthHeight: Optional birth height for wallet - /// - accountOptions: Account creation options - /// - downgradeToPublicKeyWallet: If true, creates a watch-only or externally signable wallet - /// - allowExternalSigning: If true AND downgradeToPublicKeyWallet is true, creates an externally signable wallet - /// - Returns: Tuple containing (walletId: Data, serializedWallet: Data) - public func addWalletAndSerialize( - mnemonic: String, - passphrase: String? = nil, - networks: [KeyWalletNetwork], - birthHeight: UInt32 = 0, - accountOptions: AccountCreationOption = .default, - downgradeToPublicKeyWallet: Bool = false, - allowExternalSigning: Bool = false - ) throws -> (walletId: Data, serializedWallet: Data) { - var error = FFIError() - var walletBytesPtr: UnsafeMutablePointer? - var walletBytesLen: size_t = 0 - var walletId = [UInt8](repeating: 0, count: 32) - - let networkSet = NetworkSet(networks) - - let success = mnemonic.withCString { mnemonicCStr in - var options = accountOptions.toFFIOptions() - - if let passphrase = passphrase { - return passphrase.withCString { passphraseCStr in - wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( - handle, - mnemonicCStr, - passphraseCStr, - networkSet.ffiNetworks, - birthHeight, - &options, - downgradeToPublicKeyWallet, - allowExternalSigning, - &walletBytesPtr, - &walletBytesLen, - &walletId, - &error - ) - } - } else { - return wallet_manager_add_wallet_from_mnemonic_return_serialized_bytes( - handle, - mnemonicCStr, - nil, - networkSet.ffiNetworks, - birthHeight, - &options, - downgradeToPublicKeyWallet, - allowExternalSigning, - &walletBytesPtr, - &walletBytesLen, - &walletId, - &error - ) - } - } - - defer { - if error.message != nil { - error_message_free(error.message) - } - if let ptr = walletBytesPtr { - wallet_manager_free_wallet_bytes(ptr, walletBytesLen) - } - } - - guard success, let bytesPtr = walletBytesPtr else { - throw KeyWalletError(ffiError: error) - } - - let serializedData = Data(bytes: bytesPtr, count: Int(walletBytesLen)) - let walletIdData = Data(walletId) - - return (walletId: walletIdData, serializedWallet: serializedData) - } /// Import a wallet from serialized bytes /// - Parameters: diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Models/Network.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Models/Network.swift index 5b6c99521c2..dee0dc14593 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Models/Network.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Models/Network.swift @@ -4,7 +4,18 @@ import Foundation public enum AppNetwork: String, CaseIterable, Codable, Sendable { case mainnet = "mainnet" case testnet = "testnet" + case regtest = "regtest" case devnet = "devnet" + + init(network: KeyWalletNetwork) { + switch network { + case .mainnet: self = .mainnet // Dash = 0 + case .testnet: self = .testnet // Testnet = 1 + case .regtest: self = .regtest // Regtest = 2 + case .devnet: self = .devnet // Devnet = 3 + default: self = .mainnet + } + } public var displayName: String { switch self { @@ -12,6 +23,8 @@ public enum AppNetwork: String, CaseIterable, Codable, Sendable { return "Mainnet" case .testnet: return "Testnet" + case .regtest: + return "Regtest" case .devnet: return "Devnet" } @@ -23,6 +36,8 @@ public enum AppNetwork: String, CaseIterable, Codable, Sendable { return DashSDKNetwork(rawValue: 0) case .testnet: return DashSDKNetwork(rawValue: 1) + case .regtest: + return DashSDKNetwork(rawValue: 2) case .devnet: return DashSDKNetwork(rawValue: 3) } @@ -39,6 +54,8 @@ public enum AppNetwork: String, CaseIterable, Codable, Sendable { return .mainnet case .testnet: return .testnet + case .regtest: + return .regtest case .devnet: return .devnet } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift b/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift index 515a995cca6..7d7e69c2df4 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/SPV/SPVClient.swift @@ -19,7 +19,8 @@ extension SPVClient { @MainActor public static func initializeLogging(_ level: SPVLogLevel) { level.rawValue.withCString { cstr in - _ = dash_spv_ffi_init_logging(cstr) + // TODO: provide valid log directory? + _ = dash_spv_ffi_init_logging(cstr, false, nil, 10) } LogInitState.manualInitialized = true } @@ -288,7 +289,8 @@ public class SPVClient: ObservableObject { if !LogInitState.manualInitialized { let level = (ProcessInfo.processInfo.environment["SPV_LOG"] ?? "off") _ = level.withCString { cstr in - dash_spv_ffi_init_logging(cstr) + // TODO: Provide valid log directory? + dash_spv_ffi_init_logging(cstr, false, nil, 10) } } if swiftLoggingEnabled { @@ -494,16 +496,17 @@ public class SPVClient: ObservableObject { /// Clear only the persisted sync-state snapshot while keeping headers/filters. public func clearSyncState() throws { guard let client = client else { throw SPVError.notInitialized } - - let rc = dash_spv_ffi_client_clear_sync_state(client) - if rc != 0 { - if let errorMsg = dash_spv_ffi_get_last_error() { - let message = String(cString: errorMsg) - throw SPVError.storageOperationFailed(message) - } else { - throw SPVError.storageOperationFailed("Failed to clear sync state (code \(rc))") - } - } + + // TODO: clear sync state doesnt exist anymore. Is it needed? Maybe wipe the directory? +// let rc = dash_spv_ffi_client_clear_sync_state(client) +// if rc != 0 { +// if let errorMsg = dash_spv_ffi_get_last_error() { +// let message = String(cString: errorMsg) +// throw SPVError.storageOperationFailed(message) +// } else { +// throw SPVError.storageOperationFailed("Failed to clear sync state (code \(rc))") +// } +// } self.syncProgress = nil self.lastError = nil @@ -989,6 +992,7 @@ public class SPVClient: ObservableObject { switch network.rawValue { case 0: ffiNet = FFINetwork(rawValue: 0) case 1: ffiNet = FFINetwork(rawValue: 1) + case 2: ffiNet = FFINetwork(rawValue: 2) case 3: ffiNet = FFINetwork(rawValue: 3) default: ffiNet = FFINetwork(rawValue: 1) } @@ -1009,6 +1013,7 @@ public class SPVClient: ObservableObject { switch net.rawValue { case 0: ffiNet = FFINetwork(rawValue: 0) case 1: ffiNet = FFINetwork(rawValue: 1) + case 2: ffiNet = FFINetwork(rawValue: 2) case 3: ffiNet = FFINetwork(rawValue: 3) default: ffiNet = FFINetwork(rawValue: 1) } @@ -1028,6 +1033,7 @@ public class SPVClient: ObservableObject { switch network.rawValue { case 0: ffiNet = FFINetwork(rawValue: 0) case 1: ffiNet = FFINetwork(rawValue: 1) + case 2: ffiNet = FFINetwork(rawValue: 2) case 3: ffiNet = FFINetwork(rawValue: 3) default: ffiNet = FFINetwork(rawValue: 1) } diff --git a/packages/swift-sdk/Sources/SwiftDashSDK/Tx/TransactionBuilder.swift b/packages/swift-sdk/Sources/SwiftDashSDK/Tx/TransactionBuilder.swift index abf8e5ce92a..34c039ddc05 100644 --- a/packages/swift-sdk/Sources/SwiftDashSDK/Tx/TransactionBuilder.swift +++ b/packages/swift-sdk/Sources/SwiftDashSDK/Tx/TransactionBuilder.swift @@ -25,14 +25,12 @@ public final class SDKTransactionBuilder { } } - private let network: Network private let feePerKB: UInt64 private var inputs: [Input] = [] private var outputs: [Output] = [] private var changeAddress: String? - public init(network: Network, feePerKB: UInt64 = 1000) { - self.network = network + public init(feePerKB: UInt64 = 1000) { self.feePerKB = feePerKB } diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift index a490d0221ff..de64e0142bd 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CoreContentView.swift @@ -11,24 +11,7 @@ struct CoreContentView: View { // Filter wallets by current network - show wallets that support the current network private var walletsForCurrentNetwork: [HDWallet] { - let currentNetwork = unifiedAppState.platformState.currentNetwork - // No conversion needed, just use currentNetwork directly - - // Check if wallet supports the current network using the networks bitfield - let networkBit: UInt32 - switch currentNetwork { - case .mainnet: - networkBit = 1 // DASH - case .testnet: - networkBit = 2 // TESTNET - case .devnet: - networkBit = 8 // DEVNET - } - - return wallets.filter { wallet in - // Check if the wallet has this network enabled in its bitfield - (wallet.networks & networkBit) != 0 - } + return wallets } // Progress values come from WalletService (kept in sync with SPV callbacks) @@ -401,16 +384,7 @@ struct WalletRowView: View { private func getNetworksList() -> String { var networks: [String] = [] - // Check each network bit - if (wallet.networks & 1) != 0 { - networks.append("Mainnet") - } - if (wallet.networks & 2) != 0 { - networks.append("Testnet") - } - if (wallet.networks & 8) != 0 { - networks.append("Devnet") - } + // TODO: This is probably not needed anymore? // If no networks set (shouldn't happen after migration), show the original network if networks.isEmpty { diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CreateWalletView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CreateWalletView.swift index dcaccc8ee93..9a21af0c9f2 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CreateWalletView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CreateWalletView.swift @@ -24,6 +24,7 @@ struct CreateWalletView: View { // Network selection states @State private var createForMainnet: Bool = false @State private var createForTestnet: Bool = false + @State private var createForRegtest: Bool = false @State private var createForDevnet: Bool = false enum Field: Hashable { @@ -230,6 +231,8 @@ struct CreateWalletView: View { createForMainnet = true case .testnet: createForTestnet = true + case .regtest: + createForRegtest = true case .devnet: createForDevnet = true } @@ -284,21 +287,14 @@ struct CreateWalletView: View { } // Create exactly one wallet in the SDK; do not append network to label - let wallet = try await walletService.createWallet( + let _ = try await walletService.createWallet( label: walletLabel, mnemonic: mnemonic, pin: walletPin, - network: primaryNetwork, - networks: selectedNetworks, isImport: showImportOption ) // Update wallet.networks bitfield to reflect all user selections - var networksBitfield: UInt32 = 0 - if createForMainnet { networksBitfield |= 1 } - if createForTestnet { networksBitfield |= 2 } - if createForDevnet && shouldShowDevnet { networksBitfield |= 8 } - wallet.networks = networksBitfield try? modelContext.save() print("=== WALLET CREATION SUCCESS - Created 1 wallet for \(primaryNetwork.displayName) ===") diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift index c40fc7df349..8b63562e1e7 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/WalletDetailView.swift @@ -160,6 +160,7 @@ struct WalletInfoView: View { @State private var isEditingName = false @State private var mainnetEnabled: Bool = false @State private var testnetEnabled: Bool = false + @State private var regtestEnabled: Bool = false @State private var devnetEnabled: Bool = false @State private var isUpdatingNetworks = false @State private var errorMessage: String? @@ -324,7 +325,7 @@ struct WalletInfoView: View { HStack { Text("Mainnet") Spacer() - Text(formatHeight(wallet.syncFromMainnet)) + Text(formatHeight(wallet.syncBaseHeight)) .foregroundColor(.secondary) } } @@ -332,7 +333,7 @@ struct WalletInfoView: View { HStack { Text("Testnet") Spacer() - Text(formatHeight(wallet.syncFromTestnet)) + Text(formatHeight(wallet.syncBaseHeight)) .foregroundColor(.secondary) } } @@ -340,7 +341,7 @@ struct WalletInfoView: View { HStack { Text("Devnet") Spacer() - Text(formatHeight(wallet.syncFromDevnet)) + Text(formatHeight(wallet.syncBaseHeight)) .foregroundColor(.secondary) } } @@ -404,29 +405,37 @@ struct WalletInfoView: View { } private func loadNetworkStates() { - // Check which networks this wallet is on - let networks = wallet.networks - mainnetEnabled = (networks & 1) != 0 // DASH - testnetEnabled = (networks & 2) != 0 // TESTNET - devnetEnabled = (networks & 8) != 0 // DEVNET + // TODO: Probably not needed this way anymore? + switch wallet.dashNetwork { + case .mainnet: + mainnetEnabled = true + case .testnet: + testnetEnabled = true + case .regtest: + // TODO: Handle this properly in the UI or somehow ignore it. + regtestEnabled = true + case .devnet: + devnetEnabled = true + } } private func loadAccountCounts() async { + // TODO: This can probably be refactored now with with single network manager? guard let manager = walletService.walletManager else { return } if mainnetEnabled { - if let list = try? await manager.getAccounts(for: wallet, network: .mainnet) { + if let list = try? await manager.getAccounts(for: wallet) { mainnetAccountCount = list.count } } else { mainnetAccountCount = nil } if testnetEnabled { - if let list = try? await manager.getAccounts(for: wallet, network: .testnet) { + if let list = try? await manager.getAccounts(for: wallet) { testnetAccountCount = list.count } } else { testnetAccountCount = nil } if devnetEnabled { - if let list = try? await manager.getAccounts(for: wallet, network: .devnet) { + if let list = try? await manager.getAccounts(for: wallet) { devnetAccountCount = list.count } } else { devnetAccountCount = nil } @@ -455,19 +464,8 @@ struct WalletInfoView: View { defer { isUpdatingNetworks = false } do { - // Add the network to the wallet - let networkBit: UInt32 - switch network { - case .mainnet: - networkBit = 1 // DASH - case .testnet: - networkBit = 2 // TESTNET - case .devnet: - networkBit = 8 // DEVNET - } - // Update the wallet's networks bitfield - wallet.networks = wallet.networks | networkBit + // TODO: This needs some love after single wallet refactoring. // Save to Core Data try modelContext.save() diff --git a/packages/swift-sdk/build_ios.sh b/packages/swift-sdk/build_ios.sh index 84454aa8232..c0052268910 100755 --- a/packages/swift-sdk/build_ios.sh +++ b/packages/swift-sdk/build_ios.sh @@ -33,12 +33,16 @@ rm -rf "$DEST_XCFRAMEWORK_DIR" cp -R "$SRC_XCFRAMEWORK_DIR" "$DEST_XCFRAMEWORK_DIR" # Verify required SPV symbols are present in the binary -LIB_SIM_MAIN="$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/librs_sdk_ffi.a" -LIB_SIM_SPV="$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/libdash_spv_ffi.a" -if [[ ! -f "$LIB_SIM_MAIN" ]]; then - echo "❌ Missing simulator library at $LIB_SIM_MAIN" +# Look for combined lib first (merged with SPV), then fallback to standalone +if [[ -f "$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/libDashSDKFFI_combined.a" ]]; then + LIB_SIM_MAIN="$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/libDashSDKFFI_combined.a" +elif [[ -f "$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/librs_sdk_ffi.a" ]]; then + LIB_SIM_MAIN="$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/librs_sdk_ffi.a" +else + echo "❌ Missing simulator library in $DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/" exit 1 fi +LIB_SIM_SPV="$DEST_XCFRAMEWORK_DIR/ios-arm64-simulator/libdash_spv_ffi.a" echo " - Verifying required SPV symbols are present in XCFramework libs" # Prefer ripgrep if available; fall back to grep for portability # Avoid -q with pipefail, which can cause nm to SIGPIPE and fail the check. @@ -49,23 +53,26 @@ else fi CHECK_OK=1 -if nm -gU "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then +# Use nm -g (global symbols) and grep. Disable pipefail for this check to avoid SIGPIPE issues with large archives. +set +o pipefail +if nm -g "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then : -elif [[ -f "$LIB_SIM_SPV" ]] && nm -gU "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then +elif [[ -f "$LIB_SIM_SPV" ]] && nm -g "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_add_peer" >/dev/null; then : else echo "❌ Missing symbol: dash_spv_ffi_config_add_peer (in both main and spv libs)" CHECK_OK=0 fi -if nm -gU "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then +if nm -g "$LIB_SIM_MAIN" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then : -elif [[ -f "$LIB_SIM_SPV" ]] && nm -gU "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then +elif [[ -f "$LIB_SIM_SPV" ]] && nm -g "$LIB_SIM_SPV" 2>/dev/null | "${SEARCH_CMD[@]}" "_dash_spv_ffi_config_set_restrict_to_configured_peers" >/dev/null; then : else echo "❌ Missing symbol: dash_spv_ffi_config_set_restrict_to_configured_peers (in both main and spv libs)" CHECK_OK=0 fi +set -o pipefail if [[ $CHECK_OK -ne 1 ]]; then echo " Please ensure dash-spv-ffi exports these symbols and is included in the XCFramework." @@ -78,7 +85,7 @@ if command -v xcodebuild >/dev/null 2>&1; then xcodebuild -project "$SCRIPT_DIR/SwiftExampleApp/SwiftExampleApp.xcodeproj" \ -scheme SwiftExampleApp \ -sdk iphonesimulator \ - -destination 'platform=iOS Simulator,name=iPhone 16' \ + -destination 'platform=iOS Simulator,name=iPhone 17' \ -quiet build XC_STATUS=$? set -e