Skip to content

Commit

Permalink
Track pending payjoin transactions
Browse files Browse the repository at this point in the history
Both sender original PSBT and payjoin proposal PSBT are tracked as pending.
Only the one that confirms proceeds to live in the wallet forever.
  • Loading branch information
DanGould committed Apr 2, 2024
1 parent 014dfd0 commit 7880f9d
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 deletions.
14 changes: 13 additions & 1 deletion mutiny-core/src/nodemanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,16 @@ impl<S: MutinyStorage> NodeManager<S> {
.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 {
Expand Down Expand Up @@ -798,6 +807,7 @@ impl<S: MutinyStorage> NodeManager<S> {
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;
}
Expand Down Expand Up @@ -867,11 +877,13 @@ impl<S: MutinyStorage> NodeManager<S> {
labels: Vec<String>,
) -> Result<Txid, MutinyError> {
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)
}
Expand Down
27 changes: 19 additions & 8 deletions mutiny-core/src/onchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,12 @@ impl<S: MutinyStorage> OnChainWallet<S> {
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<bool, MutinyError> {
Ok(self.wallet.try_read()?.is_mine(script))
}
Expand Down Expand Up @@ -399,26 +405,31 @@ impl<S: MutinyStorage> OnChainWallet<S> {

// 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)
},
// 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)
}
Expand Down

0 comments on commit 7880f9d

Please sign in to comment.