Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
30214fa
Revert "security(tauri): enable Content Security Policy (#851)"
nabijaczleweli Jan 14, 2026
537e793
refactor(swap/api): reduce open-coded Result::ok
nabijaczleweli Oct 19, 2025
27d54b3
refactor(asb): don't needlessly clone config.network.listen, spell sw…
nabijaczleweli Oct 19, 2025
afac39d
refactor(asb/network): lift onion_addresses collection
nabijaczleweli Oct 19, 2025
c794347
refactor(swap/tor): reduce TOR_*_TIMEOUT to const
nabijaczleweli Oct 21, 2025
c6d99c6
refactor(swap/cli): discard Result with let _ = instead of .ok()
nabijaczleweli Oct 23, 2025
347e1f1
fix(swap/network): remove DNS leak if using Tor
nabijaczleweli Oct 22, 2025
3340016
refactor(swap): deduplicate upgrading maybe_tor_client to TorTransport
nabijaczleweli Oct 24, 2025
259b40a
refactor(swap): deduplicate upgrading TorBackend to final transport
nabijaczleweli Oct 22, 2025
f7a7c6b
Add swap-tor crate to supersede swap and monero-rpc-pool open-coding …
nabijaczleweli Oct 24, 2025
520689b
Perfuse TorBackend through swap
nabijaczleweli Oct 24, 2025
6bed8cd
Perfuse TorBackend through monero-rpc-pool
nabijaczleweli Oct 24, 2025
9543f28
Add TorBackend::Socks to connect to a Tor daemon over a TCP SOCKS5 proxy
nabijaczleweli Oct 24, 2025
a89b5a8
Detect Whonix and Tails, connect to their Tors specially
nabijaczleweli Oct 24, 2025
9559650
Inform the user that (and why) Tor is forced-on (GUI). Don't ask the …
nabijaczleweli Oct 24, 2025
99a8b62
fix(monero-rpc-pool): only try to bypass unforced Tor
nabijaczleweli Oct 24, 2025
b2a14c2
Distribute required-on-Tails SOCKS5 proxy everywhere a TCP request is…
nabijaczleweli Oct 26, 2025
107b113
Forward required proxy to tauri as well
nabijaczleweli Oct 26, 2025
620df82
CHANGELOG
nabijaczleweli Nov 2, 2025
4365435
refactor: keep updaterProxy and torForcedExcuse in redux RPC store
nabijaczleweli Nov 3, 2025
3d610be
clippy
nabijaczleweli Jan 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ASB + GUI + CLI + SWAP: Split high-verbosity tracing into separate hourly-rotating JSON log files per subsystem to reduce noise and aid debugging: `tracing*.log` (core things), `tracing-tor*.log` (purely tor related), `tracing-libp2p*.log` (low level networking), `tracing-monero-wallet*.log` (low level Monero wallet related). `swap-all.log` remains for non-verbose logs.
- ASB: Fix an issue where we would not redeem the Bitcoin and force a refund even though it was still possible to do so.
- GUI: Potentially fix issue here swaps would not be displayed
- SWAP-TOR: New crate unifying the existing Arti and new SOCKS5 Tor back-ends.
- MONERO-RPC-POOL + ASB + CLI: Use SWAP-TOR.
- SWAP: Remove DNS leak if using Tor.
- SWAP-TOR + MONERO-RPC-POOL + CLI + GUI: Detect Whonix/Tails and use their system Tor daemons to connect over Tor; this cannot be disabled.
- SWAP-TOR + MONERO-RPC-POOL + CLI + GUI: Where required (Tails), use SOCKS5 proxy to dial out always.

## [3.2.7] - 2025-10-28

Expand Down
36 changes: 36 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ members = [
"swap-p2p",
"swap-proptest",
"swap-serde",
"swap-tor",
"throttle",
"tracing-ext",
]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This is the monorepo containing the source code for all of our core projects:
- [`tauri`](src-tauri/) contains the tauri bindings between binaries and user interface
- and other crates we use in our binaries

