diff --git a/Cargo.lock b/Cargo.lock index efc583c6a..18f9a8f9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2957,13 +2957,14 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "payjoin" -version = "0.10.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac532e6caa3a192dd6017a88446c2a1014d31b66cc68f04c584a846a4cb0373" +checksum = "e7b659f9e4ff06192df5d4504ea7ae866a1680eb2c87e4dca521fb14753eb0e7" dependencies = [ "bip21", "bitcoin 0.30.1", "log", + "serde_json", "url", ] diff --git a/mutiny-core/Cargo.toml b/mutiny-core/Cargo.toml index 043ec94ed..c0bb19cda 100644 --- a/mutiny-core/Cargo.toml +++ b/mutiny-core/Cargo.toml @@ -44,7 +44,7 @@ cbc = { version = "0.1", features = ["alloc"] } aes = { version = "0.8" } jwt-compact = { version = "0.8.0-beta.1", features = ["es256k"] } argon2 = { version = "0.5.0", features = ["password-hash", "alloc"] } -payjoin = { version = "0.10.0", features = ["send", "base64"] } +payjoin = { version = "0.13.0", features = ["send", "base64"] } gluesql = { version = "0.15", default-features = false, features = ["memory-storage"] } gluesql-core = "0.15.0" bincode = "1.3.3" diff --git a/mutiny-core/src/error.rs b/mutiny-core/src/error.rs index 7ab49d9c8..5b1786cdb 100644 --- a/mutiny-core/src/error.rs +++ b/mutiny-core/src/error.rs @@ -147,9 +147,9 @@ pub enum MutinyError { /// Payjoin request creation failed. #[error("Failed to create payjoin request.")] PayjoinCreateRequest, - /// Payjoin response validation failed. - #[error("Failed to validate payjoin response.")] - PayjoinValidateResponse(payjoin::send::ValidationError), + /// Payjoin request failed. + #[error("Payjoin response error: {0}")] + PayjoinResponse(payjoin::send::ResponseError), /// Payjoin configuration error #[error("Payjoin configuration failed.")] PayjoinConfigError, @@ -471,8 +471,8 @@ impl From for MutinyError { } } -impl From for MutinyError { - fn from(e: payjoin::send::ValidationError) -> Self { - Self::PayjoinValidateResponse(e) +impl From for MutinyError { + fn from(e: payjoin::send::ResponseError) -> Self { + Self::PayjoinResponse(e) } } diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index b751788b5..9221e2859 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -46,7 +46,7 @@ use lightning::util::logger::*; use lightning::{log_debug, log_error, log_info, log_warn}; use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription}; use lightning_transaction_sync::EsploraSyncClient; -use payjoin::{PjUri, PjUriExt}; +use payjoin::Uri; use reqwest::Client; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -777,16 +777,15 @@ impl NodeManager { pub async fn send_payjoin( &self, - uri: PjUri<'_>, + uri: Uri<'_, payjoin::bitcoin::address::NetworkChecked>, amount: u64, labels: Vec, fee_rate: Option, ) -> Result { let address = Address::from_str(&uri.address.to_string()) - .map_err(|_| MutinyError::PayjoinConfigError)?; + .map_err(|_| MutinyError::InvalidArgumentsError)?; let original_psbt = self.wallet.create_signed_psbt(address, amount, fee_rate)?; - let payout_scripts = std::iter::once(uri.address.script_pubkey()); let fee_rate = if let Some(rate) = fee_rate { FeeRate::from_sat_per_vb(rate) } else { @@ -797,17 +796,18 @@ impl NodeManager { let original_psbt = payjoin::bitcoin::psbt::PartiallySignedTransaction::from_str( &original_psbt.to_string(), ) - .map_err(|_| MutinyError::PayjoinConfigError)?; - let pj_params = - payjoin::send::Configuration::recommended(&original_psbt, payout_scripts, fee_rate) - .map_err(|_| MutinyError::PayjoinConfigError)?; - + .map_err(|_| MutinyError::WalletOperationFailed)?; log_debug!(self.logger, "Creating payjoin request"); - let (req, ctx) = uri.create_pj_request(original_psbt.clone(), pj_params)?; + let (req, ctx) = + payjoin::send::RequestBuilder::from_psbt_and_uri(original_psbt.clone(), uri) + .unwrap() + .build_recommended(fee_rate) + .map_err(|_| MutinyError::PayjoinCreateRequest)? + .extract_v1()?; let client = Client::builder() .build() - .map_err(|_| MutinyError::PayjoinConfigError)?; + .map_err(|e| MutinyError::Other(e.into()))?; log_debug!(self.logger, "Sending payjoin request"); let res = client @@ -825,7 +825,8 @@ impl NodeManager { log_debug!(self.logger, "Processing payjoin response"); let proposal_psbt = ctx.process_response(&mut cursor).map_err(|e| { - log_error!(self.logger, "Error processing payjoin response: {e}"); + // unrecognized error contents may only appear in debug logs and will not Display + log_debug!(self.logger, "Payjoin response error: {:?}", e); e })?; diff --git a/mutiny-wasm/Cargo.toml b/mutiny-wasm/Cargo.toml index 6ba8f34d0..4903003ea 100644 --- a/mutiny-wasm/Cargo.toml +++ b/mutiny-wasm/Cargo.toml @@ -41,7 +41,7 @@ getrandom = { version = "0.2", features = ["js"] } futures = "0.3.25" urlencoding = "2.1.2" once_cell = "1.18.0" -payjoin = { version = "0.10.0", features = ["send", "base64"] } +payjoin = { version = "0.13.0", features = ["send", "base64"] } fedimint-core = "0.2.1" # The `console_error_panic_hook` crate provides better debugging of panics by diff --git a/mutiny-wasm/src/error.rs b/mutiny-wasm/src/error.rs index 9bd5739ef..1946ac26e 100644 --- a/mutiny-wasm/src/error.rs +++ b/mutiny-wasm/src/error.rs @@ -147,9 +147,9 @@ pub enum MutinyJsError { /// Payjoin request creation failed. #[error("Failed to create payjoin request.")] PayjoinCreateRequest, - /// Payjoin response validation failed. - #[error("Failed to validate payjoin response.")] - PayjoinValidateResponse, + // Payjoin request failed. + #[error("Payjoin response error: {0}")] + PayjoinResponse(String), /// Payjoin configuration error #[error("Payjoin configuration failed.")] PayjoinConfigError, @@ -209,7 +209,7 @@ impl From for MutinyJsError { MutinyError::NetworkMismatch => MutinyJsError::NetworkMismatch, MutinyError::PayjoinConfigError => MutinyJsError::PayjoinConfigError, MutinyError::PayjoinCreateRequest => MutinyJsError::PayjoinCreateRequest, - MutinyError::PayjoinValidateResponse(_) => MutinyJsError::PayjoinValidateResponse, + MutinyError::PayjoinResponse(e) => MutinyJsError::PayjoinResponse(e.to_string()), } } } diff --git a/mutiny-wasm/src/lib.rs b/mutiny-wasm/src/lib.rs index 28576ec88..2bbcaa6f3 100644 --- a/mutiny-wasm/src/lib.rs +++ b/mutiny-wasm/src/lib.rs @@ -43,7 +43,6 @@ use mutiny_core::{ nodemanager::{create_lsp_config, NodeManager}, }; use mutiny_core::{logging::MutinyLogger, nostr::ProfileType}; -use payjoin::UriExt; use std::str::FromStr; use std::sync::Arc; use std::{ @@ -487,9 +486,7 @@ impl MutinyWallet { // I know walia parses `pj=` and `pjos=` but payjoin::Uri parses the whole bip21 uri let pj_uri = payjoin::Uri::try_from(payjoin_uri.as_str()) .map_err(|_| MutinyJsError::InvalidArgumentsError)? - .assume_checked() - .check_pj_supported() - .map_err(|_| MutinyJsError::InvalidArgumentsError)?; + .assume_checked(); Ok(self .inner .node_manager