Skip to content

Commit 885cd2f

Browse files
committed
feat: add server.version, blockchain.silentpayments.subscribe and blockchain.silentpayments.unsubscribe
1 parent d384cf2 commit 885cd2f

4 files changed

Lines changed: 173 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ tokio-util = { version = "0.7.15", features = ["compat"], optional = true }
2121
[features]
2222
default = ["tokio"]
2323
tokio = ["dep:tokio", "tokio-util"]
24+
frigate = []
2425

2526
[dev-dependencies]
2627
async-std = "1.13.0"

src/notification.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
//!
66
//! - [`Notification::Header`] for `"blockchain.headers.subscribe"`
77
//! - [`Notification::ScriptHash`] for `"blockchain.scripthash.subscribe"`
8+
//! - [`Notification::SpSubscribe`] for `"blockchain.silentpayments.subscribe"`
89
//! - [`Notification::Unknown`] for unrecognized or unsupported methods
910
//!
1011
//! Each variant wraps a struct that contains the deserialized payload for that notification type.
1112
//! Use [`Notification::new`] to construct a typed [`Notification`] from a raw JSON-RPC notification.
1213
//!
1314
//! This is useful for higher-level consumers who want to match against known server-side events.
1415
16+
#[cfg(feature = "frigate")]
17+
use bitcoin::{secp256k1::PublicKey, Txid};
1518
use serde::Deserialize;
1619

1720
use crate::{response, ElectrumScriptHash, ElectrumScriptStatus, RawNotification};
@@ -32,6 +35,11 @@ pub enum Notification {
3235
/// status.
3336
ScriptHash(ScriptHashNotification),
3437

38+
/// A notification from `"blockchain.silentpayments.subscribe"` indicating a new history
39+
/// of transactions
40+
#[cfg(feature = "frigate")]
41+
SpSubscribe(SpSubscribeNotification),
42+
3543
/// A catch-all for notifications with unrecognized methods.
3644
///
3745
/// The original [`RawNotification`] is preserved for downstream inspection.
@@ -52,6 +60,10 @@ impl Notification {
5260
"blockchain.scripthash.subscribe" => {
5361
ScriptHashNotification::deserialize(params).map(Notification::ScriptHash)
5462
}
63+
#[cfg(feature = "frigate")]
64+
"blockchain.silentpayments.subscribe" => {
65+
SpSubscribeNotification::deserialize(params).map(Notification::SpSubscribe)
66+
}
5567
_ => Ok(Notification::Unknown(raw.clone())),
5668
}
5769
}
@@ -102,3 +114,43 @@ impl ScriptHashNotification {
102114
self.param_1
103115
}
104116
}
117+
118+
#[cfg(feature = "frigate")]
119+
#[derive(Debug, Clone, serde::Deserialize)]
120+
pub struct Subscription {
121+
pub address: String,
122+
pub labels: Vec<u32>,
123+
pub start_height: u32,
124+
}
125+
126+
#[cfg(feature = "frigate")]
127+
#[derive(Debug, Clone, serde::Deserialize)]
128+
pub struct History {
129+
pub height: u32,
130+
pub tx_hash: Txid,
131+
pub tweak_key: PublicKey,
132+
}
133+
134+
/// A notification indicating new confirmed transactions
135+
///
136+
/// Corresponds to `"blockchain.silentpayments.subscribe"` Frigate Electrum notification method
137+
#[cfg(feature = "frigate")]
138+
#[derive(Debug, Clone, serde::Deserialize)]
139+
pub struct SpSubscribeNotification {
140+
pub subscription: Subscription,
141+
pub progress: f32,
142+
pub history: Vec<History>,
143+
}
144+
145+
#[cfg(feature = "frigate")]
146+
impl SpSubscribeNotification {
147+
/// Returns the history from the notification
148+
pub fn history(&self) -> &Vec<History> {
149+
&self.history
150+
}
151+
152+
/// Returns the progress of output scanning from notification
153+
pub fn progress(&self) -> f32 {
154+
self.progress
155+
}
156+
}

src/pending_request.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ macro_rules! gen_pending_request_types {
265265
};
266266
}
267267

