Skip to content

Commit 755f917

Browse files
authored
Merge pull request #156 from SatoshiPortal/dependency-updates
chore: update dependencies
2 parents 2d52ad5 + 887a45c commit 755f917

5 files changed

Lines changed: 169 additions & 18 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "boltz-client"
33
description = "a boltz exchange client for swaps between BTC/LBTC & LN"
44
authors = ["i5hi <ishi@satoshiportal.com>", "Rajarshi Maitra <raj@bitshala.org>"]
5-
version = "0.4.0"
5+
version = "0.4.1"
66
edition = "2021"
77
license = "MIT"
88

@@ -20,7 +20,7 @@ members = [
2020

2121
[workspace.dependencies]
2222
bitcoin = { version = "0.32.2", features = ["rand", "base64", "rand-std"] }
23-
elements = { version = "0.25.0", features = ["serde"] }
23+
elements = { version = "0.26.2", features = ["serde"] }
2424
serde = { version = "1.0.0", features = ["derive"] }
2525
serde_json = "1.0.0"
2626
async-trait = "0.1.86"
@@ -47,7 +47,7 @@ serde_json = { workspace = true }
4747
async-trait = { workspace = true }
4848
tokio = { workspace = true }
4949
bip39 = "2.0.0"
50-
lightning-invoice = "0.32.0"
50+
lightning-invoice = "0.34.0"
5151
url = "2.5.0"
5252
log = "^0.4"
5353
env_logger = "0.11.8"
@@ -61,7 +61,7 @@ bip85_extended = "1.1.0"
6161
lightning = "0.2.2"
6262

6363
[target.'cfg(not(all(target_family = "wasm", target_os = "unknown")))'.dependencies]
64-
electrum-client = { version = "0.21.0", default-features = false, features = ["use-rustls-ring", "proxy"], optional = true }
64+
electrum-client = { version = "0.25.0", default-features = false, features = ["use-rustls-ring", "proxy"], optional = true }
6565

6666
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
6767
getrandom = { version = "0.2", features = ["js"] }

src/network/electrum.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ enum ElectrumUrl {
2525
impl ElectrumUrl {
2626
pub fn build_client(&self, timeout: u8) -> Result<electrum_client::Client, Error> {
2727
let builder = electrum_client::ConfigBuilder::new();
28-
let builder = builder.timeout(Some(timeout));
28+
let builder = builder.timeout(Some(std::time::Duration::from_secs(timeout as u64)));
2929
let (url, builder) = match self {
3030
ElectrumUrl::Tls(url, validate) => {
3131
(format!("ssl://{url}"), builder.validate_domain(*validate))

src/swaps/boltz.rs

Lines changed: 136 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -800,30 +800,45 @@ impl BoltzApiClientV2 {
800800
self.get_json(&end_point).await
801801
}
802802

803-
/// Restore swaps from an xpub
803+
/// Restore swaps from an xpub.
804+
///
805+
/// `derivation_path` is the path boltz appends `/{index}` to when deriving
806+
/// child keys from `xpub`. Pass `"m"` when `xpub` is already the
807+
/// swap-account key (`m/44/0/0/0`), so boltz derives `xpub/{index}` to match
808+
/// our per-swap keys. Omitting the path makes boltz apply its own default
809+
/// and find nothing.
804810
pub async fn post_swap_restore(
805811
&self,
806812
xpub: &String,
813+
derivation_path: Option<String>,
814+
gap_limit: Option<u32>,
807815
) -> Result<Vec<SwapRestoreResponse>, Error> {
808-
let data = json!(
809-
{
810-
"xpub": xpub,
811-
}
812-
);
816+
let mut data = json!({ "xpub": xpub });
817+
if let Some(path) = derivation_path {
818+
data["derivationPath"] = json!(path);
819+
}
820+
if let Some(gap) = gap_limit {
821+
data["gapLimit"] = json!(gap);
822+
}
813823

814824
self.post_json("swap/restore", data).await
815825
}
816826

817-
/// Restore swaps from an xpub
827+
/// Highest swap-key derivation index boltz has seen for `xpub` (-1 if none).
828+
/// See [`Self::post_swap_restore`] for the `derivation_path` semantics.
818829
pub async fn post_swap_restore_index(
819830
&self,
820831
xpub: &String,
832+
derivation_path: Option<String>,
833+
gap_limit: Option<u32>,
821834
) -> Result<SwapRestoreIndexResponse, Error> {
822-
let data = json!(
823-
{
824-
"xpub": xpub,
825-
}
826-
);
835+
let mut data = json!({ "xpub": xpub });
836+
if let Some(path) = derivation_path {
837+
data["derivationPath"] = json!(path);
838+
}
839+
if let Some(gap) = gap_limit {
840+
data["gapLimit"] = json!(gap);
841+
}
827842

828843
self.post_json("swap/restore/index", data).await
829844
}
@@ -1871,6 +1886,115 @@ mod tests {
18711886
assert!(result.is_ok(), "Failed to get height");
18721887
}
18731888

1889+
// Hits the live mainnet swap/restore endpoint with the swap-master xpub
1890+
// derived from a known wallet mnemonic, and prints what boltz returns.
1891+
// Run: cargo test test_swap_restore_endpoint_print -- --nocapture
1892+
#[macros::async_test_all]
1893+
async fn test_swap_restore_endpoint_print() {
1894+
let wallet_mnemonic =
1895+
"slogan prevent affair connect autumn crop together earn track ribbon horn copy";
1896+
let swap_master_key =
1897+
crate::util::secrets::SwapMasterKey::new(wallet_mnemonic, None, Network::Mainnet)
1898+
.unwrap();
1899+
let xpub = swap_master_key.get_master_xpub().to_string();
1900+
println!("SWAP_RESTORE_TEST xpub: {xpub}");
1901+
1902+
let client = BoltzApiClientV2::new(BOLTZ_MAINNET_URL_V2.to_string(), None);
1903+
let responses = client
1904+
.post_swap_restore(&xpub, Some("m".to_string()), Some(100))
1905+
.await
1906+
.unwrap();
1907+
println!("SWAP_RESTORE_TEST returned {} swaps", responses.len());
1908+
for r in &responses {
1909+
println!(
1910+
"SWAP_RESTORE_TEST {} type={:?} status={} {}->{}",
1911+
r.id, r.swap_type, r.status, r.from, r.to
1912+
);
1913+
}
1914+
}
1915+
1916+
// Creates a fresh BTC->L-BTC chain swap at swap-key indexes 0 (refund) and
1917+
// 1 (claim) using the seed's xpub-derived keys, then immediately calls
1918+
// swap/restore (and swap/restore/index) with the same xpub to see whether
1919+
// boltz matches the just-registered leaf pubkeys.
1920+
// Run: cargo test test_create_chain_then_restore -- --nocapture
1921+
#[macros::async_test_all]
1922+
async fn test_create_chain_then_restore() {
1923+
use crate::util::secrets::{Preimage, SwapMasterKey};
1924+
let wallet_mnemonic =
1925+
"slogan prevent affair connect autumn crop together earn track ribbon horn copy";
1926+
let smk = SwapMasterKey::new(wallet_mnemonic, None, Network::Mainnet).unwrap();
1927+
let xpub = smk.get_master_xpub().to_string();
1928+
let refund_kps = smk.derive_swapkey(0).unwrap();
1929+
let claim_kps = smk.derive_swapkey(1).unwrap();
1930+
let refund_public_key = PublicKey {
1931+
inner: refund_kps.public_key(),
1932+
compressed: true,
1933+
};
1934+
let claim_public_key = PublicKey {
1935+
inner: claim_kps.public_key(),
1936+
compressed: true,
1937+
};
1938+
let preimage = Preimage::from_swap_key(&claim_kps);
1939+
println!("CREATE_RESTORE xpub : {xpub}");
1940+
println!("CREATE_RESTORE refund pubkey: {refund_public_key} (index 0)");
1941+
println!("CREATE_RESTORE claim pubkey : {claim_public_key} (index 1)");
1942+
1943+
let client = BoltzApiClientV2::new(BOLTZ_MAINNET_URL_V2.to_string(), None);
1944+
let req = CreateChainRequest {
1945+
from: "BTC".to_string(),
1946+
to: "L-BTC".to_string(),
1947+
preimage_hash: preimage.sha256,
1948+
claim_public_key: Some(claim_public_key),
1949+
refund_public_key: Some(refund_public_key),
1950+
user_lock_amount: Some(100_000),
1951+
server_lock_amount: None,
1952+
pair_hash: None,
1953+
referral_id: None,
1954+
webhook: None,
1955+
};
1956+
let created = client.post_chain_req(req).await;
1957+
match &created {
1958+
Ok(resp) => println!("CREATE_RESTORE created chain swap: {}", resp.id),
1959+
Err(e) => println!("CREATE_RESTORE create FAILED: {e:?}"),
1960+
}
1961+
let created_id = created.ok().map(|r| r.id);
1962+
1963+
match client
1964+
.post_swap_restore_index(&xpub, Some("m".to_string()), Some(100))
1965+
.await
1966+
{
1967+
Ok(idx) => println!("CREATE_RESTORE restore/index for xpub = {}", idx.index),
1968+
Err(e) => println!("CREATE_RESTORE restore/index FAILED: {e:?}"),
1969+
}
1970+
1971+
let responses = client
1972+
.post_swap_restore(&xpub, Some("m".to_string()), Some(100))
1973+
.await
1974+
.unwrap();
1975+
println!("CREATE_RESTORE restore returned {} swaps", responses.len());
1976+
for r in &responses {
1977+
let ck = r
1978+
.claim_details
1979+
.as_ref()
1980+
.map(|d| d.key_index as i64)
1981+
.unwrap_or(-1);
1982+
let rk = r
1983+
.refund_details
1984+
.as_ref()
1985+
.map(|d| d.key_index as i64)
1986+
.unwrap_or(-1);
1987+
println!(
1988+
"CREATE_RESTORE {} type={:?} status={} {}->{} claimIdx={} refundIdx={}",
1989+
r.id, r.swap_type, r.status, r.from, r.to, ck, rk
1990+
);
1991+
}
1992+
if let Some(id) = created_id {
1993+
let found = responses.iter().any(|r| r.id == id);
1994+
println!("CREATE_RESTORE just-created swap {id} found in restore: {found}");
1995+
}
1996+
}
1997+
18741998
#[macros::async_test_all]
18751999
async fn test_get_submarine_pairs() {
18762000
let client = BoltzApiClientV2::new(BOLTZ_MAINNET_URL_V2.to_string(), None);

src/util/secrets.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,4 +418,31 @@ mod tests {
418418

419419
Ok(())
420420
}
421+
422+
// Derives + prints the swap mnemonic / xpub / fingerprint for a known wallet
423+
// mnemonic, to cross-check against the values shown in the mobile app.
424+
// Run with: cargo test test_swap_master_key_derivation_print -- --nocapture
425+
#[macros::test_all]
426+
fn test_swap_master_key_derivation_print() -> Result<(), Error> {
427+
let wallet_mnemonic =
428+
"slogan prevent affair connect autumn crop together earn track ribbon horn copy";
429+
let network = Network::Mainnet;
430+
431+
let swap_master_key = SwapMasterKey::new(wallet_mnemonic, None, network)?;
432+
let master_xpub = swap_master_key.get_master_xpub();
433+
434+
println!("--- SWAP MASTER KEY (mainnet) ---");
435+
println!("wallet mnemonic : {wallet_mnemonic}");
436+
println!("swap mnemonic : {}", swap_master_key.mnemonic);
437+
println!("fingerprint : {}", swap_master_key.fingerprint);
438+
println!("master xprv : {}", swap_master_key.xprv);
439+
println!("master xpub : {master_xpub}");
440+
println!("--- swap keys at indexes 0..5 ---");
441+
for i in 0..5u64 {
442+
let kp = swap_master_key.derive_swapkey(i)?;
443+
println!("index {i}: pubkey {}", kp.public_key());
444+
}
445+
446+
Ok(())
447+
}
421448
}

0 commit comments

Comments
 (0)