diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index cd524d8a5..23e2fb660 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -767,7 +767,16 @@ impl NodeManager { .map_err(|_| MutinyError::IncorrectNetwork)?; let address = uri.address.clone(); let original_psbt = self.wallet.create_signed_psbt(address, amount, fee_rate)?; - // TODO ensure this creates a pending tx in the UI. Ensure locked UTXO. + // Track this transaction in the wallet so it shows as an ActivityItem in UI. + // We'll cancel it if and when this original_psbt fallback is replaced with a received payjoin. + self.wallet + .insert_tx( + original_psbt.clone().extract_tx(), + ConfirmationTime::unconfirmed(crate::utils::now().as_secs()), + None, + ) + .await?; + let fee_rate = if let Some(rate) = fee_rate { FeeRate::from_sat_per_vb(rate) } else { @@ -798,6 +807,7 @@ impl NodeManager { let proposal_psbt = match Self::poll_payjoin_sender(stop, req_ctx).await { Ok(psbt) => psbt, Err(e) => { + // self.wallet cancel_tx log_error!(logger, "Error polling payjoin sender: {e}"); return; } @@ -867,11 +877,13 @@ impl NodeManager { labels: Vec, ) -> Result { log_debug!(logger, "Sending payjoin.."); + let original_tx = original_psbt.clone().extract_tx(); let tx = wallet .send_payjoin(original_psbt, proposal_psbt, labels) .await?; let txid = tx.txid(); wallet.broadcast_transaction(tx).await?; + wallet.cancel_tx(&original_tx)?; log_info!(logger, "Payjoin broadcast! TXID: {txid}"); Ok(txid) } diff --git a/mutiny-core/src/onchain.rs b/mutiny-core/src/onchain.rs index 77e6dc538..92bd30227 100644 --- a/mutiny-core/src/onchain.rs +++ b/mutiny-core/src/onchain.rs @@ -355,6 +355,12 @@ impl OnChainWallet { Ok(()) } + pub(crate) fn cancel_tx(&self, tx: &Transaction) -> Result<(), MutinyError> { + let mut wallet = self.wallet.try_write()?; + wallet.cancel_tx(tx); + Ok(()) + } + fn is_mine(&self, script: &Script) -> Result { Ok(self.wallet.try_read()?.is_mine(script)) } @@ -399,15 +405,12 @@ impl OnChainWallet { // Outputs may be substituted for e.g. batching at this stage // We're not doing this yet. - let payjoin_proposal = provisional_payjoin.finalize_proposal( |psbt| { let mut psbt = psbt.clone(); - let wallet = self - .wallet - .try_read() - .map_err(|_| Error::Server(MutinyError::WalletSigningFailed.into()))?; - wallet + self.wallet + .try_write() + .map_err(|_| Error::Server(MutinyError::WalletSigningFailed.into()))? .sign(&mut psbt, SignOptions::default()) .map_err(|_| Error::Server(MutinyError::WalletSigningFailed.into()))?; Ok(psbt) @@ -415,10 +418,18 @@ impl OnChainWallet { // TODO: check Mutiny's minfeerate is present here Some(payjoin::bitcoin::FeeRate::MIN), )?; - let payjoin_proposal_psbt = payjoin_proposal.psbt(); + let payjoin_psbt_tx = payjoin_proposal.psbt().clone().extract_tx(); + self.wallet + .try_write() + .map_err(|_| Error::Server(MutinyError::WalletOperationFailed.into()))? + .insert_tx( + payjoin_psbt_tx, + ConfirmationTime::unconfirmed(crate::utils::now().as_secs()), + ) + .map_err(|_| Error::Server(MutinyError::WalletOperationFailed.into()))?; log::debug!( "Receiver's Payjoin proposal PSBT Rsponse: {:#?}", - payjoin_proposal_psbt + payjoin_proposal.psbt() ); Ok(payjoin_proposal) }