spark_sdk/wallet/handlers/init.rs
1use std::sync::Arc;
2
3use crate::{
4 error::SparkSdkError,
5 signer::traits::SparkSigner,
6 wallet::{
7 config::WalletConfig,
8 internal_handlers::traits::{
9 authenticate::AuthenticateInternalHandlers, leaves::LeavesInternalHandlers,
10 },
11 leaf_manager::LeafManager,
12 },
13 SparkNetwork, SparkSdk,
14};
15
16impl<S: SparkSigner + Send + Sync + Clone + 'static> SparkSdk<S> {
17 /// Creates a new instance of the Spark SDK.
18 ///
19 /// This is the main entry point for interacting with the Spark protocol. It initializes the SDK with
20 /// the provided network configuration, signer implementation, and optional data storage path.
21 ///
22 /// # Arguments
23 ///
24 /// * `network` - The Spark network to connect to (e.g. Regtest or Mainnet)
25 /// * `signer` - Implementation of the SparkSigner trait wrapped in Arc<RwLock> for thread-safe access
26 /// * `data_path` - Optional path to store wallet data. If None, defaults to WALLET_DB_PATH
27 ///
28 /// # Returns
29 ///
30 /// Returns a Result containing either:
31 /// * The initialized SparkSdk instance
32 /// * A SparkSdkError if initialization fails
33 ///
34 /// # Examples
35 ///
36 /// ```no_run
37 /// use spark_wallet_sdk::{SparkSdk, SparkNetwork, DefaultSigner};
38 /// use std::sync::Arc;
39 /// use parking_lot::RwLock;
40 ///
41 /// async fn init_sdk() {
42 /// let signer = Arc::new(RwLock::new(DefaultSigner::new().unwrap()));
43 /// let sdk = SparkSdk::new(
44 /// SparkNetwork::Regtest,
45 /// signer,
46 /// None
47 /// ).await.unwrap();
48 /// }
49 /// ```
50 pub async fn new(network: SparkNetwork, signer: Arc<S>) -> Result<Self, SparkSdkError> {
51 let config = WalletConfig::new(network).await?;
52 let leaf_manager = Arc::new(LeafManager::new());
53 let session = Arc::new(parking_lot::RwLock::new(Vec::new()));
54
55 let sdk = Self {
56 config,
57 identity_public_key: Arc::new(signer.get_identity_public_key()?),
58 signer: signer.clone(),
59 leaf_manager,
60 session,
61 };
62
63 let sessions = sdk.authenticate().await?;
64 let mut write = sdk.session.write();
65 *write = sessions;
66 drop(write);
67
68 let sdk_clone = sdk.clone();
69
70 // refresh BTC leaves
71 sdk_clone.fetch_owned_leaves_from_spark().await?;
72
73 // refresh tokens
74
75 // make a background job to claim deposits
76 tokio::spawn(async move {
77 let mut interval = tokio::time::interval(std::time::Duration::from_secs(10));
78 loop {
79 interval.tick().await;
80 let claimed_deposits = sdk_clone.claim_deposits().await;
81 // // TODO: add a log
82 // if !claimed_deposits.is_ok() {
83 // let error = claimed_deposits.err().unwrap();
84 // println!(
85 // "[Claim Deposit Background Job]: Failed to claim deposits: {}",
86 // error
87 // );
88 // } else {
89 // println!(
90 // "[Claim Deposit Background Job]: Claimed pending deposits successfully. If there was no pending deposits, did not claim anything."
91 // );
92 // }
93 }
94 });
95
96 // make a background job to claim transfers
97 let sdk_clone = sdk.clone();
98 tokio::spawn(async move {
99 let mut interval = tokio::time::interval(std::time::Duration::from_secs(10));
100 loop {
101 interval.tick().await;
102 let claimed_transfers = sdk_clone.claim_transfers().await;
103 if !claimed_transfers.is_ok() {
104 println!(
105 "[Claim Transfer Background Job] Failed to claim transfers: {}",
106 claimed_transfers.err().unwrap()
107 );
108 } else {
109 println!(
110 "[Claim Transfer Background Job] Claimed pending transfers successfully. If there was no pending transfers, did not claim anything."
111 );
112 }
113 }
114 });
115
116 Ok(sdk)
117 }
118
119 /// Returns the identity public key of the wallet.
120 ///
121 /// The identity public key is a 33-byte compressed secp256k1 public key that uniquely identifies
122 /// this wallet instance. It is used for authentication and authorization with Spark operators.
123 /// This key is generated when the wallet is first created and remains constant throughout the
124 /// wallet's lifetime.
125 ///
126 /// The identity public key serves several purposes:
127 /// - Authenticates the wallet with Spark operators during API calls
128 /// - Used in deposit address generation to prove ownership
129 /// - Required for validating operator signatures
130 /// - Helps prevent unauthorized access to wallet funds
131 ///
132 /// # Returns
133 /// A byte slice containing the 33-byte compressed secp256k1 public key in SEC format.
134 /// The first byte is either 0x02 or 0x03 (the parity), followed by the 32-byte X coordinate.
135 ///
136 /// # Examples
137 /// ```no_run
138 /// # use spark_wallet_sdk::{SparkSdk, SparkNetwork, DefaultSigner};
139 /// # use std::sync::Arc;
140 /// # use parking_lot::RwLock;
141 /// # async fn example() {
142 /// let signer = Arc::new(RwLock::new(DefaultSigner::new().unwrap()));
143 /// let sdk = SparkSdk::new(SparkNetwork::Regtest, signer, None).await.unwrap();
144 ///
145 /// let pubkey = sdk.get_identity_public_key();
146 /// assert_eq!(pubkey.len(), 33);
147 /// # }
148 /// ```
149 pub fn get_identity_public_key(&self) -> &[u8] {
150 &self.identity_public_key
151 }
152
153 /// Returns the Bitcoin network that this wallet is connected to.
154 ///
155 /// The network determines which Spark operators the wallet communicates with and which Bitcoin network
156 /// (mainnet or regtest) is used for transactions.
157 ///
158 /// # Network Types
159 /// - [`SparkNetwork::Mainnet`] - Production Bitcoin mainnet environment
160 /// - [`SparkNetwork::Regtest`] - Testing environment using Lightspark's regtest network
161 ///
162 /// The network is set when creating the wallet and cannot be changed after initialization.
163 /// All transactions and addresses will be created for the configured network.
164 ///
165 /// # Returns
166 /// Returns a [`SparkNetwork`] enum indicating whether this is a mainnet or regtest wallet.
167 ///
168 /// # Examples
169 /// ```no_run
170 /// # use spark_wallet_sdk::{SparkSdk, SparkNetwork, DefaultSigner};
171 /// # use std::sync::Arc;
172 /// # use parking_lot::RwLock;
173 /// # async fn example() {
174 /// let signer = Arc::new(RwLock::new(DefaultSigner::new().unwrap()));
175 /// let sdk = SparkSdk::new(SparkNetwork::Regtest, signer, None).await.unwrap();
176 ///
177 /// assert_eq!(sdk.get_network(), SparkNetwork::Regtest);
178 /// # }
179 /// ```
180 pub fn get_network(&self) -> SparkNetwork {
181 self.config.spark_config.network
182 }
183}