From 4a07b5d011de87d3374118f8fdba18439c2a535a Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 5 Jan 2024 12:17:29 -0500 Subject: [PATCH 1/2] Bump payjoin 0.13.0 --- Cargo.lock | 5 +++-- mutiny-core/Cargo.toml | 2 +- mutiny-core/src/error.rs | 12 ++++++------ mutiny-core/src/nodemanager.rs | 16 ++++++++-------- mutiny-wasm/Cargo.toml | 2 +- mutiny-wasm/src/error.rs | 8 ++++---- mutiny-wasm/src/lib.rs | 5 +---- 7 files changed, 24 insertions(+), 26 deletions(-) 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..47763cd63 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.")] + 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..a52f5f16b 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,7 +777,7 @@ impl NodeManager { pub async fn send_payjoin( &self, - uri: PjUri<'_>, + uri: Uri<'_, payjoin::bitcoin::address::NetworkChecked>, amount: u64, labels: Vec, fee_rate: Option, @@ -786,7 +786,6 @@ impl NodeManager { .map_err(|_| MutinyError::PayjoinConfigError)?; 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 { @@ -798,12 +797,13 @@ impl NodeManager { &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)?; - 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::PayjoinConfigError)? + .extract_v1()?; let client = Client::builder() .build() 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..9cd4d4142 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.")] + PayjoinResponse, /// 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(_) => MutinyJsError::PayjoinResponse, } } } 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 From 6e5bd38d5068e003cb1b93566932cf5d42c3813d Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 5 Jan 2024 12:28:50 -0500 Subject: [PATCH 2/2] Handle payjoin errors according to BIP 78 "The receiver is allowed to return implementation specific errors which may assist the sender to diagnose any issue. However, it is important that error codes that are not well-known and that the message do not appear on the sender's software user interface. Such error codes or messages could be used maliciously to phish a non- technical user. Instead those errors or messages can only appear in debug logs. It is advised to hard code the description of the well known error codes into the sender's software." See: https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors This commit displays templates based on a particular \`ResponseError\` and debugs the rest, according to this specification. --- mutiny-core/src/error.rs | 2 +- mutiny-core/src/nodemanager.rs | 11 ++++++----- mutiny-wasm/src/error.rs | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mutiny-core/src/error.rs b/mutiny-core/src/error.rs index 47763cd63..5b1786cdb 100644 --- a/mutiny-core/src/error.rs +++ b/mutiny-core/src/error.rs @@ -148,7 +148,7 @@ pub enum MutinyError { #[error("Failed to create payjoin request.")] PayjoinCreateRequest, /// Payjoin request failed. - #[error("Payjoin response error.")] + #[error("Payjoin response error: {0}")] PayjoinResponse(payjoin::send::ResponseError), /// Payjoin configuration error #[error("Payjoin configuration failed.")] diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index a52f5f16b..9221e2859 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -783,7 +783,7 @@ impl NodeManager { 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 fee_rate = if let Some(rate) = fee_rate { @@ -796,18 +796,18 @@ impl NodeManager { let original_psbt = payjoin::bitcoin::psbt::PartiallySignedTransaction::from_str( &original_psbt.to_string(), ) - .map_err(|_| MutinyError::PayjoinConfigError)?; + .map_err(|_| MutinyError::WalletOperationFailed)?; log_debug!(self.logger, "Creating payjoin request"); let (req, ctx) = payjoin::send::RequestBuilder::from_psbt_and_uri(original_psbt.clone(), uri) .unwrap() .build_recommended(fee_rate) - .map_err(|_| MutinyError::PayjoinConfigError)? + .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/src/error.rs b/mutiny-wasm/src/error.rs index 9cd4d4142..1946ac26e 100644 --- a/mutiny-wasm/src/error.rs +++ b/mutiny-wasm/src/error.rs @@ -148,8 +148,8 @@ pub enum MutinyJsError { #[error("Failed to create payjoin request.")] PayjoinCreateRequest, // Payjoin request failed. - #[error("Payjoin response error.")] - PayjoinResponse, + #[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::PayjoinResponse(_) => MutinyJsError::PayjoinResponse, + MutinyError::PayjoinResponse(e) => MutinyJsError::PayjoinResponse(e.to_string()), } } }