diff --git a/swap/src/asb/command.rs b/swap/src/asb/command.rs index a34ae43d..c29ad9d5 100644 --- a/swap/src/asb/command.rs +++ b/swap/src/asb/command.rs @@ -1,3 +1,5 @@ +use crate::monero::Amount; +use anyhow::Result; use std::path::PathBuf; #[derive(structopt::StructOpt, Debug)] @@ -16,6 +18,14 @@ pub struct Arguments { #[derive(structopt::StructOpt, Debug)] #[structopt(name = "xmr_btc-swap", about = "XMR BTC atomic swap")] pub enum Command { - Start, + Start { + #[structopt(long = "max-sell-xmr", help = "The maximum amount of XMR the ASB is willing to sell.", default_value="0.5", parse(try_from_str = parse_xmr))] + max_sell: Amount, + }, History, } + +fn parse_xmr(str: &str) -> Result { + let amount = Amount::parse_monero(str)?; + Ok(amount) +} diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index ed985d47..4bc1f845 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -79,7 +79,7 @@ async fn main() -> Result<()> { let wallet_data_dir = config.data.dir.join("wallet"); match opt.cmd { - Command::Start => { + Command::Start { max_sell } => { let seed = Seed::from_file_or_generate(&config.data.dir) .expect("Could not retrieve/initialize seed"); @@ -107,6 +107,7 @@ async fn main() -> Result<()> { Arc::new(monero_wallet), Arc::new(db), rate_service, + max_sell, ) .unwrap(); diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index e061d6bf..7c24f1d5 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -4,7 +4,7 @@ use crate::{ database::Database, execution_params::ExecutionParams, monero, - monero::BalanceTooLow, + monero::{Amount, BalanceTooLow}, network, network::{transport, TokioExecutor}, protocol::{ @@ -88,6 +88,7 @@ pub struct EventLoop { db: Arc, listen_address: Multiaddr, rate_service: RS, + max_sell: Amount, recv_encrypted_signature: broadcast::Sender, send_transfer_proof: mpsc::Receiver<(PeerId, TransferProof)>, @@ -102,6 +103,7 @@ impl EventLoop where RS: LatestRate, { + #[allow(clippy::too_many_arguments)] pub fn new( listen_address: Multiaddr, seed: Seed, @@ -110,6 +112,7 @@ where monero_wallet: Arc, db: Arc, rate_service: RS, + max_sell: Amount, ) -> Result<(Self, mpsc::Receiver>>)> { let identity = network::Seed::new(seed).derive_libp2p_identity(); let behaviour = Behaviour::default(); @@ -142,6 +145,7 @@ where send_transfer_proof: send_transfer_proof.receiver, send_transfer_proof_sender: send_transfer_proof.sender, swap_handle_sender: swap_handle.sender, + max_sell, }; Ok((event_loop, swap_handle.receiver)) } @@ -216,6 +220,13 @@ where let btc_amount = quote_request.btc_amount; let xmr_amount = rate.sell_quote(btc_amount)?; + if xmr_amount > self.max_sell { + anyhow!(MaximumSellAmountExceeded { + actual: xmr_amount, + max_sell: self.max_sell + }); + } + let xmr_balance = monero_wallet.get_balance().await?; let xmr_lock_fees = monero_wallet.static_tx_fee_estimate(); @@ -288,3 +299,10 @@ where Ok(()) } } + +#[derive(Debug, Clone, Copy, thiserror::Error)] +#[error("The amount {actual} exceeds the configured maximum sell amount of {max_sell} XMR")] +pub struct MaximumSellAmountExceeded { + pub max_sell: Amount, + pub actual: Amount, +} diff --git a/swap/tests/testutils/mod.rs b/swap/tests/testutils/mod.rs index 7619e18b..6fe0253e 100644 --- a/swap/tests/testutils/mod.rs +++ b/swap/tests/testutils/mod.rs @@ -384,6 +384,7 @@ where alice_monero_wallet.clone(), alice_db, fixed_rate::RateService::default(), + alice_starting_balances.xmr, ) .unwrap();