|
1 | 1 | //! An implementation of `TrustedWalletInterface` using the Spark SDK. |
2 | | -use crate::bitcoin::hashes::{Hash, sha256}; |
3 | 2 | use crate::bitcoin::hex::FromHex; |
4 | 3 | use crate::bitcoin::{Network, io}; |
5 | 4 | use crate::logging::Logger; |
6 | 5 | use crate::store::{PaymentId, TxMetadataStore, TxStatus}; |
7 | 6 | use crate::trusted_wallet::{Payment, TrustedError, TrustedWalletInterface}; |
8 | | -use crate::{Event, EventQueue, InitFailure, Mnemonic, Seed, WalletConfig}; |
| 7 | +use crate::{Event, EventQueue, InitFailure, Seed, WalletConfig}; |
9 | 8 |
|
10 | 9 | use ldk_node::lightning::util::logger::Logger as _; |
11 | 10 | use ldk_node::lightning::util::persist::KVStore; |
@@ -139,20 +138,8 @@ impl TrustedWalletInterface for Spark { |
139 | 138 | .list_payments(ListPaymentsRequest { limit: None, offset: None }) |
140 | 139 | .await?; |
141 | 140 |
|
142 | | - let payments = resp |
143 | | - .payments |
144 | | - .into_iter() |
145 | | - .map(|p| { |
146 | | - parse_payment_id(&p.id).map(|id| Payment { |
147 | | - id, |
148 | | - amount: Amount::from_sats(p.amount).unwrap(), |
149 | | - fee: Amount::from_sats(p.fees).unwrap(), |
150 | | - status: p.status.into(), |
151 | | - outbound: p.payment_type == PaymentType::Send, |
152 | | - time_since_epoch: Duration::from_secs(p.timestamp), |
153 | | - }) |
154 | | - }) |
155 | | - .collect::<Result<_, _>>()?; |
| 141 | + let payments = |
| 142 | + resp.payments.into_iter().map(|p| p.try_into()).collect::<Result<_, _>>()?; |
156 | 143 |
|
157 | 144 | Ok(payments) |
158 | 145 | }) |
@@ -238,18 +225,16 @@ impl Spark { |
238 | 225 | ) -> Result<Self, InitFailure> { |
239 | 226 | let spark_config: breez_sdk_spark::Config = spark_config.to_breez_config(config.network)?; |
240 | 227 |
|
241 | | - let (mnemonic, passphrase) = match &config.seed { |
242 | | - Seed::Seed64(bytes) => { |
243 | | - // max entropy for bip39 is 32 bytes, so we hash the 64 bytes down to 32 |
244 | | - let hash = sha256::Hash::hash(bytes); |
245 | | - let mnemonic = Mnemonic::from_entropy(hash.as_byte_array()).expect("valid length"); |
246 | | - (mnemonic.to_string(), None) |
| 228 | + let seed = match &config.seed { |
| 229 | + Seed::Seed64(bytes) => breez_sdk_spark::Seed::Entropy(bytes.to_vec()), |
| 230 | + Seed::Mnemonic { mnemonic, passphrase } => breez_sdk_spark::Seed::Mnemonic { |
| 231 | + mnemonic: mnemonic.to_string(), |
| 232 | + passphrase: passphrase.clone(), |
247 | 233 | }, |
248 | | - Seed::Mnemonic { mnemonic, passphrase } => (mnemonic.to_string(), passphrase.clone()), |
249 | 234 | }; |
250 | 235 |
|
251 | 236 | let spark_store = SparkStore(store); |
252 | | - let builder = SdkBuilder::new(spark_config, mnemonic, passphrase, Arc::new(spark_store)); |
| 237 | + let builder = SdkBuilder::new(spark_config, seed, Arc::new(spark_store)); |
253 | 238 |
|
254 | 239 | let spark_wallet = Arc::new(builder.build().await.map_err(|e| { |
255 | 240 | log_error!(logger, "Failed to initialize Spark wallet: {e:?}"); |
@@ -307,6 +292,11 @@ impl EventListener for SparkEventHandler { |
307 | 292 | log_error!(self.logger, "Failed to handle payment succeeded: {e:?}"); |
308 | 293 | } |
309 | 294 | }, |
| 295 | + SdkEvent::PaymentFailed { payment } => { |
| 296 | + if let Err(e) = self.handle_payment_failed(payment) { |
| 297 | + log_error!(self.logger, "Failed to handle payment succeeded: {e:?}"); |
| 298 | + } |
| 299 | + }, |
310 | 300 | } |
311 | 301 | } |
312 | 302 | } |
@@ -383,6 +373,36 @@ impl SparkEventHandler { |
383 | 373 |
|
384 | 374 | Ok(()) |
385 | 375 | } |
| 376 | + |
| 377 | + fn handle_payment_failed(&self, payment: breez_sdk_spark::Payment) -> Result<(), TrustedError> { |
| 378 | + log_info!(self.logger, "Spark payment failed: {payment:?}"); |
| 379 | + |
| 380 | + let id = parse_payment_id(&payment.id)?; |
| 381 | + |
| 382 | + match payment.payment_type { |
| 383 | + PaymentType::Send => match payment.details { |
| 384 | + Some(PaymentDetails::Lightning { payment_hash, .. }) => { |
| 385 | + let payment_hash: [u8; 32] = FromHex::from_hex(&payment_hash).map_err(|e| { |
| 386 | + TrustedError::Other(format!("Invalid payment_hash hex: {e:?}")) |
| 387 | + })?; |
| 388 | + |
| 389 | + self.event_queue.add_event(Event::PaymentFailed { |
| 390 | + payment_id: PaymentId::Trusted(id), |
| 391 | + payment_hash: Some(PaymentHash(payment_hash)), |
| 392 | + reason: None, |
| 393 | + })?; |
| 394 | + }, |
| 395 | + _ => { |
| 396 | + log_debug!(self.logger, "Unsupported payment details for Send: {payment:?}") |
| 397 | + }, |
| 398 | + }, |
| 399 | + PaymentType::Receive => { |
| 400 | + log_debug!(self.logger, "Receive payments cannot fail: {payment:?}"); |
| 401 | + }, |
| 402 | + } |
| 403 | + |
| 404 | + Ok(()) |
| 405 | + } |
386 | 406 | } |
387 | 407 |
|
388 | 408 | fn parse_payment_id(id: &str) -> Result<[u8; 32], TrustedError> { |
@@ -614,3 +634,20 @@ impl breez_sdk_spark::Storage for SparkStore { |
614 | 634 | Ok(()) |
615 | 635 | } |
616 | 636 | } |
| 637 | + |
| 638 | +impl TryFrom<breez_sdk_spark::Payment> for Payment { |
| 639 | + type Error = TrustedError; |
| 640 | + |
| 641 | + fn try_from(value: breez_sdk_spark::Payment) -> Result<Self, Self::Error> { |
| 642 | + let id = parse_payment_id(&value.id)?; |
| 643 | + |
| 644 | + Ok(Payment { |
| 645 | + id, |
| 646 | + amount: Amount::from_sats(value.amount).map_err(|_| TrustedError::AmountError)?, |
| 647 | + fee: Amount::from_sats(value.fees).map_err(|_| TrustedError::AmountError)?, |
| 648 | + status: value.status.into(), |
| 649 | + outbound: value.payment_type == PaymentType::Send, |
| 650 | + time_since_epoch: Duration::from_secs(value.timestamp), |
| 651 | + }) |
| 652 | + } |
| 653 | +} |
0 commit comments