spark_rust/wallet/handlers/init.rs
1use std::sync::Arc;
2
3use bitcoin::secp256k1::PublicKey;
4
5use crate::{
6 error::SparkSdkError,
7 signer::traits::SparkSigner,
8 wallet::{
9 config::WalletConfig,
10 internal_handlers::traits::{
11 authenticate::AuthenticateInternalHandlers, leaves::LeavesInternalHandlers,
12 },
13 leaf_manager::LeafManager,
14 },
15 SparkNetwork, SparkSdk,
16};
17
18impl<S: SparkSigner + Send + Sync + Clone + 'static> SparkSdk<S> {
19 /// Creates a new instance of the Spark SDK.
20 ///
21 /// This is the main entry point for interacting with the Spark protocol. It initializes the SDK with
22 /// the provided network configuration, signer implementation, and optional data storage path.
23 ///
24 /// # Arguments
25 ///
26 /// * `network` - The Spark network to connect to (e.g. Regtest or Mainnet)
27 /// * `signer` - Implementation of the SparkSigner trait wrapped in Arc for thread-safe access
28 ///
29 /// # Returns
30 ///
31 /// Returns a Result containing either:
32 /// * The initialized SparkSdk instance
33 /// * A SparkSdkError if initialization fails
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use spark_rust::{
39 /// error::SparkSdkError,
40 /// signer::default_signer::DefaultSigner,
41 /// signer::traits::SparkSigner,
42 /// SparkNetwork, SparkSdk,
43 /// };
44 ///
45 /// async fn init_sdk() {
46 /// let mnemonic = "abandon ability able about above absent absorb abstract absurd abuse access accident";
47 /// let network = SparkNetwork::Regtest;
48 /// let signer = DefaultSigner::from_mnemonic(mnemonic, network.clone()).await.unwrap();
49 /// let sdk = SparkSdk::new(
50 /// network,
51 /// signer
52 /// ).await.unwrap();
53 /// }
54 /// ```
55 #[cfg_attr(feature = "telemetry", tracing::instrument(skip_all, fields(network = ?network)))]
56 pub async fn new(network: SparkNetwork, signer: Arc<S>) -> Result<Self, SparkSdkError> {
57 let config = WalletConfig::new(network).await?;
58 let leaf_manager = Arc::new(LeafManager::new());
59
60 let sdk = Self {
61 config,
62 signer: signer.clone(),
63 leaf_manager,
64 handler_lock: Arc::new(tokio::sync::Mutex::new(())),
65 };
66
67 let sessions = sdk.authenticate().await?;
68
69 {
70 let mut write = sdk.config.spark_config.sessions.write();
71 *write = sessions;
72 }
73
74 let sdk_clone = sdk.clone();
75
76 // refresh BTC leaves
77 sdk_clone.sync_leaves().await?;
78
79 Ok(sdk)
80 }
81
82 /// Returns the Spark address of the wallet, which is the identity public key.
83 ///
84 /// The Spark address is derived from the identity public key of the wallet.
85 /// This key is generated when the wallet is first created and remains constant throughout the
86 /// wallet's lifetime.
87 ///
88 /// The Spark address serves several purposes:
89 /// - Authenticates the wallet with Spark operators during API calls
90 /// - Used in deposit address generation to prove ownership
91 /// - Required for validating operator signatures
92 /// - Helps prevent unauthorized access to wallet funds
93 ///
94 /// # Returns
95 /// A byte slice containing the 33-byte compressed secp256k1 public key in SEC format.
96 /// The first byte is either 0x02 or 0x03 (the parity), followed by the 32-byte X coordinate.
97 ///
98 /// # Examples
99 /// ```
100 /// # use spark_rust::{SparkSdk, SparkNetwork, signer::default_signer::DefaultSigner, signer::traits::SparkSigner};
101 ///
102 /// # async fn example() {
103 /// let network = SparkNetwork::Regtest;
104 /// let mnemonic = "abandon ability able about above absent absorb abstract absurd abuse access accident";
105 /// let signer = DefaultSigner::from_mnemonic(mnemonic, network.clone()).await.unwrap();
106 /// let sdk = SparkSdk::new(network, signer).await.unwrap();
107 ///
108 /// // Spark address is the identity public key of the user. This is derived using Spark's custom derivation path explained in the docs.
109 /// let spark_address = sdk.get_spark_address().unwrap();
110 ///
111 /// // Currently, a user's Spark address is their public key.
112 /// assert_eq!(spark_address.serialize().len(), 33);
113 /// # }
114 /// ```
115 #[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
116 pub fn get_spark_address(&self) -> Result<PublicKey, SparkSdkError> {
117 let account_index = 0;
118 let network = self.config.spark_config.network.to_bitcoin_network();
119 let pubkey = self
120 .signer
121 .get_identity_public_key(account_index, network)?;
122
123 Ok(pubkey)
124 }
125
126 /// Returns the Bitcoin network that this wallet is connected to.
127 ///
128 /// The network determines which Spark operators the wallet communicates with and which Bitcoin network
129 /// (mainnet or regtest) is used for transactions.
130 ///
131 /// # Network Types
132 /// - [`SparkNetwork::Mainnet`] - Production Bitcoin mainnet environment
133 /// - [`SparkNetwork::Regtest`] - Testing environment using Lightspark's regtest network
134 ///
135 /// The network is set when creating the wallet and cannot be changed after initialization.
136 /// All transactions and addresses will be created for the configured network.
137 ///
138 /// # Returns
139 /// Returns a [`SparkNetwork`] enum indicating whether this is a mainnet or regtest wallet.
140 ///
141 /// # Examples
142 /// ```
143 /// # use spark_rust::{SparkSdk, SparkNetwork, signer::default_signer::DefaultSigner, signer::traits::SparkSigner};
144 /// # async fn example() {
145 /// let mnemonic = "abandon ability able about above absent absorb abstract absurd abuse access accident";
146 /// let network = SparkNetwork::Regtest;
147 ///
148 /// // Create a DefaultSigner that implements SparkSigner
149 /// let signer = DefaultSigner::from_mnemonic(mnemonic, network.clone()).await.unwrap();
150 /// let sdk = SparkSdk::new(network, signer).await.unwrap();
151 ///
152 /// assert_eq!(sdk.get_network(), SparkNetwork::Regtest);
153 ///
154 /// # }
155 /// ```
156 #[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
157 pub fn get_network(&self) -> SparkNetwork {
158 self.config.spark_config.network
159 }
160}