mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-12-27 00:19:30 -05:00
Merge pull request #34 from comit-network/no-config
Add CLI config and remove conditional compile flags
This commit is contained in:
commit
d5c7afd7f8
.github/workflows
swap
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -36,6 +36,7 @@ jobs:
|
|||||||
cargo tomlfmt -d -p Cargo.toml
|
cargo tomlfmt -d -p Cargo.toml
|
||||||
cargo tomlfmt -d -p xmr-btc/Cargo.toml
|
cargo tomlfmt -d -p xmr-btc/Cargo.toml
|
||||||
cargo tomlfmt -d -p monero-harness/Cargo.toml
|
cargo tomlfmt -d -p monero-harness/Cargo.toml
|
||||||
|
cargo tomlfmt -d -p swap/Cargo.toml
|
||||||
|
|
||||||
- name: Check code formatting
|
- name: Check code formatting
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
|
@ -32,7 +32,7 @@ structopt = "0.3"
|
|||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
time = "0.2"
|
time = "0.2"
|
||||||
tokio = { version = "0.2", features = ["rt-threaded", "time", "macros", "sync"] }
|
tokio = { version = "0.2", features = ["rt-threaded", "time", "macros", "sync"] }
|
||||||
torut = { version = "0.1", optional = true }
|
torut = { version = "0.1" }
|
||||||
tracing = { version = "0.1", features = ["attributes"] }
|
tracing = { version = "0.1", features = ["attributes"] }
|
||||||
tracing-core = "0.1"
|
tracing-core = "0.1"
|
||||||
tracing-futures = { version = "0.2", features = ["std-future", "futures-03"] }
|
tracing-futures = { version = "0.2", features = ["std-future", "futures-03"] }
|
||||||
@ -48,7 +48,3 @@ port_check = "0.1"
|
|||||||
spectral = "0.6"
|
spectral = "0.6"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
testcontainers = "0.10"
|
testcontainers = "0.10"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
tor = ["torut"]
|
|
||||||
|
@ -28,7 +28,8 @@ use crate::{
|
|||||||
network::{
|
network::{
|
||||||
peer_tracker::{self, PeerTracker},
|
peer_tracker::{self, PeerTracker},
|
||||||
request_response::AliceToBob,
|
request_response::AliceToBob,
|
||||||
transport, TokioExecutor,
|
transport::SwapTransport,
|
||||||
|
TokioExecutor,
|
||||||
},
|
},
|
||||||
SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
|
SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
|
||||||
};
|
};
|
||||||
@ -43,7 +44,8 @@ pub async fn swap(
|
|||||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||||
monero_wallet: Arc<monero::Wallet>,
|
monero_wallet: Arc<monero::Wallet>,
|
||||||
listen: Multiaddr,
|
listen: Multiaddr,
|
||||||
local_port: Option<u16>,
|
transport: SwapTransport,
|
||||||
|
behaviour: Alice,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
struct Network {
|
struct Network {
|
||||||
swarm: Arc<Mutex<Swarm>>,
|
swarm: Arc<Mutex<Swarm>>,
|
||||||
@ -67,7 +69,6 @@ pub async fn swap(
|
|||||||
|
|
||||||
// TODO: For retry, use `backoff::ExponentialBackoff` in production as opposed
|
// TODO: For retry, use `backoff::ExponentialBackoff` in production as opposed
|
||||||
// to `ConstantBackoff`.
|
// to `ConstantBackoff`.
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ReceiveBitcoinRedeemEncsig for Network {
|
impl ReceiveBitcoinRedeemEncsig for Network {
|
||||||
async fn receive_bitcoin_redeem_encsig(&mut self) -> xmr_btc::bitcoin::EncryptedSignature {
|
async fn receive_bitcoin_redeem_encsig(&mut self) -> xmr_btc::bitcoin::EncryptedSignature {
|
||||||
@ -96,7 +97,7 @@ pub async fn swap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut swarm = new_swarm(listen, local_port)?;
|
let mut swarm = new_swarm(listen, transport, behaviour)?;
|
||||||
let message0: bob::Message0;
|
let message0: bob::Message0;
|
||||||
let mut state0: Option<alice::State0> = None;
|
let mut state0: Option<alice::State0> = None;
|
||||||
let mut last_amounts: Option<SwapAmounts> = None;
|
let mut last_amounts: Option<SwapAmounts> = None;
|
||||||
@ -230,30 +231,11 @@ pub async fn swap(
|
|||||||
|
|
||||||
pub type Swarm = libp2p::Swarm<Alice>;
|
pub type Swarm = libp2p::Swarm<Alice>;
|
||||||
|
|
||||||
fn new_swarm(listen: Multiaddr, port: Option<u16>) -> Result<Swarm> {
|
fn new_swarm(listen: Multiaddr, transport: SwapTransport, behaviour: Alice) -> Result<Swarm> {
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
|
|
||||||
let behaviour = Alice::default();
|
|
||||||
|
|
||||||
let local_key_pair = behaviour.identity();
|
|
||||||
let local_peer_id = behaviour.peer_id();
|
let local_peer_id = behaviour.peer_id();
|
||||||
|
|
||||||
let transport;
|
|
||||||
#[cfg(feature = "tor")]
|
|
||||||
{
|
|
||||||
transport = match port {
|
|
||||||
Some(port) => transport::build(local_key_pair, Some((listen.clone(), port)))?,
|
|
||||||
None => anyhow::bail!("Must supply local port"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "tor"))]
|
|
||||||
{
|
|
||||||
transport = match port {
|
|
||||||
None => transport::build(local_key_pair)?,
|
|
||||||
Some(_) => anyhow::bail!("local port should not be provided for non-tor usage"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
|
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
|
||||||
.executor(Box::new(TokioExecutor {
|
.executor(Box::new(TokioExecutor {
|
||||||
handle: tokio::runtime::Handle::current(),
|
handle: tokio::runtime::Handle::current(),
|
||||||
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use backoff::{backoff::Constant as ConstantBackoff, future::FutureOperation as _};
|
use backoff::{backoff::Constant as ConstantBackoff, future::FutureOperation as _};
|
||||||
use bitcoin::{util::psbt::PartiallySignedTransaction, Address, Transaction};
|
use bitcoin::{util::psbt::PartiallySignedTransaction, Address, Transaction};
|
||||||
use bitcoin_harness::{bitcoind_rpc::PsbtBase64, Bitcoind};
|
use bitcoin_harness::bitcoind_rpc::PsbtBase64;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
use xmr_btc::bitcoin::{
|
use xmr_btc::bitcoin::{
|
||||||
@ -20,8 +20,8 @@ pub const TX_LOCK_MINE_TIMEOUT: u64 = 3600;
|
|||||||
pub struct Wallet(pub bitcoin_harness::Wallet);
|
pub struct Wallet(pub bitcoin_harness::Wallet);
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
pub async fn new(name: &str, url: &Url) -> Result<Self> {
|
pub async fn new(name: &str, url: Url) -> Result<Self> {
|
||||||
let wallet = bitcoin_harness::Wallet::new(name, url.clone()).await?;
|
let wallet = bitcoin_harness::Wallet::new(name, url).await?;
|
||||||
|
|
||||||
Ok(Self(wallet))
|
Ok(Self(wallet))
|
||||||
}
|
}
|
||||||
@ -46,22 +46,6 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn make_wallet(
|
|
||||||
name: &str,
|
|
||||||
bitcoind: &Bitcoind<'_>,
|
|
||||||
fund_amount: Amount,
|
|
||||||
) -> Result<Wallet> {
|
|
||||||
let wallet = Wallet::new(name, &bitcoind.node_url).await?;
|
|
||||||
let buffer = Amount::from_btc(1.0).unwrap();
|
|
||||||
let amount = fund_amount + buffer;
|
|
||||||
|
|
||||||
let address = wallet.0.new_address().await.unwrap();
|
|
||||||
|
|
||||||
bitcoind.mint(address, amount).await.unwrap();
|
|
||||||
|
|
||||||
Ok(wallet)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl BuildTxLockPsbt for Wallet {
|
impl BuildTxLockPsbt for Wallet {
|
||||||
async fn build_tx_lock_psbt(
|
async fn build_tx_lock_psbt(
|
||||||
|
@ -27,7 +27,8 @@ use crate::{
|
|||||||
monero,
|
monero,
|
||||||
network::{
|
network::{
|
||||||
peer_tracker::{self, PeerTracker},
|
peer_tracker::{self, PeerTracker},
|
||||||
transport, TokioExecutor,
|
transport::SwapTransport,
|
||||||
|
TokioExecutor,
|
||||||
},
|
},
|
||||||
Cmd, Rsp, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
|
Cmd, Rsp, SwapAmounts, PUNISH_TIMELOCK, REFUND_TIMELOCK,
|
||||||
};
|
};
|
||||||
@ -38,6 +39,7 @@ use xmr_btc::{
|
|||||||
monero::CreateWalletForOutput,
|
monero::CreateWalletForOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn swap(
|
pub async fn swap(
|
||||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||||
monero_wallet: Arc<monero::Wallet>,
|
monero_wallet: Arc<monero::Wallet>,
|
||||||
@ -45,6 +47,8 @@ pub async fn swap(
|
|||||||
addr: Multiaddr,
|
addr: Multiaddr,
|
||||||
mut cmd_tx: Sender<Cmd>,
|
mut cmd_tx: Sender<Cmd>,
|
||||||
mut rsp_rx: Receiver<Rsp>,
|
mut rsp_rx: Receiver<Rsp>,
|
||||||
|
transport: SwapTransport,
|
||||||
|
behaviour: Bob,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
struct Network(Swarm);
|
struct Network(Swarm);
|
||||||
|
|
||||||
@ -80,7 +84,7 @@ pub async fn swap(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut swarm = new_swarm()?;
|
let mut swarm = new_swarm(transport, behaviour)?;
|
||||||
|
|
||||||
libp2p::Swarm::dial_addr(&mut swarm, addr)?;
|
libp2p::Swarm::dial_addr(&mut swarm, addr)?;
|
||||||
let alice = match swarm.next().await {
|
let alice = match swarm.next().await {
|
||||||
@ -202,23 +206,9 @@ pub async fn swap(
|
|||||||
|
|
||||||
pub type Swarm = libp2p::Swarm<Bob>;
|
pub type Swarm = libp2p::Swarm<Bob>;
|
||||||
|
|
||||||
fn new_swarm() -> Result<Swarm> {
|
fn new_swarm(transport: SwapTransport, behaviour: Bob) -> Result<Swarm> {
|
||||||
let behaviour = Bob::default();
|
|
||||||
|
|
||||||
let local_key_pair = behaviour.identity();
|
|
||||||
let local_peer_id = behaviour.peer_id();
|
let local_peer_id = behaviour.peer_id();
|
||||||
|
|
||||||
let transport = {
|
|
||||||
#[cfg(feature = "tor")]
|
|
||||||
{
|
|
||||||
transport::build(local_key_pair, None)?
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "tor"))]
|
|
||||||
{
|
|
||||||
transport::build(local_key_pair)?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
|
let swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, local_peer_id.clone())
|
||||||
.executor(Box::new(TokioExecutor {
|
.executor(Box::new(TokioExecutor {
|
||||||
handle: tokio::runtime::Handle::current(),
|
handle: tokio::runtime::Handle::current(),
|
||||||
|
@ -1,19 +1,36 @@
|
|||||||
|
use libp2p::core::Multiaddr;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[derive(structopt::StructOpt, Debug)]
|
#[derive(structopt::StructOpt, Debug)]
|
||||||
pub struct Options {
|
#[structopt(name = "xmr-btc-swap", about = "Trustless XMR BTC swaps")]
|
||||||
/// Run the swap as Alice.
|
pub enum Options {
|
||||||
#[structopt(long = "as-alice")]
|
Alice {
|
||||||
pub as_alice: bool,
|
#[structopt(default_value = "http://127.0.0.1:8332", long = "bitcoind")]
|
||||||
|
bitcoind_url: Url,
|
||||||
|
|
||||||
/// Run the swap as Bob and try to swap this many XMR (in piconero).
|
#[structopt(default_value = "http://127.0.0.1:18083", long = "monerod")]
|
||||||
#[structopt(long = "picos")]
|
monerod_url: Url,
|
||||||
pub piconeros: Option<u64>,
|
|
||||||
|
|
||||||
/// Run the swap as Bob and try to swap this many BTC (in satoshi).
|
#[structopt(default_value = "/ip4/127.0.0.1/tcp/9876", long = "listen-addr")]
|
||||||
#[structopt(long = "sats")]
|
listen_addr: Multiaddr,
|
||||||
pub satoshis: Option<u64>,
|
|
||||||
|
|
||||||
/// Alice's onion multitaddr (only required for Bob, Alice will autogenerate
|
#[structopt(long = "tor-port")]
|
||||||
/// one)
|
tor_port: Option<u16>,
|
||||||
#[structopt(long)]
|
},
|
||||||
pub alice_address: Option<String>,
|
Bob {
|
||||||
|
#[structopt(long = "sats")]
|
||||||
|
satoshis: u64,
|
||||||
|
|
||||||
|
#[structopt(long = "alice-addr")]
|
||||||
|
alice_addr: Multiaddr,
|
||||||
|
|
||||||
|
#[structopt(default_value = "http://127.0.0.1:8332", long = "bitcoind")]
|
||||||
|
bitcoind_url: Url,
|
||||||
|
|
||||||
|
#[structopt(default_value = "http://127.0.0.1:18083", long = "monerod")]
|
||||||
|
monerod_url: Url,
|
||||||
|
|
||||||
|
#[structopt(long = "tor")]
|
||||||
|
tor: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ pub mod bob;
|
|||||||
pub mod monero;
|
pub mod monero;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
#[cfg(feature = "tor")]
|
|
||||||
pub mod tor;
|
pub mod tor;
|
||||||
|
|
||||||
const REFUND_TIMELOCK: u32 = 10; // Relative timelock, this is number of blocks. TODO: What should it be?
|
const REFUND_TIMELOCK: u32 = 10; // Relative timelock, this is number of blocks. TODO: What should it be?
|
||||||
|
170
swap/src/main.rs
170
swap/src/main.rs
@ -12,105 +12,125 @@
|
|||||||
)]
|
)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::Result;
|
||||||
use futures::{channel::mpsc, StreamExt};
|
use futures::{channel::mpsc, StreamExt};
|
||||||
use libp2p::Multiaddr;
|
use libp2p::Multiaddr;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use std::{io, io::Write, process, sync::Arc};
|
use std::{io, io::Write, process, sync::Arc};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
use swap::{
|
||||||
|
alice,
|
||||||
|
alice::Alice,
|
||||||
|
bitcoin, bob,
|
||||||
|
bob::Bob,
|
||||||
|
monero,
|
||||||
|
network::transport::{build, build_tor, SwapTransport},
|
||||||
|
Cmd, Rsp, SwapAmounts,
|
||||||
|
};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod trace;
|
mod trace;
|
||||||
|
|
||||||
use cli::Options;
|
use cli::Options;
|
||||||
use swap::{alice, bitcoin, bob, monero, Cmd, Rsp, SwapAmounts};
|
|
||||||
|
|
||||||
// TODO: Add root seed file instead of generating new seed each run.
|
// TODO: Add root seed file instead of generating new seed each run.
|
||||||
|
|
||||||
// TODO: Add a config file with these in it.
|
|
||||||
// Alice's address and port until we have a config file.
|
|
||||||
pub const PORT: u16 = 9876; // Arbitrarily chosen.
|
|
||||||
pub const ADDR: &str = "127.0.0.1";
|
|
||||||
pub const BITCOIND_JSON_RPC_URL: &str = "http://127.0.0.1:8332";
|
|
||||||
pub const MONERO_WALLET_RPC_PORT: u16 = 18083;
|
|
||||||
|
|
||||||
#[cfg(feature = "tor")]
|
|
||||||
pub const TOR_PORT: u16 = PORT + 1;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let opt = Options::from_args();
|
let opt = Options::from_args();
|
||||||
|
|
||||||
trace::init_tracing(LevelFilter::Debug)?;
|
trace::init_tracing(LevelFilter::Debug)?;
|
||||||
|
|
||||||
#[cfg(feature = "tor")]
|
match opt {
|
||||||
let (addr, _ac) = {
|
Options::Alice {
|
||||||
let tor_secret_key = torut::onion::TorSecretKeyV3::generate();
|
bitcoind_url,
|
||||||
let onion_address = tor_secret_key
|
monerod_url,
|
||||||
.public()
|
listen_addr,
|
||||||
.get_onion_address()
|
tor_port,
|
||||||
.get_address_without_dot_onion();
|
} => {
|
||||||
(
|
info!("running swap node as Alice ...");
|
||||||
format!("/onion3/{}:{}", onion_address, TOR_PORT),
|
|
||||||
create_tor_service(tor_secret_key).await?,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[cfg(not(feature = "tor"))]
|
|
||||||
let addr = format!("/ip4/{}/tcp/{}", ADDR, PORT);
|
|
||||||
|
|
||||||
let alice: Multiaddr = addr.parse().expect("failed to parse Alice's address");
|
let behaviour = Alice::default();
|
||||||
|
let local_key_pair = behaviour.identity();
|
||||||
|
|
||||||
if opt.as_alice {
|
let (listen_addr, _ac, transport) = match tor_port {
|
||||||
info!("running swap node as Alice ...");
|
Some(tor_port) => {
|
||||||
|
let tor_secret_key = torut::onion::TorSecretKeyV3::generate();
|
||||||
|
let onion_address = tor_secret_key
|
||||||
|
.public()
|
||||||
|
.get_onion_address()
|
||||||
|
.get_address_without_dot_onion();
|
||||||
|
let onion_address_string = format!("/onion3/{}:{}", onion_address, tor_port);
|
||||||
|
let addr: Multiaddr = onion_address_string.parse()?;
|
||||||
|
let ac = create_tor_service(tor_secret_key, tor_port).await?;
|
||||||
|
let transport = build_tor(local_key_pair, Some((addr.clone(), tor_port)))?;
|
||||||
|
(addr, Some(ac), transport)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let transport = build(local_key_pair)?;
|
||||||
|
(listen_addr, None, transport)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if opt.piconeros.is_some() || opt.satoshis.is_some() {
|
let bitcoin_wallet = bitcoin::Wallet::new("alice", bitcoind_url)
|
||||||
bail!("Alice cannot set the amount to swap via the cli");
|
.await
|
||||||
|
.expect("failed to create bitcoin wallet");
|
||||||
|
let bitcoin_wallet = Arc::new(bitcoin_wallet);
|
||||||
|
|
||||||
|
let monero_wallet = Arc::new(monero::Wallet::new(monerod_url));
|
||||||
|
|
||||||
|
swap_as_alice(
|
||||||
|
bitcoin_wallet,
|
||||||
|
monero_wallet,
|
||||||
|
listen_addr,
|
||||||
|
transport,
|
||||||
|
behaviour,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
|
Options::Bob {
|
||||||
|
alice_addr,
|
||||||
|
satoshis,
|
||||||
|
bitcoind_url,
|
||||||
|
monerod_url,
|
||||||
|
tor,
|
||||||
|
} => {
|
||||||
|
info!("running swap node as Bob ...");
|
||||||
|
|
||||||
let url = Url::parse(BITCOIND_JSON_RPC_URL).expect("failed to parse url");
|
let behaviour = Bob::default();
|
||||||
let bitcoin_wallet = bitcoin::Wallet::new("alice", &url)
|
let local_key_pair = behaviour.identity();
|
||||||
.await
|
|
||||||
.expect("failed to create bitcoin wallet");
|
|
||||||
let bitcoin_wallet = Arc::new(bitcoin_wallet);
|
|
||||||
|
|
||||||
let monero_wallet = Arc::new(monero::Wallet::localhost(MONERO_WALLET_RPC_PORT));
|
let transport = match tor {
|
||||||
|
true => build_tor(local_key_pair, None)?,
|
||||||
|
false => build(local_key_pair)?,
|
||||||
|
};
|
||||||
|
|
||||||
swap_as_alice(bitcoin_wallet, monero_wallet, alice.clone()).await?;
|
let bitcoin_wallet = bitcoin::Wallet::new("bob", bitcoind_url)
|
||||||
} else {
|
.await
|
||||||
info!("running swap node as Bob ...");
|
.expect("failed to create bitcoin wallet");
|
||||||
|
let bitcoin_wallet = Arc::new(bitcoin_wallet);
|
||||||
|
|
||||||
let alice = match opt.alice_address {
|
let monero_wallet = Arc::new(monero::Wallet::new(monerod_url));
|
||||||
Some(addr) => addr,
|
|
||||||
None => bail!("Address required to dial"),
|
|
||||||
};
|
|
||||||
let alice = multiaddr(&alice)?;
|
|
||||||
|
|
||||||
let url = Url::parse(BITCOIND_JSON_RPC_URL).expect("failed to parse url");
|
swap_as_bob(
|
||||||
let bitcoin_wallet = bitcoin::Wallet::new("bob", &url)
|
bitcoin_wallet,
|
||||||
.await
|
monero_wallet,
|
||||||
.expect("failed to create bitcoin wallet");
|
satoshis,
|
||||||
let bitcoin_wallet = Arc::new(bitcoin_wallet);
|
alice_addr,
|
||||||
|
transport,
|
||||||
let monero_wallet = Arc::new(monero::Wallet::localhost(MONERO_WALLET_RPC_PORT));
|
behaviour,
|
||||||
|
)
|
||||||
match (opt.piconeros, opt.satoshis) {
|
.await?;
|
||||||
(Some(_), Some(_)) => bail!("Please supply only a single amount to swap"),
|
}
|
||||||
(None, None) => bail!("Please supply an amount to swap"),
|
|
||||||
(Some(_picos), _) => todo!("support starting with picos"),
|
|
||||||
(None, Some(sats)) => {
|
|
||||||
swap_as_bob(bitcoin_wallet, monero_wallet, sats, alice).await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tor")]
|
|
||||||
async fn create_tor_service(
|
async fn create_tor_service(
|
||||||
tor_secret_key: torut::onion::TorSecretKeyV3,
|
tor_secret_key: torut::onion::TorSecretKeyV3,
|
||||||
|
tor_port: u16,
|
||||||
) -> Result<swap::tor::AuthenticatedConnection> {
|
) -> Result<swap::tor::AuthenticatedConnection> {
|
||||||
// TODO use configurable ports for tor connection
|
// TODO use configurable ports for tor connection
|
||||||
let mut authenticated_connection = swap::tor::UnauthenticatedConnection::default()
|
let mut authenticated_connection = swap::tor::UnauthenticatedConnection::default()
|
||||||
@ -119,7 +139,7 @@ async fn create_tor_service(
|
|||||||
tracing::info!("Tor authenticated.");
|
tracing::info!("Tor authenticated.");
|
||||||
|
|
||||||
authenticated_connection
|
authenticated_connection
|
||||||
.add_service(TOR_PORT, &tor_secret_key)
|
.add_service(tor_port, &tor_secret_key)
|
||||||
.await?;
|
.await?;
|
||||||
tracing::info!("Tor service added.");
|
tracing::info!("Tor service added.");
|
||||||
|
|
||||||
@ -130,15 +150,10 @@ async fn swap_as_alice(
|
|||||||
bitcoin_wallet: Arc<swap::bitcoin::Wallet>,
|
bitcoin_wallet: Arc<swap::bitcoin::Wallet>,
|
||||||
monero_wallet: Arc<swap::monero::Wallet>,
|
monero_wallet: Arc<swap::monero::Wallet>,
|
||||||
addr: Multiaddr,
|
addr: Multiaddr,
|
||||||
|
transport: SwapTransport,
|
||||||
|
behaviour: Alice,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
#[cfg(not(feature = "tor"))]
|
alice::swap(bitcoin_wallet, monero_wallet, addr, transport, behaviour).await
|
||||||
{
|
|
||||||
alice::swap(bitcoin_wallet, monero_wallet, addr, None).await
|
|
||||||
}
|
|
||||||
#[cfg(feature = "tor")]
|
|
||||||
{
|
|
||||||
alice::swap(bitcoin_wallet, monero_wallet, addr, Some(PORT)).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn swap_as_bob(
|
async fn swap_as_bob(
|
||||||
@ -146,6 +161,8 @@ async fn swap_as_bob(
|
|||||||
monero_wallet: Arc<swap::monero::Wallet>,
|
monero_wallet: Arc<swap::monero::Wallet>,
|
||||||
sats: u64,
|
sats: u64,
|
||||||
alice: Multiaddr,
|
alice: Multiaddr,
|
||||||
|
transport: SwapTransport,
|
||||||
|
behaviour: Bob,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (cmd_tx, mut cmd_rx) = mpsc::channel(1);
|
let (cmd_tx, mut cmd_rx) = mpsc::channel(1);
|
||||||
let (mut rsp_tx, rsp_rx) = mpsc::channel(1);
|
let (mut rsp_tx, rsp_rx) = mpsc::channel(1);
|
||||||
@ -156,6 +173,8 @@ async fn swap_as_bob(
|
|||||||
alice,
|
alice,
|
||||||
cmd_tx,
|
cmd_tx,
|
||||||
rsp_rx,
|
rsp_rx,
|
||||||
|
transport,
|
||||||
|
behaviour,
|
||||||
));
|
));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -207,10 +226,3 @@ fn verify(amounts: SwapAmounts) -> Rsp {
|
|||||||
fn is_yes(s: &str) -> bool {
|
fn is_yes(s: &str) -> bool {
|
||||||
matches!(s, "y" | "Y" | "yes" | "YES" | "Yes")
|
matches!(s, "y" | "Y" | "yes" | "YES" | "Yes")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiaddr(s: &str) -> Result<Multiaddr> {
|
|
||||||
let addr = s
|
|
||||||
.parse()
|
|
||||||
.with_context(|| format!("failed to parse multiaddr: {}", s))?;
|
|
||||||
Ok(addr)
|
|
||||||
}
|
|
||||||
|
@ -5,6 +5,7 @@ use monero::{Address, Network, PrivateKey};
|
|||||||
use monero_harness::rpc::wallet;
|
use monero_harness::rpc::wallet;
|
||||||
use std::{str::FromStr, time::Duration};
|
use std::{str::FromStr, time::Duration};
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
pub use xmr_btc::monero::{
|
pub use xmr_btc::monero::{
|
||||||
Amount, CreateWalletForOutput, InsufficientFunds, PrivateViewKey, PublicKey, PublicViewKey,
|
Amount, CreateWalletForOutput, InsufficientFunds, PrivateViewKey, PublicKey, PublicViewKey,
|
||||||
Transfer, TransferProof, TxHash, WatchForTransfer, *,
|
Transfer, TransferProof, TxHash, WatchForTransfer, *,
|
||||||
@ -13,8 +14,8 @@ pub use xmr_btc::monero::{
|
|||||||
pub struct Wallet(pub wallet::Client);
|
pub struct Wallet(pub wallet::Client);
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
pub fn localhost(port: u16) -> Self {
|
pub fn new(url: Url) -> Self {
|
||||||
Self(wallet::Client::localhost(port))
|
Self(wallet::Client::new(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the balance of the primary account.
|
/// Get the balance of the primary account.
|
||||||
|
@ -18,7 +18,6 @@ use libp2p::{
|
|||||||
/// - DNS name resolution
|
/// - DNS name resolution
|
||||||
/// - authentication via noise
|
/// - authentication via noise
|
||||||
/// - multiplexing via yamux or mplex
|
/// - multiplexing via yamux or mplex
|
||||||
#[cfg(not(feature = "tor"))]
|
|
||||||
pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
|
pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
|
||||||
use libp2p::tcp::TokioTcpConfig;
|
use libp2p::tcp::TokioTcpConfig;
|
||||||
|
|
||||||
@ -40,14 +39,12 @@ pub fn build(id_keys: identity::Keypair) -> Result<SwapTransport> {
|
|||||||
|
|
||||||
Ok(transport)
|
Ok(transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a libp2p transport with Tor and with the following features:
|
/// Builds a libp2p transport with Tor and with the following features:
|
||||||
/// - TCP connection over the Tor network
|
/// - TCP connection over the Tor network
|
||||||
/// - DNS name resolution
|
/// - DNS name resolution
|
||||||
/// - authentication via noise
|
/// - authentication via noise
|
||||||
/// - multiplexing via yamux or mplex
|
/// - multiplexing via yamux or mplex
|
||||||
#[cfg(feature = "tor")]
|
pub fn build_tor(
|
||||||
pub fn build(
|
|
||||||
id_keys: identity::Keypair,
|
id_keys: identity::Keypair,
|
||||||
address_port_pair: Option<(libp2p::core::Multiaddr, u16)>,
|
address_port_pair: Option<(libp2p::core::Multiaddr, u16)>,
|
||||||
) -> Result<SwapTransport> {
|
) -> Result<SwapTransport> {
|
||||||
|
@ -5,7 +5,7 @@ mod e2e_test {
|
|||||||
use libp2p::Multiaddr;
|
use libp2p::Multiaddr;
|
||||||
use monero_harness::Monero;
|
use monero_harness::Monero;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use swap::{alice, bob};
|
use swap::{alice, bob, network::transport::build};
|
||||||
use testcontainers::clients::Cli;
|
use testcontainers::clients::Cli;
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
use tracing_subscriber::util::SubscriberInitExt;
|
||||||
|
|
||||||
@ -37,12 +37,12 @@ mod e2e_test {
|
|||||||
let xmr_bob = 0;
|
let xmr_bob = 0;
|
||||||
|
|
||||||
let alice_btc_wallet = Arc::new(
|
let alice_btc_wallet = Arc::new(
|
||||||
swap::bitcoin::Wallet::new("alice", &bitcoind.node_url)
|
swap::bitcoin::Wallet::new("alice", bitcoind.node_url.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let bob_btc_wallet = Arc::new(
|
let bob_btc_wallet = Arc::new(
|
||||||
swap::bitcoin::Wallet::new("bob", &bitcoind.node_url)
|
swap::bitcoin::Wallet::new("bob", bitcoind.node_url.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
@ -57,15 +57,20 @@ mod e2e_test {
|
|||||||
let alice_xmr_wallet = Arc::new(swap::monero::Wallet(monero.alice_wallet_rpc_client()));
|
let alice_xmr_wallet = Arc::new(swap::monero::Wallet(monero.alice_wallet_rpc_client()));
|
||||||
let bob_xmr_wallet = Arc::new(swap::monero::Wallet(monero.bob_wallet_rpc_client()));
|
let bob_xmr_wallet = Arc::new(swap::monero::Wallet(monero.bob_wallet_rpc_client()));
|
||||||
|
|
||||||
|
let alice_behaviour = alice::Alice::default();
|
||||||
|
let alice_transport = build(alice_behaviour.identity()).unwrap();
|
||||||
let alice_swap = alice::swap(
|
let alice_swap = alice::swap(
|
||||||
alice_btc_wallet.clone(),
|
alice_btc_wallet.clone(),
|
||||||
alice_xmr_wallet.clone(),
|
alice_xmr_wallet.clone(),
|
||||||
alice_multiaddr.clone(),
|
alice_multiaddr.clone(),
|
||||||
None,
|
alice_transport,
|
||||||
|
alice_behaviour,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (cmd_tx, mut _cmd_rx) = mpsc::channel(1);
|
let (cmd_tx, mut _cmd_rx) = mpsc::channel(1);
|
||||||
let (mut rsp_tx, rsp_rx) = mpsc::channel(1);
|
let (mut rsp_tx, rsp_rx) = mpsc::channel(1);
|
||||||
|
let bob_behaviour = bob::Bob::default();
|
||||||
|
let bob_transport = build(bob_behaviour.identity()).unwrap();
|
||||||
let bob_swap = bob::swap(
|
let bob_swap = bob::swap(
|
||||||
bob_btc_wallet.clone(),
|
bob_btc_wallet.clone(),
|
||||||
bob_xmr_wallet.clone(),
|
bob_xmr_wallet.clone(),
|
||||||
@ -73,6 +78,8 @@ mod e2e_test {
|
|||||||
alice_multiaddr,
|
alice_multiaddr,
|
||||||
cmd_tx,
|
cmd_tx,
|
||||||
rsp_rx,
|
rsp_rx,
|
||||||
|
bob_transport,
|
||||||
|
bob_behaviour,
|
||||||
);
|
);
|
||||||
|
|
||||||
// automate the verification step by accepting any amounts sent over by Alice
|
// automate the verification step by accepting any amounts sent over by Alice
|
||||||
|
Loading…
Reference in New Issue
Block a user