breez_sdk_spark/models/
payment_observer.rs1use std::sync::Arc;
2
3use spark_wallet::{TransferId, TransferObserverError};
4use thiserror::Error;
5
6#[derive(Debug, Clone)]
7#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
8pub struct ProvisionalPayment {
9 pub payment_id: String,
11 pub amount: u128,
13 pub details: ProvisionalPaymentDetails,
15}
16
17#[derive(Debug, Clone)]
18#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
19pub enum ProvisionalPaymentDetails {
20 Bitcoin {
21 withdrawal_address: String,
23 },
24 Lightning {
25 invoice: String,
27 },
28 Spark {
29 pay_request: String,
31 },
32 Token {
33 token_id: String,
35 pay_request: String,
37 },
38}
39
40#[derive(Debug, Error, Clone)]
41#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
42pub enum PaymentObserverError {
43 #[error("Service connectivity: {0}")]
44 ServiceConnectivity(String),
45 #[error("Generic: {0}")]
46 Generic(String),
47}
48
49impl From<PaymentObserverError> for TransferObserverError {
50 fn from(error: PaymentObserverError) -> Self {
51 match error {
52 PaymentObserverError::ServiceConnectivity(msg) => {
53 TransferObserverError::ServiceConnectivity(msg)
54 }
55 PaymentObserverError::Generic(msg) => TransferObserverError::Generic(msg),
56 }
57 }
58}
59
60#[cfg_attr(feature = "uniffi", uniffi::export(with_foreign))]
63#[macros::async_trait]
64pub trait PaymentObserver: Send + Sync {
65 async fn before_send(
67 &self,
68 payments: Vec<ProvisionalPayment>,
69 ) -> Result<(), PaymentObserverError>;
70}
71
72pub(crate) struct SparkTransferObserver {
73 inner: Arc<dyn PaymentObserver>,
74}
75
76impl SparkTransferObserver {
77 pub fn new(inner: Arc<dyn PaymentObserver>) -> Self {
78 Self { inner }
79 }
80}
81
82#[macros::async_trait]
83impl spark_wallet::TransferObserver for SparkTransferObserver {
84 async fn before_coop_exit(
85 &self,
86 transfer_id: &TransferId,
87 withdrawal_address: &bitcoin::Address,
88 amount_sats: u64,
89 ) -> Result<(), TransferObserverError> {
90 Ok(self
91 .inner
92 .before_send(vec![ProvisionalPayment {
93 payment_id: transfer_id.to_string(),
94 amount: u128::from(amount_sats),
95 details: ProvisionalPaymentDetails::Bitcoin {
96 withdrawal_address: withdrawal_address.to_string(),
97 },
98 }])
99 .await?)
100 }
101 async fn before_send_lightning_payment(
102 &self,
103 transfer_id: &TransferId,
104 invoice: &str,
105 amount_sats: u64,
106 ) -> Result<(), TransferObserverError> {
107 Ok(self
108 .inner
109 .before_send(vec![ProvisionalPayment {
110 payment_id: transfer_id.to_string(),
111 amount: u128::from(amount_sats),
112 details: ProvisionalPaymentDetails::Lightning {
113 invoice: invoice.to_string(),
114 },
115 }])
116 .await?)
117 }
118
119 async fn before_send_token(
120 &self,
121 tx_id: &str,
122 token_id: &str,
123 receiver_outputs: Vec<spark_wallet::ReceiverTokenOutput>,
124 ) -> Result<(), TransferObserverError> {
125 Ok(self
126 .inner
127 .before_send(
128 receiver_outputs
129 .into_iter()
130 .enumerate()
131 .map(|(index, output)| ProvisionalPayment {
132 payment_id: format!("{tx_id}:{index}"),
133 amount: output.amount,
134 details: ProvisionalPaymentDetails::Token {
135 token_id: token_id.to_string(),
136 pay_request: output.pay_request,
137 },
138 })
139 .collect(),
140 )
141 .await?)
142 }
143
144 async fn before_send_transfer(
145 &self,
146 transfer_id: &TransferId,
147 receiver_address: &str,
148 amount_sats: u64,
149 ) -> Result<(), TransferObserverError> {
150 Ok(self
151 .inner
152 .before_send(vec![ProvisionalPayment {
153 payment_id: transfer_id.to_string(),
154 amount: u128::from(amount_sats),
155 details: ProvisionalPaymentDetails::Spark {
156 pay_request: receiver_address.to_string(),
157 },
158 }])
159 .await?)
160 }
161}