Skip to main content

breez_sdk_spark/chain/
mod.rs

1use std::sync::Arc;
2
3use platform_utils::{DefaultHttpClient, HttpClient};
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7use crate::{
8    Credentials, Network,
9    chain::rest_client::{BasicAuth, ChainApiType, RestClientChainService},
10};
11
12pub mod rest_client;
13
14#[derive(Debug, Error, Clone)]
15#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
16pub enum ChainServiceError {
17    #[error("Invalid address: {0}")]
18    InvalidAddress(String),
19    #[error("Service connectivity: {0}")]
20    ServiceConnectivity(String),
21    #[error("Generic: {0}")]
22    Generic(String),
23}
24
25impl From<platform_utils::HttpError> for ChainServiceError {
26    fn from(value: platform_utils::HttpError) -> Self {
27        ChainServiceError::ServiceConnectivity(value.to_string())
28    }
29}
30
31impl From<bitcoin::address::ParseError> for ChainServiceError {
32    fn from(value: bitcoin::address::ParseError) -> Self {
33        ChainServiceError::InvalidAddress(value.to_string())
34    }
35}
36
37#[cfg_attr(feature = "uniffi", uniffi::export(with_foreign))]
38#[macros::async_trait]
39pub trait BitcoinChainService: Send + Sync {
40    async fn get_address_utxos(&self, address: String) -> Result<Vec<Utxo>, ChainServiceError>;
41    async fn get_transaction_status(&self, txid: String) -> Result<TxStatus, ChainServiceError>;
42    async fn get_transaction_hex(&self, txid: String) -> Result<String, ChainServiceError>;
43    async fn broadcast_transaction(&self, tx: String) -> Result<(), ChainServiceError>;
44    async fn recommended_fees(&self) -> Result<RecommendedFees, ChainServiceError>;
45}
46
47#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
48#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
49pub struct TxStatus {
50    pub confirmed: bool,
51    pub block_height: Option<u32>,
52    pub block_time: Option<u64>,
53}
54
55#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
56#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
57pub struct Utxo {
58    pub txid: String,
59    pub vout: u32,
60    pub value: u64,
61    pub status: TxStatus,
62}
63
64#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
65#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
66pub struct RecommendedFees {
67    pub fastest_fee: u64,
68    pub half_hour_fee: u64,
69    pub hour_fee: u64,
70    pub economy_fee: u64,
71    pub minimum_fee: u64,
72}
73
74/// Constructs a shareable REST-based [`BitcoinChainService`].
75///
76/// Pass the returned `Arc` to multiple [`SdkBuilder`](crate::SdkBuilder)s via
77/// [`SdkBuilder::with_chain_service`](crate::SdkBuilder::with_chain_service)
78/// to reuse a single underlying HTTP client (and its connection pool) across
79/// SDK instances. All SDKs sharing the service must use the same `network`.
80///
81/// For one-off, non-shared use, prefer
82/// [`SdkBuilder::with_rest_chain_service`](crate::SdkBuilder::with_rest_chain_service).
83#[cfg_attr(feature = "uniffi", uniffi::export(async_runtime = "tokio"))]
84#[must_use]
85pub async fn new_rest_chain_service(
86    url: String,
87    network: Network,
88    api_type: ChainApiType,
89    credentials: Option<Credentials>,
90) -> Arc<dyn BitcoinChainService> {
91    let http_client: Arc<dyn HttpClient> = Arc::new(DefaultHttpClient::default());
92    Arc::new(RestClientChainService::new(
93        url,
94        network,
95        5,
96        http_client,
97        credentials.map(|c| BasicAuth::new(c.username, c.password)),
98        api_type,
99    ))
100}