Add initial swap binary crate

In preparation for writing a fully fledged XMR/BTC swap client add a new crate
and initial binary with basic structopt cli implementation.

With this applied we can run the swap as Alice with `swap --as-alice` and run
the swap as Bob with `swap --sats 10000000`.
pull/10/head
Tobin C. Harding 4 years ago
parent 911ff396db
commit 330bd1f22c

@ -1,2 +1,2 @@
[workspace]
members = ["monero-harness", "xmr-btc"]
members = ["monero-harness", "xmr-btc", "swap"]

@ -0,0 +1,14 @@
[package]
name = "swap"
version = "0.1.0"
authors = ["CoBloX developers <team@coblox.tech>"]
edition = "2018"
description = "XMR/BTC trustless atomic swaps."
[dependencies]
anyhow = "1"
bitcoin = "0.25" # TODO: Upgrade other crates in this repo to use this version.
monero = "0.9"
structopt = "0.3"
tokio = { version = "0.2", features = ["rt-threaded", "macros"] }
xmr-btc = { path = "../xmr-btc" }

@ -0,0 +1,13 @@
//! Run an XMR/BTC swap in the role of Alice.
//! Alice holds XMR and wishes receive BTC.
use anyhow::Result;
use std::thread;
/// Entrypoint for an XMR/BTC swap in the role of Alice.
pub fn swap() -> Result<()> {
// Bob initiates the swap via network communication.
thread::park();
Ok(())
}

@ -0,0 +1,27 @@
//! Run an XMR/BTC swap in the role of Bob.
//! Bob holds BTC and wishes receive XMR.
use crate::SwapParams;
use anyhow::Result;
use xmr_btc::monero;
/// Request to swap `btc` with Alice.
///
/// Connects to a node running an instance in the role of Alice and requests to
/// swap `btc` i.e., this gets the rate from Alice for `btc`.
pub async fn request_swap_btc(_btc: ::bitcoin::Amount) -> Result<SwapParams> {
todo!("Get rate from Alice for this many btc")
}
/// Request to swap `xmr` with Alice.
///
/// Connects to a node running an instance in the role of Alice and requests to
/// swap `xmr` i.e., this gets the rate from Alice for `xmr`.
pub async fn request_swap_xmr(_xmr: monero::Amount) -> Result<SwapParams> {
todo!("Get rate from Alice for this many xmr")
}
/// XMR/BTC swap in the role of Bob.
pub fn swap(_: SwapParams) -> Result<()> {
todo!("Run the swap as Bob")
}

@ -0,0 +1,14 @@
#[derive(structopt::StructOpt, Debug)]
pub struct Options {
/// Run the swap as Alice.
#[structopt(long = "as-alice")]
pub as_alice: bool,
/// Run the swap as Bob and try to swap this many XMR (in piconero).
#[structopt(long = "picos")]
pub piconeros: Option<u64>,
/// Run the swap as Bob and try to swap this many BTC (in satoshi).
#[structopt(long = "sats")]
pub satoshis: Option<u64>,
}

@ -0,0 +1,12 @@
use xmr_btc::monero;
pub mod alice;
pub mod bob;
/// XMR/BTC swap parameters.
pub struct SwapParams {
/// Amount of BTC to swap.
pub btc: bitcoin::Amount,
/// Amount of XMR to swap.
pub xmr: monero::Amount,
}

@ -0,0 +1,85 @@
#![warn(
unused_extern_crates,
missing_debug_implementations,
missing_copy_implementations,
rust_2018_idioms,
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::fallible_impl_from,
clippy::cast_precision_loss,
clippy::cast_possible_wrap,
clippy::dbg_macro
)]
#![forbid(unsafe_code)]
mod cli;
use anyhow::{bail, Result};
use structopt::StructOpt;
use cli::Options;
use swap::{alice, bob, SwapParams};
use xmr_btc::monero;
#[tokio::main]
async fn main() -> Result<()> {
let opt = Options::from_args();
if opt.as_alice {
swap_as_alice(opt)?;
} else {
swap_as_bob(opt).await?;
}
Ok(())
}
fn swap_as_alice(opt: Options) -> Result<()> {
println!("running swap as Alice ...");
if opt.piconeros.is_some() || opt.satoshis.is_some() {
bail!("Alice cannot set the amount to swap via the cli");
}
let _ = alice::swap()?;
Ok(())
}
async fn swap_as_bob(opt: Options) -> Result<()> {
println!("running swap as Bob ...");
match (opt.piconeros, opt.satoshis) {
(Some(_), Some(_)) => bail!("Please supply only a single amount to swap"),
(None, None) => bail!("Please supply an amount to swap"),
_ => {}
}
assert_connection_to_alice()?;
let params = match (opt.piconeros, opt.satoshis) {
(Some(picos), _) => {
let xmr = monero::Amount::from_piconero(picos);
let params = bob::request_swap_xmr(xmr).await?;
confirm_amounts_with_user(params)?
}
(None, Some(sats)) => {
let btc = bitcoin::Amount::from_sat(sats);
let params = bob::request_swap_btc(btc).await?;
confirm_amounts_with_user(params)?
}
_ => unreachable!("error path done above"),
};
bob::swap(params)
}
fn assert_connection_to_alice() -> Result<()> {
todo!("assert connection to Alice")
}
fn confirm_amounts_with_user(_: SwapParams) -> Result<SwapParams> {
todo!("get user confirmation");
}
Loading…
Cancel
Save