diff --git a/Cargo.toml b/Cargo.toml index 5e3c99a..3a42602 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ tokio-util = { version = "0.7.15", features = ["compat"], optional = true } [features] default = ["tokio"] tokio = ["dep:tokio", "tokio-util"] +frigate = [] [dev-dependencies] async-std = "1.13.0" diff --git a/src/notification.rs b/src/notification.rs index 6975110..9e7a8dd 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -5,6 +5,7 @@ //! //! - [`Notification::Header`] for `"blockchain.headers.subscribe"` //! - [`Notification::ScriptHash`] for `"blockchain.scripthash.subscribe"` +//! - [`Notification::SpSubscribe`] for `"blockchain.silentpayments.subscribe"` //! - [`Notification::Unknown`] for unrecognized or unsupported methods //! //! Each variant wraps a struct that contains the deserialized payload for that notification type. @@ -32,6 +33,11 @@ pub enum Notification { /// status. ScriptHash(ScriptHashNotification), + /// A notification from `"blockchain.silentpayments.subscribe"` indicating a new history + /// of transactions + #[cfg(feature = "frigate")] + SpSubscribe(SpNotification), + /// A catch-all for notifications with unrecognized methods. /// /// The original [`RawNotification`] is preserved for downstream inspection. @@ -52,6 +58,10 @@ impl Notification { "blockchain.scripthash.subscribe" => { ScriptHashNotification::deserialize(params).map(Notification::ScriptHash) } + #[cfg(feature = "frigate")] + "blockchain.silentpayments.subscribe" => { + SpNotification::deserialize(params).map(Notification::SpSubscribe) + } _ => Ok(Notification::Unknown(raw.clone())), } } @@ -102,3 +112,30 @@ impl ScriptHashNotification { self.param_1 } } + +#[cfg(feature = "frigate")] +#[derive(Debug, Clone, serde::Deserialize)] +pub struct SpSubscription { + pub address: String, + pub labels: Vec, + pub start_height: u32, +} + +#[cfg(feature = "frigate")] +#[derive(Debug, Clone, serde::Deserialize)] +pub struct TxTweak { + pub height: u32, + pub tx_hash: bitcoin::Txid, + pub tweak_key: bitcoin::secp256k1::PublicKey, +} + +/// A notification indicating new confirmed transactions +/// +/// Corresponds to `"blockchain.silentpayments.subscribe"` Frigate Electrum notification method +#[cfg(feature = "frigate")] +#[derive(Debug, Clone, serde::Deserialize)] +pub struct SpNotification { + pub subscription: SpSubscription, + pub progress: f32, + pub history: Vec, +} diff --git a/src/pending_request.rs b/src/pending_request.rs index 4686b9c..52396c8 100644 --- a/src/pending_request.rs +++ b/src/pending_request.rs @@ -82,6 +82,7 @@ macro_rules! gen_pending_request_types { }; } +#[cfg(not(feature = "frigate"))] gen_pending_request_types! { Header, HeaderWithProof, @@ -106,6 +107,33 @@ gen_pending_request_types! { Custom } +#[cfg(feature = "frigate")] +gen_pending_request_types! { + Header, + HeaderWithProof, + Headers, + HeadersWithCheckpoint, + EstimateFee, + HeadersSubscribe, + RelayFee, + GetBalance, + GetHistory, + GetMempool, + ListUnspent, + ScriptHashSubscribe, + ScriptHashUnsubscribe, + BroadcastTx, + GetTx, + GetTxMerkle, + GetTxidFromPos, + GetFeeHistogram, + Banner, + Ping, + Version, + SpSubscribe, + SpUnSubscribe +} + type Handler = Box) -> Result, serde_json::Error> + Send + Sync>; diff --git a/src/request.rs b/src/request.rs index 9973529..e0d11cf 100644 --- a/src/request.rs +++ b/src/request.rs @@ -656,3 +656,93 @@ impl Request for Ping { ("server.ping".into(), vec![]) } } + +/// A request to establish connection with Frigate Electrum client +/// +/// This corresponds to the `"server.version"` Frigate Electrum RPC method +/// +/// See: https://github.com/sparrowwallet/frigate +#[cfg(feature = "frigate")] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Version { + pub client_name: CowStr, + pub version: CowStr, +} + +#[cfg(feature = "frigate")] +impl Request for Version { + type Response = Vec; + + fn to_method_and_params(&self) -> MethodAndParams { + ( + "server.version".into(), + vec![self.client_name.clone().into(), self.version.clone().into()], + ) + } +} + +/// A request to subscribe to payment outputs belonging to the provided keys +/// +/// This corresponds to the `"blockchain.silentpayments.subscribe"` Frigate Electrum RPC method. +/// It returns The silent payment address that has been subscribed. +/// +/// See: https://github.com/sparrowwallet/frigate#blockchainsilentpaymentssubscribe +#[cfg(feature = "frigate")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SpSubscribe { + pub scan_priv_key: bitcoin::secp256k1::SecretKey, + pub scan_pub_key: bitcoin::secp256k1::PublicKey, + pub start_height: Option, + pub labels: Option>, +} + +#[cfg(feature = "frigate")] +impl Request for SpSubscribe { + type Response = String; + + fn to_method_and_params(&self) -> MethodAndParams { + let mut params = vec![ + serde_json::json!(self.scan_priv_key), + serde_json::json!(self.scan_pub_key), + ]; + + if let Some(start_height) = self.start_height { + params.push(start_height.into()); + } + + if let Some(labels) = &self.labels { + params.push(labels.clone().into()); + } + + ("blockchain.silentpayments.subscribe".into(), params) + } +} + +/// A request to unsubscribe to payment outputs belonging to the provided keys +/// +/// This corresponds to the `"blockchain.silentpayments.unsubscribe"` Frigate Electrum RPC method. +/// It returns The silent payment address that has been subscribed.This should cancel any scans that +/// may be currently running for this address. +/// +/// See: https://github.com/sparrowwallet/frigate#blockchainsilentpaymentsunsubscribe +#[cfg(feature = "frigate")] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SpUnSubscribe { + pub scan_priv_key: bitcoin::secp256k1::SecretKey, + pub scan_pub_key: bitcoin::secp256k1::PublicKey, +} + +#[cfg(feature = "frigate")] +impl Request for SpUnSubscribe { + type Response = String; + + fn to_method_and_params(&self) -> MethodAndParams { + ( + "blockchain.silentpayments.unsubscribe".into(), + vec![ + serde_json::json!(self.scan_priv_key), + serde_json::json!(self.scan_pub_key), + ], + ) + } +}