Skip to content

Commit d5d1c0a

Browse files
committed
Update to latest spark-sdk release
1 parent c1ae27e commit d5d1c0a

3 files changed

Lines changed: 97 additions & 33 deletions

File tree

orange-sdk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ bitcoin-payment-instructions = { workspace = true }
2828
chrono = { version = "0.4", default-features = false }
2929
rand = { version = "0.8.5", optional = true }
3030
reqwest = { version = "0.12.23", default-features = false, features = ["rustls-tls"] }
31-
breez-sdk-spark = { git = "https://github.com/breez/spark-sdk.git", rev = "1c3dd78a40ae50a88d743110a79fa4a95d93d932", default-features = false, features = ["rustls-tls"], optional = true }
31+
breez-sdk-spark = { git = "https://github.com/breez/spark-sdk.git", rev = "1f2e9995230cd582d6b4aa7d06d76b99defb635e", default-features = false, features = ["rustls-tls"], optional = true }
3232
tokio = { version = "1.0", default-features = false, features = ["rt-multi-thread", "sync"] }
3333
uuid = { version = "1.0", default-features = false, optional = true }
3434
cdk = { git = "https://github.com/benthecarman/cdk.git", rev = "39c1206a4a1dda2adc1f3e23628136ef645f6c6b", default-features = false, features = ["wallet"], optional = true }

