spark_rust/
lib.rs

1//! # Spark Wallet SDK
2//!
3//! A Rust implementation of the Spark protocol wallet, providing secure Bitcoin and Lightning
4//! Network operations through the Spark Service Provider (SSP).
5//!
6//! This crate forms a complete wallet with all necessary Spark utilities, built on secure
7//! cryptographic primitives from the [spark-cryptography](https://github.com/polarityorg/spark-rs/tree/main/crates/spark-cryptography) crate.
8//!
9//! ## Overview
10//!
11//! Spark is a protocol that allows secure, non-custodial Bitcoin and Lightning Network operations,
12//! with all critical cryptographic operations performed client-side while leveraging Spark Service Providers
13//! for efficient network operations. This implementation provides:
14//!
15//! - Complete Bitcoin wallet functionality
16//! - Lightning Network payments (send and receive)
17//! - Funds transfers between Spark users
18//! - Deposit and withdrawal capabilities
19//! - Comprehensive key management and signing utilities
20//!
21//! ## Architecture
22//!
23//! The Spark Wallet SDK comprises five main components:
24//!
25//! - **config**: Configuration settings for the Spark wallet
26//! - **handlers**: User-facing APIs for wallet operations
27//! - **internal_handlers**: Service handlers for signing processes and RPC communications
28//! - **rpc**: Client for establishing secure connections to Spark nodes
29//! - **signer**: Key management, storage, and signing capabilities
30//!
31//! ## Quick Start
32//!
33//! ```rust
34//! use spark_rust::SparkSdk;
35//! use spark_rust::SparkNetwork;
36//! use spark_rust::signer::default_signer::DefaultSigner;
37//! use std::time::Duration;
38//!
39//! #[tokio::main]
40//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
41//!     // Initialize the default signer with a mnemonic phrase
42//!     let mnemonic = "abandon ability able about above absent absorb abstract absurd abuse access accident";
43//!     let network = SparkNetwork::Regtest;
44//!     let default_signer = DefaultSigner::from_mnemonic(mnemonic, network).await?;
45//!     
46//!     // Create a new SDK instance
47//!     let sdk = SparkSdk::new(network, default_signer).await?;
48//!     
49//!     // Generate a deposit address
50//!     let deposit_address = sdk.generate_deposit_address().await?;
51//!     println!("Deposit address: {}", deposit_address.deposit_address);
52//!     
53//!     // Query pending transfers
54//!     let pending = sdk.query_pending_transfers().await?;
55//!     println!("You have {} pending transfers", pending.len());
56//!     
57//!     // Claim all pending transfers
58//!     sdk.claim_transfers().await?;
59//!     
60//!     // Get your wallet balance
61//!     let balance = sdk.get_bitcoin_balance();
62//!     println!("Your balance is {} satoshis", balance);
63//!     
64//!     Ok(())
65//! }
66//! ```
67//!
68//! ## Security Model
69//!
70//! Spark operates with a security model that ensures users always maintain control of their funds:
71//!
72//! - All critical keys are managed client-side
73//! - Threshold signing with FROST ensures security with multiple participants
74//! - Transactions require both user and Spark operator signatures
75//! - The user always initiates the signing process
76//!
77//! ## Fee Structure
78//!
79//! Unlike traditional Bitcoin wallets, Spark uses a service fee model where:
80//!
81//! - Fees are charged by the Spark Service Provider (SSP) for operations they perform
82//! - You don't directly pay Bitcoin mining fees (these are handled by the SSP)
83//! - Fee estimation methods help you determine costs before performing operations
84//!
85//! Common fee operations include:
86//! - Lightning payments (sending and receiving)
87//! - Leaves swaps (optimizing wallet structure)
88//! - Cooperative exits (withdrawing to on-chain Bitcoin)
89//!
90//! ## Custom Signers
91//!
92//! While the SDK provides a default in-memory signer implementation, advanced users can
93//! implement their own signers for specialized use cases by implementing the `SparkSigner`
94//! trait and its associated sub-traits.
95//!
96//! ```rust
97//! use spark_rust::signer::traits::SparkSigner;
98//! use spark_rust::SparkNetwork;
99//!
100//! // Example of using a custom signer (implementation details omitted)
101//! #[tokio::main]
102//! async fn main() {
103//!     // my_custom_signer implements the SparkSigner trait
104//!     let my_custom_signer = create_custom_signer().await.unwrap();
105//!     let sdk = SparkSdk::new(SparkNetwork::Regtest, my_custom_signer).await.unwrap();
106//!     // ...
107//! }
108//! # async fn create_custom_signer() -> Result<impl SparkSigner, Box<dyn std::error::Error>> { todo!() }
109//! ```
110
111use core::fmt;
112use std::str::FromStr;
113pub(crate) mod constants;
114pub mod error;
115pub(crate) mod wallet;
116
117pub mod signer;
118
119// pub use wallet::utils;
120pub use wallet::handlers::cooperative_exit::{CompleteCoopExitInput, RequestCoopExitInput};
121pub use wallet::SparkSdk;
122
123pub(crate) mod common_types;
124
125#[cfg(any(test, feature = "integration-tests"))]
126pub mod spark_test_utils;
127
128pub mod rpc;
129
130/// Spark Network. This is the network of the Spark Operators that the user chooses to connect to.
131///
132/// - `Mainnet` is the Bitcoin network, and all operations involve real money.
133/// - `Regtest` is Lightspark's Regtest network for testing purposes.
134#[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
135#[non_exhaustive]
136pub enum SparkNetwork {
137    /// Mainnet Bitcoin network. Use this for real transactions with actual value.
138    Mainnet,
139
140    /// Lightspark's Regtest network for testing and development.
141    /// No real value is transferred when using this network.
142    Regtest,
143}
144
145impl SparkNetwork {
146    /// Converts a Spark network to its corresponding Bitcoin network.
147    ///
148    /// # Returns
149    /// The equivalent Bitcoin network type from the `bitcoin` crate:
150    /// - `SparkNetwork::Mainnet` returns `bitcoin::Network::Bitcoin`
151    /// - `SparkNetwork::Regtest` returns `bitcoin::Network::Regtest`
152    pub fn to_bitcoin_network(&self) -> ::bitcoin::Network {
153        match self {
154            SparkNetwork::Mainnet => ::bitcoin::Network::Bitcoin,
155            SparkNetwork::Regtest => ::bitcoin::Network::Regtest,
156        }
157    }
158
159    /// Marshals the network type to its protocol buffer representation. For most use cases, you don't need to use this method.
160    ///
161    /// # Returns
162    /// An integer representing the network in the protocol buffer format.
163    pub fn marshal_proto(&self) -> i32 {
164        match self {
165            SparkNetwork::Mainnet => spark_protos::spark::Network::Mainnet as i32,
166            SparkNetwork::Regtest => spark_protos::spark::Network::Regtest as i32,
167        }
168    }
169}
170
171impl FromStr for SparkNetwork {
172    type Err = String;
173
174    /// Creates a `SparkNetwork` from a string representation.
175    ///
176    /// The string comparison is case-insensitive, so both "mainnet" and "Mainnet"
177    /// will return `SparkNetwork::Mainnet`.
178    ///
179    /// # Arguments
180    /// * `s` - A string slice representing the network ("mainnet" or "regtest")
181    ///
182    /// # Returns
183    /// * `Ok(SparkNetwork)` if the string matches a known network
184    /// * `Err(String)` with an error message if the string does not match
185    ///
186    /// # Examples
187    /// ```
188    /// use std::str::FromStr;
189    /// use spark_rust::SparkNetwork;
190    ///
191    /// let mainnet = SparkNetwork::from_str("mainnet").unwrap();
192    /// assert_eq!(mainnet, SparkNetwork::Mainnet);
193    ///
194    /// let regtest = SparkNetwork::from_str("Regtest").unwrap();
195    /// assert_eq!(regtest, SparkNetwork::Regtest);
196    ///
197    /// let err = SparkNetwork::from_str("testnet");
198    /// assert!(err.is_err());
199    /// ```
200    fn from_str(s: &str) -> Result<Self, String> {
201        match s.to_lowercase().as_str() {
202            "mainnet" => Ok(SparkNetwork::Mainnet),
203            "regtest" => Ok(SparkNetwork::Regtest),
204            _ => Err(format!("Invalid network: {}", s)),
205        }
206    }
207}
208
209impl fmt::Display for SparkNetwork {
210    /// Formats the network as a lowercase string.
211    ///
212    /// # Returns
213    /// - `"mainnet"` for `SparkNetwork::Mainnet`
214    /// - `"regtest"` for `SparkNetwork::Regtest`
215    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216        match self {
217            SparkNetwork::Mainnet => write!(f, "mainnet"),
218            SparkNetwork::Regtest => write!(f, "regtest"),
219        }
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use std::str::FromStr as _;
226
227    use crate::SparkNetwork;
228
229    #[test]
230    fn test_spark_network_display() {
231        let network = SparkNetwork::Mainnet;
232        assert_eq!(network.to_string(), "mainnet");
233
234        let network = SparkNetwork::Regtest;
235        assert_eq!(network.to_string(), "regtest");
236    }
237
238    #[test]
239    fn test_spark_network_from_str() {
240        let network = SparkNetwork::from_str("mainnet").unwrap();
241        assert_eq!(network, SparkNetwork::Mainnet);
242        let network = SparkNetwork::from_str("Mainnet").unwrap();
243        assert_eq!(network, SparkNetwork::Mainnet);
244
245        let network = SparkNetwork::from_str("regtest").unwrap();
246        assert_eq!(network, SparkNetwork::Regtest);
247        let network = SparkNetwork::from_str("Regtest").unwrap();
248        assert_eq!(network, SparkNetwork::Regtest);
249
250        let network = SparkNetwork::from_str("testnet");
251        assert!(network.is_err());
252    }
253}