If you're just here for the software, head over to the [releases](https://github.com/eigenwallet/core/releases/latest) tab and grab the binary for your operating system! If you're just looking for documentation, check out our [docs page](https://docs.eigenwallet.org/) or our [github docs](dev-docs/README.md).
If you're just here for the software, head over to the [releases](https://github.com/eigenwallet/core/releases/latest) tab and grab the binary for your operating system! If you're just looking for documentation, check out our [docs page](https://docs.unstoppableswap.net/) or our [github docs](dev-docs/README.md).

Join our [Matrix room](https://matrix.to/#/#unstoppableswap-core:matrix.org) to follow development more closely.

Expand Down
1 change: 1 addition & 0 deletions bitcoin-wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rust_decimal = { version = "1", features = ["serde-float"] }
serde = { workspace = true }
serde_json = { workspace = true }
swap-env = { path = "../swap-env" }
swap-tor = { path = "../swap-tor" }
swap-proptest = { path = "../swap-proptest" }
swap-serde = { path = "../swap-serde" }
thiserror = { workspace = true }
Expand Down
21 changes: 17 additions & 4 deletions bitcoin-wallet/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ use bitcoin::bip32::Xpriv;
use bitcoin::{psbt::Psbt as PartiallySignedTransaction, Address, Amount, Transaction, Txid};
use bitcoin::{Psbt, ScriptBuf, Weight};
use derive_builder::Builder;
use electrum_pool::ElectrumBalancer;
use electrum_pool::{ElectrumBalancer, ElectrumBalancerConfig};
use moka;
use rust_decimal::prelude::*;
use rust_decimal::Decimal;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt::Debug;
Expand Down Expand Up @@ -1612,7 +1613,16 @@ where
impl Client {
/// Create a new client with multiple electrum servers for load balancing.
pub async fn new(electrum_rpc_urls: &[String], sync_interval: Duration) -> Result<Self> {
let balancer = ElectrumBalancer::new(electrum_rpc_urls.to_vec()).await?;
let balancer = ElectrumBalancer::new_with_config(
electrum_rpc_urls.to_vec(),
ElectrumBalancerConfig {
socks5: swap_tor::TOR_ENVIRONMENT
.and_then(|ste| ste.electrum_proxy())
.map(Cow::from),
..Default::default()
},
)
.await?;

Ok(Self {
inner: Arc::new(balancer),
Expand Down Expand Up @@ -2582,8 +2592,11 @@ mod mempool_client {
_ => bail!("mempool.space fee estimation unsupported for network"),
};

let client = reqwest::Client::builder()
.timeout(HTTP_TIMEOUT)
let mut client = reqwest::Client::builder().timeout(HTTP_TIMEOUT);
if let Some(proxy) = swap_tor::TOR_ENVIRONMENT.and_then(|ste| ste.reqwest_proxy()) {
client = client.proxy(reqwest::Proxy::all(proxy)?);
}
let client = client
.build()
.context("Failed to build mempool.space HTTP client")?;

Expand Down
2 changes: 1 addition & 1 deletion docs/components/SwapProviderTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function SwapMakerTable() {
}

async function getMakers() {
const response = await fetch("https://api.eigenwallet.org/api/list");
const response = await fetch("https://api.unstoppableswap.net/api/list");
const data = await response.json();
return data;
}
Expand Down
10 changes: 9 additions & 1 deletion electrum-pool/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use backoff::{Error as BackoffError, ExponentialBackoff};
use bdk_electrum::electrum_client::{Client, ConfigBuilder, ElectrumApi, Error};
use bdk_electrum::electrum_client::{Client, ConfigBuilder, ElectrumApi, Error, Socks5Config};
use bdk_electrum::BdkElectrumClient;
use bitcoin::Transaction;
use futures::future::join_all;
use once_cell::sync::OnceCell;
use std::borrow::Cow;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, RwLock};
use std::time::Duration;
Expand Down Expand Up @@ -544,13 +545,16 @@ pub struct ElectrumBalancerConfig {
pub request_timeout: u8,
/// Minimum number of retry attempts across all nodes
pub min_retries: usize,
/// Address of SOCKS5 proxy in `127.0.0.1:9050` format
pub socks5: Option<Cow<'static, str>>,
}

impl Default for ElectrumBalancerConfig {
fn default() -> Self {
Self {
request_timeout: 15,
min_retries: 10,
socks5: None,
}
}
}
Expand All @@ -577,6 +581,7 @@ impl ElectrumClientFactory<BdkElectrumClient<Client>> for BdkElectrumClientFacto
//
// Setting it to 0 causes some bugs, see: https://github.com/bitcoindevkit/rust-electrum-client/issues/186
.retry(1)
.socks5(config.socks5.as_ref().map(Socks5Config::new))
.build();

let client = Client::from_config(url, client_config).map_err(|e| {
Expand Down Expand Up @@ -950,6 +955,7 @@ mod tests {
let config = ElectrumBalancerConfig {
request_timeout: 5,
min_retries: 0,
socks5: None,
};

let balancer = ElectrumBalancer::new_with_config_and_factory(urls, config, factory.clone())
Expand Down Expand Up @@ -1023,6 +1029,7 @@ mod tests {
let config = ElectrumBalancerConfig {
request_timeout: 5,
min_retries: 1,
socks5: None,
};

let balancer = ElectrumBalancer::new_with_config_and_factory(urls, config, factory.clone())
Expand Down Expand Up @@ -1165,6 +1172,7 @@ mod tests {
let config = ElectrumBalancerConfig {
request_timeout: 15,
min_retries: 7,
socks5: None,
};

let factory = Arc::new(MockElectrumClientFactory::new());
Expand Down
9 changes: 7 additions & 2 deletions monero-harness/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,10 @@ impl MoneroWallet {

// Use Mainnet network type – regtest daemon accepts mainnet prefixes
// and this avoids address-parsing errors when calling daemon RPCs.
let wallet = WalletHandle::open_or_create(
let wallet = WalletHandle::open_or_create::<String>(
wallet_path.display().to_string(),
daemon,
None,
monero_address::Network::Mainnet,
background_sync,
)
Expand All @@ -467,7 +468,11 @@ impl MoneroWallet {
}

/// Get address at a given account and subaddress index.
pub async fn address_at(&self, account_index: u32, address_index: u32) -> Result<MoneroAddress> {
pub async fn address_at(
&self,
account_index: u32,
address_index: u32,
) -> Result<MoneroAddress> {
Ok(self.wallet.address(account_index, address_index).await?)
}

Expand Down
6 changes: 3 additions & 3 deletions monero-oxide-ext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl PrivateKey {

impl fmt::Display for PrivateKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", hex::encode(&self.as_bytes()))
write!(f, "{}", hex::encode(self.as_bytes()))
}
}

Expand Down Expand Up @@ -122,7 +122,7 @@ pub mod serde_compressed_edwards {
.ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Ok(PublicKey::from_slice(&bytes)
.map_err(|e| serde::de::Error::custom(e))?
.map_err(serde::de::Error::custom)?
.point)
}
}
Expand Down Expand Up @@ -200,7 +200,7 @@ impl From<curve25519_dalek_ng::edwards::CompressedEdwardsY> for PublicKey {

impl fmt::Display for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", hex::encode(&self.as_bytes()))
write!(f, "{}", hex::encode(self.as_bytes()))
}
}

Expand Down
2 changes: 2 additions & 0 deletions monero-rpc-pool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ tracing-subscriber = { workspace = true }
# Async runtime
crossbeam = "0.8.4"
tokio = { workspace = true, features = ["full"] }
tokio-socks = "0.5"

# Serialization
chrono = { version = "0.4", features = ["serde"] }
Expand Down Expand Up @@ -63,6 +64,7 @@ tor-rtcompat = { workspace = true, features = ["tokio", "rustls"] }
# Monero/Project specific
monero-address = { workspace = true }
swap-serde = { path = "../swap-serde" }
swap-tor = { path = "../swap-tor" }

# Optional dependencies (for features)
cuprate-epee-encoding = { git = "https://github.com/Cuprate/cuprate.git", optional = true }
Expand Down
4 changes: 2 additions & 2 deletions monero-rpc-pool/src/bin/stress_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.await
.expect("Failed to bootstrap Tor client");

Some(client)
swap_tor::TorBackend::Arti(client)
} else {
None
swap_tor::TorBackend::None
};

// Start the pool server
Expand Down
4 changes: 2 additions & 2 deletions monero-rpc-pool/src/bin/stress_test_downloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.await
.expect("Failed to bootstrap Tor client");

Some(client)
swap_tor::TorBackend::Arti(client)
} else {
None
swap_tor::TorBackend::None
};

// Start the pool server
Expand Down
Loading
Loading