From 73c3feb5697b547baa7aae9f771504bde15e8ffe Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Mon, 29 Sep 2025 18:05:27 +0200 Subject: [PATCH 01/10] patch secp globally, other temporary change to make lwk_boltz work --- Cargo.lock | 222 +++++++++++++++++++++++++++++++-- Cargo.toml | 4 +- lwk_bindings/Cargo.toml | 1 + lwk_bindings/tests/bindings.rs | 1 + lwk_boltz/Cargo.toml | 2 - 5 files changed, 214 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fe308407..7170e524b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -507,6 +518,34 @@ dependencies = [ "serde_with", ] +[[package]] +name = "boltz-client" +version = "0.3.0" +source = "git+https://github.com/SatoshiPortal/boltz-rust/?rev=153d7cd42572f13c08a75ca38e2107ab4034a36b#153d7cd42572f13c08a75ca38e2107ab4034a36b" +dependencies = [ + "async-trait", + "bip39", + "bitcoin", + "elements 0.25.2", + "env_logger 0.7.1", + "futures-util", + "getrandom 0.2.16", + "gloo-timers", + "hex", + "js-sys", + "lightning-invoice", + "log", + "macros", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite-wasm", + "url", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -1105,6 +1144,19 @@ dependencies = [ "regex", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.11.8" @@ -1414,6 +1466,18 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "goblin" version = "0.8.2" @@ -1473,6 +1537,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.5.2" @@ -1602,6 +1675,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "hyper" version = "1.7.0" @@ -1964,7 +2046,7 @@ version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi", + "hermit-abi 0.5.2", "libc", "windows-sys 0.59.0", ] @@ -2105,6 +2187,28 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "lightning-invoice" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ab9f6ea77e20e3129235e62a2e6bd64ed932363df104e864ee65ccffb54a8f" +dependencies = [ + "bech32 0.9.1", + "bitcoin", + "lightning-types", +] + +[[package]] +name = "lightning-types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1083b8d9137000edf3bfcb1ff011c0d25e0cdd2feb98cc21d6765e64a494148f" +dependencies = [ + "bech32 0.9.1", + "bitcoin", + "hex-conservative 0.2.1", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -2194,8 +2298,22 @@ dependencies = [ [[package]] name = "lwk_boltz" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329b8defa1d7b0c48c9cc98db7bbb7da6fde3b582424f6d81bf4ac3bb1f99069" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bip39", + "boltz-client", + "env_logger 0.11.8", + "log", + "lwk_common", + "lwk_signer", + "lwk_wollet", + "reqwest", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", +] [[package]] name = "lwk_cli" @@ -2206,7 +2324,7 @@ dependencies = [ "clap_complete", "ctrlc", "elements 0.25.2", - "env_logger", + "env_logger 0.11.8", "log", "lwk_app", "lwk_containers", @@ -2278,7 +2396,7 @@ version = "0.12.0" dependencies = [ "byteorder", "elements-miniscript", - "env_logger", + "env_logger 0.11.8", "ledger-apdu", "ledger-transport-hid", "lwk_common", @@ -2317,7 +2435,7 @@ dependencies = [ "bip39", "electrsd", "elements-miniscript", - "env_logger", + "env_logger 0.11.8", "log", "lwk_common", "lwk_containers", @@ -2409,7 +2527,7 @@ dependencies = [ "tempfile", "thiserror 1.0.69", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.24.0", "url", "wasm-bindgen-futures", "waterfalls", @@ -2425,6 +2543,16 @@ dependencies = [ "libc", ] +[[package]] +name = "macros" +version = "0.0.0" +source = "git+https://github.com/SatoshiPortal/boltz-rust/?rev=153d7cd42572f13c08a75ca38e2107ab4034a36b#153d7cd42572f13c08a75ca38e2107ab4034a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "memchr" version = "2.7.6" @@ -2970,6 +3098,12 @@ dependencies = [ "bmp-monochrome", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quinn" version = "0.11.9" @@ -3499,8 +3633,7 @@ dependencies = [ [[package]] name = "secp256k1-zkp" version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" +source = "git+https://github.com/breez/rust-secp256k1-zkp.git?rev=eac2e479255a6e32b5588bc25ee53c642fdd8395#eac2e479255a6e32b5588bc25ee53c642fdd8395" dependencies = [ "bitcoin-private", "rand 0.8.5", @@ -3512,8 +3645,7 @@ dependencies = [ [[package]] name = "secp256k1-zkp-sys" version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f08b2d0b143a22e07f798ae4f0ab20d5590d7c68e0d090f2088a48a21d1654" +source = "git+https://github.com/breez/rust-secp256k1-zkp.git?rev=eac2e479255a6e32b5588bc25ee53c642fdd8395#eac2e479255a6e32b5588bc25ee53c642fdd8395" dependencies = [ "cc", "secp256k1-sys", @@ -3929,6 +4061,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "testcontainers" version = "0.14.0" @@ -4101,10 +4242,46 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite", + "tungstenite 0.24.0", + "webpki-roots 0.26.11", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite 0.26.2", "webpki-roots 0.26.11", ] +[[package]] +name = "tokio-tungstenite-wasm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02567f5f341725fb3e452c1f55dd4e5b0f2a685355c3b10babf0fe8e137d176e" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "httparse", + "js-sys", + "rustls", + "thiserror 2.0.17", + "tokio", + "tokio-tungstenite 0.26.2", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -4217,6 +4394,25 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror 2.0.17", + "utf-8", +] + [[package]] name = "type-map" version = "0.5.1" @@ -4635,7 +4831,7 @@ dependencies = [ "clap", "elements 0.25.2", "elements-miniscript", - "env_logger", + "env_logger 0.11.8", "form_urlencoded", "fxhash", "hex-simd", diff --git a/Cargo.toml b/Cargo.toml index 516518f1b..c641b606a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ members = [ "lwk_rpc_model", "lwk_test_util", "lwk_wasm", + "lwk_boltz", ] -exclude = ["lwk_boltz"] resolver = "2" [patch.crates-io] @@ -30,6 +30,8 @@ lwk_signer = { path = "lwk_signer" } lwk_test_util = { path = "lwk_test_util" } lwk_tiny_jrpc = { path = "lwk_tiny_jrpc" } lwk_wollet = { path = "lwk_wollet" } +lwk_boltz = { path = "lwk_boltz" } +secp256k1-zkp = { git = "https://github.com/breez/rust-secp256k1-zkp.git", rev = "eac2e479255a6e32b5588bc25ee53c642fdd8395" } [profile.release-smaller] inherits = "release" diff --git a/lwk_bindings/Cargo.toml b/lwk_bindings/Cargo.toml index a03eb2248..e6fa1ca77 100644 --- a/lwk_bindings/Cargo.toml +++ b/lwk_bindings/Cargo.toml @@ -30,6 +30,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] name = "lwk" [features] +default = ["lightning"] # remove me, just for now for intellisense foreign_bindings = [] lightning = ["lwk_boltz", "tokio", "log"] diff --git a/lwk_bindings/tests/bindings.rs b/lwk_bindings/tests/bindings.rs index 3fe4e1f08..f4e7d47b5 100644 --- a/lwk_bindings/tests/bindings.rs +++ b/lwk_bindings/tests/bindings.rs @@ -11,6 +11,7 @@ uniffi::build_foreign_language_testcases!( "tests/bindings/amp0-setup.py", "tests/bindings/amp0-daily-ops.py", "tests/bindings/amp2.py", + "tests/bindings/lightning.py", "tests/bindings/list_transactions.kts", "tests/bindings/list_transactions.swift", "tests/bindings/pset_details.py", diff --git a/lwk_boltz/Cargo.toml b/lwk_boltz/Cargo.toml index 1eb1cb3ba..7800b7837 100644 --- a/lwk_boltz/Cargo.toml +++ b/lwk_boltz/Cargo.toml @@ -23,6 +23,4 @@ base64 = "0.22" lwk_signer = { version = "0.12.0" } lwk_common = { version = "0.12.0" } -[patch.crates-io] -secp256k1-zkp = { git = "https://github.com/breez/rust-secp256k1-zkp.git", rev = "eac2e479255a6e32b5588bc25ee53c642fdd8395" } From 77064d721fe37b7ec0087a8d019523d828ef4a10 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Mon, 27 Oct 2025 18:52:21 +0100 Subject: [PATCH 02/10] bindings: optionally use webhook in example --- lwk_bindings/examples/lightning.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lwk_bindings/examples/lightning.py b/lwk_bindings/examples/lightning.py index d64eb8d63..fd0fc93c3 100644 --- a/lwk_bindings/examples/lightning.py +++ b/lwk_bindings/examples/lightning.py @@ -135,7 +135,9 @@ def show_invoice(lightning_session, wollet): print(f"Claim address: {claim_address}") # Create invoice - invoice_response = lightning_session.invoice(amount, "Lightning payment", claim_address, None) # optionally accept a WebHook("https://example.com/webhook") + webhook_url = os.getenv('WEBHOOK') + webhook = WebHook(webhook_url) if webhook_url else None + invoice_response = lightning_session.invoice(amount, "Lightning payment", claim_address, webhook) # Get and print the bolt11 invoice bolt11_invoice_obj = invoice_response.bolt11_invoice() @@ -168,7 +170,9 @@ def pay_invoice(lightning_session, wollet, esplora_client, signer, skip_completi print(f"Refund address: {refund_address}") # Prepare payment - prepare_pay_response = lightning_session.prepare_pay(bolt11_invoice_obj, refund_address, None) # optionally accept a WebHook("https://example.com/webhook") + webhook_url = os.getenv('WEBHOOK') + webhook = WebHook(webhook_url) if webhook_url else None + prepare_pay_response = lightning_session.prepare_pay(bolt11_invoice_obj, refund_address, webhook) data=prepare_pay_response.serialize() swap_id=prepare_pay_response.swap_id() From 7d909f268c256670e79c657bfa1265f180fc952d Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Mon, 27 Oct 2025 18:52:39 +0100 Subject: [PATCH 03/10] bindings: wip AnyClient --- lwk_bindings/src/lightning.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lwk_bindings/src/lightning.rs b/lwk_bindings/src/lightning.rs index 742c47a46..b2e03d103 100644 --- a/lwk_bindings/src/lightning.rs +++ b/lwk_bindings/src/lightning.rs @@ -7,7 +7,7 @@ use std::{ use crate::{Address, Bolt11Invoice, ElectrumClient, LwkError, Mnemonic, Network}; use log::{Level, Metadata, Record}; -use lwk_boltz::{clients::AnyClient, InvoiceData, PreparePayData, RevSwapStates, SubSwapStates}; +use lwk_boltz::{InvoiceData, PreparePayData, RevSwapStates, SubSwapStates}; use std::fmt; /// Log level for logging messages @@ -121,6 +121,25 @@ pub enum PaymentState { Failed, } +#[derive(uniffi::Object)] +pub struct AnyClient { + inner: lwk_boltz::clients::AnyClient, +} + +#[uniffi::export] +impl AnyClient { + #[uniffi::constructor] + pub fn from_electrum(client: Arc, network: &Network) -> Self { + let inner_client = client.clone_client().expect("Failed to clone client"); + let network_value = network.into(); + let boltz_client = + lwk_boltz::clients::ElectrumClient::from_client(inner_client, network_value); + Self { + inner: lwk_boltz::clients::AnyClient::Electrum(Arc::new(boltz_client)), + } + } +} + #[uniffi::export] impl LightningSession { /// Create the lightning session @@ -163,7 +182,7 @@ impl LightningSession { let inner_client = client.clone_client()?; let boltz_client = lwk_boltz::clients::ElectrumClient::from_client(inner_client, network_value); - let client = AnyClient::Electrum(Arc::new(boltz_client)); + let client = lwk_boltz::clients::AnyClient::Electrum(Arc::new(boltz_client)); let inner = lwk_boltz::blocking::LightningSession::new( network_value, client, From 3a9e72cedb09c7ec6b302bf5dd2dac84a0f3604f Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 11:59:39 +0100 Subject: [PATCH 04/10] wollet: make EsploraClientBuilder clonable --- lwk_wollet/src/clients/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lwk_wollet/src/clients/mod.rs b/lwk_wollet/src/clients/mod.rs index 17dd05532..5828dbdac 100644 --- a/lwk_wollet/src/clients/mod.rs +++ b/lwk_wollet/src/clients/mod.rs @@ -23,6 +23,7 @@ pub mod blocking; pub mod asyncr; /// A builder for the [`crate::clients::asyncr::EsploraClient`] or [`crate::clients::blocking::EsploraClient`] +#[derive(Debug, Clone)] pub struct EsploraClientBuilder { base_url: String, waterfalls: bool, From 8eef9438219882d73a5e193f65edb276636fd632 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 12:00:09 +0100 Subject: [PATCH 05/10] bindings: keep the original builder in the esplora client --- lwk_bindings/src/esplora_client.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lwk_bindings/src/esplora_client.rs b/lwk_bindings/src/esplora_client.rs index 5debc66ea..42f8570df 100644 --- a/lwk_bindings/src/esplora_client.rs +++ b/lwk_bindings/src/esplora_client.rs @@ -11,6 +11,9 @@ use crate::{BlockHeader, LwkError, Network, Transaction, Txid, Update, Wollet}; #[derive(uniffi::Object, Debug)] pub struct EsploraClient { pub(crate) inner: Mutex, + + /// The builder used to create the client, used to create a new client with the same configuration. + pub(crate) builder: lwk_wollet::clients::EsploraClientBuilder, } /// A builder for the `EsploraClient` @@ -55,28 +58,34 @@ impl EsploraClient { /// Construct an Esplora Client #[uniffi::constructor] pub fn new(url: &str, network: &Network) -> Result, LwkError> { - let client = blocking::EsploraClient::new(url, network.into())?; + let builder = lwk_wollet::clients::EsploraClientBuilder::new(url, network.into()); + let client = builder.clone().build_blocking()?; Ok(Arc::new(Self { inner: Mutex::new(client), + builder, })) } /// Construct an Esplora Client using Waterfalls endpoint #[uniffi::constructor] pub fn new_waterfalls(url: &str, network: &Network) -> Result, LwkError> { - let client = blocking::EsploraClient::new_waterfalls(url, network.into())?; + let builder = + lwk_wollet::clients::EsploraClientBuilder::new(url, network.into()).waterfalls(true); + let client = builder.clone().build_blocking()?; Ok(Arc::new(Self { inner: Mutex::new(client), + builder, })) } /// Construct an Esplora Client from an `EsploraClientBuilder` #[uniffi::constructor] pub fn from_builder(builder: EsploraClientBuilder) -> Result, LwkError> { + let builder = lwk_wollet::clients::EsploraClientBuilder::from(builder); + let client = builder.clone().build_blocking()?; Ok(Arc::new(Self { - inner: Mutex::new( - lwk_wollet::clients::EsploraClientBuilder::from(builder).build_blocking()?, - ), + inner: Mutex::new(client), + builder, })) } From 245ad572d99bd2d5de392a536b865f2cf348b3e2 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 12:15:59 +0100 Subject: [PATCH 06/10] bindings: create AnyClient from esplora client --- lwk_bindings/src/esplora_client.rs | 19 ++++++++++++++++++- lwk_bindings/src/lightning.rs | 13 ++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lwk_bindings/src/esplora_client.rs b/lwk_bindings/src/esplora_client.rs index 42f8570df..a786479f2 100644 --- a/lwk_bindings/src/esplora_client.rs +++ b/lwk_bindings/src/esplora_client.rs @@ -1,6 +1,9 @@ use std::sync::{Arc, Mutex}; -use lwk_wollet::clients::blocking::{self, BlockchainBackend}; +use lwk_wollet::{ + asyncr, + clients::blocking::{self, BlockchainBackend}, +}; use crate::{BlockHeader, LwkError, Network, Transaction, Txid, Update, Wollet}; @@ -139,3 +142,17 @@ impl EsploraClient { Ok(Arc::new(tip.into())) } } + +impl EsploraClient { + /// Create a new esplora blocking client with the same connection parameters + #[allow(unused)] // TODO remove once lwk_boltz is integrated + pub(crate) fn clone_blocking_client(&self) -> Result { + Ok(self.builder.clone().build_blocking()?) + } + + /// Create a new esplora async client with the same connection parameters + #[allow(unused)] // TODO remove once lwk_boltz is integrated + pub(crate) fn clone_async_client(&self) -> Result { + Ok(self.builder.clone().build()?) + } +} diff --git a/lwk_bindings/src/lightning.rs b/lwk_bindings/src/lightning.rs index b2e03d103..ba4b4906c 100644 --- a/lwk_bindings/src/lightning.rs +++ b/lwk_bindings/src/lightning.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use crate::{Address, Bolt11Invoice, ElectrumClient, LwkError, Mnemonic, Network}; +use crate::{Address, Bolt11Invoice, ElectrumClient, EsploraClient, LwkError, Mnemonic, Network}; use log::{Level, Metadata, Record}; use lwk_boltz::{InvoiceData, PreparePayData, RevSwapStates, SubSwapStates}; use std::fmt; @@ -138,6 +138,17 @@ impl AnyClient { inner: lwk_boltz::clients::AnyClient::Electrum(Arc::new(boltz_client)), } } + + #[uniffi::constructor] + pub fn from_esplora(client: Arc, network: &Network) -> Self { + let inner_client = client.clone_async_client().expect("Failed to clone client"); + let network_value = network.into(); + let boltz_client = + lwk_boltz::clients::EsploraClient::from_client(Arc::new(inner_client), network_value); + Self { + inner: lwk_boltz::clients::AnyClient::Esplora(Arc::new(boltz_client)), + } + } } #[uniffi::export] From 91a61010f3a0521e92493e2be645294046ebf376 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 13:12:18 +0100 Subject: [PATCH 07/10] bindings: accept AnyClient in lightning session --- lwk_bindings/src/lightning.rs | 50 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/lwk_bindings/src/lightning.rs b/lwk_bindings/src/lightning.rs index ba4b4906c..03675fd16 100644 --- a/lwk_bindings/src/lightning.rs +++ b/lwk_bindings/src/lightning.rs @@ -122,32 +122,21 @@ pub enum PaymentState { } #[derive(uniffi::Object)] -pub struct AnyClient { - inner: lwk_boltz::clients::AnyClient, +pub enum AnyClient { + Electrum(Arc), + Esplora(Arc), } #[uniffi::export] impl AnyClient { #[uniffi::constructor] - pub fn from_electrum(client: Arc, network: &Network) -> Self { - let inner_client = client.clone_client().expect("Failed to clone client"); - let network_value = network.into(); - let boltz_client = - lwk_boltz::clients::ElectrumClient::from_client(inner_client, network_value); - Self { - inner: lwk_boltz::clients::AnyClient::Electrum(Arc::new(boltz_client)), - } + pub fn from_electrum(client: Arc) -> Self { + AnyClient::Electrum(client) } #[uniffi::constructor] - pub fn from_esplora(client: Arc, network: &Network) -> Self { - let inner_client = client.clone_async_client().expect("Failed to clone client"); - let network_value = network.into(); - let boltz_client = - lwk_boltz::clients::EsploraClient::from_client(Arc::new(inner_client), network_value); - Self { - inner: lwk_boltz::clients::AnyClient::Esplora(Arc::new(boltz_client)), - } + pub fn from_esplora(client: Arc) -> Self { + AnyClient::Esplora(client) } } @@ -161,7 +150,7 @@ impl LightningSession { #[uniffi::constructor] pub fn new( network: &Network, - client: &ElectrumClient, + client: &AnyClient, timeout: Option, logging: Option>, mnemonic: Option>, @@ -189,11 +178,24 @@ impl LightningSession { log::info!("Creating lightning session"); let network_value = network.into(); - // Transform lwk_bindings::ElectrumClient into lwk_boltz::clients::ElectrumClient - let inner_client = client.clone_client()?; - let boltz_client = - lwk_boltz::clients::ElectrumClient::from_client(inner_client, network_value); - let client = lwk_boltz::clients::AnyClient::Electrum(Arc::new(boltz_client)); + + let client = match client { + AnyClient::Electrum(client) => { + let boltz_client = lwk_boltz::clients::ElectrumClient::from_client( + client.clone_client().unwrap(), + network_value, + ); + lwk_boltz::clients::AnyClient::Electrum(Arc::new(boltz_client)) + } + AnyClient::Esplora(client) => { + let boltz_client = lwk_boltz::clients::EsploraClient::from_client( + Arc::new(client.clone_async_client().unwrap()), + network_value, + ); + lwk_boltz::clients::AnyClient::Esplora(Arc::new(boltz_client)) + } + }; + let inner = lwk_boltz::blocking::LightningSession::new( network_value, client, From 3a7c2fea0db0b6acbb192b41d81a07bc05e506be Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 13:36:36 +0100 Subject: [PATCH 08/10] bindings: use AnyClient in python test --- lwk_bindings/tests/bindings/lightning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lwk_bindings/tests/bindings/lightning.py b/lwk_bindings/tests/bindings/lightning.py index 574815cb9..1fdd8766b 100644 --- a/lwk_bindings/tests/bindings/lightning.py +++ b/lwk_bindings/tests/bindings/lightning.py @@ -14,7 +14,7 @@ def log(self, level: LogLevel, message: str): mnemonic = Mnemonic("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") network = Network.mainnet() -client = network.default_electrum_client() +client = AnyClient.from_electrum(network.default_electrum_client()) signer = Signer(mnemonic, network) desc = signer.wpkh_slip77_descriptor() wollet = Wollet(network, desc, datadir=None) From 69bea7ee40ca71ef4e2deaecbfecefd415fccff9 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 13:41:09 +0100 Subject: [PATCH 09/10] bindings: use only EsploraClient for python example --- lwk_bindings/examples/lightning.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lwk_bindings/examples/lightning.py b/lwk_bindings/examples/lightning.py index fd0fc93c3..01df28a7d 100644 --- a/lwk_bindings/examples/lightning.py +++ b/lwk_bindings/examples/lightning.py @@ -358,10 +358,6 @@ def main(): os.makedirs(swaps_dir, exist_ok=True) os.makedirs(f"{swaps_dir}/failed", exist_ok=True) - # Create wallet components - # Use ElectrumClient only for LightningSession - electrum_client = network.default_electrum_client() - # Use EsploraClient with waterfalls for all other operations b = EsploraClientBuilder( base_url="https://waterfalls.liquidwebwallet.org/liquid/api", network=network, @@ -379,10 +375,10 @@ def main(): wollet = Wollet(network, desc, datadir=None) - # Create lightning session with ElectrumClient mnemonic_lightning = signer.derive_bip85_mnemonic(0, 12) # for security reasons using a different mnemonic for the lightning session + lightning_client = AnyClient.from_esplora(esplora_client) logger = MyLogger() - lightning_session = LightningSession(network, electrum_client, 30, logger, mnemonic_lightning) # 30 second timeout + lightning_session = LightningSession(network=network, client=lightning_client, timeout=30, logging=logger, mnemonic=mnemonic_lightning) # Initial balance update update_balance(wollet, esplora_client, desc) From ed76663aeb6145e86e0db481a5d84752a98856a6 Mon Sep 17 00:00:00 2001 From: Riccardo Casatta Date: Tue, 28 Oct 2025 13:43:09 +0100 Subject: [PATCH 10/10] boltz: remove wrong comments --- lwk_boltz/src/reverse.rs | 2 +- lwk_boltz/tests/reverse.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lwk_boltz/src/reverse.rs b/lwk_boltz/src/reverse.rs index 2419f1c64..a3666f0c7 100644 --- a/lwk_boltz/src/reverse.rs +++ b/lwk_boltz/src/reverse.rs @@ -76,7 +76,7 @@ impl LightningSession { address_signature: Some(addrs_sig.to_string()), address: Some(claim_address.to_string()), claim_public_key, - referral_id: None, // Add address signature here. + referral_id: None, webhook, }; diff --git a/lwk_boltz/tests/reverse.rs b/lwk_boltz/tests/reverse.rs index 5623ba409..efc801e16 100644 --- a/lwk_boltz/tests/reverse.rs +++ b/lwk_boltz/tests/reverse.rs @@ -287,7 +287,7 @@ mod tests { address_signature: Some(addrs_sig.to_string()), address: Some(claim_address.clone()), claim_public_key, - referral_id: None, // Add address signature here. + referral_id: None, webhook: None, };