diff --git a/src/app.rs b/src/app.rs index c11d96189..5b43ca033 100644 --- a/src/app.rs +++ b/src/app.rs @@ -165,20 +165,15 @@ impl BitOrAssign for AppAction { } } impl AppState { - pub fn new(ctx: egui::Context) -> Self { - create_app_user_data_directory_if_not_exists() - .expect("Failed to create app user_data directory"); + pub fn new(ctx: egui::Context) -> Result> { + create_app_user_data_directory_if_not_exists()?; copy_env_file_if_not_exists(); initialize_logger(); - let db_file_path = app_user_data_file_path("data.db").expect("should create db file path"); - let db = Arc::new(Database::new(&db_file_path).unwrap()); - db.initialize(&db_file_path).unwrap(); + let db_file_path = app_user_data_file_path("data.db")?; + let db = Arc::new(Database::new(&db_file_path)?); + db.initialize(&db_file_path)?; - let settings = db - .get_settings() - .expect("expected to get settings") - .map(Settings::from) - .unwrap_or_default(); + let settings = db.get_settings()?.map(Settings::from).unwrap_or_default(); let password_info = settings.password_info; let theme_preference = settings.theme_mode; let overwrite_dash_conf = settings.overwrite_dash_conf; @@ -186,21 +181,14 @@ impl AppState { let subtasks = Arc::new(TaskManager::new()); let connection_status = Arc::new(ConnectionStatus::new()); - let mainnet_app_context = match AppContext::new( + let mainnet_app_context = AppContext::new( Network::Dash, db.clone(), password_info.clone(), subtasks.clone(), connection_status.clone(), - ) { - Some(context) => context, - None => { - tracing::error!( - "Failed to create the AppContext. Expected Dash config for mainnet." - ); - std::process::exit(1); - } - }; + ) + .ok_or("Failed to create AppContext for mainnet. Check your Dash configuration.")?; let testnet_app_context = AppContext::new( Network::Testnet, db.clone(), @@ -279,7 +267,38 @@ impl AppState { let mut wallets_balances_screen = WalletsBalancesScreen::new(&mainnet_app_context); let selected_main_screen = settings.root_screen_type; - let chosen_network = settings.network; + // Validate that the saved network has an available context. + // We fail fast instead of silently routing user actions to a different network. + let chosen_network = match settings.network { + Network::Dash => Network::Dash, + Network::Testnet => { + assert!( + testnet_app_context.is_some(), + "Saved network is Testnet but no Testnet AppContext is configured" + ); + Network::Testnet + } + Network::Devnet => { + assert!( + devnet_app_context.is_some(), + "Saved network is Devnet but no Devnet AppContext is configured" + ); + Network::Devnet + } + Network::Regtest => { + assert!( + local_app_context.is_some(), + "Saved network is Regtest but no Regtest AppContext is configured" + ); + Network::Regtest + } + unsupported_network => { + panic!( + "Saved network {:?} is unsupported. Refusing automatic fallback.", + unsupported_network + ); + } + }; network_chooser_screen.current_network = chosen_network; if let (Network::Testnet, Some(testnet_app_context)) = @@ -411,15 +430,21 @@ impl AppState { .map(|s| s.disable_zmq) .unwrap_or(false); let mainnet_core_zmq_listener = if !mainnet_disable_zmq { - Some( - CoreZMQListener::spawn_listener( - Network::Dash, - &mainnet_core_zmq_endpoint, - core_message_sender.clone(), // Clone the sender for each listener - Some(mainnet_app_context.sx_zmq_status.clone()), - ) - .expect("Failed to create mainnet InstantSend listener"), - ) + match CoreZMQListener::spawn_listener( + Network::Dash, + &mainnet_core_zmq_endpoint, + core_message_sender.clone(), + Some(mainnet_app_context.sx_zmq_status.clone()), + ) { + Ok(listener) => Some(listener), + Err(e) => { + tracing::error!( + "Failed to create mainnet ZMQ listener: {}. ZMQ features will be unavailable for mainnet.", + e + ); + None + } + } } else { None }; @@ -438,15 +463,21 @@ impl AppState { .map(|s| s.disable_zmq) .unwrap_or(false); let testnet_core_zmq_listener = if !testnet_disable_zmq { - Some( - CoreZMQListener::spawn_listener( - Network::Testnet, - &testnet_core_zmq_endpoint, - core_message_sender.clone(), // Use the original sender or create a new one if needed - testnet_tx_zmq_status_option, - ) - .expect("Failed to create testnet InstantSend listener"), - ) + match CoreZMQListener::spawn_listener( + Network::Testnet, + &testnet_core_zmq_endpoint, + core_message_sender.clone(), + testnet_tx_zmq_status_option, + ) { + Ok(listener) => Some(listener), + Err(e) => { + tracing::error!( + "Failed to create testnet ZMQ listener: {}. ZMQ features will be unavailable for testnet.", + e + ); + None + } + } } else { None }; @@ -465,15 +496,21 @@ impl AppState { .map(|s| s.disable_zmq) .unwrap_or(false); let devnet_core_zmq_listener = if !devnet_disable_zmq { - Some( - CoreZMQListener::spawn_listener( - Network::Devnet, - &devnet_core_zmq_endpoint, - core_message_sender.clone(), - devnet_tx_zmq_status_option, - ) - .expect("Failed to create devnet InstantSend listener"), - ) + match CoreZMQListener::spawn_listener( + Network::Devnet, + &devnet_core_zmq_endpoint, + core_message_sender.clone(), + devnet_tx_zmq_status_option, + ) { + Ok(listener) => Some(listener), + Err(e) => { + tracing::error!( + "Failed to create devnet ZMQ listener: {}. ZMQ features will be unavailable for devnet.", + e + ); + None + } + } } else { None }; @@ -492,15 +529,21 @@ impl AppState { .map(|s| s.disable_zmq) .unwrap_or(false); let local_core_zmq_listener = if !local_disable_zmq { - Some( - CoreZMQListener::spawn_listener( - Network::Regtest, - &local_core_zmq_endpoint, - core_message_sender, - local_tx_zmq_status_option, - ) - .expect("Failed to create local InstantSend listener"), - ) + match CoreZMQListener::spawn_listener( + Network::Regtest, + &local_core_zmq_endpoint, + core_message_sender, + local_tx_zmq_status_option, + ) { + Ok(listener) => Some(listener), + Err(e) => { + tracing::error!( + "Failed to create local ZMQ listener: {}. ZMQ features will be unavailable for local/regtest.", + e + ); + None + } + } } else { None }; @@ -662,7 +705,7 @@ impl AppState { } } - app_state + Ok(app_state) } /// Allows enabling or disabling animations globally for the app. @@ -684,15 +727,53 @@ impl AppState { } pub fn current_app_context(&self) -> &Arc { + // Invariant: chosen_network must always have a corresponding context. + // Fail fast on violations to avoid silently routing operations to mainnet. match self.chosen_network { Network::Dash => &self.mainnet_app_context, - Network::Testnet => self.testnet_app_context.as_ref().expect("expected testnet"), - Network::Devnet => self.devnet_app_context.as_ref().expect("expected devnet"), - Network::Regtest => self.local_app_context.as_ref().expect("expected local"), - _ => todo!(), + Network::Testnet => self.testnet_app_context.as_ref().unwrap_or_else(|| { + panic!( + "BUG: chosen network is Testnet but testnet_app_context is missing; refusing silent mainnet fallback" + ) + }), + Network::Devnet => self.devnet_app_context.as_ref().unwrap_or_else(|| { + panic!( + "BUG: chosen network is Devnet but devnet_app_context is missing; refusing silent mainnet fallback" + ) + }), + Network::Regtest => self.local_app_context.as_ref().unwrap_or_else(|| { + panic!( + "BUG: chosen network is Regtest but local_app_context is missing; refusing silent mainnet fallback" + ) + }), + unsupported_network => panic!( + "BUG: unsupported network variant {:?} in current_app_context; refusing silent mainnet fallback", + unsupported_network + ), } } + fn context_available_for_network(&self, network: Network) -> bool { + match network { + Network::Dash => true, // Mainnet is always available + Network::Testnet => self.testnet_app_context.is_some(), + Network::Devnet => self.devnet_app_context.is_some(), + Network::Regtest => self.local_app_context.is_some(), + _ => false, + } + } + + fn enforce_network_context_invariant(&mut self) { + if self.context_available_for_network(self.chosen_network) { + return; + } + + panic!( + "BUG: selected network {:?} has no AppContext. Refusing to auto-switch networks.", + self.chosen_network + ); + } + // Handle the backend task and send the result through the channel fn handle_backend_task(&self, task: BackendTask) { let sender = self.task_result_sender.clone(); @@ -742,6 +823,14 @@ impl AppState { } pub fn change_network(&mut self, network: Network) { + if !self.context_available_for_network(network) { + tracing::error!( + "Cannot switch to {:?}: network context not available. Staying on current network.", + network + ); + return; + } + self.chosen_network = network; let app_context = self.current_app_context().clone(); @@ -802,6 +891,7 @@ impl App for AppState { // Apply Dash theme with user preference crate::ui::theme::apply_theme(ctx, self.theme_preference); + self.enforce_network_context_invariant(); let active_context = self.current_app_context().clone(); // Poll the receiver for any new task results diff --git a/src/app_dir.rs b/src/app_dir.rs index c9bd54acd..d623679c9 100644 --- a/src/app_dir.rs +++ b/src/app_dir.rs @@ -52,15 +52,20 @@ pub fn core_cookie_path( network: Network, devnet_name: &Option, ) -> Result { - core_user_data_dir_path().map(|path| { + core_user_data_dir_path().and_then(|path| { let network_dir = match network { Network::Dash => "", Network::Testnet => "testnet3", Network::Devnet => devnet_name.as_deref().unwrap_or(""), Network::Regtest => "regtest", - _ => unimplemented!(), + _ => { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Unsupported network for cookie path: {:?}", network), + )); + } }; - path.join(network_dir).join(".cookie") + Ok(path.join(network_dir).join(".cookie")) }) } diff --git a/src/backend_task/contested_names/query_dpns_contested_resources.rs b/src/backend_task/contested_names/query_dpns_contested_resources.rs index 502d01c7b..1b02cac28 100644 --- a/src/backend_task/contested_names/query_dpns_contested_resources.rs +++ b/src/backend_task/contested_names/query_dpns_contested_resources.rs @@ -21,7 +21,7 @@ impl AppContext { let data_contract = self.dpns_contract.as_ref(); let document_type = data_contract .document_type_for_name("domain") - .expect("expected document type"); + .map_err(|_| "DPNS contract missing 'domain' document type".to_string())?; let Some(contested_index) = document_type.find_contested_index() else { return Err( "Contested resource query failed: No contested index on dpns domains.".to_string(), @@ -128,16 +128,21 @@ impl AppContext { let contested_resources_as_strings: Vec = contested_resources .0 .into_iter() - .map(|contested_resource| { - contested_resource - .0 - .as_str() - .expect("expected str") - .to_string() + .filter_map(|contested_resource| match contested_resource.0.as_str() { + Some(s) => Some(s.to_string()), + None => { + tracing::warn!( + "Contested resource value is not a string: {:?}", + contested_resource.0 + ); + None + } }) .collect(); - let last_found_name = contested_resources_as_strings.last().unwrap().clone(); + let Some(last_found_name) = contested_resources_as_strings.last().cloned() else { + break; + }; let new_names_to_be_updated = self .db @@ -172,22 +177,32 @@ impl AppContext { tokio::spawn(async move { // Acquire a permit from the semaphore - let _permit: OwnedSemaphorePermit = semaphore.acquire_owned().await.unwrap(); + let _permit: OwnedSemaphorePermit = match semaphore.acquire_owned().await { + Ok(permit) => permit, + Err(e) => { + tracing::error!("Semaphore closed while querying dpns end times: {}", e); + return; + } + }; match self_ref.query_dpns_ending_times(sdk, sender.clone()).await { Ok(_) => { // Send a refresh message if the query succeeded - sender - .send(TaskResult::Refresh) - .await - .expect("expected to send refresh"); + if let Err(e) = sender.send(TaskResult::Refresh).await { + tracing::warn!( + "Failed to send refresh after dpns end times query: {}", + e + ); + } } Err(e) => { tracing::error!("Error querying dpns end times: {}", e); - sender - .send(TaskResult::Error(e)) - .await - .expect("expected to send error"); + if let Err(send_err) = sender.send(TaskResult::Error(e)).await { + tracing::warn!( + "Failed to send error for dpns end times query: {}", + send_err + ); + } } } }) @@ -205,7 +220,17 @@ impl AppContext { // Spawn each task with a permit from the semaphore let handle = tokio::spawn(async move { // Acquire a permit from the semaphore - let _permit: OwnedSemaphorePermit = semaphore.acquire_owned().await.unwrap(); + let _permit: OwnedSemaphorePermit = match semaphore.acquire_owned().await { + Ok(permit) => permit, + Err(e) => { + tracing::error!( + "Semaphore closed while querying vote contenders for {}: {}", + name, + e + ); + return; + } + }; // Perform the query match self_ref @@ -214,17 +239,23 @@ impl AppContext { { Ok(_) => { // Send a refresh message if the query succeeded - sender - .send(TaskResult::Refresh) - .await - .expect("expected to send refresh"); + if let Err(e) = sender.send(TaskResult::Refresh).await { + tracing::warn!( + "Failed to send refresh after vote contenders query for {}: {}", + name, + e + ); + } } Err(e) => { tracing::error!("Error querying dpns vote contenders for {}: {}", name, e); - sender - .send(TaskResult::Error(e)) - .await - .expect("expected to send error"); + if let Err(send_err) = sender.send(TaskResult::Error(e)).await { + tracing::warn!( + "Failed to send error for vote contenders query for {}: {}", + name, + send_err + ); + } } } }); diff --git a/src/backend_task/contested_names/query_dpns_vote_contenders.rs b/src/backend_task/contested_names/query_dpns_vote_contenders.rs index 6381d2a00..8c94618e8 100644 --- a/src/backend_task/contested_names/query_dpns_vote_contenders.rs +++ b/src/backend_task/contested_names/query_dpns_vote_contenders.rs @@ -22,7 +22,7 @@ impl AppContext { let data_contract = self.dpns_contract.as_ref(); let document_type = data_contract .document_type_for_name("domain") - .expect("expected document type"); + .map_err(|_| "DPNS contract missing 'domain' document type".to_string())?; let Some(contested_index) = document_type.find_contested_index() else { return Err("No contested index on dpns domains".to_string()); }; diff --git a/src/backend_task/contested_names/vote_on_dpns_name.rs b/src/backend_task/contested_names/vote_on_dpns_name.rs index 26f7cdfb9..a472ce0ec 100644 --- a/src/backend_task/contested_names/vote_on_dpns_name.rs +++ b/src/backend_task/contested_names/vote_on_dpns_name.rs @@ -36,7 +36,7 @@ impl AppContext { let data_contract = self.dpns_contract.as_ref(); let document_type = data_contract .document_type_for_name("domain") - .expect("expected document type"); + .map_err(|_| "DPNS contract missing 'domain' document type".to_string())?; let Some(contested_index) = document_type.find_contested_index() else { return Err("Error voting: No contested index on dpns domains".to_string()); diff --git a/src/backend_task/contract.rs b/src/backend_task/contract.rs index cc9db1411..42486ac33 100644 --- a/src/backend_task/contract.rs +++ b/src/backend_task/contract.rs @@ -100,9 +100,20 @@ impl AppContext { let mut token_infos = vec![]; for token in contract.tokens() { - let token_configuration = contract + let token_configuration = match contract .expected_token_configuration(*token.0) - .expect("Expected to get token configuration"); + { + Ok(config) => config, + Err(e) => { + tracing::warn!( + "Skipping token at position {} in contract {}: {}", + token.0, + contract.id(), + e + ); + continue; + } + }; let token_name = { let TokenConfigurationConvention::V0(conventions) = &token_configuration.conventions(); diff --git a/src/backend_task/dashpay/contacts.rs b/src/backend_task/dashpay/contacts.rs index 4539722d3..fa680daf1 100644 --- a/src/backend_task/dashpay/contacts.rs +++ b/src/backend_task/dashpay/contacts.rs @@ -261,7 +261,13 @@ pub async fn load_contacts( for (_, outgoing_doc) in outgoing.iter() { if let Some(Value::Identifier(to_id_bytes)) = outgoing_doc.properties().get("toUserId") { - let to_id = Identifier::from_bytes(to_id_bytes.as_slice()).unwrap(); + let Ok(to_id) = Identifier::from_bytes(to_id_bytes.as_slice()) else { + tracing::warn!( + "Failed to parse contact request toUserId ({} bytes), skipping", + to_id_bytes.len() + ); + continue; + }; if to_id == from_id { // Mutual contact found contacts.insert(from_id); @@ -305,7 +311,13 @@ pub async fn load_contacts( if let Some(Value::Bytes(enc_user_id)) = props.get("encToUserId") && let Ok(decrypted_id) = decrypt_to_user_id(enc_user_id, &enc_user_id_key) { - let contact_id = Identifier::from_bytes(&decrypted_id).unwrap(); + let Ok(contact_id) = Identifier::from_bytes(&decrypted_id) else { + tracing::warn!( + "Failed to parse decrypted contact ID (length {}), skipping contact info entry", + decrypted_id.len() + ); + continue; + }; // Decrypt private data if available let mut nickname = None; diff --git a/src/backend_task/dashpay/payments.rs b/src/backend_task/dashpay/payments.rs index 7edb372b5..4122acc7b 100644 --- a/src/backend_task/dashpay/payments.rs +++ b/src/backend_task/dashpay/payments.rs @@ -296,7 +296,7 @@ pub async fn send_payment_to_contact_impl( "{}_{}", std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_millis(), to_contact_id.to_string(Encoding::Base58) ), @@ -309,7 +309,7 @@ pub async fn send_payment_to_contact_impl( memo: memo.clone(), timestamp: std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), status: PaymentStatus::Broadcast, address_index, diff --git a/src/backend_task/identity/register_identity.rs b/src/backend_task/identity/register_identity.rs index 1fc51b931..889f287bf 100644 --- a/src/backend_task/identity/register_identity.rs +++ b/src/backend_task/identity/register_identity.rs @@ -320,10 +320,11 @@ impl AppContext { Err(e) => return Err(format!("Error fetching identity: {}", e)), }; - let identity = existing_identity.clone().unwrap_or_else(|| { - Identity::new_with_id_and_keys(identity_id, public_keys, sdk.version()) - .expect("expected to make identity") - }); + let identity = match existing_identity.clone() { + Some(id) => id, + None => Identity::new_with_id_and_keys(identity_id, public_keys, sdk.version()) + .map_err(|e| format!("Failed to create identity: {}", e))?, + }; let wallet_seed_hash = { wallet.read().unwrap().seed_hash() }; let mut qualified_identity = QualifiedIdentity { @@ -602,21 +603,24 @@ impl AppContext { ); } - let identity_create_transition = - IdentityCreateTransition::try_from_identity_with_signer( - identity, - asset_lock_proof, - asset_lock_proof_private_key.inner.as_ref(), - &qualified_identity, - &NativeBlsModule, - 0, - self.platform_version(), - ) - .expect("expected to make transition"); - format!( - "error: {}, transaction is {:?}", - e, identity_create_transition - ) + match IdentityCreateTransition::try_from_identity_with_signer( + identity, + asset_lock_proof, + asset_lock_proof_private_key.inner.as_ref(), + &qualified_identity, + &NativeBlsModule, + 0, + self.platform_version(), + ) { + Ok(transition) => format!( + "error: {}, transaction is {:?}", + e, transition + ), + Err(transition_err) => format!( + "error: {}, also failed to recreate transition for debugging: {}", + e, transition_err + ), + } }) } else { Err(e.to_string()) diff --git a/src/backend_task/identity/top_up_identity.rs b/src/backend_task/identity/top_up_identity.rs index 93c89c461..0dc89d08d 100644 --- a/src/backend_task/identity/top_up_identity.rs +++ b/src/backend_task/identity/top_up_identity.rs @@ -422,20 +422,23 @@ impl AppContext { ); } - let identity_create_transition = - IdentityTopUpTransition::try_from_identity( - &qualified_identity.identity, - asset_lock_proof, - asset_lock_proof_private_key.inner.as_ref(), - 0, - self.platform_version(), - None, - ) - .expect("expected to make transition"); - format!( - "error: {}, transaction is {:?}", - e, identity_create_transition - ) + match IdentityTopUpTransition::try_from_identity( + &qualified_identity.identity, + asset_lock_proof, + asset_lock_proof_private_key.inner.as_ref(), + 0, + self.platform_version(), + None, + ) { + Ok(transition) => format!( + "error: {}, transaction is {:?}", + e, transition + ), + Err(transition_err) => format!( + "error: {}, also failed to recreate transition for debugging: {}", + e, transition_err + ), + } })? } else { return Err(error_string); diff --git a/src/backend_task/platform_info.rs b/src/backend_task/platform_info.rs index eed11ee2e..71cbe738c 100644 --- a/src/backend_task/platform_info.rs +++ b/src/backend_task/platform_info.rs @@ -28,7 +28,6 @@ use dash_sdk::query_types::{ CurrentQuorumsInfo, NoParamQuery, ProtocolVersionUpgrades, TotalCreditsInPlatform, }; use dash_sdk::query_types::AddressInfo; -use itertools::Itertools; use std::sync::Arc; use chrono::{prelude::*, LocalResult}; use chrono_humanize::{Accuracy, HumanTime, Tense}; @@ -203,60 +202,65 @@ fn format_withdrawal_documents_with_daily_limit( withdrawal_documents: &[Document], total_credits_on_platform: Credits, network: Network, -) -> String { +) -> Result { let total_amount: Credits = withdrawal_documents .iter() .map(|document| { document .properties() .get_integer::(AMOUNT) - .expect("expected amount on withdrawal") + .map_err(|e| format!("Failed to get withdrawal amount: {}", e)) }) + .collect::, String>>()? + .into_iter() .sum(); - let amounts = withdrawal_documents + let amounts: Vec = withdrawal_documents .iter() .map(|document| { - let index = document.created_at().expect("expected created at"); - let utc_datetime = - DateTime::::from_timestamp_millis(index as i64).expect("expected date time"); + let index = document + .created_at() + .ok_or("Withdrawal document missing created_at timestamp")?; + let utc_datetime = DateTime::::from_timestamp_millis(index as i64) + .ok_or("Invalid withdrawal created_at timestamp")?; let local_datetime: DateTime = utc_datetime.with_timezone(&Local); let amount = document .properties() .get_integer::(AMOUNT) - .expect("expected amount on withdrawal"); - let status: WithdrawalStatus = document + .map_err(|e| format!("Failed to get withdrawal amount: {}", e))?; + let status_u8: u8 = document .properties() .get_integer::(STATUS) - .expect("expected status on withdrawal") + .map_err(|e| format!("Failed to get withdrawal status: {}", e))?; + let status: WithdrawalStatus = status_u8 .try_into() - .expect("expected a withdrawal status"); + .map_err(|_| format!("Invalid withdrawal status value: {}", status_u8))?; let owner_id = document.owner_id(); let address_bytes = document .properties() .get_bytes(OUTPUT_SCRIPT) - .expect("expected output script"); + .map_err(|e| format!("Failed to get withdrawal output script: {}", e))?; let output_script = ScriptBuf::from_bytes(address_bytes); let address = Address::from_script(&output_script, network) .map(|addr| addr.to_string()) .unwrap_or_else(|e| format!("Invalid Address: {}", e)); - format!( + Ok(format!( "{}: {:.8} Dash for {} towards {} ({})", local_datetime.format("%Y-%m-%d %H:%M:%S"), amount as f64 / (dash_to_credits!(1) as f64), owner_id, address, status, - ) + )) }) - .join("\n "); + .collect::, String>>()?; let daily_withdrawal_limit = daily_withdrawal_limit(total_credits_on_platform, PlatformVersion::latest()) - .expect("expected to get daily withdrawal limit"); + .map_err(|e| format!("Failed to calculate daily withdrawal limit: {}", e))?; - format!( + Ok(format!( "Withdrawal Information:\n\n\ Total Amount: {:.8} Dash\n\ Daily Withdrawal Limit: {:.8} Dash\n\ @@ -264,69 +268,75 @@ fn format_withdrawal_documents_with_daily_limit( Recent Withdrawals:\n {}", total_amount as f64 / (dash_to_credits!(1) as f64), daily_withdrawal_limit as f64 / (dash_to_credits!(1) as f64), - daily_withdrawal_limit.saturating_sub(0) as f64 / (dash_to_credits!(1) as f64), // We don't have 24h amount - amounts - ) + daily_withdrawal_limit as f64 / (dash_to_credits!(1) as f64), // TODO: subtract actual 24h withdrawal amount when available + amounts.join("\n ") + )) } fn format_withdrawal_documents_to_bare_info( withdrawal_documents: &[Document], network: Network, -) -> String { +) -> Result { let total_amount: Credits = withdrawal_documents .iter() .map(|document| { document .properties() .get_integer::(AMOUNT) - .expect("expected amount on withdrawal") + .map_err(|e| format!("Failed to get withdrawal amount: {}", e)) }) + .collect::, String>>()? + .into_iter() .sum(); - let amounts = withdrawal_documents + let amounts: Vec = withdrawal_documents .iter() .map(|document| { - let index = document.created_at().expect("expected created at"); - let utc_datetime = - DateTime::::from_timestamp_millis(index as i64).expect("expected date time"); + let index = document + .created_at() + .ok_or("Withdrawal document missing created_at timestamp")?; + let utc_datetime = DateTime::::from_timestamp_millis(index as i64) + .ok_or("Invalid withdrawal created_at timestamp")?; let local_datetime: DateTime = utc_datetime.with_timezone(&Local); let amount = document .properties() .get_integer::(AMOUNT) - .expect("expected amount on withdrawal"); - let status: WithdrawalStatus = document + .map_err(|e| format!("Failed to get withdrawal amount: {}", e))?; + let status_u8: u8 = document .properties() .get_integer::(STATUS) - .expect("expected status on withdrawal") + .map_err(|e| format!("Failed to get withdrawal status: {}", e))?; + let status: WithdrawalStatus = status_u8 .try_into() - .expect("expected a withdrawal status"); + .map_err(|_| format!("Invalid withdrawal status value: {}", status_u8))?; let owner_id = document.owner_id(); let address_bytes = document .properties() .get_bytes(OUTPUT_SCRIPT) - .expect("expected output script"); + .map_err(|e| format!("Failed to get withdrawal output script: {}", e))?; let output_script = ScriptBuf::from_bytes(address_bytes); - let address = - Address::from_script(&output_script, network).expect("expected an address"); - format!( + let address = Address::from_script(&output_script, network) + .map(|addr| addr.to_string()) + .unwrap_or_else(|e| format!("Invalid Address: {}", e)); + Ok(format!( "{}: {:.8} Dash for {} towards {} ({})", local_datetime.format("%Y-%m-%d %H:%M:%S"), amount as f64 / (dash_to_credits!(1) as f64), owner_id, address, status, - ) + )) }) - .join("\n "); + .collect::, String>>()?; - format!( + Ok(format!( "Withdrawal Information:\n\n\ Total Amount: {:.8} Dash\n\n\ Recent Withdrawals:\n {}", total_amount as f64 / (dash_to_credits!(1) as f64), - amounts - ) + amounts.join("\n ") + )) } impl AppContext { @@ -446,7 +456,7 @@ impl AppContext { SystemDataContract::Withdrawals, PlatformVersion::latest(), ) - .expect("expected to get withdrawal contract"); + .map_err(|e| format!("Failed to load withdrawal contract: {}", e))?; // Try the simplest possible query first - no where clauses or ordering let queued_document_query = DocumentQuery { @@ -470,7 +480,7 @@ impl AppContext { &withdrawal_docs, total_credits.0, self.network, - ); + )?; Ok(BackendTaskSuccessResult::PlatformInfo( PlatformInfoTaskResult::TextResult(formatted), )) @@ -480,7 +490,7 @@ impl AppContext { let formatted = format_withdrawal_documents_to_bare_info( &withdrawal_docs, self.network, - ); + )?; Ok(BackendTaskSuccessResult::PlatformInfo( PlatformInfoTaskResult::TextResult(formatted), )) @@ -496,7 +506,7 @@ impl AppContext { SystemDataContract::Withdrawals, PlatformVersion::latest(), ) - .expect("expected to get withdrawal contract"); + .map_err(|e| format!("Failed to load withdrawal contract: {}", e))?; let completed_document_query = DocumentQuery { data_contract: Arc::new(withdrawal_contract), @@ -551,44 +561,62 @@ impl AppContext { document .properties() .get_integer::(AMOUNT) - .expect("expected amount on withdrawal") + .map_err(|e| { + format!("Failed to get withdrawal amount: {}", e) + }) }) + .collect::, String>>()? + .into_iter() .sum(); - let amounts = withdrawal_docs + let amounts: Vec = withdrawal_docs .iter() .map(|document| { - let index = document.updated_at().expect("expected updated at"); + let index = document.updated_at().ok_or( + "Withdrawal document missing updated_at timestamp", + )?; let utc_datetime = DateTime::::from_timestamp_millis(index as i64) - .expect("expected date time"); + .ok_or("Invalid withdrawal updated_at timestamp")?; let local_datetime: DateTime = utc_datetime.with_timezone(&Local); let amount = document .properties() .get_integer::(AMOUNT) - .expect("expected amount on withdrawal"); - let status: WithdrawalStatus = document - .properties() - .get_integer::(STATUS) - .expect("expected status on withdrawal") - .try_into() - .expect("expected a withdrawal status"); + .map_err(|e| { + format!("Failed to get withdrawal amount: {}", e) + })?; + let status_u8: u8 = + document.properties().get_integer::(STATUS).map_err( + |e| format!("Failed to get withdrawal status: {}", e), + )?; + let status: WithdrawalStatus = + status_u8.try_into().map_err(|_| { + format!( + "Invalid withdrawal status value: {}", + status_u8 + ) + })?; let owner_id = document.owner_id(); let address_bytes = document .properties() .get_bytes(OUTPUT_SCRIPT) - .expect("expected output script"); + .map_err(|e| { + format!("Failed to get withdrawal output script: {}", e) + })?; let transaction_index = document .properties() .get_integer::(TRANSACTION_INDEX) - .expect("expected transaction index"); + .map_err(|e| { + format!("Failed to get transaction index: {}", e) + })?; let output_script = ScriptBuf::from_bytes(address_bytes); let address = Address::from_script(&output_script, self.network) - .expect("expected an address"); - format!( + .map(|addr| addr.to_string()) + .unwrap_or_else(|e| format!("Invalid Address: {}", e)); + Ok(format!( "TX #{}: {:.8} Dash for {} to {} ({}) at {}", transaction_index, amount as f64 / (dash_to_credits!(1) as f64), @@ -596,9 +624,9 @@ impl AppContext { address, status, local_datetime.format("%Y-%m-%d %H:%M:%S"), - ) + )) }) - .join("\n "); + .collect::, String>>()?; let formatted = format!( "Recently Completed Withdrawals:\n\n\ @@ -607,7 +635,7 @@ impl AppContext { Recent Transactions:\n {}", total_amount as f64 / (dash_to_credits!(1) as f64), withdrawal_docs.len(), - amounts + amounts.join("\n ") ); Ok(BackendTaskSuccessResult::PlatformInfo( diff --git a/src/components/core_p2p_handler.rs b/src/components/core_p2p_handler.rs index bb770fff9..77ddfe37c 100644 --- a/src/components/core_p2p_handler.rs +++ b/src/components/core_p2p_handler.rs @@ -51,7 +51,7 @@ impl CoreP2PHandler { Network::Testnet => 19999, // Dash Testnet default Network::Devnet => 29999, // Dash Devnet default Network::Regtest => 29999, // Dash Regtest default - _ => panic!("Unsupported network type"), + _ => return Err(format!("Unsupported network type: {:?}", network)), }); let stream = TcpStream::connect_timeout( &format!("127.0.0.1:{}", port) diff --git a/src/config.rs b/src/config.rs index 287fb4a73..7b63ddc1c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -302,8 +302,13 @@ impl NetworkConfig { } /// List of DAPI addresses - pub fn dapi_address_list(&self) -> AddressList { - AddressList::from_str(&self.dapi_addresses).expect("Could not parse DAPI addresses") + pub fn dapi_address_list(&self) -> Result { + AddressList::from_str(&self.dapi_addresses).map_err(|e| { + format!( + "Could not parse DAPI addresses '{}': {}", + self.dapi_addresses, e + ) + }) } /// Update just the `core_rpc_password` in a builder-like manner. @@ -371,7 +376,7 @@ mod tests { #[test] fn test_dapi_address_list_single_address() { let config = make_network_config("https://127.0.0.1:443", 9998); - let list = config.dapi_address_list(); + let list = config.dapi_address_list().unwrap(); assert_eq!(list.len(), 1); } @@ -381,17 +386,21 @@ mod tests { "https://127.0.0.1:443,https://192.168.1.1:443,https://10.0.0.1:443", 9998, ); - let list = config.dapi_address_list(); + let list = config.dapi_address_list().unwrap(); assert_eq!(list.len(), 3); } #[test] - #[should_panic(expected = "Could not parse DAPI addresses")] - fn test_dapi_address_list_empty_panics() { + fn test_dapi_address_list_empty_returns_error() { let config = make_network_config("", 9998); - let _list = config.dapi_address_list(); + let result = config.dapi_address_list(); + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .contains("Could not parse DAPI addresses") + ); } - // ── NetworkConfig::update_core_rpc_password ───────────────────── #[test] diff --git a/src/context/mod.rs b/src/context/mod.rs index a10533275..2900b6060 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -121,74 +121,136 @@ impl AppContext { let (sx_zmq_status, rx_zmq_status) = crossbeam_channel::unbounded(); // Create both providers; bind to app context later (post construction) due to circularity - let spv_provider = - SpvProvider::new(db.clone(), network).expect("Failed to initialize SPV provider"); - let rpc_provider = RpcProvider::new(db.clone(), network, &network_config) - .expect("Failed to initialize RPC provider"); + let spv_provider = match SpvProvider::new(db.clone(), network) { + Ok(p) => p, + Err(e) => { + tracing::error!(?network, "Failed to initialize SPV provider: {e}"); + return None; + } + }; + let rpc_provider = match RpcProvider::new(db.clone(), network, &network_config) { + Ok(p) => p, + Err(e) => { + tracing::error!(?network, "Failed to initialize RPC provider: {e}"); + return None; + } + }; // Default to SPV provider initially; UI can switch backend after - let sdk = initialize_sdk(&network_config, network, spv_provider.clone()); + let sdk = match initialize_sdk(&network_config, network, spv_provider.clone()) { + Ok(sdk) => sdk, + Err(e) => { + tracing::error!("Failed to initialize SDK: {e}"); + return None; + } + }; let platform_version = sdk.version(); - let dpns_contract = load_system_data_contract(SystemDataContract::DPNS, platform_version) - .expect("expected to load dpns contract"); + let dpns_contract = + match load_system_data_contract(SystemDataContract::DPNS, platform_version) { + Ok(c) => c, + Err(e) => { + tracing::error!(?network, "Failed to load DPNS contract: {e}"); + return None; + } + }; let withdrawal_contract = - load_system_data_contract(SystemDataContract::Withdrawals, platform_version) - .expect("expected to get withdrawal contract"); + match load_system_data_contract(SystemDataContract::Withdrawals, platform_version) { + Ok(c) => c, + Err(e) => { + tracing::error!(?network, "Failed to load Withdrawals contract: {e}"); + return None; + } + }; let token_history_contract = - load_system_data_contract(SystemDataContract::TokenHistory, platform_version) - .expect("expected to get token history contract"); + match load_system_data_contract(SystemDataContract::TokenHistory, platform_version) { + Ok(c) => c, + Err(e) => { + tracing::error!(?network, "Failed to load TokenHistory contract: {e}"); + return None; + } + }; let keyword_search_contract = - load_system_data_contract(SystemDataContract::KeywordSearch, platform_version) - .expect("expected to get keyword search contract"); + match load_system_data_contract(SystemDataContract::KeywordSearch, platform_version) { + Ok(c) => c, + Err(e) => { + tracing::error!(?network, "Failed to load KeywordSearch contract: {e}"); + return None; + } + }; let dashpay_contract = - load_system_data_contract(SystemDataContract::Dashpay, platform_version) - .expect("expected to get dashpay contract"); + match load_system_data_contract(SystemDataContract::Dashpay, platform_version) { + Ok(c) => c, + Err(e) => { + tracing::error!(?network, "Failed to load Dashpay contract: {e}"); + return None; + } + }; let addr = format!( "http://{}:{}", network_config.core_host, network_config.core_rpc_port ); - let cookie_path = core_cookie_path(network, &network_config.devnet_name) - .expect("expected to get cookie path"); + let cookie_path = match core_cookie_path(network, &network_config.devnet_name) { + Ok(p) => p, + Err(e) => { + tracing::error!(?network, "Failed to get core cookie path: {e}"); + return None; + } + }; - // Try cookie authentication first + // Try cookie authentication first, then user/password let core_client = match Client::new(&addr, Auth::CookieFile(cookie_path.clone())) { - Ok(client) => Ok(client), + Ok(client) => client, Err(_) => { - // If cookie auth fails, try user/password authentication tracing::info!( "Failed to authenticate using .cookie file at {:?}, falling back to user/pass", cookie_path, ); - Client::new( + match Client::new( &addr, Auth::UserPass( network_config.core_rpc_user.to_string(), network_config.core_rpc_password.to_string(), ), - ) + ) { + Ok(client) => client, + Err(e) => { + tracing::error!(?network, "Failed to create CoreClient: {e}"); + return None; + } + } + } + }; + + let wallets: BTreeMap<_, _> = match db.get_wallets(&network) { + Ok(w) => w, + Err(e) => { + tracing::error!(?network, "Failed to load wallets from database: {e}"); + return None; + } + } + .into_iter() + .map(|w| (w.seed_hash(), Arc::new(RwLock::new(w)))) + .collect(); + + let single_key_wallets: BTreeMap<_, _> = match db.get_single_key_wallets(network) { + Ok(w) => w, + Err(e) => { + tracing::error!( + ?network, + "Failed to load single key wallets from database: {e}" + ); + return None; } } - .expect("Failed to create CoreClient"); - - let wallets: BTreeMap<_, _> = db - .get_wallets(&network) - .expect("expected to get wallets") - .into_iter() - .map(|w| (w.seed_hash(), Arc::new(RwLock::new(w)))) - .collect(); - - let single_key_wallets: BTreeMap<_, _> = db - .get_single_key_wallets(network) - .expect("expected to get single key wallets") - .into_iter() - .map(|w| (w.key_hash(), Arc::new(RwLock::new(w)))) - .collect(); + .into_iter() + .map(|w| (w.key_hash(), Arc::new(RwLock::new(w)))) + .collect(); let developer_mode_enabled = config.developer_mode.unwrap_or(false); @@ -459,7 +521,7 @@ impl AppContext { .read() .map_err(|_| "SPV provider lock poisoned".to_string())? .clone(); - initialize_sdk(&cfg, self.network, provider) + initialize_sdk(&cfg, self.network, provider)? } CoreBackendMode::Rpc => { // Create a fresh RPC provider with the new config @@ -473,7 +535,7 @@ impl AppContext { .map_err(|_| "RPC provider lock poisoned".to_string())?; *guard = rpc_provider.clone(); } - initialize_sdk(&cfg, self.network, rpc_provider) + initialize_sdk(&cfg, self.network, rpc_provider)? } }; @@ -518,6 +580,6 @@ pub(crate) const fn default_platform_version(network: &Network) -> &'static Plat Network::Testnet => &PLATFORM_V11, Network::Devnet => &PLATFORM_V11, Network::Regtest => &PLATFORM_V11, - _ => panic!("unsupported network"), + _ => panic!("Unsupported network for default_platform_version"), } } diff --git a/src/context/transaction_processing.rs b/src/context/transaction_processing.rs index 79104db57..f89cbfca6 100644 --- a/src/context/transaction_processing.rs +++ b/src/context/transaction_processing.rs @@ -240,13 +240,18 @@ impl AppContext { self.network, )?; - let first = payload - .credit_outputs - .first() - .expect("Expected at least one credit output"); + let first = payload.credit_outputs.first().ok_or_else(|| { + rusqlite::Error::InvalidParameterName( + "Asset lock transaction has no credit outputs".to_string(), + ) + })?; - let address = Address::from_script(&first.script_pubkey, self.network) - .expect("expected an address"); + let address = + Address::from_script(&first.script_pubkey, self.network).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Failed to derive address from asset lock credit output script: {e}" + )) + })?; // Add the asset lock to the wallet's unused_asset_locks wallet diff --git a/src/database/contacts.rs b/src/database/contacts.rs index 8787b9081..95631748e 100644 --- a/src/database/contacts.rs +++ b/src/database/contacts.rs @@ -73,9 +73,9 @@ impl crate::database::Database { ], |row| { Ok(( - row.get::<_, String>(0).unwrap_or_default(), - row.get::<_, String>(1).unwrap_or_default(), - row.get::<_, i32>(2).unwrap_or(0) != 0, + row.get::<_, Option>(0)?.unwrap_or_default(), + row.get::<_, Option>(1)?.unwrap_or_default(), + row.get::<_, Option>(2)?.unwrap_or(0) != 0, )) }, ); diff --git a/src/database/contested_names.rs b/src/database/contested_names.rs index ee09b3bc9..173e5de70 100644 --- a/src/database/contested_names.rs +++ b/src/database/contested_names.rs @@ -74,7 +74,17 @@ impl Database { // Convert `awarded_to` to `Identifier` if it exists let awarded_to_id = awarded_to - .map(|id| Identifier::from_bytes(&id).expect("Expected 32 bytes for awarded_to")); + .map(|id| { + Identifier::from_bytes(&id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + rusqlite::types::Type::Blob, + format!("Invalid awarded_to identifier ({} bytes): {}", id.len(), e) + .into(), + ) + }) + }) + .transpose()?; let state = if locked { ContestState::Locked @@ -82,7 +92,10 @@ impl Database { ContestState::WonBy(awarded_to_id) } else if let Some(created_at) = created_at { let elapsed_time = Duration::from_millis( - (std::time::UNIX_EPOCH.elapsed().unwrap().as_millis() as u64) + (std::time::UNIX_EPOCH + .elapsed() + .unwrap_or_default() + .as_millis() as u64) .saturating_sub(created_at), ); @@ -115,16 +128,36 @@ impl Database { (identity_id, contestant_name, votes, document_id) { let contestant = Contestant { - id: Identifier::from_bytes(&identity_id) - .expect("Expected 32 bytes for identity_id"), + id: Identifier::from_bytes(&identity_id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 7, + rusqlite::types::Type::Blob, + format!( + "Invalid identity_id identifier ({} bytes): {}", + identity_id.len(), + e + ) + .into(), + ) + })?, name: contestant_name, info: identity_info.unwrap_or_default(), votes, created_at, created_at_block_height, created_at_core_block_height, - document_id: Identifier::from_bytes(&document_id) - .expect("Expected 32 bytes for document_id"), + document_id: Identifier::from_bytes(&document_id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 13, + rusqlite::types::Type::Blob, + format!( + "Invalid document_id identifier ({} bytes): {}", + document_id.len(), + e + ) + .into(), + ) + })?, }; // Add the contestant to the contestants list @@ -155,7 +188,10 @@ impl Database { } else { Duration::from_secs(60 * 90) }; - let current_timestamp = std::time::UNIX_EPOCH.elapsed().unwrap().as_millis() as u64; + let current_timestamp = std::time::UNIX_EPOCH + .elapsed() + .unwrap_or_default() + .as_millis() as u64; let conn = self.conn.lock().unwrap(); let mut stmt = conn.prepare( "SELECT @@ -208,7 +244,17 @@ impl Database { // Convert `awarded_to` to `Identifier` if it exists let awarded_to_id = awarded_to - .map(|id| Identifier::from_bytes(&id).expect("Expected 32 bytes for awarded_to")); + .map(|id| { + Identifier::from_bytes(&id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + rusqlite::types::Type::Blob, + format!("Invalid awarded_to identifier ({} bytes): {}", id.len(), e) + .into(), + ) + }) + }) + .transpose()?; let state = if locked { ContestState::Locked @@ -216,7 +262,10 @@ impl Database { ContestState::WonBy(awarded_to_id) } else if let Some(created_at) = created_at { let elapsed_time = Duration::from_millis( - (std::time::UNIX_EPOCH.elapsed().unwrap().as_millis() as u64) + (std::time::UNIX_EPOCH + .elapsed() + .unwrap_or_default() + .as_millis() as u64) .saturating_sub(created_at), ); @@ -249,16 +298,36 @@ impl Database { (identity_id, contestant_name, votes, document_id) { let contestant = Contestant { - id: Identifier::from_bytes(&identity_id) - .expect("Expected 32 bytes for identity_id"), + id: Identifier::from_bytes(&identity_id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 7, + rusqlite::types::Type::Blob, + format!( + "Invalid identity_id identifier ({} bytes): {}", + identity_id.len(), + e + ) + .into(), + ) + })?, name: contestant_name, info: identity_info.unwrap_or_default(), votes, created_at, created_at_block_height, created_at_core_block_height, - document_id: Identifier::from_bytes(&document_id) - .expect("Expected 32 bytes for document_id"), + document_id: Identifier::from_bytes(&document_id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 13, + rusqlite::types::Type::Blob, + format!( + "Invalid document_id identifier ({} bytes): {}", + document_id.len(), + e + ) + .into(), + ) + })?, }; // Add the contestant to the contestants list @@ -309,11 +378,26 @@ impl Database { match result { Ok((locked_votes, abstain_votes, awarded_to, ending_time)) => { // Compare the current values with the new values + let db_awarded_to = awarded_to + .as_ref() + .map(|id| { + Identifier::from_bytes(id).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 2, + rusqlite::types::Type::Blob, + format!( + "Invalid awarded_to identifier ({} bytes): {}", + id.len(), + e + ) + .into(), + ) + }) + }) + .transpose()?; let should_update = locked_votes != contested_name.locked_votes || abstain_votes != contested_name.abstain_votes - || awarded_to.as_ref().map(|id| { - Identifier::from_bytes(id).expect("expected 32 bytes for awarded to") - }) != contested_name.awarded_to + || db_awarded_to != contested_name.awarded_to || ending_time != contested_name.end_time; if should_update { diff --git a/src/database/initialization.rs b/src/database/initialization.rs index a9cf640e0..95be50b61 100644 --- a/src/database/initialization.rs +++ b/src/database/initialization.rs @@ -37,11 +37,11 @@ impl Database { if current_version != DEFAULT_DB_VERSION { self.backup_db(db_file_path)?; if let Err(e) = self.try_perform_migration(current_version, DEFAULT_DB_VERSION) { - let version_after_migration = self.db_schema_version()?; - panic!( - "Database migration from version {} to {} failed, database is at version {}. Error: {:?}", + let version_after_migration = self.db_schema_version().unwrap_or(0); + return Err(rusqlite::Error::InvalidParameterName(format!( + "Database migration from version {} to {} failed (database is at version {}): {}", current_version, DEFAULT_DB_VERSION, version_after_migration, e - ); + ))); } } } diff --git a/src/database/scheduled_votes.rs b/src/database/scheduled_votes.rs index c70f0831f..3bbfd0336 100644 --- a/src/database/scheduled_votes.rs +++ b/src/database/scheduled_votes.rs @@ -156,13 +156,14 @@ impl Database { let contested_name: String = row.get(1)?; let vote_choice_string: String = row.get(2)?; let time: u64 = row.get(3)?; - let executed_successfully: bool = match row.get(4)? { + let executed_successfully: bool = match row.get::<_, i64>(4)? { 0 => false, 1 => true, other => { tracing::warn!( - "Unexpected value {} for executed column in scheduled_votes, defaulting to false", - other + "Unexpected 'executed' value {} for scheduled vote '{}', treating as not executed", + other, + contested_name ); false } diff --git a/src/database/wallet.rs b/src/database/wallet.rs index bd113a43a..092993ca4 100644 --- a/src/database/wallet.rs +++ b/src/database/wallet.rs @@ -140,8 +140,7 @@ impl Database { ) -> rusqlite::Result<()> { let conn = self.conn.lock().unwrap(); - let address = check_address_for_network(address.as_unchecked().clone(), network) - .expect("Expected address to be valid for network"); + let address = check_address_for_network(address.as_unchecked().clone(), network)?; // Step 1: Check if the address already exists for the given seed. let mut stmt = conn.prepare( @@ -441,11 +440,16 @@ impl Database { // Reconstruct the extended public keys let master_ecdsa_extended_public_key = - ExtendedPubKey::decode(&master_ecdsa_bip44_account_0_epk_bytes) - .expect("Failed to decode ExtendedPubKey"); + ExtendedPubKey::decode(&master_ecdsa_bip44_account_0_epk_bytes).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Failed to decode ExtendedPubKey: {}", + e + )) + })?; - let seed_hash_array: [u8; 32] = - seed_hash.try_into().expect("Seed hash should be 32 bytes"); + let seed_hash_array: [u8; 32] = seed_hash.try_into().map_err(|_| { + rusqlite::Error::InvalidParameterName("Seed hash should be 32 bytes".to_string()) + })?; let closed_wallet_seed = ClosedKeyItem { seed_hash: seed_hash_array, encrypted_seed: encrypted_seed.clone(), @@ -457,9 +461,11 @@ impl Database { WalletSeed::Closed(closed_wallet_seed) } else { WalletSeed::Open(OpenWalletSeed { - seed: encrypted_seed - .try_into() - .expect("expected to decrypt seed with no password"), + seed: encrypted_seed.try_into().map_err(|_| { + rusqlite::Error::InvalidParameterName( + "Seed should be 64 bytes for open wallet".to_string(), + ) + })?, wallet_info: closed_wallet_seed, }) }; @@ -519,8 +525,11 @@ impl Database { let path_type: u32 = row.get(5)?; let total_received: Option = row.get(6)?; - let seed_hash_array: [u8; 32] = - seed_hash.try_into().expect("Seed hash should be 32 bytes"); + let seed_hash_array: [u8; 32] = seed_hash.try_into().map_err(|_| { + rusqlite::Error::InvalidParameterName( + "Seed hash should be 32 bytes".to_string(), + ) + })?; // Convert u32 to DerivationPathReference safely let path_reference = @@ -553,12 +562,21 @@ impl Database { } else { // Standard Core addresses - validate network let address_unchecked = - Address::from_str(&address_str).expect("Invalid address format"); + Address::from_str(&address_str).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Invalid address format '{}': {}", + address_str, e + )) + })?; check_address_for_network(address_unchecked, network)? }; - let derivation_path = DerivationPath::from_str(&derivation_path) - .expect("Expected to convert to derivation path"); + let derivation_path = DerivationPath::from_str(&derivation_path).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Invalid derivation path '{}': {}", + derivation_path, e + )) + })?; let path_type = DerivationPathType::from_bits_truncate(path_type); @@ -645,11 +663,18 @@ impl Database { let script_pubkey: Vec = row.get(4)?; let address = Address::from_str(&address) - .expect("Invalid address format") + .map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Invalid UTXO address format '{}': {}", + address, e + )) + })? .assume_checked(); let outpoint = OutPoint { - txid: Txid::from_slice(&txid).expect("Invalid txid"), + txid: Txid::from_slice(&txid).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!("Invalid UTXO txid: {}", e)) + })?, vout: vout as u32, }; let tx_out = TxOut { @@ -685,30 +710,49 @@ impl Database { let islock_data: Option> = row.get(3)?; let chain_locked_height: Option = row.get(4)?; - let wallet_seed_hash_array: [u8; 32] = - wallet_seed.try_into().expect("Seed should be 64 bytes"); - let tx: Transaction = deserialize(&tx_data).expect("Failed to deserialize transaction"); + let wallet_seed_hash_array: [u8; 32] = wallet_seed.try_into().map_err(|_| { + rusqlite::Error::InvalidParameterName("Wallet seed should be 32 bytes".to_string()) + })?; + let tx: Transaction = deserialize(&tx_data).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Failed to deserialize asset lock transaction: {}", + e + )) + })?; // Ensure the transaction payload is AssetLockPayloadType let Some(TransactionPayload::AssetLockPayloadType(payload)) = &tx.special_transaction_payload else { - panic!("Expected AssetLockPayloadType in special_transaction_payload"); + return Err(rusqlite::Error::InvalidParameterName( + "Expected AssetLockPayloadType in special_transaction_payload".to_string(), + )); }; // Get the first credit output - let first = payload - .credit_outputs - .first() - .expect("Expected at least one credit output"); - - let address = - Address::from_script(&first.script_pubkey, *network).expect("expected an address"); + let first = + payload + .credit_outputs + .first() + .ok_or(rusqlite::Error::InvalidParameterName( + "Expected at least one credit output in asset lock".to_string(), + ))?; + + let address = Address::from_script(&first.script_pubkey, *network).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Failed to derive address from credit output: {}", + e + )) + })?; let (islock, proof) = if let Some(islock_bytes) = islock_data { // Deserialize the InstantLock - let is_lock: InstantLock = - deserialize(&islock_bytes).expect("Failed to deserialize InstantLock"); + let is_lock: InstantLock = deserialize(&islock_bytes).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Failed to deserialize InstantLock: {}", + e + )) + })?; ( Some(is_lock.clone()), Some(AssetLockProof::Instant(InstantAssetLockProof::new( @@ -761,14 +805,26 @@ impl Database { let is_ours: bool = row.get(8)?; let raw_transaction: Vec = row.get(9)?; - let seed_hash_array: [u8; 32] = - seed_hash.try_into().expect("Seed hash should be 32 bytes"); - let txid = Txid::from_slice(&txid_bytes).expect("Invalid txid bytes"); - let transaction: Transaction = - deserialize(&raw_transaction).expect("Failed to deserialize transaction"); + let seed_hash_array: [u8; 32] = seed_hash.try_into().map_err(|_| { + rusqlite::Error::InvalidParameterName("Seed hash should be 32 bytes".to_string()) + })?; + let txid = Txid::from_slice(&txid_bytes).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!("Invalid transaction txid: {}", e)) + })?; + let transaction: Transaction = deserialize(&raw_transaction).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!( + "Failed to deserialize transaction: {}", + e + )) + })?; let block_hash = block_hash_bytes .as_ref() - .map(|bytes| BlockHash::from_slice(bytes).expect("Invalid block hash")); + .map(|bytes| { + BlockHash::from_slice(bytes).map_err(|e| { + rusqlite::Error::InvalidParameterName(format!("Invalid block hash: {}", e)) + }) + }) + .transpose()?; let fee = fee.map(|f| f as u64); let height = height.map(|h| h as u32); @@ -861,8 +917,9 @@ impl Database { let balance: i64 = row.get(2)?; let nonce: i64 = row.get(3)?; let last_full_sync_balance: Option = row.get(4)?; - let seed_hash_array: [u8; 32] = - seed_hash.try_into().expect("Seed hash should be 32 bytes"); + let seed_hash_array: [u8; 32] = seed_hash.try_into().map_err(|_| { + rusqlite::Error::InvalidParameterName("Seed hash should be 32 bytes".to_string()) + })?; Ok(( seed_hash_array, address_str, diff --git a/src/main.rs b/src/main.rs index 2b364f62d..c5a65f6c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,6 +61,6 @@ async fn start(app_data_dir: &std::path::Path) -> Result<(), eframe::Error> { eframe::run_native( &format!("Dash Evo Tool v{}", VERSION), native_options, - Box::new(|cc| Ok(Box::new(crate::app::AppState::new(cc.egui_ctx.clone())))), + Box::new(|cc| Ok(Box::new(crate::app::AppState::new(cc.egui_ctx.clone())?))), ) } diff --git a/src/sdk_wrapper.rs b/src/sdk_wrapper.rs index 36be904c9..ae3df534f 100644 --- a/src/sdk_wrapper.rs +++ b/src/sdk_wrapper.rs @@ -10,9 +10,9 @@ pub fn initialize_sdk( config: &NetworkConfig, network: Network, context_provider: P, -) -> Sdk { +) -> Result { // Setup Platform SDK - let address_list = config.dapi_address_list(); + let address_list = config.dapi_address_list()?; let request_settings = RequestSettings { connect_timeout: Some(Duration::from_secs(1)), timeout: Some(Duration::from_secs(10)), @@ -28,7 +28,7 @@ pub fn initialize_sdk( .with_context_provider(context_provider) .with_settings(request_settings) .build() - .expect("Failed to build SDK"); + .map_err(|e| format!("Failed to build SDK: {e}"))?; info!( ?network, @@ -36,5 +36,5 @@ pub fn initialize_sdk( "SDK initialized successfully" ); - sdk + Ok(sdk) } diff --git a/src/ui/contracts_documents/add_contracts_screen.rs b/src/ui/contracts_documents/add_contracts_screen.rs index a0d69c5c4..991c49d33 100644 --- a/src/ui/contracts_documents/add_contracts_screen.rs +++ b/src/ui/contracts_documents/add_contracts_screen.rs @@ -82,7 +82,7 @@ impl AddContractsScreen { self.add_contracts_status = AddContractsStatus::WaitingForResult( SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(), ); AppAction::BackendTask(BackendTask::ContractTask(Box::new( @@ -369,7 +369,7 @@ impl ScreenLike for AddContractsScreen { AddContractsStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/contracts_documents/contracts_documents_screen.rs b/src/ui/contracts_documents/contracts_documents_screen.rs index 66b1895c8..9aa6d3738 100644 --- a/src/ui/contracts_documents/contracts_documents_screen.rs +++ b/src/ui/contracts_documents/contracts_documents_screen.rs @@ -211,7 +211,7 @@ impl DocumentQueryScreen { // Set the status to waiting and capture the current time let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.document_query_status = DocumentQueryStatus::WaitingForResult(now); self.current_page = 1; // Reset to first page @@ -346,7 +346,7 @@ impl DocumentQueryScreen { DocumentQueryStatus::WaitingForResult(start_time) => { let time_elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs() - start_time; ui.horizontal(|ui| { @@ -390,7 +390,7 @@ impl DocumentQueryScreen { self.document_query_status = DocumentQueryStatus::WaitingForResult( SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(), ); self.current_page -= 1; @@ -403,7 +403,7 @@ impl DocumentQueryScreen { self.document_query_status = DocumentQueryStatus::WaitingForResult( SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(), ); self.current_page = 1; @@ -424,7 +424,7 @@ impl DocumentQueryScreen { self.document_query_status = DocumentQueryStatus::WaitingForResult( SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(), ); if self.current_page > 1 { diff --git a/src/ui/contracts_documents/document_action_screen.rs b/src/ui/contracts_documents/document_action_screen.rs index f6661b06d..4d0301d5f 100644 --- a/src/ui/contracts_documents/document_action_screen.rs +++ b/src/ui/contracts_documents/document_action_screen.rs @@ -383,7 +383,7 @@ impl DocumentActionScreen { self.broadcast_status = BroadcastStatus::Fetching( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); action = AppAction::BackendTask(BackendTask::DocumentTask(Box::new( @@ -464,7 +464,7 @@ impl DocumentActionScreen { if let BroadcastStatus::Fetching(start) = &self.broadcast_status { let elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs() - start; ui.add_space(10.0); @@ -507,7 +507,7 @@ impl DocumentActionScreen { self.broadcast_status = BroadcastStatus::Fetching( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); action = AppAction::BackendTask(BackendTask::DocumentTask(Box::new( @@ -523,7 +523,7 @@ impl DocumentActionScreen { if let BroadcastStatus::Fetching(start) = &self.broadcast_status { let elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs() - start; ui.add_space(10.0); @@ -572,7 +572,7 @@ impl DocumentActionScreen { self.broadcast_status = BroadcastStatus::Fetching( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); action = AppAction::BackendTask(BackendTask::DocumentTask(Box::new( @@ -589,7 +589,7 @@ impl DocumentActionScreen { if let BroadcastStatus::Fetching(start) = &self.broadcast_status { let elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs() - start; ui.add_space(10.0); @@ -925,7 +925,7 @@ impl DocumentActionScreen { self.broadcast_status = BroadcastStatus::Broadcasting( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); action = AppAction::BackendTask(task); @@ -938,7 +938,7 @@ impl DocumentActionScreen { ui.add_space(10.0); let elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs() - start_time; ui.label(format!("Broadcasting... {}s", elapsed)); @@ -947,7 +947,7 @@ impl DocumentActionScreen { ui.add_space(10.0); let elapsed = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs() - start_time; ui.label(format!("Fetching... {}s", elapsed)); diff --git a/src/ui/contracts_documents/group_actions_screen.rs b/src/ui/contracts_documents/group_actions_screen.rs index 278376cea..ae2cb6056 100644 --- a/src/ui/contracts_documents/group_actions_screen.rs +++ b/src/ui/contracts_documents/group_actions_screen.rs @@ -564,7 +564,7 @@ impl ScreenLike for GroupActionsScreen { self.fetch_group_actions_status = FetchGroupActionsStatus::WaitingForResult( SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(), ); fetch_clicked = true; @@ -598,7 +598,7 @@ impl ScreenLike for GroupActionsScreen { FetchGroupActionsStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; let status = if elapsed < 60 { diff --git a/src/ui/contracts_documents/register_contract_screen.rs b/src/ui/contracts_documents/register_contract_screen.rs index c565754fe..0ad014a53 100644 --- a/src/ui/contracts_documents/register_contract_screen.rs +++ b/src/ui/contracts_documents/register_contract_screen.rs @@ -268,7 +268,7 @@ impl RegisterDataContractScreen { // Show how long we've been broadcasting let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!( @@ -279,7 +279,7 @@ impl RegisterDataContractScreen { BroadcastStatus::ProofError(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label("Broadcasted but received proof error. ⚠"); @@ -299,7 +299,7 @@ impl RegisterDataContractScreen { self.broadcast_status = BroadcastStatus::Broadcasting( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); } @@ -357,7 +357,7 @@ impl ScreenLike for RegisterDataContractScreen { self.broadcast_status = BroadcastStatus::Broadcasting( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); } @@ -369,7 +369,7 @@ impl ScreenLike for RegisterDataContractScreen { self.broadcast_status = BroadcastStatus::ProofError( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); } diff --git a/src/ui/contracts_documents/update_contract_screen.rs b/src/ui/contracts_documents/update_contract_screen.rs index e5c12fdcf..f88293156 100644 --- a/src/ui/contracts_documents/update_contract_screen.rs +++ b/src/ui/contracts_documents/update_contract_screen.rs @@ -277,7 +277,7 @@ impl UpdateDataContractScreen { // Show how long we've been fetching nonce let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!( @@ -289,7 +289,7 @@ impl UpdateDataContractScreen { // Show how long we've been broadcasting let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label("Fetched nonce successfully. ✅ "); @@ -301,7 +301,7 @@ impl UpdateDataContractScreen { BroadcastStatus::ProofError(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label("Fetched nonce successfully. ✅ "); @@ -321,7 +321,7 @@ impl UpdateDataContractScreen { self.broadcast_status = BroadcastStatus::FetchingNonce( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); } @@ -378,7 +378,7 @@ impl ScreenLike for UpdateDataContractScreen { self.broadcast_status = BroadcastStatus::Broadcasting( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); } @@ -390,7 +390,7 @@ impl ScreenLike for UpdateDataContractScreen { self.broadcast_status = BroadcastStatus::ProofError( SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), ); } diff --git a/src/ui/dashpay/contact_profile_viewer.rs b/src/ui/dashpay/contact_profile_viewer.rs index 77c6e59e6..c1e5a4838 100644 --- a/src/ui/dashpay/contact_profile_viewer.rs +++ b/src/ui/dashpay/contact_profile_viewer.rs @@ -17,7 +17,7 @@ use dash_sdk::platform::Identifier; use egui::{ColorImage, RichText, ScrollArea, TextureHandle, Ui}; use std::collections::HashMap; use std::sync::Arc; -use tracing::error; +use tracing::warn; const PUBLIC_PROFILE_INFO_TEXT: &str = "About Public Profiles:\n\n\ This is the contact's public DashPay profile.\n\n\ @@ -193,7 +193,7 @@ impl ContactProfileViewerScreen { } } Err(e) => { - error!("Failed to fetch contact avatar image: {}", e); + warn!("Failed to fetch contact avatar image: {}", e); } } }); diff --git a/src/ui/identities/add_existing_identity_screen.rs b/src/ui/identities/add_existing_identity_screen.rs index 699b1a0e5..4e0ad46d2 100644 --- a/src/ui/identities/add_existing_identity_screen.rs +++ b/src/ui/identities/add_existing_identity_screen.rs @@ -454,7 +454,7 @@ impl AddExistingIdentityScreen { if ui.add_enabled(is_valid_id, button).clicked() { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.add_identity_status = AddIdentityStatus::WaitingForResult(now); action = self.load_identity_clicked(); @@ -656,7 +656,7 @@ impl AddExistingIdentityScreen { if ui.add(button).clicked() { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.add_identity_status = AddIdentityStatus::WaitingForResult(now); self.backend_message = None; @@ -813,7 +813,7 @@ impl AddExistingIdentityScreen { if ui.add_enabled(is_valid, button).clicked() { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.add_identity_status = AddIdentityStatus::WaitingForResult(now); self.backend_message = None; @@ -1115,7 +1115,7 @@ impl ScreenLike for AddExistingIdentityScreen { AddIdentityStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/identities/keys/add_key_screen.rs b/src/ui/identities/keys/add_key_screen.rs index 4b048eca2..970a9a3cd 100644 --- a/src/ui/identities/keys/add_key_screen.rs +++ b/src/ui/identities/keys/add_key_screen.rs @@ -644,7 +644,7 @@ impl ScreenLike for AddKeyScreen { // Set the status to waiting and capture the current time let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.add_key_status = AddKeyStatus::WaitingForResult(now); inner_action |= self.validate_and_add_key(); @@ -658,7 +658,7 @@ impl ScreenLike for AddKeyScreen { AddKeyStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/identities/register_dpns_name_screen.rs b/src/ui/identities/register_dpns_name_screen.rs index 6236b47d2..7ceb12809 100644 --- a/src/ui/identities/register_dpns_name_screen.rs +++ b/src/ui/identities/register_dpns_name_screen.rs @@ -545,7 +545,7 @@ impl ScreenLike for RegisterDpnsNameScreen { // Set the status to waiting and capture the current time let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.register_dpns_name_status = RegisterDpnsNameStatus::WaitingForResult(now); inner_action = self.register_dpns_name_clicked(); @@ -561,7 +561,7 @@ impl ScreenLike for RegisterDpnsNameScreen { RegisterDpnsNameStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/identities/transfer_screen.rs b/src/ui/identities/transfer_screen.rs index 451b1c6da..4a45c1713 100644 --- a/src/ui/identities/transfer_screen.rs +++ b/src/ui/identities/transfer_screen.rs @@ -320,7 +320,7 @@ impl TransferScreen { // Set waiting state let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.transfer_credits_status = TransferCreditsStatus::WaitingForResult(now); @@ -373,7 +373,7 @@ impl TransferScreen { // Set waiting state and create backend task let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.transfer_credits_status = TransferCreditsStatus::WaitingForResult(now); @@ -771,7 +771,7 @@ impl ScreenLike for TransferScreen { TransferCreditsStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/identities/withdraw_screen.rs b/src/ui/identities/withdraw_screen.rs index 02a193099..b3de54760 100644 --- a/src/ui/identities/withdraw_screen.rs +++ b/src/ui/identities/withdraw_screen.rs @@ -275,7 +275,7 @@ impl WithdrawalScreen { self.confirmation_dialog = None; let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.withdraw_from_identity_status = WithdrawFromIdentityStatus::WaitingForResult(now); @@ -614,9 +614,9 @@ impl ScreenLike for WithdrawalScreen { WithdrawFromIdentityStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); - let elapsed_seconds = now - start_time; + let elapsed_seconds = now.saturating_sub(*start_time); let display_time = if elapsed_seconds < 60 { format!( diff --git a/src/ui/network_chooser_screen.rs b/src/ui/network_chooser_screen.rs index 961b1cbfe..cb11fec43 100644 --- a/src/ui/network_chooser_screen.rs +++ b/src/ui/network_chooser_screen.rs @@ -2039,7 +2039,7 @@ impl ScreenLike for NetworkChooserScreen { if self.any_rpc_backend() { let current_time = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards"); + .unwrap_or_default(); if let Some(time) = self.recheck_time { if current_time.as_millis() as u64 >= time { action = AppAction::BackendTask(BackendTask::CoreTask( diff --git a/src/ui/tokens/burn_tokens_screen.rs b/src/ui/tokens/burn_tokens_screen.rs index 950611c62..1ca585a5d 100644 --- a/src/ui/tokens/burn_tokens_screen.rs +++ b/src/ui/tokens/burn_tokens_screen.rs @@ -264,7 +264,7 @@ impl BurnTokensScreen { self.confirmation_dialog = None; let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = BurnTokensStatus::WaitingForResult(now); @@ -655,7 +655,7 @@ impl ScreenLike for BurnTokensScreen { BurnTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Burning... elapsed: {} seconds", elapsed)); diff --git a/src/ui/tokens/claim_tokens_screen.rs b/src/ui/tokens/claim_tokens_screen.rs index 2034815e8..850955b08 100644 --- a/src/ui/tokens/claim_tokens_screen.rs +++ b/src/ui/tokens/claim_tokens_screen.rs @@ -215,7 +215,7 @@ impl ClaimTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = ClaimTokensStatus::WaitingForResult(now); @@ -576,7 +576,7 @@ impl ScreenLike for ClaimTokensScreen { ClaimTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Claiming... elapsed: {}s", elapsed)); diff --git a/src/ui/tokens/destroy_frozen_funds_screen.rs b/src/ui/tokens/destroy_frozen_funds_screen.rs index 3ed2afdc7..42baa30b3 100644 --- a/src/ui/tokens/destroy_frozen_funds_screen.rs +++ b/src/ui/tokens/destroy_frozen_funds_screen.rs @@ -286,7 +286,7 @@ impl DestroyFrozenFundsScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = DestroyFrozenFundsStatus::WaitingForResult(now); @@ -625,7 +625,7 @@ impl ScreenLike for DestroyFrozenFundsScreen { DestroyFrozenFundsStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!( diff --git a/src/ui/tokens/direct_token_purchase_screen.rs b/src/ui/tokens/direct_token_purchase_screen.rs index 3f715ea52..700761815 100644 --- a/src/ui/tokens/direct_token_purchase_screen.rs +++ b/src/ui/tokens/direct_token_purchase_screen.rs @@ -287,7 +287,7 @@ impl PurchaseTokenScreen { self.confirmation_dialog = None; let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = PurchaseTokensStatus::WaitingForResult(now); @@ -639,7 +639,7 @@ impl ScreenLike for PurchaseTokenScreen { PurchaseTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Purchasing... elapsed: {} seconds", elapsed)); diff --git a/src/ui/tokens/freeze_tokens_screen.rs b/src/ui/tokens/freeze_tokens_screen.rs index b54bbe138..0a45fd075 100644 --- a/src/ui/tokens/freeze_tokens_screen.rs +++ b/src/ui/tokens/freeze_tokens_screen.rs @@ -277,7 +277,7 @@ impl FreezeTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = FreezeTokensStatus::WaitingForResult(now); @@ -623,7 +623,7 @@ impl ScreenLike for FreezeTokensScreen { FreezeTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Freezing... elapsed: {}s", elapsed)); diff --git a/src/ui/tokens/mint_tokens_screen.rs b/src/ui/tokens/mint_tokens_screen.rs index c52e28faf..ca3c879aa 100644 --- a/src/ui/tokens/mint_tokens_screen.rs +++ b/src/ui/tokens/mint_tokens_screen.rs @@ -310,7 +310,7 @@ impl MintTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = MintTokensStatus::WaitingForResult(now); @@ -708,7 +708,7 @@ impl ScreenLike for MintTokensScreen { MintTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Minting... elapsed: {} seconds", elapsed)); diff --git a/src/ui/tokens/pause_tokens_screen.rs b/src/ui/tokens/pause_tokens_screen.rs index 6b9ed6525..5e7d023ac 100644 --- a/src/ui/tokens/pause_tokens_screen.rs +++ b/src/ui/tokens/pause_tokens_screen.rs @@ -219,7 +219,7 @@ impl PauseTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = PauseTokensStatus::WaitingForResult(now); @@ -528,7 +528,7 @@ impl ScreenLike for PauseTokensScreen { PauseTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Pausing... elapsed: {}s", elapsed)); diff --git a/src/ui/tokens/resume_tokens_screen.rs b/src/ui/tokens/resume_tokens_screen.rs index f10837fe3..b99686160 100644 --- a/src/ui/tokens/resume_tokens_screen.rs +++ b/src/ui/tokens/resume_tokens_screen.rs @@ -219,7 +219,7 @@ impl ResumeTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = ResumeTokensStatus::WaitingForResult(now); @@ -528,7 +528,7 @@ impl ScreenLike for ResumeTokensScreen { ResumeTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Resuming... elapsed: {}s", elapsed)); diff --git a/src/ui/tokens/set_token_price_screen.rs b/src/ui/tokens/set_token_price_screen.rs index 813d9c50f..6e86365b2 100644 --- a/src/ui/tokens/set_token_price_screen.rs +++ b/src/ui/tokens/set_token_price_screen.rs @@ -728,7 +728,7 @@ impl SetTokenPriceScreen { // Set waiting state let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = SetTokenPriceStatus::WaitingForResult(now); @@ -1143,7 +1143,7 @@ impl ScreenLike for SetTokenPriceScreen { SetTokenPriceStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Setting price... elapsed: {} seconds", elapsed)); diff --git a/src/ui/tokens/transfer_tokens_screen.rs b/src/ui/tokens/transfer_tokens_screen.rs index 53719d284..338d2faac 100644 --- a/src/ui/tokens/transfer_tokens_screen.rs +++ b/src/ui/tokens/transfer_tokens_screen.rs @@ -225,7 +225,7 @@ impl TransferTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.transfer_tokens_status = TransferTokensStatus::WaitingForResult(now); @@ -552,7 +552,7 @@ impl ScreenLike for TransferTokensScreen { TransferTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/tokens/unfreeze_tokens_screen.rs b/src/ui/tokens/unfreeze_tokens_screen.rs index 9bbbe4ad5..90aab2d03 100644 --- a/src/ui/tokens/unfreeze_tokens_screen.rs +++ b/src/ui/tokens/unfreeze_tokens_screen.rs @@ -279,7 +279,7 @@ impl UnfreezeTokensScreen { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.status = UnfreezeTokensStatus::WaitingForResult(now); @@ -612,7 +612,7 @@ impl ScreenLike for UnfreezeTokensScreen { UnfreezeTokensStatus::WaitingForResult(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed = now - start_time; ui.label(format!("Unfreezing... elapsed: {}s", elapsed)); diff --git a/src/ui/tokens/update_token_config.rs b/src/ui/tokens/update_token_config.rs index 82ea57b3f..f7ab218a3 100644 --- a/src/ui/tokens/update_token_config.rs +++ b/src/ui/tokens/update_token_config.rs @@ -676,7 +676,7 @@ impl UpdateTokenConfigScreen { ui.label("No parameters to edit for this entry."); } TokenConfigurationChangeItem::MarketplaceTradeMode(_) => { - unimplemented!("marketplace settings not implemented yet") + ui.label("Marketplace settings are not yet supported."); } } }); diff --git a/src/ui/tools/transition_visualizer_screen.rs b/src/ui/tools/transition_visualizer_screen.rs index 8faa82106..169e56650 100644 --- a/src/ui/tools/transition_visualizer_screen.rs +++ b/src/ui/tools/transition_visualizer_screen.rs @@ -237,7 +237,7 @@ impl TransitionVisualizerScreen { // Mark as submitting let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); self.broadcast_status = TransitionBroadcastStatus::Submitting(now); @@ -265,7 +265,7 @@ impl TransitionVisualizerScreen { TransitionBroadcastStatus::Submitting(start_time) => { let now = SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs(); let elapsed_seconds = now - start_time; diff --git a/src/ui/wallets/send_screen.rs b/src/ui/wallets/send_screen.rs index bfd70e3dc..7e3059cfb 100644 --- a/src/ui/wallets/send_screen.rs +++ b/src/ui/wallets/send_screen.rs @@ -485,7 +485,7 @@ impl WalletSendScreen { fn now_epoch_secs() -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) - .expect("Time went backwards") + .unwrap_or_default() .as_secs() } diff --git a/src/ui/wallets/wallets_screen/dialogs.rs b/src/ui/wallets/wallets_screen/dialogs.rs index 899840c16..5c9b640d2 100644 --- a/src/ui/wallets/wallets_screen/dialogs.rs +++ b/src/ui/wallets/wallets_screen/dialogs.rs @@ -16,7 +16,7 @@ use dash_sdk::dpp::key_wallet::bip32::DerivationPath; use eframe::egui::{self, ComboBox, Context}; use eframe::epaint::TextureHandle; use egui::load::SizedTexture; -use egui::{Color32, Frame, Margin, RichText, TextureOptions}; +use egui::{Frame, Margin, RichText, TextureOptions}; use std::sync::{Arc, RwLock}; use super::WalletsBalancesScreen; diff --git a/tests/e2e/navigation.rs b/tests/e2e/navigation.rs index 322193f8a..8681c1fb7 100644 --- a/tests/e2e/navigation.rs +++ b/tests/e2e/navigation.rs @@ -12,7 +12,9 @@ fn test_basic_navigation() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -35,7 +37,9 @@ fn test_navigation_responsive_layout() { for size in sizes { let mut harness = Harness::builder().with_max_steps(50).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(size); @@ -50,7 +54,9 @@ fn test_rapid_frame_navigation() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(300).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -68,7 +74,9 @@ fn test_extended_navigation_stability() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(500).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1280.0, 720.0)); @@ -88,7 +96,9 @@ fn test_minimum_size_navigation() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(50).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Very small window diff --git a/tests/e2e/wallet_flows.rs b/tests/e2e/wallet_flows.rs index 124af420d..d375740d4 100644 --- a/tests/e2e/wallet_flows.rs +++ b/tests/e2e/wallet_flows.rs @@ -12,7 +12,9 @@ fn test_wallet_state_initialization() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -26,7 +28,9 @@ fn test_wallet_balance_rendering() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -42,7 +46,9 @@ fn test_wallet_ui_responsiveness() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(200).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -62,7 +68,9 @@ fn test_wallet_resize_stability() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(150).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Test various resize scenarios diff --git a/tests/kittest/create_asset_lock_screen.rs b/tests/kittest/create_asset_lock_screen.rs index be1d984f2..0296ed2d2 100644 --- a/tests/kittest/create_asset_lock_screen.rs +++ b/tests/kittest/create_asset_lock_screen.rs @@ -7,7 +7,9 @@ fn test_create_asset_lock_screen_renders() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -21,7 +23,9 @@ fn test_create_asset_lock_screen_resize() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Test various window sizes @@ -45,7 +49,9 @@ fn test_create_asset_lock_screen_frame_stability() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(200).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); diff --git a/tests/kittest/identities_screen.rs b/tests/kittest/identities_screen.rs index 01927d089..bf4cdf273 100644 --- a/tests/kittest/identities_screen.rs +++ b/tests/kittest/identities_screen.rs @@ -7,7 +7,9 @@ fn test_identities_screen_renders() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -21,7 +23,9 @@ fn test_minimum_window_size() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(50).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Test with a small window size @@ -36,7 +40,9 @@ fn test_window_resize() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Start small @@ -59,7 +65,9 @@ fn test_frame_batch_processing() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(150).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); diff --git a/tests/kittest/network_chooser.rs b/tests/kittest/network_chooser.rs index 1d249b45c..022a11449 100644 --- a/tests/kittest/network_chooser.rs +++ b/tests/kittest/network_chooser.rs @@ -9,7 +9,9 @@ fn test_network_chooser_renders() { // Create a test harness for the egui app let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Set the window size @@ -26,7 +28,9 @@ fn test_app_handles_frame_stepping() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(50).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(800.0, 600.0)); @@ -51,7 +55,9 @@ fn test_app_renders_at_various_sizes() { for size in sizes { let mut harness = Harness::builder().with_max_steps(50).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(size); diff --git a/tests/kittest/startup.rs b/tests/kittest/startup.rs index 3ea5c7151..44a55d0aa 100644 --- a/tests/kittest/startup.rs +++ b/tests/kittest/startup.rs @@ -10,7 +10,9 @@ fn test_app_startup() { // Create a test harness for the egui app let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); // Set the window size diff --git a/tests/kittest/wallets_screen.rs b/tests/kittest/wallets_screen.rs index c305fdcc4..ed40249ea 100644 --- a/tests/kittest/wallets_screen.rs +++ b/tests/kittest/wallets_screen.rs @@ -7,7 +7,9 @@ fn test_wallets_screen_renders() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -21,7 +23,9 @@ fn test_app_stability_over_many_frames() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(200).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(1024.0, 768.0)); @@ -37,7 +41,9 @@ fn test_rapid_frame_stepping() { let _guard = rt.enter(); let mut harness = Harness::builder().with_max_steps(100).build_eframe(|ctx| { - dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()).with_animations(false) + dash_evo_tool::app::AppState::new(ctx.egui_ctx.clone()) + .expect("Failed to create AppState") + .with_animations(false) }); harness.set_size(egui::vec2(800.0, 600.0));