Network check upon spot price request

pull/490/head
Daniel Karzel 3 years ago
parent 02974811ad
commit af60d3bb54
No known key found for this signature in database
GPG Key ID: 30C3FC2E438ADB6E

@ -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<u32>,
#[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<u64>,
#[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 {

@ -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 {

@ -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(

@ -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,

@ -1,5 +1,4 @@
use crate::bitcoin::{CancelTimelock, PunishTimelock};
use crate::monero;
use std::cmp::max;
use std::time::Duration;
use time::NumericalStdDurationShort;

@ -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<monero::Network> 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<Network> 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();

@ -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(),

@ -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);

@ -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<LR>(
seed: &Seed,
balance: monero::Amount,
@ -16,6 +17,7 @@ pub fn alice<LR>(
max_buy: bitcoin::Amount,
latest_rate: LR,
resume_only: bool,
env_config: env::Config,
) -> Result<Swarm<alice::Behaviour<LR>>>
where
LR: LatestRate + Send + 'static + Debug,
@ -29,6 +31,7 @@ where
max_buy,
latest_rate,
resume_only,
env_config,
),
)
}

@ -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,
),

@ -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 { .. }

@ -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<dyn std::error::Error + Send + 'static>),
#[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<alice::spot_price::Behaviour<TestRate>>,
bob_swarm: Swarm<spot_price::Behaviour>,
@ -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)]

@ -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<Behaviour>,
alice_peer_id: PeerId,
bitcoin_wallet: Arc<bitcoin::Wallet>,
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<EncryptedSignature, ()>,
spot_price: bmrng::RequestSender<spot_price::Request, spot_price::Response>,
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<monero::Amount> {
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 {

@ -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<spot_price::Error> 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,
}
}

@ -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,
)
}
}

Loading…
Cancel
Save