diff --git a/Cargo.lock b/Cargo.lock index 0117f80ec..5fe844cd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -743,6 +743,38 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -2364,6 +2396,15 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -2554,6 +2595,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "negentropy" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe" + [[package]] name = "normalize-line-endings" version = "0.3.0" @@ -2562,9 +2609,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nostr" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0af088a37ea0026bf96dcd66db8bf21ed7ff528b7cbe34b7f32f6af3ae14a0" +checksum = "72adfa99eb5f1e5afa3f1fe6503c89989b7b0b61c4e5ec23c5b839967cd54da1" dependencies = [ "aes", "base64 0.21.5", @@ -2574,6 +2621,7 @@ dependencies = [ "chacha20", "getrandom", "instant", + "negentropy", "once_cell", "serde", "serde_json", @@ -2581,14 +2629,29 @@ dependencies = [ "url-fork", ] +[[package]] +name = "nostr-database" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "569f72670f79c10437eed69325b5b10ac69a1e23c2ee45d7d5781e6ec791cbce" +dependencies = [ + "async-trait", + "nostr", + "rayon", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "nostr-sdk" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5facab78c73baf3853f8c807006e23567dd3825392ef13a3a07122f4ce18b56d" +checksum = "a96ff1b1be7872abe0f6c0e151c2a1fd45b374756f05f2c00e328b003333f0c5" dependencies = [ "async-utility", "nostr", + "nostr-database", "nostr-sdk-net", "once_cell", "thiserror", @@ -2598,9 +2661,9 @@ dependencies = [ [[package]] name = "nostr-sdk-net" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4058b0267a1537c25b4674db9ed7a18152fc4c33df246dd4a88701007084ee" +checksum = "d7eccf4d9be57b513f5ee77e1931bf2fbf02da8ca1edae1feb001558e1e23332" dependencies = [ "futures-util", "thiserror", @@ -2609,8 +2672,8 @@ dependencies = [ "tokio-socks", "tokio-tungstenite 0.20.1", "url-fork", + "wasm-ws", "webpki-roots", - "ws_stream_wasm", ] [[package]] @@ -3091,6 +3154,26 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -4449,6 +4532,23 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-ws" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601c6f6340b473083c38e6cdda1f39dfc35d67b0e4b54fa56624d6189c2aa366" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "pharos", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.65" @@ -4591,25 +4691,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper 0.6.0", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wyz" version = "0.5.1" diff --git a/mutiny-core/Cargo.toml b/mutiny-core/Cargo.toml index 449e2bced..385e3d28b 100644 --- a/mutiny-core/Cargo.toml +++ b/mutiny-core/Cargo.toml @@ -38,8 +38,8 @@ futures-util = { version = "0.3", default-features = false } reqwest = { version = "0.11", default-features = false, features = ["json"] } async-trait = "0.1.68" url = { version = "2.3.1", features = ["serde"] } -nostr = { version = "0.24.0", default-features = false, features = ["nip47"] } -nostr-sdk = { version = "0.24.0", default-features = false } +nostr = { version = "0.26.0", default-features = false, features = ["nip47"] } +nostr-sdk = { version = "0.26.0", default-features = false } cbc = { version = "0.1", features = ["alloc"] } aes = { version = "0.8" } jwt-compact = { version = "0.8.0-beta.1", features = ["es256k"] } diff --git a/mutiny-core/src/lib.rs b/mutiny-core/src/lib.rs index 6881c6286..667cbab83 100644 --- a/mutiny-core/src/lib.rs +++ b/mutiny-core/src/lib.rs @@ -66,7 +66,7 @@ use crate::{ use crate::{nodemanager::NodeManager, nostr::ProfileType}; use crate::{nostr::NostrManager, utils::sleep}; use ::nostr::key::XOnlyPublicKey; -use ::nostr::{Event, Kind, Metadata}; +use ::nostr::{Event, JsonUtil, Kind, Metadata}; use bdk_chain::ConfirmationTime; use bip39::Mnemonic; use bitcoin::util::bip32::ExtendedPrivKey; @@ -473,19 +473,12 @@ impl MutinyWallet { log_warn!(logger, "Failed to clear expired NWC invoices: {e}"); } - // clear successful single-use profiles - let client = Client::new(&nostr.primary_key); - #[cfg(target_arch = "wasm32")] - let add_relay_res = client.add_relays(nostr.get_relays()).await; - - #[cfg(not(target_arch = "wasm32"))] - let add_relay_res = client - .add_relays(nostr.get_relays().into_iter().map(|s| (s, None)).collect()) - .await; - - add_relay_res.expect("Failed to add relays"); + client + .add_relays(nostr.get_relays()) + .await + .expect("Failed to add relays"); client.connect().await; let mut last_filters = nostr.get_nwc_filters(); @@ -513,7 +506,7 @@ impl MutinyWallet { select! { notification = read_fut => { match notification { - Ok(RelayPoolNotification::Event(_url, event)) => { + Ok(RelayPoolNotification::Event { event, .. }) => { if event.kind == Kind::WalletConnectRequest && event.verify().is_ok() { match nostr.handle_nwc_request(event, &self_clone).await { Ok(Some(event)) => { @@ -528,7 +521,7 @@ impl MutinyWallet { } } }, - Ok(RelayPoolNotification::Message(_, _)) => {}, // ignore messages + Ok(RelayPoolNotification::Message { .. }) => {}, // ignore messages Ok(RelayPoolNotification::Shutdown) => break, // if we disconnect, we restart to reconnect Ok(RelayPoolNotification::Stop) => {}, // Currently unused Ok(RelayPoolNotification::RelayStatus { .. }) => {}, // Currently unused diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index a205490d0..985d9d64a 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -49,7 +49,7 @@ use lightning_transaction_sync::EsploraSyncClient; use lnurl::lnurl::LnUrl; use lnurl::{AsyncClient as LnUrlClient, LnUrlResponse, Response}; use nostr::key::XOnlyPublicKey; -use nostr::{EventBuilder, Keys, Kind, Tag, TagKind}; +use nostr::{EventBuilder, JsonUtil, Keys, Kind, Tag, TagKind}; use payjoin::{PjUri, PjUriExt}; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -1617,13 +1617,20 @@ impl NodeManager { let zap_request = match zap_npub { Some(zap_npub) => { let tags = vec![ - Tag::PubKey(zap_npub, None), - Tag::Amount(msats), + Tag::PublicKey { + public_key: zap_npub, + relay_url: None, + alias: None, + }, + Tag::Amount { + millisats: msats, + bolt11: None, + }, Tag::Lnurl(lnurl.to_string()), Tag::Relays(vec!["wss://nostr.mutinywallet.com".into()]), Tag::Generic(TagKind::Custom("anon".to_string()), vec![]), ]; - EventBuilder::new(Kind::ZapRequest, "", &tags) + EventBuilder::new(Kind::ZapRequest, "", tags) .to_event(&Keys::generate()) .ok() .map(|z| z.as_json()) diff --git a/mutiny-core/src/nostr/mod.rs b/mutiny-core/src/nostr/mod.rs index df1a55931..5fe87bed8 100644 --- a/mutiny-core/src/nostr/mod.rs +++ b/mutiny-core/src/nostr/mod.rs @@ -23,7 +23,7 @@ use lightning::{log_error, log_warn}; use nostr::key::SecretKey; use nostr::nips::nip47::*; use nostr::prelude::{decrypt, encrypt}; -use nostr::{Event, EventBuilder, EventId, Filter, Keys, Kind, Tag}; +use nostr::{Event, EventBuilder, EventId, Filter, JsonUtil, Keys, Kind, Tag}; use nostr_sdk::{Client, RelayPoolNotification}; use std::sync::{atomic::Ordering, Arc, RwLock}; use std::time::Duration; @@ -440,13 +440,10 @@ impl NostrManager { if let Some(info_event) = info_event { let client = Client::new(&self.primary_key); - #[cfg(target_arch = "wasm32")] - let add_relay_res = client.add_relay(profile.relay.as_str()).await; - - #[cfg(not(target_arch = "wasm32"))] - let add_relay_res = client.add_relay(profile.relay.as_str(), None).await; - - add_relay_res.expect("Failed to add relays"); + client + .add_relay(profile.relay.as_str()) + .await + .expect("Failed to add relays"); client.connect().await; client.send_event(info_event).await.map_err(|e| { @@ -503,17 +500,10 @@ impl NostrManager { if let Some(nwc) = nwc { let client = Client::new(&self.primary_key); - #[cfg(target_arch = "wasm32")] - let add_relay_res = client + client .add_relays(vec![relay, profile.relay.to_string()]) - .await; - - #[cfg(not(target_arch = "wasm32"))] - let add_relay_res = client - .add_relays(vec![(relay, None), (profile.relay.to_string(), None)]) - .await; - - add_relay_res.expect("Failed to add relays"); + .await + .expect("Failed to add relays"); client.connect().await; if let Some(event) = nwc.create_auth_confirmation_event(secret, commands)? { @@ -580,13 +570,10 @@ impl NostrManager { ) -> Result { let client = Client::new(&self.primary_key); - #[cfg(target_arch = "wasm32")] - let add_relay_res = client.add_relay(nwc.profile.relay.as_str()).await; - - #[cfg(not(target_arch = "wasm32"))] - let add_relay_res = client.add_relay(nwc.profile.relay.as_str(), None).await; - - add_relay_res.expect("Failed to add relays"); + client + .add_relay(nwc.profile.relay.as_str()) + .await + .expect("Failed to add relays"); client.connect().await; let encrypted = encrypt( @@ -596,9 +583,17 @@ impl NostrManager { ) .unwrap(); - let p_tag = Tag::PubKey(inv.pubkey, None); - let e_tag = Tag::Event(inv.event_id, None, None); - let response = EventBuilder::new(Kind::WalletConnectResponse, encrypted, &[p_tag, e_tag]) + let p_tag = Tag::PublicKey { + public_key: inv.pubkey, + relay_url: None, + alias: None, + }; + let e_tag = Tag::Event { + event_id: inv.event_id, + relay_url: None, + marker: None, + }; + let response = EventBuilder::new(Kind::WalletConnectResponse, encrypted, [p_tag, e_tag]) .to_event(&nwc.server_key) .map_err(|e| MutinyError::Other(anyhow::anyhow!("Failed to create event: {e:?}")))?; @@ -690,16 +685,10 @@ impl NostrManager { { let client = Client::new(&self.primary_key); - let relays = self.get_relays(); - for relay in relays { - #[cfg(target_arch = "wasm32")] - let add_relay_res = client.add_relay(relay.as_str()).await; - #[cfg(not(target_arch = "wasm32"))] - let add_relay_res = client.add_relay(relay.as_str(), None).await; - - add_relay_res.expect("Failed to add relays"); - } - + client + .add_relays(self.get_relays()) + .await + .expect("Failed to add relays"); client.connect().await; let invoices: Vec = self @@ -725,10 +714,18 @@ impl NostrManager { ) .unwrap(); - let p_tag = Tag::PubKey(inv.pubkey, None); - let e_tag = Tag::Event(inv.event_id, None, None); + let p_tag = Tag::PublicKey { + public_key: inv.pubkey, + relay_url: None, + alias: None, + }; + let e_tag = Tag::Event { + event_id: inv.event_id, + relay_url: None, + marker: None, + }; let response = - EventBuilder::new(Kind::WalletConnectResponse, encrypted, &[p_tag, e_tag]) + EventBuilder::new(Kind::WalletConnectResponse, encrypted, [p_tag, e_tag]) .to_event(&nwc.server_key) .map_err(|e| { MutinyError::Other(anyhow::anyhow!("Failed to create event: {e:?}")) @@ -835,13 +832,10 @@ impl NostrManager { let secret = Keys::new(nwc.secret); let client = Client::new(&secret); - #[cfg(target_arch = "wasm32")] - let add_relay_res = client.add_relay(nwc.relay_url.as_str()).await; - - #[cfg(not(target_arch = "wasm32"))] - let add_relay_res = client.add_relay(nwc.relay_url.as_str(), None).await; - - add_relay_res.expect("Failed to add relays"); + client + .add_relay(nwc.relay_url.as_str()) + .await + .expect("Failed to add relays"); client.connect().await; let invoice = invoice_handler @@ -857,13 +851,17 @@ impl NostrManager { }), }; let encrypted = encrypt(&nwc.secret, &nwc.public_key, req.as_json())?; - let p_tag = Tag::PubKey(nwc.public_key, None); + let p_tag = Tag::PublicKey { + public_key: nwc.public_key, + relay_url: None, + alias: None, + }; let request_event = - EventBuilder::new(Kind::WalletConnectRequest, encrypted, &[p_tag]).to_event(&secret)?; + EventBuilder::new(Kind::WalletConnectRequest, encrypted, [p_tag]).to_event(&secret)?; let filter = Filter::new() .kind(Kind::WalletConnectResponse) - .author(nwc.public_key.to_hex()) + .author(nwc.public_key) .pubkey(secret.public_key()) .event(request_event.id); @@ -906,9 +904,9 @@ impl NostrManager { select! { notification = read_fut => { match notification { - Ok(RelayPoolNotification::Event(_url, event)) => { + Ok(RelayPoolNotification::Event { event, .. }) => { let has_e_tag = event.tags.iter().any(|x| { - if let Tag::Event(id, _, _) = x { + if let Tag::Event { event_id: id, .. } = x { *id == request_event.id } else { false @@ -935,7 +933,7 @@ impl NostrManager { } } }, - Ok(RelayPoolNotification::Message(_, _)) => {}, // ignore messages + Ok(RelayPoolNotification::Message { .. }) => {}, // ignore messages Ok(RelayPoolNotification::Stop) => {}, // ignore stops Ok(RelayPoolNotification::RelayStatus { .. }) => {}, // ignore status updates Ok(RelayPoolNotification::Shutdown) => diff --git a/mutiny-core/src/nostr/nip49.rs b/mutiny-core/src/nostr/nip49.rs index 663f62d25..69d5f5b09 100644 --- a/mutiny-core/src/nostr/nip49.rs +++ b/mutiny-core/src/nostr/nip49.rs @@ -133,26 +133,6 @@ pub struct NIP49URI { pub identity: Option, } -fn method_from_str(s: &str) -> Result { - match s { - "pay_invoice" => Ok(Method::PayInvoice), - "make_invoice" => Ok(Method::MakeInvoice), - "lookup_invoice" => Ok(Method::LookupInvoice), - "get_balance" => Ok(Method::GetBalance), - _ => Err(Error::InvalidURI), - } -} - -fn method_to_string(method: &Method) -> String { - match method { - Method::PayInvoice => "pay_invoice", - Method::MakeInvoice => "make_invoice", - Method::LookupInvoice => "lookup_invoice", - Method::GetBalance => "get_balance", - } - .to_string() -} - impl FromStr for NIP49URI { type Err = Error; fn from_str(uri: &str) -> Result { @@ -183,13 +163,13 @@ impl FromStr for NIP49URI { Cow::Borrowed("required_commands") => { required_commands = value .split(' ') - .map(method_from_str) + .map(Method::from_str) .collect::, Error>>()?; } Cow::Borrowed("optional_commands") => { optional_commands = value .split(' ') - .map(method_from_str) + .map(Method::from_str) .collect::, Error>>()?; } Cow::Borrowed("budget") => { @@ -234,7 +214,7 @@ impl fmt::Display for NIP49URI { url_encode( self.required_commands .iter() - .map(method_to_string) + .map(|x| x.to_string()) .join(" ") ), )?; @@ -245,7 +225,7 @@ impl fmt::Display for NIP49URI { url_encode( self.optional_commands .iter() - .map(method_to_string) + .map(|x| x.to_string()) .join(" ") ) )?; diff --git a/mutiny-core/src/nostr/nwc.rs b/mutiny-core/src/nostr/nwc.rs index 96b16f06a..134ea394b 100644 --- a/mutiny-core/src/nostr/nwc.rs +++ b/mutiny-core/src/nostr/nwc.rs @@ -17,7 +17,7 @@ use lightning_invoice::Bolt11Invoice; use nostr::key::XOnlyPublicKey; use nostr::nips::nip47::*; use nostr::prelude::{decrypt, encrypt}; -use nostr::{Event, EventBuilder, EventId, Filter, Keys, Kind, Tag}; +use nostr::{Event, EventBuilder, EventId, Filter, JsonUtil, Keys, Kind, Tag}; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::str::FromStr; @@ -269,13 +269,13 @@ impl NostrWalletConnect { pub fn create_nwc_filter(&self) -> Filter { Filter::new() .kinds(vec![Kind::WalletConnectRequest]) - .author(self.client_pubkey().to_string()) + .author(self.client_pubkey()) .pubkey(self.server_pubkey()) } /// Create Nostr Wallet Connect Info event pub fn create_nwc_info_event(&self) -> anyhow::Result { - let info = EventBuilder::new(Kind::WalletConnectInfo, "pay_invoice".to_string(), &[]) + let info = EventBuilder::new(Kind::WalletConnectInfo, "pay_invoice".to_string(), []) .to_event(&self.server_key)?; Ok(info) } @@ -302,7 +302,7 @@ impl NostrWalletConnect { serde_json::to_string(&json)?, )?; let d_tag = Tag::Identifier(self.client_pubkey().to_hex()); - let event = EventBuilder::new(Kind::ParameterizedReplaceable(33194), content, &[d_tag]) + let event = EventBuilder::new(Kind::ParameterizedReplaceable(33194), content, [d_tag]) .to_event(&self.server_key)?; Ok(Some(event)) } @@ -367,13 +367,18 @@ impl NostrWalletConnect { Ok(()) } - fn get_skipped_error_event(&self, event: &Event, message: String) -> anyhow::Result { + fn get_skipped_error_event( + &self, + event: &Event, + error_code: ErrorCode, + message: String, + ) -> anyhow::Result { let server_key = self.server_key.secret_key()?; let client_pubkey = self.client_key.public_key(); let content = Response { result_type: Method::PayInvoice, error: Some(NIP47Error { - code: ErrorCode::Other, + code: error_code, message, }), result: None, @@ -381,9 +386,17 @@ impl NostrWalletConnect { let encrypted = encrypt(&server_key, &client_pubkey, content.as_json())?; - let p_tag = Tag::PubKey(event.pubkey, None); - let e_tag = Tag::Event(event.id, None, None); - let response = EventBuilder::new(Kind::WalletConnectResponse, encrypted, &[p_tag, e_tag]) + let p_tag = Tag::PublicKey { + public_key: event.pubkey, + relay_url: None, + alias: None, + }; + let e_tag = Tag::Event { + event_id: event.id, + relay_url: None, + marker: None, + }; + let response = EventBuilder::new(Kind::WalletConnectResponse, encrypted, [p_tag, e_tag]) .to_event(&self.server_key)?; Ok(response) @@ -408,11 +421,32 @@ impl NostrWalletConnect { let server_key = self.server_key.secret_key()?; let decrypted = decrypt(&server_key, &client_pubkey, &event.content)?; - let req: Request = Request::from_json(decrypted)?; + let req: Request = match Request::from_json(decrypted) { + Ok(req) => req, + Err(e) => { + log_warn!( + nostr_manager.logger, + "Failed to parse request: {e}, skipping..." + ); + return self + .get_skipped_error_event( + &event, + ErrorCode::NotImplemented, + "Failed to parse request.".to_string(), + ) + .map(Some); + } + }; // only respond to pay invoice requests if req.method != Method::PayInvoice { - return Ok(None); + return self + .get_skipped_error_event( + &event, + ErrorCode::NotImplemented, + "Command is not supported.".to_string(), + ) + .map(Some); } let invoice = match req.params { @@ -424,7 +458,11 @@ impl NostrWalletConnect { // if the invoice has expired, skip it if invoice.would_expire(utils::now()) { return self - .get_skipped_error_event(&event, "Invoice expired".to_string()) + .get_skipped_error_event( + &event, + ErrorCode::Other, + "Invoice expired".to_string(), + ) .map(Some); } @@ -435,7 +473,11 @@ impl NostrWalletConnect { "NWC Invoice amount not set, cannot pay: {invoice}" ); return self - .get_skipped_error_event(&event, "Invoice amount not set".to_string()) + .get_skipped_error_event( + &event, + ErrorCode::Other, + "Invoice amount not set".to_string(), + ) .map(Some); } @@ -451,6 +493,7 @@ impl NostrWalletConnect { return self .get_skipped_error_event( &event, + ErrorCode::Other, "Paying hodl invoices disabled".to_string(), ) .map(Some); @@ -578,10 +621,18 @@ impl NostrWalletConnect { let encrypted = encrypt(&server_key, &client_pubkey, content.as_json())?; - let p_tag = Tag::PubKey(event.pubkey, None); - let e_tag = Tag::Event(event.id, None, None); + let p_tag = Tag::PublicKey { + public_key: event.pubkey, + relay_url: None, + alias: None, + }; + let e_tag = Tag::Event { + event_id: event.id, + relay_url: None, + marker: None, + }; let response = - EventBuilder::new(Kind::WalletConnectResponse, encrypted, &[p_tag, e_tag]) + EventBuilder::new(Kind::WalletConnectResponse, encrypted, [p_tag, e_tag]) .to_event(&self.server_key)?; if needs_delete { @@ -725,10 +776,18 @@ impl NostrWalletConnect { let encrypted = encrypt(&server_key, &client_pubkey, content.as_json())?; - let p_tag = Tag::PubKey(event.pubkey, None); - let e_tag = Tag::Event(event.id, None, None); + let p_tag = Tag::PublicKey { + public_key: event.pubkey, + relay_url: None, + alias: None, + }; + let e_tag = Tag::Event { + event_id: event.id, + relay_url: None, + marker: None, + }; let response = - EventBuilder::new(Kind::WalletConnectResponse, encrypted, &[p_tag, e_tag]) + EventBuilder::new(Kind::WalletConnectResponse, encrypted, [p_tag, e_tag]) .to_event(&self.server_key)?; return Ok(Some(response)); @@ -1123,6 +1182,7 @@ mod wasm_test { use bitcoin::Network; use mockall::predicate::eq; use nostr::key::SecretKey; + use serde_json::json; use std::sync::{atomic::AtomicBool, Arc}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; @@ -1227,7 +1287,7 @@ mod wasm_test { // test wrong kind let event = { - EventBuilder::new(Kind::TextNote, "", &[]) + EventBuilder::new(Kind::TextNote, "", []) .to_event(&Keys::new(uri.secret)) .unwrap() }; @@ -1235,6 +1295,31 @@ mod wasm_test { assert_eq!(result.unwrap(), None); check_no_pending_invoices(&storage); + // test unknown command + let event = { + let req = json!({"method": "fake_command", "params": {}}); + + let encrypted = encrypt(&uri.secret, &uri.public_key, req.to_string()).unwrap(); + let p_tag = Tag::PublicKey { + public_key: uri.public_key, + relay_url: None, + alias: None, + }; + EventBuilder::new(Kind::WalletConnectRequest, encrypted, [p_tag]) + .to_event(&Keys::new(uri.secret)) + .unwrap() + }; + let result = nwc.handle_nwc_request(event, &node, &nostr_manager).await; + check_nwc_error_response( + result.unwrap().unwrap(), + &uri.secret, + NIP47Error { + code: ErrorCode::NotImplemented, + message: "Failed to parse request.".to_string(), + }, + ); + check_no_pending_invoices(&storage); + // test unexpected command let event = { let req = Request { @@ -1243,13 +1328,24 @@ mod wasm_test { }; let encrypted = encrypt(&uri.secret, &uri.public_key, req.as_json()).unwrap(); - let p_tag = Tag::PubKey(uri.public_key, None); - EventBuilder::new(Kind::WalletConnectRequest, encrypted, &[p_tag]) + let p_tag = Tag::PublicKey { + public_key: uri.public_key, + relay_url: None, + alias: None, + }; + EventBuilder::new(Kind::WalletConnectRequest, encrypted, [p_tag]) .to_event(&Keys::new(uri.secret)) .unwrap() }; let result = nwc.handle_nwc_request(event, &node, &nostr_manager).await; - assert_eq!(result.unwrap(), None); + check_nwc_error_response( + result.unwrap().unwrap(), + &uri.secret, + NIP47Error { + code: ErrorCode::NotImplemented, + message: "Command is not supported.".to_string(), + }, + ); check_no_pending_invoices(&storage); // test invalid invoice diff --git a/mutiny-core/src/test_utils.rs b/mutiny-core/src/test_utils.rs index 4c50354b1..978a0ffaa 100644 --- a/mutiny-core/src/test_utils.rs +++ b/mutiny-core/src/test_utils.rs @@ -44,9 +44,13 @@ pub fn create_nwc_request(nwc: &NostrWalletConnectURI, invoice: String) -> Event }; let encrypted = encrypt(&nwc.secret, &nwc.public_key, req.as_json()).unwrap(); - let p_tag = Tag::PubKey(nwc.public_key, None); + let p_tag = Tag::PublicKey { + public_key: nwc.public_key, + relay_url: None, + alias: None, + }; - EventBuilder::new(Kind::WalletConnectRequest, encrypted, &[p_tag]) + EventBuilder::new(Kind::WalletConnectRequest, encrypted, [p_tag]) .to_event(&Keys::new(nwc.secret)) .unwrap() } @@ -206,7 +210,7 @@ use lightning_transaction_sync::EsploraSyncClient; pub(crate) use log; use nostr::nips::nip47::*; use nostr::prelude::{encrypt, NostrWalletConnectURI}; -use nostr::{Event, EventBuilder, Keys, Kind, Tag}; +use nostr::{Event, EventBuilder, JsonUtil, Keys, Kind, Tag}; use std::sync::atomic::AtomicBool; use std::sync::Arc; use uuid::Uuid; diff --git a/mutiny-wasm/Cargo.toml b/mutiny-wasm/Cargo.toml index 4e33e7f54..2fb99d26b 100644 --- a/mutiny-wasm/Cargo.toml +++ b/mutiny-wasm/Cargo.toml @@ -30,7 +30,7 @@ lightning-invoice = { version = "0.26.0" } thiserror = "1.0" instant = { version = "0.1", features = ["wasm-bindgen"] } lnurl-rs = { version = "0.3.1", default-features = false } -nostr = { version = "0.24.0", default-features = false } +nostr = { version = "0.26.0", default-features = false } wasm-logger = "0.2.0" log = "0.4.17" rexie = "0.5.0"