Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit eb70217

Browse files
committed
Track pending payjoin transactions
Both sender original PSBT and payjoin proposal PSBT are tracked as pending. Only the one that confirms proceeds to live in the wallet forever.
1 parent 2686dfd commit eb70217

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

mutiny-core/src/nodemanager.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,16 @@ impl<S: MutinyStorage> NodeManager<S> {
767767
.map_err(|_| MutinyError::IncorrectNetwork)?;
768768
let address = uri.address.clone();
769769
let original_psbt = self.wallet.create_signed_psbt(address, amount, fee_rate)?;
770-
// TODO ensure this creates a pending tx in the UI. Ensure locked UTXO.
770+
// Track this transaction in the wallet so it shows as an ActivityItem in UI.
771+
// We'll cancel it if and when this original_psbt fallback is replaced with a received payjoin.
772+
self.wallet
773+
.insert_tx(
774+
original_psbt.clone().extract_tx(),
775+
ConfirmationTime::unconfirmed(crate::utils::now().as_secs()),
776+
None,
777+
)
778+
.await?;
779+
771780
let fee_rate = if let Some(rate) = fee_rate {
772781
FeeRate::from_sat_per_vb(rate)
773782
} else {
@@ -798,6 +807,7 @@ impl<S: MutinyStorage> NodeManager<S> {
798807
let proposal_psbt = match Self::poll_payjoin_sender(stop, req_ctx).await {
799808
Ok(psbt) => psbt,
800809
Err(e) => {
810+
// self.wallet cancel_tx
801811
log_error!(logger, "Error polling payjoin sender: {e}");
802812
return;
803813
}
@@ -867,11 +877,13 @@ impl<S: MutinyStorage> NodeManager<S> {
867877
labels: Vec<String>,
868878
) -> Result<Txid, MutinyError> {
869879
log_debug!(logger, "Sending payjoin..");
880+
let original_tx = original_psbt.clone().extract_tx();
870881
let tx = wallet
871882
.send_payjoin(original_psbt, proposal_psbt, labels)
872883
.await?;
873884
let txid = tx.txid();
874885
wallet.broadcast_transaction(tx).await?;
886+
wallet.cancel_tx(&original_tx)?;
875887
log_info!(logger, "Payjoin broadcast! TXID: {txid}");
876888
Ok(txid)
877889
}

mutiny-core/src/onchain.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,12 @@ impl<S: MutinyStorage> OnChainWallet<S> {
355355
Ok(())
356356
}
357357

358+
pub(crate) fn cancel_tx(&self, tx: &Transaction) -> Result<(), MutinyError> {
359+
let mut wallet = self.wallet.try_write()?;
360+
wallet.cancel_tx(tx);
361+
Ok(())
362+
}
363+
358364
fn is_mine(&self, script: &Script) -> Result<bool, MutinyError> {
359365
Ok(self.wallet.try_read()?.is_mine(script))
360366
}
@@ -400,7 +406,10 @@ impl<S: MutinyStorage> OnChainWallet<S> {
400406

401407
// Outputs may be substituted for e.g. batching at this stage
402408
// We're not doing this yet.
403-
409+
let mut wallet = self
410+
.wallet
411+
.try_write()
412+
.map_err(|_| Error::Server(MutinyError::WalletSigningFailed.into()))?;
404413
let payjoin_proposal = provisional_payjoin.finalize_proposal(
405414
|psbt| {
406415
let mut psbt = psbt.clone();
@@ -416,10 +425,16 @@ impl<S: MutinyStorage> OnChainWallet<S> {
416425
// TODO: check Mutiny's minfeerate is present here
417426
Some(payjoin::bitcoin::FeeRate::MIN),
418427
)?;
419-
let payjoin_proposal_psbt = payjoin_proposal.psbt();
428+
let payjoin_psbt_tx = payjoin_proposal.psbt().clone().extract_tx();
429+
wallet
430+
.insert_tx(
431+
payjoin_psbt_tx,
432+
ConfirmationTime::unconfirmed(crate::utils::now().as_secs()),
433+
)
434+
.map_err(|_| Error::Server(MutinyError::WalletOperationFailed.into()))?;
420435
log::debug!(
421436
"Receiver's Payjoin proposal PSBT Rsponse: {:#?}",
422-
payjoin_proposal_psbt
437+
payjoin_proposal.psbt()
423438
);
424439
Ok(payjoin_proposal)
425440
}

0 commit comments

Comments
 (0)