breez_sdk_liquid/
bindings.rs

1//! Dart / flutter bindings
2
3use std::sync::Arc;
4
5use anyhow::Result;
6use flutter_rust_bridge::frb;
7use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};
8pub use sdk_common::prelude::*;
9
10use crate::{error::*, frb_generated::StreamSink, model::*, sdk::LiquidSdk};
11
12pub struct BindingEventListener {
13    pub stream: StreamSink<SdkEvent>,
14}
15
16impl EventListener for BindingEventListener {
17    fn on_event(&self, e: SdkEvent) {
18        let _ = self.stream.add(e);
19    }
20}
21
22struct DartBindingLogger {
23    log_stream: StreamSink<LogEntry>,
24}
25
26impl DartBindingLogger {
27    fn init(log_stream: StreamSink<LogEntry>) -> Result<(), SetLoggerError> {
28        let binding_logger: DartBindingLogger = DartBindingLogger { log_stream };
29        log::set_boxed_logger(Box::new(binding_logger))
30            .map(|_| log::set_max_level(LevelFilter::Trace))
31    }
32}
33
34impl log::Log for DartBindingLogger {
35    fn enabled(&self, m: &Metadata) -> bool {
36        m.level() <= Level::Trace
37    }
38
39    fn log(&self, record: &Record) {
40        if self.enabled(record.metadata()) {
41            let _ = self.log_stream.add(LogEntry {
42                line: record.args().to_string(),
43                level: record.level().as_str().to_string(),
44            });
45        }
46    }
47    fn flush(&self) {}
48}
49
50pub async fn connect(req: ConnectRequest) -> Result<BindingLiquidSdk, SdkError> {
51    let ln_sdk = LiquidSdk::connect(req).await?;
52    Ok(BindingLiquidSdk { sdk: ln_sdk })
53}
54
55/// If used, this must be called before `connect`. It can only be called once.
56pub fn breez_log_stream(s: StreamSink<LogEntry>) -> Result<()> {
57    DartBindingLogger::init(s).map_err(|_| SdkError::generic("Log stream already created"))?;
58    Ok(())
59}
60
61#[frb(sync)]
62pub fn default_config(
63    network: LiquidNetwork,
64    breez_api_key: Option<String>,
65) -> Result<Config, SdkError> {
66    LiquidSdk::default_config(network, breez_api_key)
67}
68
69#[frb(sync)]
70pub fn parse_invoice(input: String) -> Result<LNInvoice, PaymentError> {
71    LiquidSdk::parse_invoice(&input)
72}
73
74pub struct BindingLiquidSdk {
75    sdk: Arc<LiquidSdk>,
76}
77
78impl BindingLiquidSdk {
79    pub async fn get_info(&self) -> Result<GetInfoResponse, SdkError> {
80        self.sdk.get_info().await
81    }
82
83    #[frb(sync)]
84    pub fn sign_message(&self, req: SignMessageRequest) -> Result<SignMessageResponse, SdkError> {
85        self.sdk.sign_message(&req)
86    }
87
88    #[frb(sync)]
89    pub fn check_message(
90        &self,
91        req: CheckMessageRequest,
92    ) -> Result<CheckMessageResponse, SdkError> {
93        self.sdk.check_message(&req)
94    }
95
96    pub async fn parse(&self, input: String) -> Result<InputType, PaymentError> {
97        self.sdk.parse(&input).await
98    }
99
100    pub async fn add_event_listener(
101        &self,
102        listener: StreamSink<SdkEvent>,
103    ) -> Result<String, SdkError> {
104        self.sdk
105            .add_event_listener(Box::new(BindingEventListener { stream: listener }))
106            .await
107    }
108
109    pub async fn prepare_send_payment(
110        &self,
111        req: PrepareSendRequest,
112    ) -> Result<PrepareSendResponse, PaymentError> {
113        self.sdk.prepare_send_payment(&req).await
114    }
115
116    pub async fn send_payment(
117        &self,
118        req: SendPaymentRequest,
119    ) -> Result<SendPaymentResponse, PaymentError> {
120        self.sdk.send_payment(&req).await
121    }
122
123    pub async fn prepare_receive_payment(
124        &self,
125        req: PrepareReceiveRequest,
126    ) -> Result<PrepareReceiveResponse, PaymentError> {
127        self.sdk.prepare_receive_payment(&req).await
128    }
129
130    pub async fn receive_payment(
131        &self,
132        req: ReceivePaymentRequest,
133    ) -> Result<ReceivePaymentResponse, PaymentError> {
134        self.sdk.receive_payment(&req).await
135    }
136
137    pub async fn create_bolt12_invoice(
138        &self,
139        req: CreateBolt12InvoiceRequest,
140    ) -> Result<CreateBolt12InvoiceResponse, PaymentError> {
141        self.sdk.create_bolt12_invoice(&req).await
142    }
143
144    pub async fn fetch_lightning_limits(
145        &self,
146    ) -> Result<LightningPaymentLimitsResponse, PaymentError> {
147        self.sdk.fetch_lightning_limits().await
148    }
149
150    pub async fn fetch_onchain_limits(&self) -> Result<OnchainPaymentLimitsResponse, PaymentError> {
151        self.sdk.fetch_onchain_limits().await
152    }
153
154    pub async fn prepare_pay_onchain(
155        &self,
156        req: PreparePayOnchainRequest,
157    ) -> Result<PreparePayOnchainResponse, PaymentError> {
158        self.sdk.prepare_pay_onchain(&req).await
159    }
160
161    pub async fn pay_onchain(
162        &self,
163        req: PayOnchainRequest,
164    ) -> Result<SendPaymentResponse, PaymentError> {
165        self.sdk.pay_onchain(&req).await
166    }
167
168    pub async fn prepare_buy_bitcoin(
169        &self,
170        req: PrepareBuyBitcoinRequest,
171    ) -> Result<PrepareBuyBitcoinResponse, PaymentError> {
172        self.sdk.prepare_buy_bitcoin(&req).await
173    }
174
175    pub async fn buy_bitcoin(&self, req: BuyBitcoinRequest) -> Result<String, PaymentError> {
176        self.sdk.buy_bitcoin(&req).await
177    }
178
179    pub async fn list_payments(
180        &self,
181        req: ListPaymentsRequest,
182    ) -> Result<Vec<Payment>, PaymentError> {
183        self.sdk.list_payments(&req).await
184    }
185
186    pub async fn get_payment(
187        &self,
188        req: GetPaymentRequest,
189    ) -> Result<Option<Payment>, PaymentError> {
190        self.sdk.get_payment(&req).await
191    }
192
193    pub async fn fetch_payment_proposed_fees(
194        &self,
195        req: FetchPaymentProposedFeesRequest,
196    ) -> Result<FetchPaymentProposedFeesResponse, SdkError> {
197        self.sdk.fetch_payment_proposed_fees(&req).await
198    }
199
200    pub async fn accept_payment_proposed_fees(
201        &self,
202        req: AcceptPaymentProposedFeesRequest,
203    ) -> Result<(), PaymentError> {
204        self.sdk.accept_payment_proposed_fees(&req).await
205    }
206
207    pub async fn prepare_lnurl_pay(
208        &self,
209        req: PrepareLnUrlPayRequest,
210    ) -> Result<PrepareLnUrlPayResponse, duplicates::LnUrlPayError> {
211        self.sdk.prepare_lnurl_pay(req).await.map_err(Into::into)
212    }
213
214    pub async fn lnurl_pay(
215        &self,
216        req: crate::model::LnUrlPayRequest,
217    ) -> Result<LnUrlPayResult, duplicates::LnUrlPayError> {
218        self.sdk.lnurl_pay(req).await.map_err(Into::into)
219    }
220
221    pub async fn lnurl_withdraw(
222        &self,
223        req: LnUrlWithdrawRequest,
224    ) -> Result<duplicates::LnUrlWithdrawResult, duplicates::LnUrlWithdrawError> {
225        self.sdk
226            .lnurl_withdraw(req)
227            .await
228            .map(Into::into)
229            .map_err(Into::into)
230    }
231
232    pub async fn lnurl_auth(
233        &self,
234        req_data: LnUrlAuthRequestData,
235    ) -> Result<duplicates::LnUrlCallbackStatus, duplicates::LnUrlAuthError> {
236        self.sdk
237            .lnurl_auth(req_data)
238            .await
239            .map(Into::into)
240            .map_err(Into::into)
241    }
242
243    pub async fn register_webhook(&self, webhook_url: String) -> Result<(), SdkError> {
244        self.sdk.register_webhook(webhook_url).await
245    }
246
247    pub async fn unregister_webhook(&self) -> Result<(), SdkError> {
248        self.sdk.unregister_webhook().await
249    }
250
251    pub async fn fetch_fiat_rates(&self) -> Result<Vec<Rate>, SdkError> {
252        self.sdk.fetch_fiat_rates().await
253    }
254
255    pub async fn list_fiat_currencies(&self) -> Result<Vec<FiatCurrency>, SdkError> {
256        self.sdk.list_fiat_currencies().await
257    }
258
259    pub async fn list_refundables(&self) -> Result<Vec<RefundableSwap>, SdkError> {
260        self.sdk.list_refundables().await
261    }
262
263    pub async fn prepare_refund(
264        &self,
265        req: PrepareRefundRequest,
266    ) -> Result<PrepareRefundResponse, SdkError> {
267        self.sdk.prepare_refund(&req).await
268    }
269
270    pub async fn refund(&self, req: RefundRequest) -> Result<RefundResponse, PaymentError> {
271        self.sdk.refund(&req).await
272    }
273
274    pub async fn rescan_onchain_swaps(&self) -> Result<(), SdkError> {
275        self.sdk.rescan_onchain_swaps().await
276    }
277
278    #[frb(name = "sync")]
279    pub async fn sync(&self) -> Result<(), SdkError> {
280        self.sdk.sync(false).await.map_err(Into::into)
281    }
282
283    pub async fn recommended_fees(&self) -> Result<RecommendedFees, SdkError> {
284        self.sdk.recommended_fees().await
285    }
286
287    #[frb(sync)]
288    pub fn empty_wallet_cache(&self) -> Result<(), SdkError> {
289        self.sdk.empty_wallet_cache().map_err(Into::into)
290    }
291
292    #[frb(sync)]
293    pub fn backup(&self, req: BackupRequest) -> Result<(), SdkError> {
294        self.sdk.backup(req).map_err(Into::into)
295    }
296
297    #[frb(sync)]
298    pub fn restore(&self, req: RestoreRequest) -> Result<(), SdkError> {
299        self.sdk.restore(req).map_err(Into::into)
300    }
301
302    pub async fn disconnect(&self) -> Result<(), SdkError> {
303        self.sdk.disconnect().await
304    }
305}
306
307// === FRB mirroring
308//
309// This section contains frb "mirroring" structs and enums.
310// These are needed by the flutter bridge in order to use structs defined in an external crate.
311// See <https://cjycode.com/flutter_rust_bridge/v1/feature/lang_external.html#types-in-other-crates>
312
313#[frb(mirror(Network))]
314pub enum _Network {
315    Bitcoin,
316    Testnet,
317    Signet,
318    Regtest,
319}
320
321#[frb(mirror(ExternalInputParser))]
322pub struct _ExternalInputParser {
323    pub provider_id: String,
324    pub input_regex: String,
325    pub parser_url: String,
326}
327
328#[frb(mirror(LNInvoice))]
329pub struct _LNInvoice {
330    pub bolt11: String,
331    pub network: Network,
332    pub payee_pubkey: String,
333    pub payment_hash: String,
334    pub description: Option<String>,
335    pub description_hash: Option<String>,
336    pub amount_msat: Option<u64>,
337    pub timestamp: u64,
338    pub expiry: u64,
339    pub routing_hints: Vec<RouteHint>,
340    pub payment_secret: Vec<u8>,
341    pub min_final_cltv_expiry_delta: u64,
342}
343
344#[frb(mirror(RouteHint))]
345pub struct _RouteHint {
346    pub hops: Vec<RouteHintHop>,
347}
348
349#[frb(mirror(RouteHintHop))]
350pub struct _RouteHintHop {
351    pub src_node_id: String,
352    pub short_channel_id: String,
353    pub fees_base_msat: u32,
354    pub fees_proportional_millionths: u32,
355    pub cltv_expiry_delta: u64,
356    pub htlc_minimum_msat: Option<u64>,
357    pub htlc_maximum_msat: Option<u64>,
358}
359
360#[frb(mirror(Amount))]
361pub enum _Amount {
362    Bitcoin {
363        amount_msat: u64,
364    },
365    Currency {
366        iso4217_code: String,
367        fractional_amount: u64,
368    },
369}
370
371#[frb(mirror(LnOfferBlindedPath))]
372pub struct _LnOfferBlindedPath {
373    pub blinded_hops: Vec<String>,
374}
375
376#[frb(mirror(LNOffer))]
377pub struct _LNOffer {
378    pub offer: String,
379    pub chains: Vec<String>,
380    pub min_amount: Option<Amount>,
381    pub description: Option<String>,
382    pub absolute_expiry: Option<u64>,
383    pub issuer: Option<String>,
384    pub signing_pubkey: Option<String>,
385    pub paths: Vec<LnOfferBlindedPath>,
386}
387
388#[frb(mirror(InputType))]
389pub enum _InputType {
390    BitcoinAddress {
391        address: BitcoinAddressData,
392    },
393    LiquidAddress {
394        address: LiquidAddressData,
395    },
396    Bolt11 {
397        invoice: LNInvoice,
398    },
399    Bolt12Offer {
400        offer: LNOffer,
401        bip353_address: Option<String>,
402    },
403    NodeId {
404        node_id: String,
405    },
406    Url {
407        url: String,
408    },
409    LnUrlPay {
410        data: LnUrlPayRequestData,
411        bip353_address: Option<String>,
412    },
413    LnUrlWithdraw {
414        data: LnUrlWithdrawRequestData,
415    },
416    LnUrlAuth {
417        data: LnUrlAuthRequestData,
418    },
419    LnUrlError {
420        data: LnUrlErrorData,
421    },
422}
423
424#[frb(mirror(BitcoinAddressData))]
425pub struct _BitcoinAddressData {
426    pub address: String,
427    pub network: sdk_common::prelude::Network,
428    pub amount_sat: Option<u64>,
429    pub label: Option<String>,
430    pub message: Option<String>,
431}
432
433#[frb(mirror(LiquidAddressData))]
434pub struct _LiquidAddressData {
435    pub address: String,
436    pub network: Network,
437    pub asset_id: Option<String>,
438    pub amount: Option<f64>,
439    pub amount_sat: Option<u64>,
440    pub label: Option<String>,
441    pub message: Option<String>,
442}
443
444#[frb(mirror(LnUrlPayRequestData))]
445pub struct _LnUrlPayRequestData {
446    pub callback: String,
447    pub min_sendable: u64,
448    pub max_sendable: u64,
449    pub metadata_str: String,
450    pub comment_allowed: u16,
451    pub domain: String,
452    pub allows_nostr: bool,
453    pub nostr_pubkey: Option<String>,
454    pub ln_address: Option<String>,
455}
456
457#[frb(mirror(SuccessAction))]
458pub enum _SuccessAction {
459    Aes { data: AesSuccessActionData },
460    Message { data: MessageSuccessActionData },
461    Url { data: UrlSuccessActionData },
462}
463
464#[frb(mirror(SuccessActionProcessed))]
465pub enum _SuccessActionProcessed {
466    Aes { result: AesSuccessActionDataResult },
467    Message { data: MessageSuccessActionData },
468    Url { data: UrlSuccessActionData },
469}
470
471#[frb(mirror(AesSuccessActionData))]
472pub struct _AesSuccessActionData {
473    pub description: String,
474    pub ciphertext: String,
475    pub iv: String,
476}
477
478#[frb(mirror(AesSuccessActionDataResult))]
479pub enum _AesSuccessActionDataResult {
480    Decrypted { data: AesSuccessActionDataDecrypted },
481    ErrorStatus { reason: String },
482}
483
484#[frb(mirror(AesSuccessActionDataDecrypted))]
485pub struct _AesSuccessActionDataDecrypted {
486    pub description: String,
487    pub plaintext: String,
488}
489
490#[frb(mirror(MessageSuccessActionData))]
491pub struct _MessageSuccessActionData {
492    pub message: String,
493}
494
495#[frb(mirror(UrlSuccessActionData))]
496pub struct _UrlSuccessActionData {
497    pub description: String,
498    pub url: String,
499    pub matches_callback_domain: bool,
500}
501
502#[frb(mirror(LnUrlPayErrorData))]
503pub struct _LnUrlPayErrorData {
504    pub payment_hash: String,
505    pub reason: String,
506}
507
508#[frb(mirror(LnUrlWithdrawRequestData))]
509pub struct _LnUrlWithdrawRequestData {
510    pub callback: String,
511    pub k1: String,
512    pub default_description: String,
513    pub min_withdrawable: u64,
514    pub max_withdrawable: u64,
515}
516
517#[frb(mirror(LnUrlAuthRequestData))]
518pub struct _LnUrlAuthRequestData {
519    pub k1: String,
520    pub action: Option<String>,
521    pub domain: String,
522    pub url: String,
523}
524
525#[frb(mirror(LnUrlErrorData))]
526pub struct _LnUrlErrorData {
527    pub reason: String,
528}
529
530#[frb(mirror(LnUrlWithdrawRequest))]
531pub struct _LnUrlWithdrawRequest {
532    pub data: LnUrlWithdrawRequestData,
533    pub amount_msat: u64,
534    pub description: Option<String>,
535}
536
537#[frb(mirror(Rate))]
538pub struct _Rate {
539    pub coin: String,
540    pub value: f64,
541}
542
543#[frb(mirror(FiatCurrency))]
544pub struct _FiatCurrency {
545    pub id: String,
546    pub info: CurrencyInfo,
547}
548
549#[frb(mirror(CurrencyInfo))]
550pub struct _CurrencyInfo {
551    pub name: String,
552    pub fraction_size: u32,
553    pub spacing: Option<u32>,
554    pub symbol: Option<Symbol>,
555    pub uniq_symbol: Option<Symbol>,
556    pub localized_name: Vec<LocalizedName>,
557    pub locale_overrides: Vec<LocaleOverrides>,
558}
559
560#[frb(mirror(LocaleOverrides))]
561pub struct _LocaleOverrides {
562    pub locale: String,
563    pub spacing: Option<u32>,
564    pub symbol: Symbol,
565}
566
567#[frb(mirror(LocalizedName))]
568pub struct _LocalizedName {
569    pub locale: String,
570    pub name: String,
571}
572
573#[frb(mirror(Symbol))]
574pub struct _Symbol {
575    pub grapheme: Option<String>,
576    pub template: Option<String>,
577    pub rtl: Option<bool>,
578    pub position: Option<u32>,
579}
580
581/// External structs that cannot be mirrored for FRB, so are therefore duplicated instead
582pub mod duplicates {
583    use sdk_common::prelude::*;
584    use serde::{Deserialize, Serialize};
585    use thiserror::Error;
586
587    #[derive(Clone, Debug, Error)]
588    pub enum LnUrlPayError {
589        /// This error is raised when attempting to pay an invoice that has already being paid.
590        #[error("Invoice already paid")]
591        AlreadyPaid,
592
593        /// This error is raised when a general error occurs not specific to other error variants
594        /// in this enum.
595        #[error("Generic: {err}")]
596        Generic { err: String },
597
598        /// This error is raised when the node does not have enough funds to make the payment.
599        #[error("Insufficient balance: {err}")]
600        InsufficientBalance { err: String },
601
602        /// This error is raised when the amount from the parsed invoice is not set.
603        #[error("Invalid amount: {err}")]
604        InvalidAmount { err: String },
605
606        /// This error is raised when the lightning invoice cannot be parsed.
607        #[error("Invalid invoice: {err}")]
608        InvalidInvoice { err: String },
609
610        /// This error is raised when the lightning invoice is for a different Bitcoin network.
611        #[error("Invalid network: {err}")]
612        InvalidNetwork { err: String },
613
614        /// This error is raised when the decoded LNURL URI is not compliant to the specification.
615        #[error("Invalid uri: {err}")]
616        InvalidUri { err: String },
617
618        /// This error is raised when the lightning invoice has passed it's expiry time.
619        #[error("Invoice expired: {err}")]
620        InvoiceExpired { err: String },
621
622        /// This error is raised when attempting to make a payment by the node fails.
623        #[error("Payment failed: {err}")]
624        PaymentFailed { err: String },
625
626        /// This error is raised when attempting to make a payment takes too long.
627        #[error("Payment timeout: {err}")]
628        PaymentTimeout { err: String },
629
630        /// This error is raised when no route can be found when attempting to make a
631        /// payment by the node.
632        #[error("Route not found: {err}")]
633        RouteNotFound { err: String },
634
635        /// This error is raised when the route is considered too expensive when
636        /// attempting to make a payment by the node.
637        #[error("Route too expensive: {err}")]
638        RouteTooExpensive { err: String },
639
640        /// This error is raised when a connection to an external service fails.
641        #[error("Service connectivity: {err}")]
642        ServiceConnectivity { err: String },
643    }
644    impl From<sdk_common::prelude::LnUrlPayError> for LnUrlPayError {
645        fn from(value: sdk_common::prelude::LnUrlPayError) -> Self {
646            match value {
647                sdk_common::prelude::LnUrlPayError::AlreadyPaid => Self::AlreadyPaid,
648                sdk_common::prelude::LnUrlPayError::Generic { err } => Self::Generic { err },
649                sdk_common::prelude::LnUrlPayError::InsufficientBalance { err } => {
650                    Self::InsufficientBalance { err }
651                }
652                sdk_common::prelude::LnUrlPayError::InvalidAmount { err } => {
653                    Self::InvalidAmount { err }
654                }
655                sdk_common::prelude::LnUrlPayError::InvalidInvoice { err } => {
656                    Self::InvalidInvoice { err }
657                }
658                sdk_common::prelude::LnUrlPayError::InvalidNetwork { err } => {
659                    Self::InvalidNetwork { err }
660                }
661                sdk_common::prelude::LnUrlPayError::InvalidUri { err } => Self::InvalidUri { err },
662                sdk_common::prelude::LnUrlPayError::InvoiceExpired { err } => {
663                    Self::InvoiceExpired { err }
664                }
665                sdk_common::prelude::LnUrlPayError::PaymentFailed { err } => {
666                    Self::PaymentFailed { err }
667                }
668                sdk_common::prelude::LnUrlPayError::PaymentTimeout { err } => {
669                    Self::PaymentTimeout { err }
670                }
671                sdk_common::prelude::LnUrlPayError::RouteNotFound { err } => {
672                    Self::RouteNotFound { err }
673                }
674                sdk_common::prelude::LnUrlPayError::RouteTooExpensive { err } => {
675                    Self::RouteTooExpensive { err }
676                }
677                sdk_common::prelude::LnUrlPayError::ServiceConnectivity { err } => {
678                    Self::ServiceConnectivity { err }
679                }
680            }
681        }
682    }
683
684    #[derive(Debug, Error)]
685    pub enum LnUrlWithdrawError {
686        /// This error is raised when a general error occurs not specific to other error variants
687        /// in this enum.
688        #[error("Generic: {err}")]
689        Generic { err: String },
690
691        /// This error is raised when the amount is zero or the amount does not cover
692        /// the cost to open a new channel.
693        #[error("Invalid amount: {err}")]
694        InvalidAmount { err: String },
695
696        /// This error is raised when the lightning invoice cannot be parsed.
697        #[error("Invalid invoice: {err}")]
698        InvalidInvoice { err: String },
699
700        /// This error is raised when the decoded LNURL URI is not compliant to the specification.
701        #[error("Invalid uri: {err}")]
702        InvalidUri { err: String },
703
704        /// This error is raised when no routing hints were able to be added to the invoice
705        /// while trying to receive a payment.
706        #[error("No routing hints: {err}")]
707        InvoiceNoRoutingHints { err: String },
708
709        /// This error is raised when a connection to an external service fails.
710        #[error("Service connectivity: {err}")]
711        ServiceConnectivity { err: String },
712    }
713
714    impl From<sdk_common::prelude::LnUrlWithdrawError> for LnUrlWithdrawError {
715        fn from(value: sdk_common::prelude::LnUrlWithdrawError) -> Self {
716            match value {
717                sdk_common::prelude::LnUrlWithdrawError::Generic { err } => Self::Generic { err },
718                sdk_common::prelude::LnUrlWithdrawError::InvalidAmount { err } => {
719                    Self::InvalidAmount { err }
720                }
721                sdk_common::prelude::LnUrlWithdrawError::InvalidInvoice { err } => {
722                    Self::InvalidInvoice { err }
723                }
724                sdk_common::prelude::LnUrlWithdrawError::InvalidUri { err } => {
725                    Self::InvalidUri { err }
726                }
727                sdk_common::prelude::LnUrlWithdrawError::InvoiceNoRoutingHints { err } => {
728                    Self::InvoiceNoRoutingHints { err }
729                }
730                sdk_common::prelude::LnUrlWithdrawError::ServiceConnectivity { err } => {
731                    Self::ServiceConnectivity { err }
732                }
733            }
734        }
735    }
736
737    #[derive(Clone, Serialize)]
738    pub enum LnUrlWithdrawResult {
739        Ok { data: LnUrlWithdrawSuccessData },
740        Timeout { data: LnUrlWithdrawSuccessData },
741        ErrorStatus { data: LnUrlErrorData },
742    }
743    impl From<sdk_common::prelude::LnUrlWithdrawResult> for LnUrlWithdrawResult {
744        fn from(value: sdk_common::prelude::LnUrlWithdrawResult) -> Self {
745            match value {
746                sdk_common::prelude::LnUrlWithdrawResult::Ok { data } => {
747                    Self::Ok { data: data.into() }
748                }
749                sdk_common::prelude::LnUrlWithdrawResult::Timeout { data } => {
750                    Self::Timeout { data: data.into() }
751                }
752                sdk_common::prelude::LnUrlWithdrawResult::ErrorStatus { data } => {
753                    Self::ErrorStatus { data }
754                }
755            }
756        }
757    }
758
759    #[derive(Clone, Deserialize, Debug, Serialize)]
760    pub struct LnUrlWithdrawSuccessData {
761        pub invoice: LNInvoice,
762    }
763    impl From<sdk_common::prelude::LnUrlWithdrawSuccessData> for LnUrlWithdrawSuccessData {
764        fn from(value: sdk_common::prelude::LnUrlWithdrawSuccessData) -> Self {
765            Self {
766                invoice: value.invoice,
767            }
768        }
769    }
770
771    #[derive(Debug, Error)]
772    pub enum LnUrlAuthError {
773        /// This error is raised when a general error occurs not specific to other error variants
774        /// in this enum.
775        #[error("Generic: {err}")]
776        Generic { err: String },
777
778        /// This error is raised when the decoded LNURL URI is not compliant to the specification.
779        #[error("Invalid uri: {err}")]
780        InvalidUri { err: String },
781
782        /// This error is raised when a connection to an external service fails.
783        #[error("Service connectivity: {err}")]
784        ServiceConnectivity { err: String },
785    }
786    impl From<sdk_common::prelude::LnUrlAuthError> for LnUrlAuthError {
787        fn from(value: prelude::LnUrlAuthError) -> Self {
788            match value {
789                sdk_common::prelude::LnUrlAuthError::Generic { err } => Self::Generic { err },
790                sdk_common::prelude::LnUrlAuthError::InvalidUri { err } => Self::InvalidUri { err },
791                sdk_common::prelude::LnUrlAuthError::ServiceConnectivity { err } => {
792                    Self::ServiceConnectivity { err }
793                }
794            }
795        }
796    }
797
798    /// Contains the result of the entire LNURL interaction, as reported by the LNURL endpoint.
799    ///
800    /// * `Ok` indicates the interaction with the endpoint was valid, and the endpoint
801    ///  - started to pay the invoice asynchronously in the case of LNURL-withdraw,
802    ///  - verified the client signature in the case of LNURL-auth,
803    /// * `Error` indicates a generic issue the LNURL endpoint encountered, including a freetext
804    ///   description of the reason.
805    ///
806    /// Both cases are described in LUD-03 <https://github.com/lnurl/luds/blob/luds/03.md> & LUD-04: <https://github.com/lnurl/luds/blob/luds/04.md>
807    #[derive(Clone, Deserialize, Debug, Serialize)]
808    #[serde(rename_all = "UPPERCASE")]
809    #[serde(tag = "status")]
810    pub enum LnUrlCallbackStatus {
811        /// On-wire format is: `{"status": "OK"}`
812        Ok,
813        /// On-wire format is: `{"status": "ERROR", "reason": "error details..."}`
814        #[serde(rename = "ERROR")]
815        ErrorStatus {
816            #[serde(flatten)]
817            data: LnUrlErrorData,
818        },
819    }
820    impl From<sdk_common::prelude::LnUrlCallbackStatus> for LnUrlCallbackStatus {
821        fn from(value: prelude::LnUrlCallbackStatus) -> Self {
822            match value {
823                sdk_common::prelude::LnUrlCallbackStatus::Ok => Self::Ok,
824                sdk_common::prelude::LnUrlCallbackStatus::ErrorStatus { data } => {
825                    Self::ErrorStatus { data }
826                }
827            }
828        }
829    }
830}