diff --git a/payjoin-cli/src/app.rs b/payjoin-cli/src/app.rs index a750a1af..46b61327 100644 --- a/payjoin-cli/src/app.rs +++ b/payjoin-cli/src/app.rs @@ -286,20 +286,21 @@ impl App { })?; log::trace!("check4"); - let mut payjoin = payjoin.identify_receiver_outputs(|output_script| { - if let Ok(address) = bitcoin::Address::from_script(output_script, network) { - self.bitcoind - .get_address_info(&address) - .map(|info| info.is_mine.unwrap_or(false)) - .map_err(|e| Error::Server(e.into())) - } else { - Ok(false) - } - })?; + let mut provisional_payjoin: ProvisionalProposal = + payjoin.identify_receiver_outputs(|output_script| { + if let Ok(address) = bitcoin::Address::from_script(output_script, network) { + self.bitcoind + .get_address_info(&address) + .map(|info| info.is_mine.unwrap_or(false)) + .map_err(|e| Error::Server(e.into())) + } else { + Ok(false) + } + })?; if !self.config.sub_only { // Select receiver payjoin inputs. - _ = try_contributing_inputs(&mut payjoin, &self.bitcoind) + _ = try_contributing_inputs(&mut provisional_payjoin, &self.bitcoind) .map_err(|e| log::warn!("Failed to contribute inputs: {}", e)); } @@ -308,24 +309,25 @@ impl App { .get_new_address(None, None) .map_err(|e| Error::Server(e.into()))? .assume_checked(); - payjoin.substitute_output_address(receiver_substitute_address); - - let payjoin_proposal_psbt = payjoin.apply_fee(Some(1))?; - - log::debug!("Extracted PSBT: {:#?}", payjoin_proposal_psbt); - // Sign payjoin psbt - let payjoin_base64_string = base64::encode(&payjoin_proposal_psbt.serialize()); - // `wallet_process_psbt` adds available utxo data and finalizes - let payjoin_proposal_psbt = self - .bitcoind - .wallet_process_psbt(&payjoin_base64_string, None, None, Some(false)) - .map_err(|e| Error::Server(e.into()))? - .psbt; - let payjoin_proposal_psbt = Psbt::from_str(&payjoin_proposal_psbt) - .context("Failed to parse PSBT") - .map_err(|e| Error::Server(e.into()))?; - let payjoin_proposal = payjoin.prepare_psbt(payjoin_proposal_psbt)?; - let payjoin_proposal_psbt = payjoin_proposal.get_payjoin_psbt(); + provisional_payjoin.substitute_output_address(receiver_substitute_address); + + let final_payjoin = provisional_payjoin + .finalize_proposal( + |psbt: &Psbt| { + self.bitcoind + .wallet_process_psbt( + &bitcoin::base64::encode(psbt.serialize()), + None, + None, + Some(false), + ) + .map(|res| res.psbt) + .map_err(|e| Error::Server(e.into())) + }, + Some(1), + ) + .unwrap(); + let payjoin_proposal_psbt = final_payjoin.get_payjoin_psbt(); log::debug!("Receiver's Payjoin proposal PSBT Rsponse: {:#?}", payjoin_proposal_psbt); let payload = base64::encode(&payjoin_proposal_psbt.serialize()); diff --git a/payjoin/src/receive/mod.rs b/payjoin/src/receive/mod.rs index 81c32214..4a02546d 100644 --- a/payjoin/src/receive/mod.rs +++ b/payjoin/src/receive/mod.rs @@ -277,7 +277,6 @@ mod error; mod optional_parameters; use bitcoind::bitcoincore_rpc; -use bitcoind::bitcoincore_rpc::core_rpc_json::WalletProcessPsbtResult; pub use error::{Error, RequestError, SelectionError}; use error::{InternalRequestError, InternalSelectionError}; use optional_parameters::Params; @@ -724,10 +723,7 @@ impl ProvisionalProposal { /// this is kind of a "build_proposal" step before we sign and finalize and extract /// /// WARNING: DO NOT ALTER INPUTS OR OUTPUTS AFTER THIS STEP - pub fn apply_fee( - &mut self, - min_feerate_sat_per_vb: Option, - ) -> Result<&Psbt, RequestError> { + fn apply_fee(&mut self, min_feerate_sat_per_vb: Option) -> Result<&Psbt, RequestError> { let min_feerate = FeeRate::from_sat_per_vb_unchecked(min_feerate_sat_per_vb.unwrap_or_default()); log::trace!("min_feerate: {:?}", min_feerate); @@ -777,7 +773,7 @@ impl ProvisionalProposal { /// and return a PSBT that can produce a consensus-valid transaction that the sender will accept. /// /// wallet_process_psbt should sign and finalize receiver inputs - pub fn prepare_psbt(mut self, processed_psbt: Psbt) -> Result { + fn prepare_psbt(mut self, processed_psbt: Psbt) -> Result { self.payjoin_psbt = processed_psbt; log::trace!("Preparing PSBT {:#?}", self.payjoin_psbt); for input in self.payjoin_psbt.inputs_mut() { @@ -817,16 +813,19 @@ impl ProvisionalProposal { pub fn finalize_proposal( mut self, - wallet_process_psbt: impl Fn(&str) -> Result, + wallet_process_psbt: impl Fn(&Psbt) -> Result, min_feerate_sat_per_vb: Option, ) -> Result { let payjoin_proposal_psbt: &Psbt = self.apply_fee(min_feerate_sat_per_vb)?; - let payjoin_base64_string = bitcoin::base64::encode(&payjoin_proposal_psbt.serialize()); - let payjoin_proposal_psbt = match wallet_process_psbt(&payjoin_base64_string) { - Ok(p) => p.psbt, - Err(e) => return Err(RequestError::from(InternalRequestError::BitcoinCoreRpc(e))), + let payjoin_proposal_psbt = match wallet_process_psbt(payjoin_proposal_psbt) { + Ok(p) => p, + Err(_) => { + return Err(RequestError::from(InternalRequestError::PsbtFinalizingError( + "wallet_process_psbt failed", + ))); + } }; - let payjoin_proposal_psbt = match Psbt::from_str(&payjoin_proposal_psbt) { + let payjoin_proposal_psbt = match Psbt::from_str(&payjoin_proposal_psbt.to_string()) { Ok(p) => p, Err(e) => return Err(RequestError::from(InternalRequestError::PsbtParseError(e))), }; diff --git a/payjoin/tests/integration.rs b/payjoin/tests/integration.rs index 0f63bedc..3395e407 100644 --- a/payjoin/tests/integration.rs +++ b/payjoin/tests/integration.rs @@ -12,7 +12,7 @@ mod integration { use payjoin::bitcoin::base64; use payjoin::receive::Headers; use payjoin::send::Request; - use payjoin::{bitcoin, PjUriExt, Uri, UriExt}; + use payjoin::{bitcoin, Error, PjUriExt, Uri, UriExt}; #[test] fn integration_test() { @@ -200,20 +200,24 @@ mod integration { let receiver_substitute_address = receiver.get_new_address(None, None).unwrap().assume_checked(); payjoin.substitute_output_address(receiver_substitute_address); - - let payjoin_proposal_psbt = payjoin.apply_fee(None).unwrap(); - - // Sign payjoin psbt - let payjoin_base64_string = base64::encode(&payjoin_proposal_psbt.serialize()); - let payjoin_proposal_psbt = receiver - .wallet_process_psbt(&payjoin_base64_string, None, None, Some(false)) - .unwrap() - .psbt; - let payjoin_proposal_psbt = Psbt::from_str(&payjoin_proposal_psbt).unwrap(); - - let payjoin_proposal_psbt = payjoin.prepare_psbt(payjoin_proposal_psbt).unwrap(); - debug!("Receiver's Payjoin proposal PSBT: {:#?}", payjoin_proposal_psbt.get_payjoin_psbt()); - - base64::encode(&payjoin_proposal_psbt.get_payjoin_psbt().serialize()) + let payjoin_proposal = payjoin + .finalize_proposal( + |psbt: &Psbt| { + receiver + .wallet_process_psbt( + &bitcoin::base64::encode(psbt.serialize()), + None, + None, + Some(false), + ) + .map(|res| res.psbt) + .map_err(|e| Error::Server(e.into())) + }, + Some(1), + ) + .unwrap(); + let psbt = payjoin_proposal.get_payjoin_psbt(); + debug!("Receiver's Payjoin proposal PSBT: {:#?}", &psbt); + base64::encode(&psbt.serialize()) } }