diff --git a/swap/src/asb/config.rs b/swap/src/asb/config.rs index 2c34ec73..08ba65c5 100644 --- a/swap/src/asb/config.rs +++ b/swap/src/asb/config.rs @@ -1,6 +1,5 @@ use crate::env::{Mainnet, Testnet}; use crate::fs::{ensure_directory_exists, system_config_dir, system_data_dir}; -use crate::monero; use crate::tor::{DEFAULT_CONTROL_PORT, DEFAULT_SOCKS5_PORT}; use anyhow::{bail, Context, Result}; use config::ConfigError; @@ -121,6 +120,8 @@ pub struct Network { pub struct Bitcoin { pub electrum_rpc_url: Url, pub target_block: usize, + pub finality_confirmations: Option, + #[serde(with = "crate::bitcoin::network")] pub network: bitcoin::Network, } @@ -128,6 +129,8 @@ pub struct Bitcoin { #[serde(deny_unknown_fields)] pub struct Monero { pub wallet_rpc_url: Url, + pub finality_confirmations: Option, + #[serde(with = "crate::monero::network")] pub network: monero::Network, } @@ -335,7 +338,7 @@ mod tests { monero: Monero { wallet_rpc_url: defaults.monero_wallet_rpc_url, - network: monero::Network::Testnet, + network: monero::Network::Stagenet, }, tor: Default::default(), maker: Maker { diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index 6149fd8c..511955ac 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -151,6 +151,7 @@ async fn main() -> Result<()> { config.maker.max_buy_btc, kraken_rate.clone(), resume_only, + env_config, )?; for listen in config.network.listen { diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index 5e643dd1..09ec0f88 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -82,8 +82,13 @@ async fn main() -> Result<()> { .add_address(seller_peer_id, seller_addr); let swap_id = Uuid::new_v4(); - let (event_loop, mut event_loop_handle) = - EventLoop::new(swap_id, swarm, seller_peer_id, bitcoin_wallet.clone())?; + let (event_loop, mut event_loop_handle) = EventLoop::new( + swap_id, + swarm, + seller_peer_id, + bitcoin_wallet.clone(), + env_config, + )?; let event_loop = tokio::spawn(event_loop.run()); let max_givable = || bitcoin_wallet.max_giveable(TxLock::script_size()); @@ -151,7 +156,7 @@ async fn main() -> Result<()> { let seed = Seed::from_file_or_generate(data_dir.as_path()) .context("Failed to read in seed file")?; - if monero_receive_address.network != env_config.monero_network.into() { + if monero_receive_address.network != env_config.monero_network { bail!("The given monero address is on network {:?}, expected address of network {:?}.", monero_receive_address.network, env_config.monero_network) } @@ -176,8 +181,13 @@ async fn main() -> Result<()> { .behaviour_mut() .add_address(seller_peer_id, seller_addr); - let (event_loop, event_loop_handle) = - EventLoop::new(swap_id, swarm, seller_peer_id, bitcoin_wallet.clone())?; + let (event_loop, event_loop_handle) = EventLoop::new( + swap_id, + swarm, + seller_peer_id, + bitcoin_wallet.clone(), + env_config, + )?; let handle = tokio::spawn(event_loop.run()); let swap = Swap::from_db( @@ -294,7 +304,7 @@ async fn init_monero_wallet( let monero_wallet_rpc = monero::WalletRpc::new(data_dir.join("monero")).await?; let monero_wallet_rpc_process = monero_wallet_rpc - .run(network.into(), monero_daemon_address.as_str()) + .run(network, monero_daemon_address.as_str()) .await?; let monero_wallet = monero::Wallet::open_or_create( diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 9e7f323c..9534bd04 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -37,6 +37,17 @@ use serde::{Deserialize, Serialize}; use sha2::Sha256; use std::str::FromStr; +#[derive(Serialize, Deserialize)] +#[serde(remote = "Network")] +#[allow(non_camel_case_types)] +pub enum network { + #[serde(rename = "Mainnet")] + Bitcoin, + Testnet, + Signet, + Regtest, +} + #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] pub struct SecretKey { inner: Scalar, diff --git a/swap/src/env.rs b/swap/src/env.rs index debe18c7..3164c3bd 100644 --- a/swap/src/env.rs +++ b/swap/src/env.rs @@ -1,5 +1,4 @@ use crate::bitcoin::{CancelTimelock, PunishTimelock}; -use crate::monero; use std::cmp::max; use std::time::Duration; use time::NumericalStdDurationShort; diff --git a/swap/src/monero.rs b/swap/src/monero.rs index c56a4622..c4649410 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -1,6 +1,7 @@ pub mod wallet; mod wallet_rpc; +pub use ::monero::network::Network; pub use ::monero::{Address, PrivateKey, PublicKey}; pub use curve25519_dalek::scalar::Scalar; pub use wallet::Wallet; @@ -19,33 +20,15 @@ use std::str::FromStr; pub const PICONERO_OFFSET: u64 = 1_000_000_000_000; -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)] -pub enum Network { +#[derive(Serialize, Deserialize)] +#[serde(remote = "Network")] +#[allow(non_camel_case_types)] +pub enum network { Mainnet, Stagenet, Testnet, } -impl From for Network { - fn from(network: monero::Network) -> Self { - match network { - monero::Network::Mainnet => Self::Mainnet, - monero::Network::Stagenet => Self::Stagenet, - monero::Network::Testnet => Self::Testnet, - } - } -} - -impl From for monero::Network { - fn from(network: Network) -> Self { - match network { - Network::Mainnet => monero::Network::Mainnet, - Network::Stagenet => monero::Network::Stagenet, - Network::Testnet => monero::Network::Testnet, - } - } -} - pub fn private_key_from_secp256k1_scalar(scalar: bitcoin::Scalar) -> PrivateKey { let mut bytes = scalar.to_bytes(); diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index 686c783c..4732a632 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -47,7 +47,7 @@ impl Wallet { monero::Address::from_str(client.get_address(0).await?.address.as_str())?; Ok(Self { inner: Mutex::new(client), - network: env_config.monero_network.into(), + network: env_config.monero_network, name, main_address, sync_interval: env_config.monero_sync_interval(), diff --git a/swap/src/network/spot_price.rs b/swap/src/network/spot_price.rs index 84838c27..8268d146 100644 --- a/swap/src/network/spot_price.rs +++ b/swap/src/network/spot_price.rs @@ -32,6 +32,7 @@ impl ProtocolName for SpotPriceProtocol { pub struct Request { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] pub btc: bitcoin::Amount, + pub blockchain_network: BlockchainNetwork, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -59,11 +60,23 @@ pub enum Error { #[serde(with = "::bitcoin::util::amount::serde::as_sat")] buy: bitcoin::Amount, }, + BlockchainNetworkMismatch { + cli: BlockchainNetwork, + asb: BlockchainNetwork, + }, /// To be used for errors that cannot be explained on the CLI side (e.g. /// rate update problems on the seller side) Other, } +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)] +pub struct BlockchainNetwork { + #[serde(with = "crate::bitcoin::network")] + pub bitcoin: bitcoin::Network, + #[serde(with = "crate::monero::network")] + pub monero: monero::Network, +} + #[cfg(test)] mod tests { use super::*; @@ -103,6 +116,21 @@ mod tests { .unwrap(); assert_eq!(error, serialized); + let error = r#"{"Error":{"BlockchainNetworkMismatch":{"cli":{"bitcoin":"Mainnet","monero":"Mainnet"},"asb":{"bitcoin":"Testnet","monero":"Stagenet"}}}}"#.to_string(); + let serialized = + serde_json::to_string(&Response::Error(Error::BlockchainNetworkMismatch { + cli: BlockchainNetwork { + bitcoin: bitcoin::Network::Bitcoin, + monero: monero::Network::Mainnet, + }, + asb: BlockchainNetwork { + bitcoin: bitcoin::Network::Testnet, + monero: monero::Network::Stagenet, + }, + })) + .unwrap(); + assert_eq!(error, serialized); + let error = r#"{"Error":"Other"}"#.to_string(); let serialized = serde_json::to_string(&Response::Error(Error::Other)).unwrap(); assert_eq!(error, serialized); diff --git a/swap/src/network/swarm.rs b/swap/src/network/swarm.rs index 27171392..5a27a8c0 100644 --- a/swap/src/network/swarm.rs +++ b/swap/src/network/swarm.rs @@ -2,12 +2,13 @@ use crate::network::transport; use crate::protocol::alice::event_loop::LatestRate; use crate::protocol::{alice, bob}; use crate::seed::Seed; -use crate::{monero, tor}; +use crate::{env, monero, tor}; use anyhow::Result; use libp2p::swarm::{NetworkBehaviour, SwarmBuilder}; use libp2p::{PeerId, Swarm}; use std::fmt::Debug; +#[allow(clippy::too_many_arguments)] pub fn alice( seed: &Seed, balance: monero::Amount, @@ -16,6 +17,7 @@ pub fn alice( max_buy: bitcoin::Amount, latest_rate: LR, resume_only: bool, + env_config: env::Config, ) -> Result>> where LR: LatestRate + Send + 'static + Debug, @@ -29,6 +31,7 @@ where max_buy, latest_rate, resume_only, + env_config, ), ) } diff --git a/swap/src/protocol/alice/behaviour.rs b/swap/src/protocol/alice/behaviour.rs index 7e036040..6d2ad548 100644 --- a/swap/src/protocol/alice/behaviour.rs +++ b/swap/src/protocol/alice/behaviour.rs @@ -1,8 +1,8 @@ -use crate::monero; use crate::network::quote::BidQuote; use crate::network::{encrypted_signature, quote, transfer_proof}; use crate::protocol::alice::event_loop::LatestRate; use crate::protocol::alice::{execution_setup, spot_price, State3}; +use crate::{env, monero}; use anyhow::{anyhow, Error}; use libp2p::request_response::{RequestId, ResponseChannel}; use libp2p::{NetworkBehaviour, PeerId}; @@ -88,6 +88,7 @@ where max_buy: bitcoin::Amount, latest_rate: LR, resume_only: bool, + env_config: env::Config, ) -> Self { Self { quote: quote::alice(), @@ -96,6 +97,7 @@ where lock_fee, min_buy, max_buy, + env_config, latest_rate, resume_only, ), diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index ae26d1f1..832f658c 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -211,7 +211,8 @@ where match error { Error::ResumeOnlyMode | Error::AmountBelowMinimum { .. } - | Error::AmountAboveMaximum { .. } => { + | Error::AmountAboveMaximum { .. } + | Error::BlockchainNetworkMismatch { .. } => { tracing::warn!(%peer, "Ignoring spot price request because: {}", error); } Error::BalanceTooLow { .. } diff --git a/swap/src/protocol/alice/spot_price.rs b/swap/src/protocol/alice/spot_price.rs index 81b0bdb8..43fcf600 100644 --- a/swap/src/protocol/alice/spot_price.rs +++ b/swap/src/protocol/alice/spot_price.rs @@ -1,9 +1,9 @@ -use crate::monero; use crate::network::cbor_request_response::CborCodec; use crate::network::spot_price; -use crate::network::spot_price::SpotPriceProtocol; +use crate::network::spot_price::{BlockchainNetwork, SpotPriceProtocol}; use crate::protocol::alice; use crate::protocol::alice::event_loop::LatestRate; +use crate::{env, monero}; use libp2p::request_response::{ ProtocolSupport, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, @@ -48,6 +48,8 @@ where #[behaviour(ignore)] max_buy: bitcoin::Amount, #[behaviour(ignore)] + env_config: env::Config, + #[behaviour(ignore)] latest_rate: LR, #[behaviour(ignore)] resume_only: bool, @@ -66,6 +68,7 @@ where lock_fee: monero::Amount, min_buy: bitcoin::Amount, max_buy: bitcoin::Amount, + env_config: env::Config, latest_rate: LR, resume_only: bool, ) -> Self { @@ -80,6 +83,7 @@ where lock_fee, min_buy, max_buy, + env_config, latest_rate, resume_only, } @@ -154,6 +158,19 @@ where } }; + let blockchain_network = BlockchainNetwork { + bitcoin: self.env_config.bitcoin_network, + monero: self.env_config.monero_network, + }; + + if request.blockchain_network != blockchain_network { + self.decline(peer, channel, Error::BlockchainNetworkMismatch { + cli: request.blockchain_network, + asb: blockchain_network, + }); + return; + } + if self.resume_only { self.decline(peer, channel, Error::ResumeOnlyMode); return; @@ -246,12 +263,15 @@ pub enum Error { balance: monero::Amount, buy: bitcoin::Amount, }, - #[error("Failed to fetch latest rate")] LatestRateFetchFailed(#[source] Box), - #[error("Failed to calculate quote: {0}")] SellQuoteCalculationFailed(#[source] anyhow::Error), + #[error("Blockchain networks did not match, we are on {asb:?}, but request from {cli:?}")] + BlockchainNetworkMismatch { + cli: spot_price::BlockchainNetwork, + asb: spot_price::BlockchainNetwork, + }, } impl Error { @@ -267,6 +287,12 @@ impl Error { buy: *buy, }, Error::BalanceTooLow { buy, .. } => spot_price::Error::BalanceTooLow { buy: *buy }, + Error::BlockchainNetworkMismatch { cli, asb } => { + spot_price::Error::BlockchainNetworkMismatch { + cli: *cli, + asb: *asb, + } + } Error::LatestRateFetchFailed(_) | Error::SellQuoteCalculationFailed(_) => { spot_price::Error::Other } @@ -278,6 +304,7 @@ impl Error { mod tests { use super::*; use crate::asb::Rate; + use crate::env::GetConfig; use crate::monero; use crate::network::test::{await_events_or_timeout, connect, new_swarm}; use crate::protocol::{alice, bob}; @@ -294,6 +321,7 @@ mod tests { max_buy: bitcoin::Amount::from_btc(0.01).unwrap(), rate: TestRate::default(), // 0.01 resume_only: false, + env_config: env::Testnet::get_config(), } } } @@ -305,9 +333,7 @@ mod tests { let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); let expected_xmr = monero::Amount::from_monero(1.0).unwrap(); - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_price((btc_to_swap, expected_xmr), expected_xmr) .await; } @@ -321,9 +347,7 @@ mod tests { let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::BalanceTooLow { balance: monero::Amount::ZERO, @@ -341,9 +365,7 @@ mod tests { let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); let expected_xmr = monero::Amount::from_monero(1.0).unwrap(); - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_price((btc_to_swap, expected_xmr), expected_xmr) .await; @@ -351,9 +373,7 @@ mod tests { .behaviour_mut() .update_balance(monero::Amount::ZERO); - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::BalanceTooLow { balance: monero::Amount::ZERO, @@ -376,10 +396,7 @@ mod tests { .await; let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); - - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::BalanceTooLow { balance, @@ -398,10 +415,7 @@ mod tests { SpotPriceTest::setup(AliceBehaviourValues::default().with_min_buy(min_buy)).await; let btc_to_swap = bitcoin::Amount::from_btc(0.0001).unwrap(); - - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::AmountBelowMinimum { buy: btc_to_swap, @@ -424,9 +438,7 @@ mod tests { let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::AmountAboveMaximum { buy: btc_to_swap, @@ -446,10 +458,7 @@ mod tests { SpotPriceTest::setup(AliceBehaviourValues::default().with_resume_only(true)).await; let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); - - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::ResumeOnlyMode, bob::spot_price::Error::NoSwapsAccepted, @@ -464,10 +473,7 @@ mod tests { .await; let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); - - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::LatestRateFetchFailed(Box::new(TestRateError {})), bob::spot_price::Error::Other, @@ -484,9 +490,7 @@ mod tests { let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); - let request = spot_price::Request { btc: btc_to_swap }; - - test.send_request(request); + test.construct_and_send_request(btc_to_swap); test.assert_error( alice::spot_price::Error::SellQuoteCalculationFailed(anyhow!( "Error text irrelevant, won't be checked here" @@ -496,6 +500,79 @@ mod tests { .await; } + #[tokio::test] + async fn given_alice_mainnnet_bob_testnet_then_network_mismatch_error() { + let mut test = SpotPriceTest::setup( + AliceBehaviourValues::default().with_env_config(env::Mainnet::get_config()), + ) + .await; + + let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); + test.construct_and_send_request(btc_to_swap); + test.assert_error( + alice::spot_price::Error::BlockchainNetworkMismatch { + cli: BlockchainNetwork { + bitcoin: bitcoin::Network::Testnet, + monero: monero::Network::Stagenet, + }, + asb: BlockchainNetwork { + bitcoin: bitcoin::Network::Bitcoin, + monero: monero::Network::Mainnet, + }, + }, + bob::spot_price::Error::BlockchainNetworkMismatch { + cli: BlockchainNetwork { + bitcoin: bitcoin::Network::Testnet, + monero: monero::Network::Stagenet, + }, + asb: BlockchainNetwork { + bitcoin: bitcoin::Network::Bitcoin, + monero: monero::Network::Mainnet, + }, + }, + ) + .await; + } + + #[tokio::test] + async fn given_alice_testnet_bob_mainnet_then_network_mismatch_error() { + let mut test = SpotPriceTest::setup(AliceBehaviourValues::default()).await; + + let btc_to_swap = bitcoin::Amount::from_btc(0.01).unwrap(); + let request = spot_price::Request { + btc: btc_to_swap, + blockchain_network: BlockchainNetwork { + bitcoin: bitcoin::Network::Bitcoin, + monero: monero::Network::Mainnet, + }, + }; + + test.send_request(request); + test.assert_error( + alice::spot_price::Error::BlockchainNetworkMismatch { + cli: BlockchainNetwork { + bitcoin: bitcoin::Network::Bitcoin, + monero: monero::Network::Mainnet, + }, + asb: BlockchainNetwork { + bitcoin: bitcoin::Network::Testnet, + monero: monero::Network::Stagenet, + }, + }, + bob::spot_price::Error::BlockchainNetworkMismatch { + cli: BlockchainNetwork { + bitcoin: bitcoin::Network::Bitcoin, + monero: monero::Network::Mainnet, + }, + asb: BlockchainNetwork { + bitcoin: bitcoin::Network::Testnet, + monero: monero::Network::Stagenet, + }, + }, + ) + .await; + } + struct SpotPriceTest { alice_swarm: Swarm>, bob_swarm: Swarm, @@ -511,6 +588,7 @@ mod tests { values.lock_fee, values.min_buy, values.max_buy, + values.env_config, values.rate.clone(), values.resume_only, ) @@ -526,6 +604,17 @@ mod tests { } } + pub fn construct_and_send_request(&mut self, btc_to_swap: bitcoin::Amount) { + let request = spot_price::Request { + btc: btc_to_swap, + blockchain_network: BlockchainNetwork { + bitcoin: bitcoin::Network::Testnet, + monero: monero::Network::Stagenet, + }, + }; + self.send_request(request); + } + pub fn send_request(&mut self, spot_price_request: spot_price::Request) { self.bob_swarm .behaviour_mut() @@ -588,6 +677,19 @@ mod tests { assert_eq!(balance1, balance2); assert_eq!(buy1, buy2); } + ( + alice::spot_price::Error::BlockchainNetworkMismatch { + cli: cli1, + asb: asb1, + }, + alice::spot_price::Error::BlockchainNetworkMismatch { + cli: cli2, + asb: asb2, + }, + ) => { + assert_eq!(cli1, cli2); + assert_eq!(asb1, asb2); + } ( alice::spot_price::Error::AmountBelowMinimum { .. }, alice::spot_price::Error::AmountBelowMinimum { .. }, @@ -640,6 +742,7 @@ mod tests { pub max_buy: bitcoin::Amount, pub rate: TestRate, // 0.01 pub resume_only: bool, + pub env_config: env::Config, } impl AliceBehaviourValues { @@ -672,6 +775,11 @@ mod tests { self.rate = rate; self } + + pub fn with_env_config(mut self, env_config: env::Config) -> AliceBehaviourValues { + self.env_config = env_config; + self + } } #[derive(Clone, Debug)] diff --git a/swap/src/protocol/bob/event_loop.rs b/swap/src/protocol/bob/event_loop.rs index d3aa2a29..4fe347bf 100644 --- a/swap/src/protocol/bob/event_loop.rs +++ b/swap/src/protocol/bob/event_loop.rs @@ -1,10 +1,10 @@ use crate::bitcoin::EncryptedSignature; use crate::network::quote::BidQuote; -use crate::network::spot_price::Response; +use crate::network::spot_price::{BlockchainNetwork, Response}; use crate::network::{encrypted_signature, spot_price}; use crate::protocol::bob; use crate::protocol::bob::{Behaviour, OutEvent, State0, State2}; -use crate::{bitcoin, monero}; +use crate::{bitcoin, env, monero}; use anyhow::{bail, Context, Result}; use futures::future::{BoxFuture, OptionFuture}; use futures::{FutureExt, StreamExt}; @@ -55,6 +55,7 @@ impl EventLoop { swarm: Swarm, alice_peer_id: PeerId, bitcoin_wallet: Arc, + env_config: env::Config, ) -> Result<(Self, EventLoopHandle)> { let execution_setup = bmrng::channel_with_timeout(1, Duration::from_secs(30)); let transfer_proof = bmrng::channel_with_timeout(1, Duration::from_secs(30)); @@ -85,6 +86,7 @@ impl EventLoop { encrypted_signature: encrypted_signature.0, spot_price: spot_price.0, quote: quote.0, + env_config, }; Ok((event_loop, handle)) @@ -242,6 +244,7 @@ pub struct EventLoopHandle { encrypted_signature: bmrng::RequestSender, spot_price: bmrng::RequestSender, quote: bmrng::RequestSender<(), BidQuote>, + env_config: env::Config, } impl EventLoopHandle { @@ -265,7 +268,13 @@ impl EventLoopHandle { pub async fn request_spot_price(&mut self, btc: bitcoin::Amount) -> Result { let response = self .spot_price - .send_receive(spot_price::Request { btc }) + .send_receive(spot_price::Request { + btc, + blockchain_network: BlockchainNetwork { + bitcoin: self.env_config.bitcoin_network, + monero: self.env_config.monero_network, + }, + }) .await?; match response { diff --git a/swap/src/protocol/bob/spot_price.rs b/swap/src/protocol/bob/spot_price.rs index 58d03643..072fdb2d 100644 --- a/swap/src/protocol/bob/spot_price.rs +++ b/swap/src/protocol/bob/spot_price.rs @@ -54,6 +54,12 @@ pub enum Error { #[error("Seller's XMR balance is currently too low to fulfill the swap request to buy {buy}, please try again later")] BalanceTooLow { buy: bitcoin::Amount }, + #[error("Seller blockchain network {asb:?} setup did not match your blockchain network setup {cli:?}")] + BlockchainNetworkMismatch { + cli: spot_price::BlockchainNetwork, + asb: spot_price::BlockchainNetwork, + }, + /// To be used for errors that cannot be explained on the CLI side (e.g. /// rate update problems on the seller side) #[error("Seller encountered a problem, please try again later.")] @@ -71,6 +77,9 @@ impl From for Error { Error::AmountAboveMaximum { max, buy } } spot_price::Error::BalanceTooLow { buy } => Error::BalanceTooLow { buy }, + spot_price::Error::BlockchainNetworkMismatch { cli, asb } => { + Error::BlockchainNetworkMismatch { cli, asb } + } spot_price::Error::Other => Error::Other, } } diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 52e1e6f5..3807cb94 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -239,6 +239,7 @@ async fn start_alice( max_buy, latest_rate, resume_only, + env_config, ) .unwrap(); swarm.listen_on(listen_address).unwrap(); @@ -458,6 +459,7 @@ impl BobParams { swarm, self.alice_peer_id, self.bitcoin_wallet.clone(), + self.env_config, ) } }