1pub(crate) mod adaptors;
2pub mod payment_observer;
3pub use payment_observer::*;
4
5use core::fmt;
6use lnurl_models::RecoverLnurlPayResponse;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::{collections::HashMap, fmt::Display, str::FromStr};
10
11use crate::{
12 BitcoinAddressDetails, BitcoinChainService, BitcoinNetwork, Bolt11InvoiceDetails,
13 ExternalInputParser, FiatCurrency, LnurlPayRequestDetails, LnurlWithdrawRequestDetails, Rate,
14 SdkError, SparkInvoiceDetails, SuccessAction, SuccessActionProcessed, error::DepositClaimError,
15};
16
17pub const DEFAULT_EXTERNAL_INPUT_PARSERS: &[(&str, &str, &str)] = &[
20 (
21 "picknpay",
22 "(.*)(za.co.electrum.picknpay)(.*)",
23 "https://cryptoqr.net/.well-known/lnurlp/<input>",
24 ),
25 (
26 "bootleggers",
27 r"(.*)(wigroup\.co|yoyogroup\.co)(.*)",
28 "https://cryptoqr.net/.well-known/lnurlw/<input>",
29 ),
30];
31
32#[derive(Debug, Clone)]
35#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
36pub enum Seed {
37 Mnemonic {
39 mnemonic: String,
41 passphrase: Option<String>,
43 },
44 Entropy(Vec<u8>),
46}
47
48impl Seed {
49 pub fn to_bytes(&self) -> Result<Vec<u8>, SdkError> {
50 match self {
51 Seed::Mnemonic {
52 mnemonic,
53 passphrase,
54 } => {
55 let mnemonic = bip39::Mnemonic::parse(mnemonic)
56 .map_err(|e| SdkError::Generic(e.to_string()))?;
57
58 Ok(mnemonic
59 .to_seed(passphrase.as_deref().unwrap_or(""))
60 .to_vec())
61 }
62 Seed::Entropy(entropy) => Ok(entropy.clone()),
63 }
64 }
65}
66
67#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
68pub struct ConnectRequest {
69 pub config: Config,
70 pub seed: Seed,
71 pub storage_dir: String,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
76#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
77pub enum PaymentType {
78 Send,
80 Receive,
82}
83
84impl fmt::Display for PaymentType {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 match self {
87 PaymentType::Send => write!(f, "send"),
88 PaymentType::Receive => write!(f, "receive"),
89 }
90 }
91}
92
93impl FromStr for PaymentType {
94 type Err = String;
95
96 fn from_str(s: &str) -> Result<Self, Self::Err> {
97 Ok(match s.to_lowercase().as_str() {
98 "receive" => PaymentType::Receive,
99 "send" => PaymentType::Send,
100 _ => return Err(format!("invalid payment type '{s}'")),
101 })
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
107#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
108pub enum PaymentStatus {
109 Completed,
111 Pending,
113 Failed,
115}
116
117impl PaymentStatus {
118 pub fn is_final(&self) -> bool {
120 matches!(self, PaymentStatus::Completed | PaymentStatus::Failed)
121 }
122}
123
124impl fmt::Display for PaymentStatus {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 PaymentStatus::Completed => write!(f, "completed"),
128 PaymentStatus::Pending => write!(f, "pending"),
129 PaymentStatus::Failed => write!(f, "failed"),
130 }
131 }
132}
133
134impl FromStr for PaymentStatus {
135 type Err = String;
136
137 fn from_str(s: &str) -> Result<Self, Self::Err> {
138 Ok(match s.to_lowercase().as_str() {
139 "completed" => PaymentStatus::Completed,
140 "pending" => PaymentStatus::Pending,
141 "failed" => PaymentStatus::Failed,
142 _ => return Err(format!("Invalid payment status '{s}'")),
143 })
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
148#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
149pub enum PaymentMethod {
150 Lightning,
151 Spark,
152 Token,
153 Deposit,
154 Withdraw,
155 Unknown,
156}
157
158impl Display for PaymentMethod {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 match self {
161 PaymentMethod::Lightning => write!(f, "lightning"),
162 PaymentMethod::Spark => write!(f, "spark"),
163 PaymentMethod::Token => write!(f, "token"),
164 PaymentMethod::Deposit => write!(f, "deposit"),
165 PaymentMethod::Withdraw => write!(f, "withdraw"),
166 PaymentMethod::Unknown => write!(f, "unknown"),
167 }
168 }
169}
170
171impl FromStr for PaymentMethod {
172 type Err = ();
173
174 fn from_str(s: &str) -> Result<Self, Self::Err> {
175 match s {
176 "lightning" => Ok(PaymentMethod::Lightning),
177 "spark" => Ok(PaymentMethod::Spark),
178 "token" => Ok(PaymentMethod::Token),
179 "deposit" => Ok(PaymentMethod::Deposit),
180 "withdraw" => Ok(PaymentMethod::Withdraw),
181 "unknown" => Ok(PaymentMethod::Unknown),
182 _ => Err(()),
183 }
184 }
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
190pub struct Payment {
191 pub id: String,
193 pub payment_type: PaymentType,
195 pub status: PaymentStatus,
197 pub amount: u128,
199 pub fees: u128,
201 pub timestamp: u64,
203 pub method: PaymentMethod,
206 pub details: Option<PaymentDetails>,
208}
209
210#[cfg(feature = "uniffi")]
211uniffi::custom_type!(u128, String);
212
213#[cfg(feature = "uniffi")]
214impl crate::UniffiCustomTypeConverter for u128 {
215 type Builtin = String;
216
217 fn into_custom(val: Self::Builtin) -> ::uniffi::Result<Self>
218 where
219 Self: ::std::marker::Sized,
220 {
221 val.parse::<u128>()
222 .map_err(uniffi::deps::anyhow::Error::msg)
223 }
224
225 fn from_custom(obj: Self) -> Self::Builtin {
226 obj.to_string()
227 }
228}
229
230#[allow(clippy::large_enum_variant)]
233#[derive(Debug, Clone, Serialize, Deserialize)]
234#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
235pub enum PaymentDetails {
236 Spark {
237 invoice_details: Option<SparkInvoicePaymentDetails>,
239 htlc_details: Option<SparkHtlcDetails>,
241 },
242 Token {
243 metadata: TokenMetadata,
244 tx_hash: String,
245 invoice_details: Option<SparkInvoicePaymentDetails>,
247 },
248 Lightning {
249 description: Option<String>,
251 preimage: Option<String>,
253 invoice: String,
257
258 payment_hash: String,
260
261 destination_pubkey: String,
263
264 lnurl_pay_info: Option<LnurlPayInfo>,
266
267 lnurl_withdraw_info: Option<LnurlWithdrawInfo>,
269
270 lnurl_receive_metadata: Option<LnurlReceiveMetadata>,
272 },
273 Withdraw {
274 tx_id: String,
275 },
276 Deposit {
277 tx_id: String,
278 },
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
282#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
283pub struct SparkInvoicePaymentDetails {
284 pub description: Option<String>,
286 pub invoice: String,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
291#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
292pub struct SparkHtlcDetails {
293 pub payment_hash: String,
295 pub preimage: Option<String>,
297 pub expiry_time: u64,
299 pub status: SparkHtlcStatus,
301}
302
303#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
304#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
305pub enum SparkHtlcStatus {
306 WaitingForPreimage,
308 PreimageShared,
310 Returned,
312}
313
314impl fmt::Display for SparkHtlcStatus {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 match self {
317 SparkHtlcStatus::WaitingForPreimage => write!(f, "WaitingForPreimage"),
318 SparkHtlcStatus::PreimageShared => write!(f, "PreimageShared"),
319 SparkHtlcStatus::Returned => write!(f, "Returned"),
320 }
321 }
322}
323
324impl FromStr for SparkHtlcStatus {
325 type Err = String;
326
327 fn from_str(s: &str) -> Result<Self, Self::Err> {
328 match s {
329 "WaitingForPreimage" => Ok(SparkHtlcStatus::WaitingForPreimage),
330 "PreimageShared" => Ok(SparkHtlcStatus::PreimageShared),
331 "Returned" => Ok(SparkHtlcStatus::Returned),
332 _ => Err("Invalid Spark HTLC status".to_string()),
333 }
334 }
335}
336
337#[derive(Debug, Clone, Copy)]
338#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
339pub enum Network {
340 Mainnet,
341 Regtest,
342}
343
344impl std::fmt::Display for Network {
345 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346 match self {
347 Network::Mainnet => write!(f, "Mainnet"),
348 Network::Regtest => write!(f, "Regtest"),
349 }
350 }
351}
352
353impl From<Network> for BitcoinNetwork {
354 fn from(network: Network) -> Self {
355 match network {
356 Network::Mainnet => BitcoinNetwork::Bitcoin,
357 Network::Regtest => BitcoinNetwork::Regtest,
358 }
359 }
360}
361
362impl From<Network> for breez_sdk_common::network::BitcoinNetwork {
363 fn from(network: Network) -> Self {
364 match network {
365 Network::Mainnet => breez_sdk_common::network::BitcoinNetwork::Bitcoin,
366 Network::Regtest => breez_sdk_common::network::BitcoinNetwork::Regtest,
367 }
368 }
369}
370
371impl From<Network> for bitcoin::Network {
372 fn from(network: Network) -> Self {
373 match network {
374 Network::Mainnet => bitcoin::Network::Bitcoin,
375 Network::Regtest => bitcoin::Network::Regtest,
376 }
377 }
378}
379
380impl FromStr for Network {
381 type Err = String;
382
383 fn from_str(s: &str) -> Result<Self, Self::Err> {
384 match s {
385 "mainnet" => Ok(Network::Mainnet),
386 "regtest" => Ok(Network::Regtest),
387 _ => Err("Invalid network".to_string()),
388 }
389 }
390}
391
392#[derive(Debug, Clone)]
393#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
394pub struct Config {
395 pub api_key: Option<String>,
396 pub network: Network,
397 pub sync_interval_secs: u32,
398
399 pub max_deposit_claim_fee: Option<MaxFee>,
402
403 pub lnurl_domain: Option<String>,
405
406 pub prefer_spark_over_lightning: bool,
410
411 pub external_input_parsers: Option<Vec<ExternalInputParser>>,
415 pub use_default_external_input_parsers: bool,
419
420 pub real_time_sync_server_url: Option<String>,
422
423 pub private_enabled_default: bool,
428}
429
430impl Config {
431 pub(crate) fn get_all_external_input_parsers(&self) -> Vec<ExternalInputParser> {
432 let mut external_input_parsers = Vec::new();
433 if self.use_default_external_input_parsers {
434 let default_parsers = DEFAULT_EXTERNAL_INPUT_PARSERS
435 .iter()
436 .map(|(id, regex, url)| ExternalInputParser {
437 provider_id: (*id).to_string(),
438 input_regex: (*regex).to_string(),
439 parser_url: (*url).to_string(),
440 })
441 .collect::<Vec<_>>();
442 external_input_parsers.extend(default_parsers);
443 }
444 external_input_parsers.extend(self.external_input_parsers.clone().unwrap_or_default());
445
446 external_input_parsers
447 }
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
451#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
452pub enum MaxFee {
453 Fixed { amount: u64 },
455 Rate { sat_per_vbyte: u64 },
457 NetworkRecommended { leeway_sat_per_vbyte: u64 },
459}
460
461impl MaxFee {
462 pub(crate) async fn to_fee(&self, client: &dyn BitcoinChainService) -> Result<Fee, SdkError> {
463 match self {
464 MaxFee::Fixed { amount } => Ok(Fee::Fixed { amount: *amount }),
465 MaxFee::Rate { sat_per_vbyte } => Ok(Fee::Rate {
466 sat_per_vbyte: *sat_per_vbyte,
467 }),
468 MaxFee::NetworkRecommended {
469 leeway_sat_per_vbyte,
470 } => {
471 let recommended_fees = client.recommended_fees().await?;
472 let max_fee_rate = recommended_fees
473 .fastest_fee
474 .saturating_add(*leeway_sat_per_vbyte);
475 Ok(Fee::Rate {
476 sat_per_vbyte: max_fee_rate,
477 })
478 }
479 }
480 }
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
484#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
485pub enum Fee {
486 Fixed { amount: u64 },
488 Rate { sat_per_vbyte: u64 },
490}
491
492impl Fee {
493 pub fn to_sats(&self, vbytes: u64) -> u64 {
494 match self {
495 Fee::Fixed { amount } => *amount,
496 Fee::Rate { sat_per_vbyte } => sat_per_vbyte.saturating_mul(vbytes),
497 }
498 }
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize)]
502#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
503pub struct DepositInfo {
504 pub txid: String,
505 pub vout: u32,
506 pub amount_sats: u64,
507 pub refund_tx: Option<String>,
508 pub refund_tx_id: Option<String>,
509 pub claim_error: Option<DepositClaimError>,
510}
511
512#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
513pub struct ClaimDepositRequest {
514 pub txid: String,
515 pub vout: u32,
516 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
517 pub max_fee: Option<MaxFee>,
518}
519
520#[derive(Debug, Clone, Serialize)]
521#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
522pub struct ClaimDepositResponse {
523 pub payment: Payment,
524}
525
526#[derive(Debug, Clone, Serialize)]
527#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
528pub struct RefundDepositRequest {
529 pub txid: String,
530 pub vout: u32,
531 pub destination_address: String,
532 pub fee: Fee,
533}
534
535#[derive(Debug, Clone, Serialize)]
536#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
537pub struct RefundDepositResponse {
538 pub tx_id: String,
539 pub tx_hex: String,
540}
541
542#[derive(Debug, Clone, Serialize)]
543#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
544pub struct ListUnclaimedDepositsRequest {}
545
546#[derive(Debug, Clone, Serialize)]
547#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
548pub struct ListUnclaimedDepositsResponse {
549 pub deposits: Vec<DepositInfo>,
550}
551
552impl std::fmt::Display for MaxFee {
553 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
554 match self {
555 MaxFee::Fixed { amount } => write!(f, "Fixed: {amount}"),
556 MaxFee::Rate { sat_per_vbyte } => write!(f, "Rate: {sat_per_vbyte}"),
557 MaxFee::NetworkRecommended {
558 leeway_sat_per_vbyte,
559 } => write!(f, "NetworkRecommended: {leeway_sat_per_vbyte}"),
560 }
561 }
562}
563
564#[derive(Debug, Clone)]
565#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
566pub struct Credentials {
567 pub username: String,
568 pub password: String,
569}
570
571#[derive(Debug, Clone)]
573#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
574pub struct GetInfoRequest {
575 pub ensure_synced: Option<bool>,
576}
577
578#[derive(Debug, Clone, Serialize)]
580#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
581pub struct GetInfoResponse {
582 pub balance_sats: u64,
584 pub token_balances: HashMap<String, TokenBalance>,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
589#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
590pub struct TokenBalance {
591 pub balance: u128,
592 pub token_metadata: TokenMetadata,
593}
594
595#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
596#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
597pub struct TokenMetadata {
598 pub identifier: String,
599 pub issuer_public_key: String,
601 pub name: String,
602 pub ticker: String,
603 pub decimals: u32,
605 pub max_supply: u128,
606 pub is_freezable: bool,
607}
608
609#[derive(Debug, Clone)]
611#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
612pub struct SyncWalletRequest {}
613
614#[derive(Debug, Clone, Serialize)]
616#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
617pub struct SyncWalletResponse {}
618
619#[derive(Debug, Clone, Serialize)]
620#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
621pub enum ReceivePaymentMethod {
622 SparkAddress,
623 SparkInvoice {
624 amount: Option<u128>,
626 token_identifier: Option<String>,
629 expiry_time: Option<u64>,
631 description: Option<String>,
633 sender_public_key: Option<String>,
635 },
636 BitcoinAddress,
637 Bolt11Invoice {
638 description: String,
639 amount_sats: Option<u64>,
640 },
641}
642
643#[derive(Debug, Clone, Serialize)]
644#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
645pub enum SendPaymentMethod {
646 BitcoinAddress {
647 address: BitcoinAddressDetails,
648 fee_quote: SendOnchainFeeQuote,
649 },
650 Bolt11Invoice {
651 invoice_details: Bolt11InvoiceDetails,
652 spark_transfer_fee_sats: Option<u64>,
653 lightning_fee_sats: u64,
654 }, SparkAddress {
656 address: String,
657 fee: u128,
660 token_identifier: Option<String>,
663 },
664 SparkInvoice {
665 spark_invoice_details: SparkInvoiceDetails,
666 fee: u128,
669 token_identifier: Option<String>,
672 },
673}
674
675#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
676#[derive(Debug, Clone, Serialize)]
677pub struct SendOnchainFeeQuote {
678 pub id: String,
679 pub expires_at: u64,
680 pub speed_fast: SendOnchainSpeedFeeQuote,
681 pub speed_medium: SendOnchainSpeedFeeQuote,
682 pub speed_slow: SendOnchainSpeedFeeQuote,
683}
684
685#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
686#[derive(Debug, Clone, Serialize)]
687pub struct SendOnchainSpeedFeeQuote {
688 pub user_fee_sat: u64,
689 pub l1_broadcast_fee_sat: u64,
690}
691
692impl SendOnchainSpeedFeeQuote {
693 pub fn total_fee_sat(&self) -> u64 {
694 self.user_fee_sat.saturating_add(self.l1_broadcast_fee_sat)
695 }
696}
697
698#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
699pub struct ReceivePaymentRequest {
700 pub payment_method: ReceivePaymentMethod,
701}
702
703#[derive(Debug, Clone, Serialize)]
704#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
705pub struct ReceivePaymentResponse {
706 pub payment_request: String,
707 pub fee: u128,
710}
711
712#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
713pub struct PrepareLnurlPayRequest {
714 pub amount_sats: u64,
715 pub pay_request: LnurlPayRequestDetails,
716 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
717 pub comment: Option<String>,
718 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
719 pub validate_success_action_url: Option<bool>,
720}
721
722#[derive(Debug)]
723#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
724pub struct PrepareLnurlPayResponse {
725 pub amount_sats: u64,
726 pub comment: Option<String>,
727 pub pay_request: LnurlPayRequestDetails,
728 pub fee_sats: u64,
729 pub invoice_details: Bolt11InvoiceDetails,
730 pub success_action: Option<SuccessAction>,
731}
732
733#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
734pub struct LnurlPayRequest {
735 pub prepare_response: PrepareLnurlPayResponse,
736 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
740 pub idempotency_key: Option<String>,
741}
742
743#[derive(Debug, Serialize)]
744#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
745pub struct LnurlPayResponse {
746 pub payment: Payment,
747 pub success_action: Option<SuccessActionProcessed>,
748}
749
750#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
751pub struct LnurlWithdrawRequest {
752 pub amount_sats: u64,
755 pub withdraw_request: LnurlWithdrawRequestDetails,
756 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
760 pub completion_timeout_secs: Option<u32>,
761}
762
763#[derive(Debug, Serialize)]
764#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
765pub struct LnurlWithdrawResponse {
766 pub payment_request: String,
768 pub payment: Option<Payment>,
769}
770
771#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
773#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
774pub struct LnurlPayInfo {
775 pub ln_address: Option<String>,
776 pub comment: Option<String>,
777 pub domain: Option<String>,
778 pub metadata: Option<String>,
779 pub processed_success_action: Option<SuccessActionProcessed>,
780 pub raw_success_action: Option<SuccessAction>,
781}
782
783#[derive(Clone, Debug, Deserialize, Serialize)]
785#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
786pub struct LnurlWithdrawInfo {
787 pub withdraw_url: String,
788}
789
790impl LnurlPayInfo {
791 pub fn extract_description(&self) -> Option<String> {
792 let Some(metadata) = &self.metadata else {
793 return None;
794 };
795
796 let Ok(metadata) = serde_json::from_str::<Vec<Vec<Value>>>(metadata) else {
797 return None;
798 };
799
800 for arr in metadata {
801 if arr.len() != 2 {
802 continue;
803 }
804 if let (Some(key), Some(value)) = (arr[0].as_str(), arr[1].as_str())
805 && key == "text/plain"
806 {
807 return Some(value.to_string());
808 }
809 }
810
811 None
812 }
813}
814
815#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
816#[derive(Debug, Clone, Serialize)]
817pub enum OnchainConfirmationSpeed {
818 Fast,
819 Medium,
820 Slow,
821}
822
823#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
824pub struct PrepareSendPaymentRequest {
825 pub payment_request: String,
826 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
829 pub amount: Option<u128>,
830 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
833 pub token_identifier: Option<String>,
834}
835
836#[derive(Debug, Clone, Serialize)]
837#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
838pub struct PrepareSendPaymentResponse {
839 pub payment_method: SendPaymentMethod,
840 pub amount: u128,
843 pub token_identifier: Option<String>,
846}
847
848#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
849pub enum SendPaymentOptions {
850 BitcoinAddress {
851 confirmation_speed: OnchainConfirmationSpeed,
852 },
853 Bolt11Invoice {
854 prefer_spark: bool,
855
856 completion_timeout_secs: Option<u32>,
859 },
860 SparkAddress {
861 htlc_options: Option<SparkHtlcOptions>,
864 },
865}
866
867#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
868pub struct SparkHtlcOptions {
869 pub payment_hash: String,
871 pub expiry_duration_secs: u64,
874}
875
876#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
877pub struct SendPaymentRequest {
878 pub prepare_response: PrepareSendPaymentResponse,
879 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
880 pub options: Option<SendPaymentOptions>,
881 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
886 pub idempotency_key: Option<String>,
887}
888
889#[derive(Debug, Clone, Serialize)]
890#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
891pub struct SendPaymentResponse {
892 pub payment: Payment,
893}
894
895#[derive(Debug, Clone, Default)]
897#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
898pub struct ListPaymentsRequest {
899 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
900 pub type_filter: Option<Vec<PaymentType>>,
901 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
902 pub status_filter: Option<Vec<PaymentStatus>>,
903 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
904 pub asset_filter: Option<AssetFilter>,
905 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
907 pub spark_htlc_status_filter: Option<Vec<SparkHtlcStatus>>,
908 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
910 pub from_timestamp: Option<u64>,
911 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
913 pub to_timestamp: Option<u64>,
914 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
916 pub offset: Option<u32>,
917 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
919 pub limit: Option<u32>,
920 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
921 pub sort_ascending: Option<bool>,
922}
923
924#[derive(Debug, Clone)]
926#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
927pub enum AssetFilter {
928 Bitcoin,
929 Token {
930 token_identifier: Option<String>,
932 },
933}
934
935impl FromStr for AssetFilter {
936 type Err = String;
937
938 fn from_str(s: &str) -> Result<Self, Self::Err> {
939 Ok(match s.to_lowercase().as_str() {
940 "bitcoin" => AssetFilter::Bitcoin,
941 "token" => AssetFilter::Token {
942 token_identifier: None,
943 },
944 str if str.starts_with("token:") => AssetFilter::Token {
945 token_identifier: Some(
946 str.split_once(':')
947 .ok_or(format!("Invalid asset filter '{s}'"))?
948 .1
949 .to_string(),
950 ),
951 },
952 _ => return Err(format!("Invalid asset filter '{s}'")),
953 })
954 }
955}
956
957#[derive(Debug, Clone, Serialize)]
959#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
960pub struct ListPaymentsResponse {
961 pub payments: Vec<Payment>,
963}
964
965#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
966pub struct GetPaymentRequest {
967 pub payment_id: String,
968}
969
970#[derive(Debug, Clone, Serialize)]
971#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
972pub struct GetPaymentResponse {
973 pub payment: Payment,
974}
975
976#[cfg_attr(feature = "uniffi", uniffi::export(callback_interface))]
977pub trait Logger: Send + Sync {
978 fn log(&self, l: LogEntry);
979}
980
981#[derive(Debug, Clone, Serialize)]
982#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
983pub struct LogEntry {
984 pub line: String,
985 pub level: String,
986}
987
988#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
989#[derive(Debug, Clone, Serialize, Deserialize)]
990pub struct CheckLightningAddressRequest {
991 pub username: String,
992}
993
994#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
995#[derive(Debug, Clone, Serialize, Deserialize)]
996pub struct RegisterLightningAddressRequest {
997 pub username: String,
998 #[cfg_attr(feature = "uniffi", uniffi(default=None))]
999 pub description: Option<String>,
1000}
1001
1002#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1003#[derive(Deserialize, Serialize)]
1004pub struct LightningAddressInfo {
1005 pub description: String,
1006 pub lightning_address: String,
1007 pub lnurl: String,
1008 pub username: String,
1009}
1010
1011impl From<RecoverLnurlPayResponse> for LightningAddressInfo {
1012 fn from(resp: RecoverLnurlPayResponse) -> Self {
1013 Self {
1014 description: resp.description,
1015 lightning_address: resp.lightning_address,
1016 lnurl: resp.lnurl,
1017 username: resp.username,
1018 }
1019 }
1020}
1021
1022#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
1023#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
1024pub enum KeySetType {
1025 #[default]
1026 Default,
1027 Taproot,
1028 NativeSegwit,
1029 WrappedSegwit,
1030 Legacy,
1031}
1032
1033impl From<spark_wallet::KeySetType> for KeySetType {
1034 fn from(value: spark_wallet::KeySetType) -> Self {
1035 match value {
1036 spark_wallet::KeySetType::Default => KeySetType::Default,
1037 spark_wallet::KeySetType::Taproot => KeySetType::Taproot,
1038 spark_wallet::KeySetType::NativeSegwit => KeySetType::NativeSegwit,
1039 spark_wallet::KeySetType::WrappedSegwit => KeySetType::WrappedSegwit,
1040 spark_wallet::KeySetType::Legacy => KeySetType::Legacy,
1041 }
1042 }
1043}
1044
1045impl From<KeySetType> for spark_wallet::KeySetType {
1046 fn from(value: KeySetType) -> Self {
1047 match value {
1048 KeySetType::Default => spark_wallet::KeySetType::Default,
1049 KeySetType::Taproot => spark_wallet::KeySetType::Taproot,
1050 KeySetType::NativeSegwit => spark_wallet::KeySetType::NativeSegwit,
1051 KeySetType::WrappedSegwit => spark_wallet::KeySetType::WrappedSegwit,
1052 KeySetType::Legacy => spark_wallet::KeySetType::Legacy,
1053 }
1054 }
1055}
1056
1057#[derive(Debug, Clone, Serialize)]
1059#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1060pub struct ListFiatCurrenciesResponse {
1061 pub currencies: Vec<FiatCurrency>,
1063}
1064
1065#[derive(Debug, Clone, Serialize)]
1067#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1068pub struct ListFiatRatesResponse {
1069 pub rates: Vec<Rate>,
1071}
1072
1073pub(crate) enum WaitForPaymentIdentifier {
1074 PaymentId(String),
1075 PaymentRequest(String),
1076}
1077
1078#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1079pub struct GetTokensMetadataRequest {
1080 pub token_identifiers: Vec<String>,
1081}
1082
1083#[derive(Debug, Clone, Serialize)]
1084#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1085pub struct GetTokensMetadataResponse {
1086 pub tokens_metadata: Vec<TokenMetadata>,
1087}
1088
1089#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1090pub struct SignMessageRequest {
1091 pub message: String,
1092 pub compact: bool,
1094}
1095
1096#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1097pub struct SignMessageResponse {
1098 pub pubkey: String,
1099 pub signature: String,
1101}
1102
1103#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1104pub struct CheckMessageRequest {
1105 pub message: String,
1107 pub pubkey: String,
1109 pub signature: String,
1111}
1112
1113#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1114pub struct CheckMessageResponse {
1115 pub is_valid: bool,
1116}
1117
1118#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1119#[derive(Debug, Clone, Serialize)]
1120pub struct UserSettings {
1121 pub spark_private_mode_enabled: bool,
1122}
1123
1124#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1125pub struct UpdateUserSettingsRequest {
1126 pub spark_private_mode_enabled: Option<bool>,
1127}
1128
1129#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1130pub struct ClaimHtlcPaymentRequest {
1131 pub preimage: String,
1132}
1133
1134#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1135pub struct ClaimHtlcPaymentResponse {
1136 pub payment: Payment,
1137}
1138
1139#[derive(Debug, Clone, Deserialize, Serialize)]
1140#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
1141pub struct LnurlReceiveMetadata {
1142 pub nostr_zap_request: Option<String>,
1143 pub nostr_zap_receipt: Option<String>,
1144 pub sender_comment: Option<String>,
1145}