2021-04-29 21:01:30 -04:00
use crate ::fs ::system_data_dir ;
2021-03-03 18:46:54 -05:00
use anyhow ::{ Context , Result } ;
2021-03-03 19:28:58 -05:00
use libp2p ::core ::Multiaddr ;
use libp2p ::PeerId ;
2021-04-29 21:01:30 -04:00
use std ::path ::{ Path , PathBuf } ;
2021-03-03 19:28:58 -05:00
use std ::str ::FromStr ;
2021-03-14 21:02:42 -04:00
use url ::Url ;
2020-11-05 19:10:22 -05:00
use uuid ::Uuid ;
2020-10-28 23:45:45 -04:00
2021-03-05 00:10:45 -05:00
// Port is assumed to be stagenet standard port 38081
pub const DEFAULT_STAGENET_MONERO_DAEMON_HOST : & str = " monero-stagenet.exan.tech " ;
2021-03-14 21:02:42 -04:00
pub const DEFAULT_ELECTRUM_HTTP_URL : & str = " https://blockstream.info/testnet/api/ " ;
const DEFAULT_ELECTRUM_RPC_URL : & str = " ssl://electrum.blockstream.info:60002 " ;
2021-04-21 21:33:36 -04:00
const DEFAULT_TOR_SOCKS5_PORT : & str = " 9050 " ;
2021-05-02 19:48:40 -04:00
// Bitcoin transactions should be confirmed within X blocks
const DEFAUL_BITCOIN_CONFIRMATION_TARGET : & str = " 3 " ;
2020-12-15 05:26:02 -05:00
#[ derive(structopt::StructOpt, Debug) ]
2021-03-25 23:31:14 -04:00
#[ structopt(name = " swap " , about = " CLI for swapping BTC for XMR " , author) ]
2021-02-10 17:47:42 -05:00
pub struct Arguments {
2021-01-26 21:33:32 -05:00
#[ structopt(
2021-03-14 21:02:42 -04:00
long = " --data-dir " ,
help = " Provide the data directory path to be used to store application data " ,
default_value
2021-01-26 21:33:32 -05:00
) ]
2021-03-14 21:02:42 -04:00
pub data : Data ,
2020-12-15 05:26:02 -05:00
2021-02-28 20:19:05 -05:00
#[ structopt(long, help = " Activate debug logging. " ) ]
pub debug : bool ,
2020-12-15 05:26:02 -05:00
#[ structopt(subcommand) ]
2021-03-02 06:07:48 -05:00
pub cmd : Command ,
2020-12-15 05:26:02 -05:00
}
2020-10-15 18:14:39 -04:00
#[ derive(structopt::StructOpt, Debug) ]
2020-12-15 05:26:02 -05:00
pub enum Command {
2021-03-05 00:16:18 -05:00
/// Start a XMR for BTC swap
2020-12-04 00:27:17 -05:00
BuyXmr {
2021-04-01 00:13:29 -04:00
#[ structopt(long = " seller-peer-id " , help = " The seller's peer id " ) ]
2021-03-30 00:40:59 -04:00
alice_peer_id : PeerId ,
2021-04-01 00:13:29 -04:00
#[ structopt(long = " seller-addr " , help = " The seller's multiaddress " ) ]
2021-04-05 21:05:36 -04:00
alice_multiaddr : Multiaddr ,
2021-03-02 06:07:48 -05:00
2021-03-11 02:16:00 -05:00
#[ structopt(long = " electrum-rpc " ,
help = " Provide the Bitcoin Electrum RPC URL " ,
default_value = DEFAULT_ELECTRUM_RPC_URL
) ]
electrum_rpc_url : Url ,
2021-03-14 21:02:42 -04:00
2021-03-05 00:00:52 -05:00
#[ structopt(flatten) ]
monero_params : MoneroParams ,
2021-04-21 21:33:36 -04:00
#[ structopt(long = " tor-socks5-port " , help = " Your local Tor socks5 proxy port " , default_value = DEFAULT_TOR_SOCKS5_PORT) ]
tor_socks5_port : u16 ,
2021-05-02 19:48:40 -04:00
#[ structopt(long = " bitcoin-target-block " , help = " Within how many blocks should the Bitcoin transactions be confirmed. " , default_value = DEFAUL_BITCOIN_CONFIRMATION_TARGET) ]
bitcoin_target_block : usize ,
2020-10-28 23:45:45 -04:00
} ,
2021-03-05 00:16:18 -05:00
/// Show a list of past ongoing and completed swaps
2020-11-05 00:55:30 -05:00
History ,
2021-03-05 00:16:18 -05:00
/// Resume a swap
2021-02-25 22:44:48 -05:00
Resume {
2021-03-05 00:16:18 -05:00
#[ structopt(
long = " swap-id " ,
help = " The swap id can be retrieved using the history subcommand "
) ]
2020-12-20 22:43:44 -05:00
swap_id : Uuid ,
2021-04-01 00:13:29 -04:00
#[ structopt(long = " seller-addr " , help = " The seller's multiaddress " ) ]
2021-04-05 21:05:36 -04:00
alice_multiaddr : Multiaddr ,
2020-12-18 01:39:04 -05:00
2021-03-11 02:16:00 -05:00
#[ structopt(long = " electrum-rpc " ,
help = " Provide the Bitcoin Electrum RPC URL " ,
default_value = DEFAULT_ELECTRUM_RPC_URL
) ]
electrum_rpc_url : Url ,
2021-03-14 21:02:42 -04:00
2021-03-05 00:00:52 -05:00
#[ structopt(flatten) ]
monero_params : MoneroParams ,
2021-04-21 21:33:36 -04:00
#[ structopt(long = " tor-socks5-port " , help = " Your local Tor socks5 proxy port " , default_value = DEFAULT_TOR_SOCKS5_PORT) ]
tor_socks5_port : u16 ,
2021-05-02 19:48:40 -04:00
#[ structopt(long = " bitcoin-target-block " , help = " Within how many blocks should the Bitcoin transactions be confirmed. " , default_value = DEFAUL_BITCOIN_CONFIRMATION_TARGET) ]
bitcoin_target_block : usize ,
2020-11-05 19:10:22 -05:00
} ,
2021-03-05 00:16:18 -05:00
/// Try to cancel an ongoing swap (expert users only)
2021-02-25 22:44:48 -05:00
Cancel {
2021-03-05 00:16:18 -05:00
#[ structopt(
long = " swap-id " ,
help = " The swap id can be retrieved using the history subcommand "
) ]
2021-02-01 00:25:33 -05:00
swap_id : Uuid ,
2021-02-01 06:32:54 -05:00
#[ structopt(short, long) ]
force : bool ,
2021-03-14 21:02:42 -04:00
2021-03-11 02:16:00 -05:00
#[ structopt(long = " electrum-rpc " ,
help = " Provide the Bitcoin Electrum RPC URL " ,
default_value = DEFAULT_ELECTRUM_RPC_URL
) ]
electrum_rpc_url : Url ,
2021-05-02 19:48:40 -04:00
#[ structopt(long = " bitcoin-target-block " , help = " Within how many blocks should the Bitcoin transactions be confirmed. " , default_value = DEFAUL_BITCOIN_CONFIRMATION_TARGET) ]
bitcoin_target_block : usize ,
2021-02-01 00:25:33 -05:00
} ,
2021-03-05 00:16:18 -05:00
/// Try to cancel a swap and refund my BTC (expert users only)
2021-02-25 22:44:48 -05:00
Refund {
2021-03-05 00:16:18 -05:00
#[ structopt(
long = " swap-id " ,
help = " The swap id can be retrieved using the history subcommand "
) ]
2021-02-01 00:10:43 -05:00
swap_id : Uuid ,
2021-02-01 06:32:54 -05:00
#[ structopt(short, long) ]
force : bool ,
2021-03-14 21:02:42 -04:00
2021-03-11 02:16:00 -05:00
#[ structopt(long = " electrum-rpc " ,
help = " Provide the Bitcoin Electrum RPC URL " ,
default_value = DEFAULT_ELECTRUM_RPC_URL
) ]
electrum_rpc_url : Url ,
2021-05-02 19:48:40 -04:00
#[ structopt(long = " bitcoin-target-block " , help = " Within how many blocks should the Bitcoin transactions be confirmed. " , default_value = DEFAUL_BITCOIN_CONFIRMATION_TARGET) ]
bitcoin_target_block : usize ,
2021-02-01 00:10:43 -05:00
} ,
}
2021-02-28 18:53:43 -05:00
2021-03-05 00:00:52 -05:00
#[ derive(structopt::StructOpt, Debug) ]
pub struct MoneroParams {
2021-03-05 00:16:18 -05:00
#[ structopt(long = " receive-address " ,
help = " Provide the monero address where you would like to receive monero " ,
parse ( try_from_str = parse_monero_address )
) ]
2021-03-05 00:00:52 -05:00
pub receive_monero_address : monero ::Address ,
2021-03-05 00:10:45 -05:00
#[ structopt(
2021-03-05 00:16:18 -05:00
long = " monero-daemon-host " ,
help = " Specify to connect to a monero daemon of your choice " ,
default_value = DEFAULT_STAGENET_MONERO_DAEMON_HOST
2021-03-05 00:10:45 -05:00
) ]
pub monero_daemon_host : String ,
2021-03-05 00:00:52 -05:00
}
2021-03-14 21:02:42 -04:00
#[ derive(Clone, Debug) ]
pub struct Data ( pub PathBuf ) ;
2021-04-29 04:50:49 -04:00
/// Default location for storing data for the CLI
2021-04-29 21:01:30 -04:00
// Takes the default system data-dir and adds a `/cli`
2021-03-14 21:02:42 -04:00
impl Default for Data {
fn default ( ) -> Self {
2021-04-29 04:50:49 -04:00
Data (
2021-04-29 21:01:30 -04:00
system_data_dir ( )
. map ( | proj_dir | Path ::join ( & proj_dir , " cli " ) )
2021-04-29 04:50:49 -04:00
. expect ( " computed valid path for data dir " ) ,
)
2021-03-14 21:02:42 -04:00
}
}
impl FromStr for Data {
type Err = core ::convert ::Infallible ;
fn from_str ( s : & str ) -> Result < Self , Self ::Err > {
Ok ( Data ( PathBuf ::from_str ( s ) ? ) )
}
}
impl ToString for Data {
fn to_string ( & self ) -> String {
self . 0
. clone ( )
. into_os_string ( )
. into_string ( )
. expect ( " default datadir to be convertible to string " )
}
}
2021-03-03 18:46:54 -05:00
fn parse_monero_address ( s : & str ) -> Result < monero ::Address > {
monero ::Address ::from_str ( s ) . with_context ( | | {
format! (
" Failed to parse {} as a monero address, please make sure it is a valid address " ,
s
)
} )
}