268+
#[cfg(not(feature = "frigate"))]
268269
gen_pending_request_types! {
269270
Header,
270271
HeaderWithProof,
@@ -289,6 +290,32 @@ gen_pending_request_types! {
289290
Custom
290291
}
291292

293+
#[cfg(feature = "frigate")]
294+
gen_pending_request_types! {
295+
Header,
296+
HeaderWithProof,
297+
Headers,
298+
HeadersWithCheckpoint,
299+
EstimateFee,
300+
HeadersSubscribe,
301+
GetBalance,
302+
GetHistory,
303+
GetMempool,
304+
ListUnspent,
305+
ScriptHashSubscribe,
306+
ScriptHashUnsubscribe,
307+
BroadcastTx,
308+
GetTx,
309+
GetTxMerkle,
310+
GetTxidFromPos,
311+
GetFeeHistogram,
312+
Banner,
313+
Ping,
314+
Version,
315+
Subscribe,
316+
UnSubscribe
317+
}
318+
292319
impl<A: PendingRequest> PendingRequest for Box<A> {
293320
fn to_method_and_params(&self) -> MethodAndParams {
294321
self.as_ref().to_method_and_params()

src/request.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
1919
use bitcoin::{consensus::Encodable, hex::DisplayHex, Script, Txid};
2020

21+
#[cfg(feature = "frigate")]
22+
use bitcoin::secp256k1::{PublicKey, SecretKey};
23+
2124
use crate::{
2225
response, CowStr, ElectrumScriptHash, ElectrumScriptStatus, MethodAndParams, RawRequest,
2326
ResponseError,
@@ -656,3 +659,93 @@ impl Request for Ping {
656659
("server.ping".into(), vec![])
657660
}
658661
}
662+
663+
/// A request to establish connection with Frigate Electrum client
664+
///
665+
/// This corresponds to the `"server.version"` Frigate Electrum RPC method
666+
///
667+
/// See: https://github.com/sparrowwallet/frigate
668+
#[cfg(feature = "frigate")]
669+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
670+
pub struct Version {
671+
pub client_name: CowStr,
672+
pub version: CowStr,
673+
}
674+
675+
#[cfg(feature = "frigate")]
676+
impl Request for Version {
677+
type Response = Vec<String>;
678+
679+
fn to_method_and_params(&self) -> MethodAndParams {
680+
(
681+
"server.version".into(),
682+
vec![self.client_name.clone().into(), self.version.clone().into()],
683+
)
684+
}
685+
}
686+
687+
/// A request to subscribe to payment outputs belonging to the provided keys
688+
///
689+
/// This corresponds to the `"blockchain.silentpayments.subscribe"` Frigate Electrum RPC method.
690+
/// It returns The silent payment address that has been subscribed.
691+
///
692+
/// See: https://github.com/sparrowwallet/frigate#blockchainsilentpaymentssubscribe
693+
#[cfg(feature = "frigate")]
694+
#[derive(Debug, Clone, PartialEq, Eq)]
695+
pub struct Subscribe {
696+
pub scan_priv_key: SecretKey,
697+
pub scan_pub_key: PublicKey,
698+
pub start_height: Option<u32>,
699+
pub labels: Option<Vec<u32>>,
700+
}
701+
702+
#[cfg(feature = "frigate")]
703+
impl Request for Subscribe {
704+
type Response = String;
705+
706+
fn to_method_and_params(&self) -> MethodAndParams {
707+
let mut params = vec![
708+
serde_json::json!(self.scan_priv_key),
709+
serde_json::json!(self.scan_pub_key),
710+
];
711+
712+
if let Some(start_height) = self.start_height {
713+
params.push(start_height.into());
714+
}
715+
716+
if let Some(labels) = &self.labels {
717+
params.push(labels.clone().into());
718+
}
719+
720+
("blockchain.silentpayments.subscribe".into(), params)
721+
}
722+
}
723+
724+
/// A request to unsubscribe to payment outputs belonging to the provided keys
725+
///
726+
/// This corresponds to the `"blockchain.silentpayments.unsubscribe"` Frigate Electrum RPC method.
727+
/// It returns The silent payment address that has been subscribed.This should cancel any scans that
728+
/// may be currently running for this address.
729+
///
730+
/// See: https://github.com/sparrowwallet/frigate#blockchainsilentpaymentsunsubscribe
731+
#[cfg(feature = "frigate")]
732+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
733+
pub struct UnSubscribe {
734+
pub scan_priv_key: SecretKey,
735+
pub scan_pub_key: PublicKey,
736+
}
737+
738+
#[cfg(feature = "frigate")]
739+
impl Request for UnSubscribe {
740+
type Response = String;
741+
742+
fn to_method_and_params(&self) -> MethodAndParams {
743+
(
744+
"blockchain.silentpayments.unsubscribe".into(),
745+
vec![
746+
serde_json::json!(self.scan_priv_key),
747+
serde_json::json!(self.scan_pub_key),
748+
],
749+
)
750+
}
751+
}

0 commit comments

Comments
 (0)