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

Commit 4a0fa7b

Browse files
committed
Track pending payjoin psbt transactions
Both sender original PSBT and payjoin proposal PSBT are tracked.
1 parent e203a83 commit 4a0fa7b

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

mutiny-core/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ pub enum ActivityItem {
208208
OnChain(TransactionDetails),
209209
Lightning(Box<MutinyInvoice>),
210210
ChannelClosed(ChannelClosure),
211+
// /// A payjoin proposal is posted to the directory but not yet broadcast from the sender
212+
// PendingPayjoin,
211213
}
212214

213215
impl ActivityItem {
@@ -1477,7 +1479,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
14771479
let Ok(address) = self.node_manager.get_new_address(labels.clone()) else {
14781480
return Err(MutinyError::WalletOperationFailed);
14791481
};
1480-
1482+
log_info!(self.logger, "created new address: {address}");
14811483
let (pj, ohttp) = match self.node_manager.start_payjoin_session().await {
14821484
Ok((enrolled, ohttp_keys)) => {
14831485
let session = self

mutiny-core/src/nodemanager.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,17 @@ impl<S: MutinyStorage> NodeManager<S> {
768768
.map_err(|_| MutinyError::IncorrectNetwork)?;
769769
let address = uri.address.clone();
770770
let original_psbt = self.wallet.create_signed_psbt(address, amount, fee_rate)?;
771-
// TODO ensure this creates a pending tx in the UI. Ensure locked UTXO.
771+
// Track this transaction in the wallet so it shows as an ActivityItem in UI.
772+
// We'll cancel it if and when this original_psbt fallback is replaced with a payjoin.
773+
// TODO mark as a payjoin
774+
self.wallet
775+
.insert_tx(
776+
original_psbt.clone().extract_tx(),
777+
ConfirmationTime::unconfirmed(crate::utils::now().as_secs()),
778+
None,
779+
)
780+
.await?;
781+
772782
let fee_rate = if let Some(rate) = fee_rate {
773783
FeeRate::from_sat_per_vb(rate)
774784
} else {
@@ -799,6 +809,7 @@ impl<S: MutinyStorage> NodeManager<S> {
799809
let proposal_psbt = match Self::poll_payjoin_sender(stop, req_ctx).await {
800810
Ok(psbt) => psbt,
801811
Err(e) => {
812+
// self.wallet cancel_tx
802813
log_error!(logger, "Error polling payjoin sender: {e}");
803814
return;
804815
}
@@ -869,11 +880,13 @@ impl<S: MutinyStorage> NodeManager<S> {
869880
labels: Vec<String>,
870881
) -> Result<Txid, MutinyError> {
871882
log_debug!(logger, "Sending payjoin..");
883+
let original_tx = original_psbt.clone().extract_tx();
872884
let tx = wallet
873885
.send_payjoin(original_psbt, proposal_psbt, labels)
874886
.await?;
875887
let txid = tx.txid();
876888
wallet.broadcast_transaction(tx).await?;
889+
wallet.cancel_tx(&original_tx)?;
877890
log_info!(logger, "Payjoin broadcast! TXID: {txid}");
878891
Ok(txid)
879892
}
@@ -908,7 +921,7 @@ impl<S: MutinyStorage> NodeManager<S> {
908921
let (req, ohttp_ctx) = payjoin_proposal.extract_v2_req()?;
909922
let res = http_client
910923
.post(req.url)
911-
.header("Content-Type", "message/ohttp-req")
924+
.header("content-type", "message/ohttp-req")
912925
.body(req.body)
913926
.send()
914927
.await?;
@@ -936,7 +949,7 @@ impl<S: MutinyStorage> NodeManager<S> {
936949
let (req, context) = session.enrolled.extract_req()?;
937950
let ohttp_response = client
938951
.post(req.url)
939-
.header("Content-Type", "message/ohttp-req")
952+
.header("content-type", "message/ohttp-req")
940953
.body(req.body)
941954
.send()
942955
.await?;

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)