orange-sdk/src/trusted_wallet/spark/mod.rs

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,13 @@ impl SparkWalletConfig {
7070
network,
7171
sync_interval_secs: self.sync_interval_secs,
7272
prefer_spark_over_lightning: self.prefer_spark_over_lightning,
73+
external_input_parsers: None,
74+
use_default_external_input_parsers: false,
75+
real_time_sync_server_url: None,
7376
api_key: Some(BREEZ_API_KEY.to_string()),
7477
max_deposit_claim_fee: None,
7578
lnurl_domain: None,
79+
private_enabled_default: true,
7680
})
7781
}
7882
}
@@ -91,7 +95,7 @@ impl TrustedWalletInterface for Spark {
9195
&self,
9296
) -> Pin<Box<dyn Future<Output = Result<Amount, TrustedError>> + Send + '_>> {
9397
Box::pin(async move {
94-
let info = self.spark_wallet.get_info(GetInfoRequest {}).await?;
98+
let info = self.spark_wallet.get_info(GetInfoRequest { ensure_synced: None }).await?;
9599
Amount::from_sats(info.balance_sats).map_err(|_| TrustedError::AmountError)
96100
})
97101
}
@@ -138,10 +142,7 @@ impl TrustedWalletInterface for Spark {
138142
&self,
139143
) -> Pin<Box<dyn Future<Output = Result<Vec<Payment>, TrustedError>> + Send + '_>> {
140144
Box::pin(async move {
141-
let resp = self
142-
.spark_wallet
143-
.list_payments(ListPaymentsRequest { limit: None, offset: None })
144-
.await?;
145+
let resp = self.spark_wallet.list_payments(ListPaymentsRequest::default()).await?;
145146

146147
let payments =
147148
resp.payments.into_iter().map(|p| p.try_into()).collect::<Result<_, _>>()?;
@@ -163,7 +164,8 @@ impl TrustedWalletInterface for Spark {
163164

164165
let params = PrepareSendPaymentRequest {
165166
payment_request: invoice.to_string(),
166-
amount_sats: Some(sats),
167+
amount: Some(sats.into()),
168+
token_identifier: None,
167169
};
168170
let prepare = self.spark_wallet.prepare_send_payment(params).await?;
169171
match prepare.payment_method {
@@ -194,7 +196,8 @@ impl TrustedWalletInterface for Spark {
194196

195197
let params = PrepareSendPaymentRequest {
196198
payment_request: invoice.to_string(),
197-
amount_sats: Some(sats),
199+
amount: Some(sats.into()),
200+
token_identifier: None,
198201
};
199202
let prepare = self.spark_wallet.prepare_send_payment(params).await?;
200203

@@ -218,11 +221,8 @@ impl TrustedWalletInterface for Spark {
218221
) -> Pin<Box<dyn Future<Output = Option<ReceivedLightningPayment>> + Send + '_>> {
219222
Box::pin(async move {
220223
loop {
221-
let res = self
222-
.spark_wallet
223-
.list_payments(ListPaymentsRequest { offset: None, limit: None })
224-
.await
225-
.ok()?;
224+
let res =
225+
self.spark_wallet.list_payments(ListPaymentsRequest::default()).await.ok()?;
226226

227227
let tx = res.payments.into_iter().find(|p| {
228228
if let Some(PaymentDetails::Lightning { payment_hash: ph, .. }) = &p.details {
@@ -236,7 +236,7 @@ impl TrustedWalletInterface for Spark {
236236
if tx.status == PaymentStatus::Completed {
237237
return Some(ReceivedLightningPayment {
238238
id: payment_hash,
239-
fee_paid_msat: Some(tx.fees * 1_000),
239+
fee_paid_msat: Some((tx.fees * 1_000) as u64),
240240
});
241241
}
242242

@@ -270,8 +270,8 @@ impl Spark {
270270
},
271271
};
272272

273-
let spark_store = spark_store::SparkStore(store);
274-
let builder = SdkBuilder::new(spark_config, seed, Arc::new(spark_store));
273+
let spark_store = Arc::new(spark_store::SparkStore(store));
274+
let builder = SdkBuilder::new(spark_config, seed).with_storage(spark_store);
275275

276276
let spark_wallet = Arc::new(builder.build().await.map_err(|e| {
277277
log_error!(logger, "Failed to initialize Spark wallet: {e:?}");
@@ -290,13 +290,13 @@ impl Spark {
290290
logger: Arc::clone(&logger),
291291
};
292292

293-
let listener_id = spark_wallet.add_event_listener(Box::new(listener));
294-
log_info!(logger, "Added Spark event listener with ID: {}", listener_id);
293+
let listener_id = spark_wallet.add_event_listener(Box::new(listener)).await;
294+
log_info!(logger, "Added Spark event listener with ID: {listener_id}");
295295
let w = Arc::clone(&spark_wallet);
296296
let mut shutdown_recv = shutdown_receiver.clone();
297297
runtime.spawn(async move {
298298
let _ = shutdown_recv.changed().await;
299-
w.remove_event_listener(&listener_id);
299+
w.remove_event_listener(&listener_id).await;
300300
});
301301

302302
log_info!(logger, "Spark wallet initialized");
@@ -318,19 +318,26 @@ struct SparkEventHandler {
318318
logger: Arc<Logger>,
319319
}
320320

321+
#[async_trait::async_trait]
321322
impl EventListener for SparkEventHandler {
322-
fn on_event(&self, event: SdkEvent) {
323+
async fn on_event(&self, event: SdkEvent) {
323324
match event {
324325
SdkEvent::Synced => {
325326
log_debug!(self.logger, "Spark wallet synced");
326327
},
327-
SdkEvent::ClaimDepositsFailed { unclaimed_deposits } => {
328+
SdkEvent::DataSynced { did_pull_new_records } => {
329+
log_debug!(
330+
self.logger,
331+
"Spark wallet data synced, did_pull_new_records: {did_pull_new_records}"
332+
);
333+
},
334+
SdkEvent::UnclaimedDeposits { unclaimed_deposits } => {
328335
log_warn!(
329336
self.logger,
330337
"Spark wallet failed to claim deposits! {unclaimed_deposits:?}"
331338
);
332339
},
333-
SdkEvent::ClaimDepositsSucceeded { claimed_deposits } => {
340+
SdkEvent::ClaimedDeposits { claimed_deposits } => {
334341
log_info!(self.logger, "Spark wallet claimed deposits! {claimed_deposits:?}");
335342
},
336343
SdkEvent::PaymentSucceeded { payment } => {
@@ -343,6 +350,12 @@ impl EventListener for SparkEventHandler {
343350
log_error!(self.logger, "Failed to handle payment succeeded: {e:?}");
344351
}
345352
},
353+
SdkEvent::PaymentPending { payment } => {
354+
log_debug!(
355+
self.logger,
356+
"Spark payment pending event received for payment: {payment:?}"
357+
);
358+
},
346359
}
347360
}
348361
}
@@ -400,7 +413,7 @@ impl SparkEventHandler {
400413
payment_id,
401414
payment_hash: PaymentHash(payment_hash),
402415
payment_preimage: PaymentPreimage(preimage),
403-
fee_paid_msat: Some(payment.fees * 1_000), // convert to msats
416+
fee_paid_msat: Some((payment.fees * 1_000) as u64), // convert to msats
404417
})?;
405418

406419
self.payment_success_sender.send(()).unwrap();
@@ -421,13 +434,13 @@ impl SparkEventHandler {
421434
let lsp_fee_msats = if payment.fees == 0 {
422435
None
423436
} else {
424-
Some(payment.fees * 1_000) // convert to msats
437+
Some((payment.fees * 1_000) as u64) // convert to msats
425438
};
426439

427440
self.event_queue.add_event(Event::PaymentReceived {
428441
payment_id: PaymentId::Trusted(id),
429442
payment_hash: PaymentHash(payment_hash),
430-
amount_msat: payment.amount * 1_000, // convert to msats
443+
amount_msat: (payment.amount * 1_000) as u64, // convert to msats
431444
custom_records: vec![],
432445
lsp_fee_msats,
433446
})?;
@@ -537,8 +550,9 @@ impl TryFrom<breez_sdk_spark::Payment> for Payment {
537550

538551
Ok(Payment {
539552
id,
540-
amount: Amount::from_sats(value.amount).map_err(|_| TrustedError::AmountError)?,
541-
fee: Amount::from_sats(value.fees).map_err(|_| TrustedError::AmountError)?,
553+
amount: Amount::from_sats(value.amount as u64)
554+
.map_err(|_| TrustedError::AmountError)?,
555+
fee: Amount::from_sats(value.fees as u64).map_err(|_| TrustedError::AmountError)?,
542556
status: value.status.into(),
543557
outbound: value.payment_type == PaymentType::Send,
544558
time_since_epoch: Duration::from_secs(value.timestamp),

orange-sdk/src/trusted_wallet/spark/spark_store.rs

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ use std::sync::Arc;
44

55
use crate::{KVStore, io};
66

7-
use breez_sdk_spark::{DepositInfo, PaymentMetadata, StorageError, UpdateDepositPayload};
7+
use breez_sdk_spark::{
8+
DepositInfo, ListPaymentsRequest, Payment, PaymentDetails, PaymentMetadata, StorageError,
9+
UpdateDepositPayload,
10+
};
11+
use ldk_node::lightning::util::persist::KVSTORE_NAMESPACE_KEY_MAX_LEN;
812

913
const SPARK_PRIMARY_NAMESPACE: &str = "spark";
1014
const SPARK_CACHE_NAMESPACE: &str = "cache";
@@ -14,16 +18,27 @@ const SPARK_DEPOSITS_NAMESPACE: &str = "deposit";
1418
#[derive(Clone)]
1519
pub(crate) struct SparkStore(pub(crate) Arc<dyn KVStore + Send + Sync>);
1620

21+
/// The Spark sdk can produce keys that are too long, we just truncate them here
22+
fn sanitize_key(key: String) -> String {
23+
if key.len() > KVSTORE_NAMESPACE_KEY_MAX_LEN {
24+
key[..KVSTORE_NAMESPACE_KEY_MAX_LEN].to_string()
25+
} else {
26+
key
27+
}
28+
}
29+
1730
#[async_trait::async_trait]
1831
impl breez_sdk_spark::Storage for SparkStore {
1932
async fn delete_cached_item(&self, key: String) -> Result<(), StorageError> {
33+
let key = sanitize_key(key);
2034
self.0
2135
.remove(SPARK_PRIMARY_NAMESPACE, SPARK_CACHE_NAMESPACE, &key, false)
2236
.map_err(|e| StorageError::Implementation(format!("{e:?}")))?;
2337
Ok(())
2438
}
2539

2640
async fn get_cached_item(&self, key: String) -> Result<Option<String>, StorageError> {
41+
let key = sanitize_key(key);
2742
match self.0.read(SPARK_PRIMARY_NAMESPACE, SPARK_CACHE_NAMESPACE, &key) {
2843
Ok(bytes) => Ok(Some(String::from_utf8(bytes).map_err(|e| {
2944
StorageError::Serialization(format!("Invalid UTF-8 in cached item: {e:?}"))
@@ -39,14 +54,15 @@ impl breez_sdk_spark::Storage for SparkStore {
3954
}
4055

4156
async fn set_cached_item(&self, key: String, value: String) -> Result<(), StorageError> {
57+
let key = sanitize_key(key);
4258
self.0
4359
.write(SPARK_PRIMARY_NAMESPACE, SPARK_CACHE_NAMESPACE, &key, value.as_bytes())
4460
.map_err(|e| StorageError::Implementation(format!("{e:?}")))?;
4561
Ok(())
4662
}
4763

4864
async fn list_payments(
49-
&self, offset: Option<u32>, limit: Option<u32>,
65+
&self, request: ListPaymentsRequest,
5066
) -> Result<Vec<breez_sdk_spark::Payment>, StorageError> {
5167
let keys = self
5268
.0
@@ -64,12 +80,17 @@ impl breez_sdk_spark::Storage for SparkStore {
6480
.map_err(|e| StorageError::Serialization(format!("{e:?}")))?;
6581
payments.push(payment);
6682
}
67-
// sort
68-
payments.sort_by_key(|p| p.timestamp);
83+
84+
let sort_ascending = request.sort_ascending.unwrap_or(false);
85+
if sort_ascending {
86+
payments.sort_by_key(|p| p.timestamp);
87+
} else {
88+
payments.sort_by_key(|p| std::cmp::Reverse(p.timestamp));
89+
}
6990

7091
// apply offset and limit
71-
let start = offset.unwrap_or(0) as usize;
72-
let end = if let Some(l) = limit {
92+
let start = request.offset.unwrap_or(0) as usize;
93+
let end = if let Some(l) = request.limit {
7394
(start + l as usize).min(payments.len())
7495
} else {
7596
payments.len()
@@ -110,6 +131,35 @@ impl breez_sdk_spark::Storage for SparkStore {
110131
Ok(payment)
111132
}
112133

134+
async fn get_payment_by_invoice(
135+
&self, invoice: String,
136+
) -> Result<Option<Payment>, StorageError> {
137+
let payments = self.list_payments(ListPaymentsRequest::default()).await?;
138+
139+
let p = payments.into_iter().find(|p| {
140+
if let Some(details) = p.details.as_ref() {
141+
match details {
142+
PaymentDetails::Spark { invoice_details } => {
143+
if invoice_details.as_ref().is_some_and(|i| i.invoice == invoice) {
144+
return true;
145+
}
146+
},
147+
PaymentDetails::Token { .. } => {},
148+
PaymentDetails::Lightning { invoice: inv, .. } => {
149+
if *inv == invoice {
150+
return true;
151+
}
152+
},
153+
PaymentDetails::Withdraw { .. } => {},
154+
PaymentDetails::Deposit { .. } => {},
155+
}
156+
}
157+
false
158+
});
159+
160+
Ok(p)
161+
}
162+
113163
async fn add_deposit(
114164
&self, txid: String, vout: u32, amount_sats: u64,
115165
) -> Result<(), StorageError> {

0 commit comments

Comments
 (0)