diff --git a/src/backend_task/identity/mod.rs b/src/backend_task/identity/mod.rs index e1b50b5d2..a7718339e 100644 --- a/src/backend_task/identity/mod.rs +++ b/src/backend_task/identity/mod.rs @@ -452,7 +452,7 @@ impl AppContext { .await } IdentityTask::RegisterIdentity(registration_info) => { - self.register_identity(registration_info, sender).await + self.register_identity(registration_info).await } IdentityTask::RegisterDpnsName(input) => self.register_dpns_name(sdk, input).await, IdentityTask::RefreshIdentity(qualified_identity) => self @@ -467,9 +467,7 @@ impl AppContext { self.load_user_identity_from_wallet(sdk, wallet, identity_index) .await } - IdentityTask::TopUpIdentity(top_up_info) => { - self.top_up_identity(top_up_info, sender).await - } + IdentityTask::TopUpIdentity(top_up_info) => self.top_up_identity(top_up_info).await, IdentityTask::RefreshLoadedIdentitiesOwnedDPNSNames => { self.refresh_loaded_identities_dpns_names(sender).await } diff --git a/src/backend_task/identity/register_identity.rs b/src/backend_task/identity/register_identity.rs index 837460c2f..63f9258a3 100644 --- a/src/backend_task/identity/register_identity.rs +++ b/src/backend_task/identity/register_identity.rs @@ -1,4 +1,3 @@ -use crate::app::TaskResult; use crate::backend_task::BackendTaskSuccessResult; use crate::backend_task::identity::{IdentityRegistrationInfo, RegisterIdentityFundingMethod}; use crate::context::AppContext; @@ -20,93 +19,9 @@ use std::collections::BTreeMap; use std::time::Duration; impl AppContext { - // pub(crate) async fn broadcast_and_retrieve_asset_lock( - // &self, - // asset_lock_transaction: &Transaction, - // address: &Address, - // ) -> Result { - // // Use the span only for synchronous logging before the first await. - // // tracing::debug_span!( - // // "broadcast_and_retrieve_asset_lock", - // // transaction_id = asset_lock_transaction.txid().to_string(), - // // ) - // // .in_scope(|| { - // // tracing::debug!("Starting asset lock broadcast."); - // // }); - // - // let sdk = &self.sdk; - // - // let block_hash = sdk - // .execute(GetBlockchainStatusRequest {}, RequestSettings::default()) - // .await? - // .chain - // .map(|chain| chain.best_block_hash) - // .ok_or_else(|| dash_sdk::Error::DapiClientError("Missing `chain` field".to_owned()))?; - // - // // tracing::debug!( - // // "Starting the stream from the tip block hash {}", - // // hex::encode(&block_hash) - // // ); - // - // let mut asset_lock_stream = sdk - // .start_instant_send_lock_stream(block_hash, address) - // .await?; - // - // // tracing::debug!("Stream is started."); - // - // let request = BroadcastTransactionRequest { - // transaction: asset_lock_transaction.serialize(), - // allow_high_fees: false, - // bypass_limits: false, - // }; - // - // // tracing::debug!("Broadcasting the transaction."); - // - // match sdk.execute(request, RequestSettings::default()).await { - // Ok(_) => {} - // Err(error) if error.to_string().contains("AlreadyExists") => { - // // tracing::warn!("Transaction already broadcasted."); - // - // let GetTransactionResponse { block_hash, .. } = sdk - // .execute( - // GetTransactionRequest { - // id: asset_lock_transaction.txid().to_string(), - // }, - // RequestSettings::default(), - // ) - // .await?; - // - // // tracing::debug!( - // // "Restarting the stream from the transaction mined block hash {}", - // // hex::encode(&block_hash) - // // ); - // - // asset_lock_stream = sdk - // .start_instant_send_lock_stream(block_hash, address) - // .await?; - // - // // tracing::debug!("Stream restarted."); - // } - // Err(error) => { - // // tracing::error!("Transaction broadcast failed: {error}"); - // return Err(error.into()); - // } - // } - // - // // tracing::debug!("Waiting for asset lock proof."); - // - // sdk.wait_for_asset_lock_proof_for_transaction( - // asset_lock_stream, - // asset_lock_transaction, - // Some(Duration::from_secs(4 * 60)), - // ) - // .await - // } - pub(super) async fn register_identity( &self, input: IdentityRegistrationInfo, - sender: crate::utils::egui_mpsc::SenderAsync, ) -> Result { let IdentityRegistrationInfo { alias_input, @@ -203,12 +118,6 @@ impl AppContext { }; let tx_id = asset_lock_transaction.txid(); - // todo: maybe one day we will want to use platform again, but for right now we use - // the local core as it is more stable - // let asset_lock_proof = self - // .broadcast_and_retrieve_asset_lock(&asset_lock_transaction, &change_address) - // .await - // .map_err(|e| e.to_string())?; { let mut proofs = self.transactions_waiting_for_finality.lock().unwrap(); @@ -270,12 +179,6 @@ impl AppContext { }; let tx_id = asset_lock_transaction.txid(); - // todo: maybe one day we will want to use platform again, but for right now we use - // the local core as it is more stable - // let asset_lock_proof = self - // .broadcast_and_retrieve_asset_lock(&asset_lock_transaction, &change_address) - // .await - // .map_err(|e| e.to_string())?; { let mut proofs = self.transactions_waiting_for_finality.lock().unwrap(); @@ -414,13 +317,6 @@ impl AppContext { .set_asset_lock_identity_id(tx_id.as_byte_array(), identity_id.as_bytes()) .map_err(|e| e.to_string())?; - sender - .send(TaskResult::Success(Box::new( - BackendTaskSuccessResult::None, - ))) - .await - .map_err(|e| e.to_string())?; - Ok(BackendTaskSuccessResult::RegisteredIdentity( qualified_identity, )) diff --git a/src/backend_task/identity/top_up_identity.rs b/src/backend_task/identity/top_up_identity.rs index b2bb94808..3743b4d47 100644 --- a/src/backend_task/identity/top_up_identity.rs +++ b/src/backend_task/identity/top_up_identity.rs @@ -1,4 +1,3 @@ -use crate::app::TaskResult; use crate::backend_task::BackendTaskSuccessResult; use crate::backend_task::identity::{IdentityTopUpInfo, TopUpIdentityFundingMethod}; use crate::context::AppContext; @@ -21,7 +20,6 @@ impl AppContext { pub(super) async fn top_up_identity( &self, input: IdentityTopUpInfo, - sender: crate::utils::egui_mpsc::SenderAsync, ) -> Result { let IdentityTopUpInfo { mut qualified_identity, @@ -331,13 +329,6 @@ impl AppContext { .map_err(|e| e.to_string())?; } - sender - .send(TaskResult::Success(Box::new( - BackendTaskSuccessResult::None, - ))) - .await - .map_err(|e| e.to_string())?; - Ok(BackendTaskSuccessResult::ToppedUpIdentity( qualified_identity, )) diff --git a/src/ui/identities/add_new_identity_screen/by_using_unused_asset_lock.rs b/src/ui/identities/add_new_identity_screen/by_using_unused_asset_lock.rs index 628dd333f..aea781aeb 100644 --- a/src/ui/identities/add_new_identity_screen/by_using_unused_asset_lock.rs +++ b/src/ui/identities/add_new_identity_screen/by_using_unused_asset_lock.rs @@ -102,18 +102,14 @@ impl AddNewIdentityScreen { ui.add_space(20.0); } - ui.vertical_centered(|ui| { - match step { - WalletFundedScreenStep::WaitingForPlatformAcceptance => { - ui.heading("=> Waiting for Platform acknowledgement <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); - } - WalletFundedScreenStep::Success => { - ui.heading("...Success..."); - } - _ => {} + ui.vertical_centered(|ui| match step { + WalletFundedScreenStep::WaitingForPlatformAcceptance => { + ui.heading("=> Waiting for Platform acknowledgement <="); } + WalletFundedScreenStep::Success => { + ui.heading("...Success..."); + } + _ => {} }); ui.add_space(40.0); diff --git a/src/ui/identities/add_new_identity_screen/by_using_unused_balance.rs b/src/ui/identities/add_new_identity_screen/by_using_unused_balance.rs index fe6c25daf..81612bedc 100644 --- a/src/ui/identities/add_new_identity_screen/by_using_unused_balance.rs +++ b/src/ui/identities/add_new_identity_screen/by_using_unused_balance.rs @@ -61,23 +61,17 @@ impl AddNewIdentityScreen { ui.add_space(20.0); } - ui.vertical_centered(|ui| { - match step { - WalletFundedScreenStep::WaitingForAssetLock => { - ui.heading("=> Waiting for Core Chain to produce proof of transfer of funds. <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); - } - WalletFundedScreenStep::WaitingForPlatformAcceptance => { - ui.heading("=> Waiting for Platform acknowledgement <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); - } - WalletFundedScreenStep::Success => { - ui.heading("...Success..."); - } - _ => {} + ui.vertical_centered(|ui| match step { + WalletFundedScreenStep::WaitingForAssetLock => { + ui.heading("=> Waiting for Core Chain to produce proof of transfer of funds. <="); } + WalletFundedScreenStep::WaitingForPlatformAcceptance => { + ui.heading("=> Waiting for Platform acknowledgement <="); + } + WalletFundedScreenStep::Success => { + ui.heading("...Success..."); + } + _ => {} }); ui.add_space(40.0); diff --git a/src/ui/identities/add_new_identity_screen/by_wallet_qr_code.rs b/src/ui/identities/add_new_identity_screen/by_wallet_qr_code.rs index 14b905714..c3c9c3455 100644 --- a/src/ui/identities/add_new_identity_screen/by_wallet_qr_code.rs +++ b/src/ui/identities/add_new_identity_screen/by_wallet_qr_code.rs @@ -6,7 +6,7 @@ use crate::backend_task::identity::{ use crate::ui::identities::add_new_identity_screen::{ AddNewIdentityScreen, WalletFundedScreenStep, }; -use crate::ui::identities::funding_common::{copy_to_clipboard, generate_qr_code_image}; +use crate::ui::identities::funding_common::{self, copy_to_clipboard, generate_qr_code_image}; use dash_sdk::dashcore_rpc::RpcApi; use eframe::epaint::TextureHandle; use egui::{Color32, Ui}; @@ -119,6 +119,15 @@ impl AddNewIdentityScreen { } pub fn render_ui_by_wallet_qr_code(&mut self, ui: &mut Ui, step_number: u32) -> AppAction { + // Update state when funds land on the QR funding address + if let Some(utxo) = funding_common::capture_qr_funding_utxo_if_available( + &self.step, + self.selected_wallet.as_ref(), + self.funding_address.as_ref(), + ) { + self.funding_utxo = Some(utxo); + } + // Extract the step from the RwLock to minimize borrow scope let step = *self.step.read().unwrap(); @@ -136,6 +145,11 @@ impl AddNewIdentityScreen { self.render_funding_amount_input(ui); + if step == WalletFundedScreenStep::WaitingOnFunds { + ui.ctx() + .request_repaint_after(std::time::Duration::from_secs(1)); + } + let Ok(amount_dash) = self.funding_amount.parse::() else { return AppAction::None; }; @@ -148,65 +162,65 @@ impl AddNewIdentityScreen { egui::Layout::top_down(egui::Align::Min).with_cross_align(egui::Align::Center), |ui| { if let Err(e) = self.render_qr_code(ui, amount_dash) { - self.error_message = Some(e); - } - - ui.add_space(20.0); + self.error_message = Some(e); + } - if let Some(error_message) = self.error_message.as_ref() { - ui.colored_label(Color32::DARK_RED, error_message); ui.add_space(20.0); - } - match step { - WalletFundedScreenStep::ChooseFundingMethod => {} - WalletFundedScreenStep::WaitingOnFunds => { - ui.heading("=> Waiting for funds. <="); + if let Some(error_message) = self.error_message.as_ref() { + ui.colored_label(Color32::DARK_RED, error_message); + ui.add_space(20.0); } - WalletFundedScreenStep::FundsReceived => { - let Some(selected_wallet) = &self.selected_wallet else { - return AppAction::None; - }; - if let Some((utxo, tx_out, address)) = self.funding_utxo.clone() { - let identity_input = IdentityRegistrationInfo { - alias_input: self.alias_input.clone(), - keys: self.identity_keys.clone(), - wallet: Arc::clone(selected_wallet), // Clone the Arc reference - wallet_identity_index: self.identity_id_number, - identity_funding_method: RegisterIdentityFundingMethod::FundWithUtxo( - utxo, - tx_out, - address, - self.identity_id_number, - ), - }; - - let mut step = self.step.write().unwrap(); - *step = WalletFundedScreenStep::WaitingForAssetLock; - // Create the backend task to register the identity - return AppAction::BackendTask(BackendTask::IdentityTask( - IdentityTask::RegisterIdentity(identity_input), - )) + match step { + WalletFundedScreenStep::ChooseFundingMethod => {} + WalletFundedScreenStep::WaitingOnFunds => { + ui.heading("=> Waiting for funds. <="); + } + WalletFundedScreenStep::FundsReceived => { + let Some(selected_wallet) = &self.selected_wallet else { + return AppAction::None; + }; + if let Some((utxo, tx_out, address)) = self.funding_utxo.clone() { + let identity_input = IdentityRegistrationInfo { + alias_input: self.alias_input.clone(), + keys: self.identity_keys.clone(), + wallet: Arc::clone(selected_wallet), // Clone the Arc reference + wallet_identity_index: self.identity_id_number, + identity_funding_method: + RegisterIdentityFundingMethod::FundWithUtxo( + utxo, + tx_out, + address, + self.identity_id_number, + ), + }; + + let mut step = self.step.write().unwrap(); + *step = WalletFundedScreenStep::WaitingForAssetLock; + + // Create the backend task to register the identity + return AppAction::BackendTask(BackendTask::IdentityTask( + IdentityTask::RegisterIdentity(identity_input), + )); + } + } + WalletFundedScreenStep::ReadyToCreate => {} + WalletFundedScreenStep::WaitingForAssetLock => { + ui.heading( + "=> Waiting for Core Chain to produce proof of transfer of funds. <=", + ); + } + WalletFundedScreenStep::WaitingForPlatformAcceptance => { + ui.heading("=> Waiting for Platform acknowledgement. <="); + } + WalletFundedScreenStep::Success => { + ui.heading("...Success..."); } } - WalletFundedScreenStep::ReadyToCreate => {} - WalletFundedScreenStep::WaitingForAssetLock => { - ui.heading("=> Waiting for Core Chain to produce proof of transfer of funds. <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); - } - WalletFundedScreenStep::WaitingForPlatformAcceptance => { - ui.heading("=> Waiting for Platform acknowledgement. <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); - } - WalletFundedScreenStep::Success => { - ui.heading("...Success..."); - } - } - AppAction::None - }); + AppAction::None + }, + ); ui.add_space(40.0); diff --git a/src/ui/identities/add_new_identity_screen/mod.rs b/src/ui/identities/add_new_identity_screen/mod.rs index 87d8b2f0e..040b1a540 100644 --- a/src/ui/identities/add_new_identity_screen/mod.rs +++ b/src/ui/identities/add_new_identity_screen/mod.rs @@ -888,19 +888,29 @@ impl ScreenLike for AddNewIdentityScreen { } } fn display_task_result(&mut self, backend_task_success_result: BackendTaskSuccessResult) { + if let BackendTaskSuccessResult::RegisteredIdentity(qualified_identity) = + &backend_task_success_result + { + self.successful_qualified_identity_id = Some(qualified_identity.identity.id()); + let mut step = self.step.write().unwrap(); + *step = WalletFundedScreenStep::Success; + return; + } + let mut step = self.step.write().unwrap(); - match *step { + let current_step = *step; + match current_step { WalletFundedScreenStep::ChooseFundingMethod => {} WalletFundedScreenStep::WaitingOnFunds => { if let Some(funding_address) = self.funding_address.as_ref() && let BackendTaskSuccessResult::CoreItem( CoreItem::ReceivedAvailableUTXOTransaction(_, outpoints_with_addresses), - ) = backend_task_success_result + ) = &backend_task_success_result { for (outpoint, tx_out, address) in outpoints_with_addresses { - if funding_address == &address { + if funding_address == address { *step = WalletFundedScreenStep::FundsReceived; - self.funding_utxo = Some((outpoint, tx_out, address)) + self.funding_utxo = Some((*outpoint, tx_out.clone(), address.clone())) } } } @@ -910,9 +920,9 @@ impl ScreenLike for AddNewIdentityScreen { WalletFundedScreenStep::WaitingForAssetLock => { if let BackendTaskSuccessResult::CoreItem( CoreItem::ReceivedAvailableUTXOTransaction(tx, _), - ) = backend_task_success_result + ) = &backend_task_success_result && let Some(TransactionPayload::AssetLockPayloadType(asset_lock_payload)) = - tx.special_transaction_payload + &tx.special_transaction_payload && asset_lock_payload.credit_outputs.iter().any(|tx_out| { let Ok(address) = Address::from_script(&tx_out.script_pubkey, self.app_context.network) @@ -930,14 +940,7 @@ impl ScreenLike for AddNewIdentityScreen { *step = WalletFundedScreenStep::WaitingForPlatformAcceptance; } } - WalletFundedScreenStep::WaitingForPlatformAcceptance => { - if let BackendTaskSuccessResult::RegisteredIdentity(qualified_identity) = - backend_task_success_result - { - self.successful_qualified_identity_id = Some(qualified_identity.identity.id()); - *step = WalletFundedScreenStep::Success; - } - } + WalletFundedScreenStep::WaitingForPlatformAcceptance => {} WalletFundedScreenStep::Success => {} } } diff --git a/src/ui/identities/funding_common.rs b/src/ui/identities/funding_common.rs index 4dd6802d9..d1909e044 100644 --- a/src/ui/identities/funding_common.rs +++ b/src/ui/identities/funding_common.rs @@ -3,6 +3,11 @@ use eframe::epaint::{Color32, ColorImage}; use egui::Vec2; use image::Luma; use qrcode::QrCode; +use std::sync::{Arc, RwLock}; + +use crate::model::wallet::Wallet; +use dash_sdk::dashcore_rpc::dashcore::Address; +use dash_sdk::dpp::dashcore::{OutPoint, TxOut}; #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] pub enum WalletFundedScreenStep { @@ -47,3 +52,43 @@ pub fn copy_to_clipboard(text: &str) -> Result<(), String> { .set_text(text.to_string()) .map_err(|e| e.to_string()) } + +pub fn capture_qr_funding_utxo_if_available( + step: &Arc>, + wallet: Option<&Arc>>, + funding_address: Option<&Address>, +) -> Option<(OutPoint, TxOut, Address)> { + if !matches!( + *step.read().expect("wallet funding step lock poisoned"), + WalletFundedScreenStep::WaitingOnFunds + ) { + return None; + } + + let address = funding_address.cloned()?; + + let wallet_arc = wallet?; + + let candidate_utxo = { + let wallet = wallet_arc + .read() + .expect("wallet lock poisoned while checking funding UTXO"); + wallet.utxos.get(&address).and_then(|utxos| { + utxos + .iter() + .filter(|(_, tx_out)| tx_out.value > 0) + .max_by_key(|(_, tx_out)| tx_out.value) + .map(|(outpoint, tx_out)| (*outpoint, tx_out.clone())) + }) + }; + + if let Some((outpoint, tx_out)) = candidate_utxo { + let mut step = step + .write() + .expect("wallet funding step write lock poisoned"); + *step = WalletFundedScreenStep::FundsReceived; + Some((outpoint, tx_out, address)) + } else { + None + } +} diff --git a/src/ui/identities/top_up_identity_screen/by_using_unused_asset_lock.rs b/src/ui/identities/top_up_identity_screen/by_using_unused_asset_lock.rs index ccb420274..4b9ea0a4c 100644 --- a/src/ui/identities/top_up_identity_screen/by_using_unused_asset_lock.rs +++ b/src/ui/identities/top_up_identity_screen/by_using_unused_asset_lock.rs @@ -115,8 +115,6 @@ impl TopUpIdentityScreen { ui.vertical_centered(|ui| match step { WalletFundedScreenStep::WaitingForPlatformAcceptance => { ui.heading("=> Waiting for Platform acknowledgement <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); } WalletFundedScreenStep::Success => { ui.heading("...Success..."); diff --git a/src/ui/identities/top_up_identity_screen/by_using_unused_balance.rs b/src/ui/identities/top_up_identity_screen/by_using_unused_balance.rs index 762f4a051..0a9e598e7 100644 --- a/src/ui/identities/top_up_identity_screen/by_using_unused_balance.rs +++ b/src/ui/identities/top_up_identity_screen/by_using_unused_balance.rs @@ -68,14 +68,12 @@ impl TopUpIdentityScreen { ui.vertical_centered(|ui| { match step { WalletFundedScreenStep::WaitingForAssetLock => { - ui.heading("=> Waiting for Core Chain to produce proof of transfer of funds. <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); + ui.heading( + "=> Waiting for Core Chain to produce proof of transfer of funds. <=", + ); } WalletFundedScreenStep::WaitingForPlatformAcceptance => { ui.heading("=> Waiting for Platform acknowledgement <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); } WalletFundedScreenStep::Success => { ui.heading("...Success..."); diff --git a/src/ui/identities/top_up_identity_screen/by_wallet_qr_code.rs b/src/ui/identities/top_up_identity_screen/by_wallet_qr_code.rs index 4ee0b1575..d3bf7c213 100644 --- a/src/ui/identities/top_up_identity_screen/by_wallet_qr_code.rs +++ b/src/ui/identities/top_up_identity_screen/by_wallet_qr_code.rs @@ -1,7 +1,7 @@ use crate::app::AppAction; use crate::backend_task::BackendTask; use crate::backend_task::identity::{IdentityTask, IdentityTopUpInfo, TopUpIdentityFundingMethod}; -use crate::ui::identities::funding_common::{copy_to_clipboard, generate_qr_code_image}; +use crate::ui::identities::funding_common::{self, copy_to_clipboard, generate_qr_code_image}; use crate::ui::identities::top_up_identity_screen::{TopUpIdentityScreen, WalletFundedScreenStep}; use dash_sdk::dashcore_rpc::RpcApi; use eframe::epaint::TextureHandle; @@ -92,6 +92,15 @@ impl TopUpIdentityScreen { } pub fn render_ui_by_wallet_qr_code(&mut self, ui: &mut Ui, step_number: u32) -> AppAction { + // Update state when the QR funding address receives funds + if let Some(utxo) = funding_common::capture_qr_funding_utxo_if_available( + &self.step, + self.wallet.as_ref(), + self.funding_address.as_ref(), + ) { + self.funding_utxo = Some(utxo); + } + // Extract the step from the RwLock to minimize borrow scope let step = *self.step.read().unwrap(); @@ -107,6 +116,11 @@ impl TopUpIdentityScreen { self.top_up_funding_amount_input(ui); + if step == WalletFundedScreenStep::WaitingOnFunds { + ui.ctx() + .request_repaint_after(std::time::Duration::from_secs(1)); + } + let response = ui.vertical_centered(|ui| { // Only try to render QR code if we have a valid amount if let Ok(amount_dash) = self.funding_amount.parse::() { @@ -169,14 +183,12 @@ impl TopUpIdentityScreen { } WalletFundedScreenStep::ReadyToCreate => {} WalletFundedScreenStep::WaitingForAssetLock => { - ui.heading("=> Waiting for Core Chain to produce proof of transfer of funds. <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); + ui.heading( + "=> Waiting for Core Chain to produce proof of transfer of funds. <=", + ); } WalletFundedScreenStep::WaitingForPlatformAcceptance => { ui.heading("=> Waiting for Platform acknowledgement. <="); - ui.add_space(20.0); - ui.label("NOTE: If this gets stuck, the funds were likely either transferred to the wallet or asset locked,\nand you can use the funding method selector in step 1 to change the method and use those funds to complete the process."); } WalletFundedScreenStep::Success => { ui.heading("...Success..."); diff --git a/src/ui/identities/top_up_identity_screen/mod.rs b/src/ui/identities/top_up_identity_screen/mod.rs index 13d844691..56b5f19ed 100644 --- a/src/ui/identities/top_up_identity_screen/mod.rs +++ b/src/ui/identities/top_up_identity_screen/mod.rs @@ -72,10 +72,15 @@ impl TopUpIdentityScreen { } fn render_wallet_selection(&mut self, ui: &mut Ui) -> bool { - if self.app_context.has_wallet.load(Ordering::Relaxed) { - let wallets = self.app_context.wallets.read().unwrap(); + let mut selected_wallet_update: Option>> = None; + let mut step_update_method: Option = None; + + let rendered = if self.app_context.has_wallet.load(Ordering::Relaxed) { + let wallets_guard = self.app_context.wallets.read().unwrap(); + let wallets = &*wallets_guard; + if wallets.len() > 1 { - // Get the current funding method + // Cache current funding method to avoid holding the lock across UI callbacks let funding_method = *self.funding_method.read().unwrap(); // Retrieve the alias of the currently selected wallet, if any @@ -115,19 +120,8 @@ impl TopUpIdentityScreen { ui.add_enabled_ui(has_required_resources, |ui| { if ui.selectable_label(is_selected, wallet_alias).clicked() { - // Update the selected wallet from app_context - self.wallet = Some(wallet.clone()); - // Reset the funding address - self.funding_address = None; - // Reset the funding asset lock - self.funding_asset_lock = None; - // Reset the funding UTXO - self.funding_utxo = None; - // Reset the copied to clipboard state - self.copied_to_clipboard = None; - // Reset the step to choose funding method - let mut step = self.step.write().unwrap(); - *step = WalletFundedScreenStep::ChooseFundingMethod; + selected_wallet_update = Some(wallet.clone()); + step_update_method = Some(funding_method); } }); } @@ -135,7 +129,7 @@ impl TopUpIdentityScreen { true } else if let Some(wallet) = wallets.values().next() { if self.wallet.is_none() { - // Get the current funding method + // Cache current funding method to avoid holding the lock across updates let funding_method = *self.funding_method.read().unwrap(); // Check if the wallet has the required resources @@ -152,7 +146,8 @@ impl TopUpIdentityScreen { if has_required_resources { // Automatically select the only available wallet from app_context - self.wallet = Some(wallet.clone()); + selected_wallet_update = Some(wallet.clone()); + step_update_method = Some(funding_method); } } false @@ -161,7 +156,36 @@ impl TopUpIdentityScreen { } } else { false + }; + + if let Some(wallet) = selected_wallet_update { + self.wallet = Some(wallet); + self.funding_address = None; + self.funding_asset_lock = None; + self.funding_utxo = None; + self.copied_to_clipboard = None; + + if let Some(method) = step_update_method { + self.update_step_after_wallet_change(method); + } else { + let mut step = self.step.write().unwrap(); + *step = WalletFundedScreenStep::ChooseFundingMethod; + } } + + rendered + } + + /// Adjust the current step to match the funding method after a wallet switch. + fn update_step_after_wallet_change(&mut self, funding_method: FundingMethod) { + let mut step = self.step.write().unwrap(); + *step = match funding_method { + FundingMethod::AddressWithQRCode => WalletFundedScreenStep::WaitingOnFunds, + FundingMethod::UseUnusedAssetLock | FundingMethod::UseWalletBalance => { + WalletFundedScreenStep::ReadyToCreate + } + FundingMethod::NoSelection => WalletFundedScreenStep::ChooseFundingMethod, + }; } fn render_funding_method(&mut self, ui: &mut egui::Ui) { @@ -371,19 +395,36 @@ impl ScreenLike for TopUpIdentityScreen { } } fn display_task_result(&mut self, backend_task_success_result: BackendTaskSuccessResult) { + if let BackendTaskSuccessResult::ToppedUpIdentity(qualified_identity) = + &backend_task_success_result + { + self.identity = qualified_identity.clone(); + self.funding_address = None; + self.funding_utxo = None; + self.funding_amount.clear(); + self.funding_amount_exact = None; + self.copied_to_clipboard = None; + self.error_message = None; + + let mut step = self.step.write().unwrap(); + *step = WalletFundedScreenStep::Success; + return; + } + let mut step = self.step.write().unwrap(); - match *step { + let current_step = *step; + match current_step { WalletFundedScreenStep::ChooseFundingMethod => {} WalletFundedScreenStep::WaitingOnFunds => { if let Some(funding_address) = self.funding_address.as_ref() && let BackendTaskSuccessResult::CoreItem( CoreItem::ReceivedAvailableUTXOTransaction(_, outpoints_with_addresses), - ) = backend_task_success_result + ) = &backend_task_success_result { for (outpoint, tx_out, address) in outpoints_with_addresses { - if funding_address == &address { + if funding_address == address { *step = WalletFundedScreenStep::FundsReceived; - self.funding_utxo = Some((outpoint, tx_out, address)) + self.funding_utxo = Some((*outpoint, tx_out.clone(), address.clone())) } } } @@ -393,9 +434,9 @@ impl ScreenLike for TopUpIdentityScreen { WalletFundedScreenStep::WaitingForAssetLock => { if let BackendTaskSuccessResult::CoreItem( CoreItem::ReceivedAvailableUTXOTransaction(tx, _), - ) = backend_task_success_result + ) = &backend_task_success_result && let Some(TransactionPayload::AssetLockPayloadType(asset_lock_payload)) = - tx.special_transaction_payload + &tx.special_transaction_payload && asset_lock_payload.credit_outputs.iter().any(|tx_out| { let Ok(address) = Address::from_script(&tx_out.script_pubkey, self.app_context.network) @@ -413,13 +454,7 @@ impl ScreenLike for TopUpIdentityScreen { *step = WalletFundedScreenStep::WaitingForPlatformAcceptance; } } - WalletFundedScreenStep::WaitingForPlatformAcceptance => { - if let BackendTaskSuccessResult::ToppedUpIdentity(_qualified_identity) = - backend_task_success_result - { - *step = WalletFundedScreenStep::Success; - } - } + WalletFundedScreenStep::WaitingForPlatformAcceptance => {} WalletFundedScreenStep::Success => {} } }