Only pass btc amount to CLI

The CLI requests a quote to nectar to know how much xmr it can get.
Also align terminology with the sequence diagram.
This commit is contained in:
Franck Royer 2021-02-15 13:01:38 +11:00
parent 144da75270
commit 2dbd43e2c0
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
8 changed files with 77 additions and 105 deletions

View File

@ -35,7 +35,6 @@ use swap::{
protocol::{ protocol::{
bob, bob,
bob::{cancel::CancelError, Builder}, bob::{cancel::CancelError, Builder},
SwapAmounts,
}, },
seed::Seed, seed::Seed,
trace::init_tracing, trace::init_tracing,
@ -89,21 +88,15 @@ async fn main() -> Result<()> {
alice_peer_id, alice_peer_id,
alice_addr, alice_addr,
send_bitcoin, send_bitcoin,
receive_monero,
} => { } => {
let swap_amounts = SwapAmounts {
btc: send_bitcoin,
xmr: receive_monero,
};
let (bitcoin_wallet, monero_wallet) = let (bitcoin_wallet, monero_wallet) =
init_wallets(config, bitcoin_network, monero_network).await?; init_wallets(config, bitcoin_network, monero_network).await?;
let swap_id = Uuid::new_v4(); let swap_id = Uuid::new_v4();
info!( info!(
"Swap sending {} and receiving {} started with ID {}", "Swap buy XMR with {} started with ID {}",
send_bitcoin, receive_monero, swap_id send_bitcoin, swap_id
); );
let bob_factory = Builder::new( let bob_factory = Builder::new(
@ -116,7 +109,7 @@ async fn main() -> Result<()> {
alice_peer_id, alice_peer_id,
execution_params, execution_params,
); );
let (swap, event_loop) = bob_factory.with_init_params(swap_amounts).build().await?; let (swap, event_loop) = bob_factory.with_init_params(send_bitcoin).build().await?;
tokio::spawn(async move { event_loop.run().await }); tokio::spawn(async move { event_loop.run().await });
bob::run(swap).await?; bob::run(swap).await?;

View File

@ -1,4 +1,4 @@
use crate::{bitcoin, monero}; use crate::bitcoin;
use libp2p::{core::Multiaddr, PeerId}; use libp2p::{core::Multiaddr, PeerId};
use std::path::PathBuf; use std::path::PathBuf;
use uuid::Uuid; use uuid::Uuid;
@ -28,9 +28,6 @@ pub enum Command {
#[structopt(long = "send-btc", help = "Bitcoin amount as floating point nr without denomination (e.g. 1.25)", parse(try_from_str = parse_btc))] #[structopt(long = "send-btc", help = "Bitcoin amount as floating point nr without denomination (e.g. 1.25)", parse(try_from_str = parse_btc))]
send_bitcoin: bitcoin::Amount, send_bitcoin: bitcoin::Amount,
#[structopt(long = "receive-xmr", help = "Monero amount as floating point nr without denomination (e.g. 125.1)", parse(try_from_str = parse_xmr))]
receive_monero: monero::Amount,
}, },
History, History,
Resume(Resume), Resume(Resume),
@ -92,8 +89,3 @@ fn parse_btc(str: &str) -> anyhow::Result<bitcoin::Amount> {
let amount = bitcoin::Amount::from_str_in(str, ::bitcoin::Denomination::Bitcoin)?; let amount = bitcoin::Amount::from_str_in(str, ::bitcoin::Denomination::Bitcoin)?;
Ok(amount) Ok(amount)
} }
fn parse_xmr(str: &str) -> anyhow::Result<monero::Amount> {
let amount = monero::Amount::parse_monero(str)?;
Ok(amount)
}

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
monero::TransferProof, monero::TransferProof,
protocol::{bob, bob::BobState, SwapAmounts}, protocol::{bob, bob::BobState},
}; };
use ::bitcoin::hashes::core::fmt::Display; use ::bitcoin::hashes::core::fmt::Display;
use monero_harness::rpc::wallet::BlockHeight; use monero_harness::rpc::wallet::BlockHeight;
@ -9,10 +9,10 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub enum Bob { pub enum Bob {
Started { Started {
state0: bob::State0, #[serde(with = "::bitcoin::util::amount::serde::as_sat")]
amounts: SwapAmounts, btc_amount: bitcoin::Amount,
}, },
Negotiated { ExecutionSetupDone {
state2: bob::State2, state2: bob::State2,
}, },
BtcLocked { BtcLocked {
@ -46,8 +46,8 @@ pub enum BobEndState {
impl From<BobState> for Bob { impl From<BobState> for Bob {
fn from(bob_state: BobState) -> Self { fn from(bob_state: BobState) -> Self {
match bob_state { match bob_state {
BobState::Started { state0, amounts } => Bob::Started { state0, amounts }, BobState::Started { btc_amount } => Bob::Started { btc_amount },
BobState::Negotiated(state2) => Bob::Negotiated { state2 }, BobState::ExecutionSetupDone(state2) => Bob::ExecutionSetupDone { state2 },
BobState::BtcLocked(state3) => Bob::BtcLocked { state3 }, BobState::BtcLocked(state3) => Bob::BtcLocked { state3 },
BobState::XmrLockProofReceived { BobState::XmrLockProofReceived {
state, state,
@ -78,8 +78,8 @@ impl From<BobState> for Bob {
impl From<Bob> for BobState { impl From<Bob> for BobState {
fn from(db_state: Bob) -> Self { fn from(db_state: Bob) -> Self {
match db_state { match db_state {
Bob::Started { state0, amounts } => BobState::Started { state0, amounts }, Bob::Started { btc_amount } => BobState::Started { btc_amount },
Bob::Negotiated { state2 } => BobState::Negotiated(state2), Bob::ExecutionSetupDone { state2 } => BobState::ExecutionSetupDone(state2),
Bob::BtcLocked { state3 } => BobState::BtcLocked(state3), Bob::BtcLocked { state3 } => BobState::BtcLocked(state3),
Bob::XmrLockProofReceived { Bob::XmrLockProofReceived {
state, state,
@ -109,7 +109,7 @@ impl Display for Bob {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Bob::Started { .. } => write!(f, "Started"), Bob::Started { .. } => write!(f, "Started"),
Bob::Negotiated { .. } => f.write_str("Negotiated"), Bob::ExecutionSetupDone { .. } => f.write_str("Execution setup done"),
Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"), Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Bob::XmrLockProofReceived { .. } => { Bob::XmrLockProofReceived { .. } => {
f.write_str("XMR lock transaction transfer proof received") f.write_str("XMR lock transaction transfer proof received")

View File

@ -25,7 +25,7 @@ use tracing::{debug, error, trace, warn};
use uuid::Uuid; use uuid::Uuid;
// TODO: Use dynamic // TODO: Use dynamic
const RATE: u32 = 100; pub const RATE: u32 = 100;
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct MpscChannels<T> { pub struct MpscChannels<T> {

View File

@ -9,12 +9,11 @@ use crate::{
peer_tracker::{self, PeerTracker}, peer_tracker::{self, PeerTracker},
transport::build, transport::build,
}, },
protocol::{alice, alice::TransferProof, bob, SwapAmounts}, protocol::{alice, alice::TransferProof, bob},
seed::Seed, seed::Seed,
}; };
use anyhow::{bail, Error, Result}; use anyhow::{bail, Error, Result};
use libp2p::{core::Multiaddr, identity::Keypair, NetworkBehaviour, PeerId}; use libp2p::{core::Multiaddr, identity::Keypair, NetworkBehaviour, PeerId};
use rand::rngs::OsRng;
use std::sync::Arc; use std::sync::Arc;
use tracing::{debug, info}; use tracing::{debug, info};
use uuid::Uuid; use uuid::Uuid;
@ -69,7 +68,7 @@ pub struct Builder {
enum InitParams { enum InitParams {
None, None,
New { swap_amounts: SwapAmounts }, New { btc_amount: bitcoin::Amount },
} }
impl Builder { impl Builder {
@ -101,19 +100,17 @@ impl Builder {
} }
} }
pub fn with_init_params(self, swap_amounts: SwapAmounts) -> Self { pub fn with_init_params(self, btc_amount: bitcoin::Amount) -> Self {
Self { Self {
init_params: InitParams::New { swap_amounts }, init_params: InitParams::New { btc_amount },
..self ..self
} }
} }
pub async fn build(self) -> Result<(bob::Swap, bob::EventLoop)> { pub async fn build(self) -> Result<(bob::Swap, bob::EventLoop)> {
match self.init_params { match self.init_params {
InitParams::New { swap_amounts } => { InitParams::New { btc_amount } => {
let initial_state = self let initial_state = BobState::Started { btc_amount };
.make_initial_state(swap_amounts.btc, swap_amounts.xmr, self.execution_params)
.await?;
let (event_loop, event_loop_handle) = self.init_event_loop()?; let (event_loop, event_loop_handle) = self.init_event_loop()?;
@ -175,31 +172,6 @@ impl Builder {
self.bitcoin_wallet.clone(), self.bitcoin_wallet.clone(),
) )
} }
async fn make_initial_state(
&self,
btc_to_swap: bitcoin::Amount,
xmr_to_swap: monero::Amount,
execution_params: ExecutionParams,
) -> Result<BobState> {
let amounts = SwapAmounts {
btc: btc_to_swap,
xmr: xmr_to_swap,
};
let refund_address = self.bitcoin_wallet.new_address().await?;
let state0 = bob::State0::new(
&mut OsRng,
btc_to_swap,
xmr_to_swap,
execution_params.bitcoin_cancel_timelock,
execution_params.bitcoin_punish_timelock,
refund_address,
execution_params.monero_finality_confirmations,
);
Ok(BobState::Started { state0, amounts })
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -11,7 +11,6 @@ use crate::{
protocol::{ protocol::{
alice::{Message1, Message3}, alice::{Message1, Message3},
bob::{EncryptedSignature, Message0, Message2, Message4}, bob::{EncryptedSignature, Message0, Message2, Message4},
SwapAmounts,
}, },
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
@ -25,10 +24,9 @@ use std::fmt;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum BobState { pub enum BobState {
Started { Started {
state0: State0, btc_amount: bitcoin::Amount,
amounts: SwapAmounts,
}, },
Negotiated(State2), ExecutionSetupDone(State2),
BtcLocked(State3), BtcLocked(State3),
XmrLockProofReceived { XmrLockProofReceived {
state: State3, state: State3,
@ -53,8 +51,8 @@ pub enum BobState {
impl fmt::Display for BobState { impl fmt::Display for BobState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
BobState::Started { .. } => write!(f, "started"), BobState::Started { .. } => write!(f, "quote has been requested"),
BobState::Negotiated(..) => write!(f, "negotiated"), BobState::ExecutionSetupDone(..) => write!(f, "execution setup done"),
BobState::BtcLocked(..) => write!(f, "btc is locked"), BobState::BtcLocked(..) => write!(f, "btc is locked"),
BobState::XmrLockProofReceived { .. } => { BobState::XmrLockProofReceived { .. } => {
write!(f, "XMR lock transaction transfer proof received") write!(f, "XMR lock transaction transfer proof received")

View File

@ -4,13 +4,11 @@ use crate::{
database::{Database, Swap}, database::{Database, Swap},
execution_params::ExecutionParams, execution_params::ExecutionParams,
monero, monero,
protocol::{ protocol::bob::{self, event_loop::EventLoopHandle, state::*, QuoteRequest},
bob::{self, event_loop::EventLoopHandle, state::*, QuoteRequest},
SwapAmounts,
},
}; };
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use async_recursion::async_recursion; use async_recursion::async_recursion;
use rand::rngs::OsRng;
use std::sync::Arc; use std::sync::Arc;
use tokio::select; use tokio::select;
use tracing::info; use tracing::info;
@ -67,12 +65,20 @@ async fn run_until_internal(
Ok(state) Ok(state)
} else { } else {
match state { match state {
BobState::Started { state0, amounts } => { BobState::Started { btc_amount } => {
let bitcoin_refund_address = bitcoin_wallet.new_address().await?;
event_loop_handle.dial().await?; event_loop_handle.dial().await?;
let state2 = negotiate(state0, amounts, &mut event_loop_handle).await?; let state2 = request_quote_and_setup(
btc_amount,
&mut event_loop_handle,
execution_params,
bitcoin_refund_address,
)
.await?;
let state = BobState::Negotiated(state2); let state = BobState::ExecutionSetupDone(state2);
let db_state = state.clone().into(); let db_state = state.clone().into();
db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?; db.insert_latest_state(swap_id, Swap::Bob(db_state)).await?;
run_until_internal( run_until_internal(
@ -87,7 +93,7 @@ async fn run_until_internal(
) )
.await .await
} }
BobState::Negotiated(state2) => { BobState::ExecutionSetupDone(state2) => {
// Do not lock Bitcoin if not connected to Alice. // Do not lock Bitcoin if not connected to Alice.
event_loop_handle.dial().await?; event_loop_handle.dial().await?;
// Alice and Bob have exchanged info // Alice and Bob have exchanged info
@ -368,21 +374,27 @@ async fn run_until_internal(
} }
} }
pub async fn negotiate( pub async fn request_quote_and_setup(
state0: crate::protocol::bob::state::State0, btc_amount: bitcoin::Amount,
amounts: SwapAmounts,
event_loop_handle: &mut EventLoopHandle, event_loop_handle: &mut EventLoopHandle,
execution_params: ExecutionParams,
bitcoin_refund_address: bitcoin::Address,
) -> Result<bob::state::State2> { ) -> Result<bob::state::State2> {
tracing::trace!("Starting negotiate");
event_loop_handle event_loop_handle
.send_quote_request(QuoteRequest { .send_quote_request(QuoteRequest { btc_amount })
btc_amount: amounts.btc,
})
.await?; .await?;
// TODO: Use this once Bob's CLI is modified to only pass xmr amount in let quote_response = event_loop_handle.recv_quote_response().await?;
// argument.
let _quote_response = event_loop_handle.recv_quote_response().await?; let state0 = State0::new(
&mut OsRng,
btc_amount,
quote_response.xmr_amount,
execution_params.bitcoin_cancel_timelock,
execution_params.bitcoin_punish_timelock,
bitcoin_refund_address,
execution_params.monero_finality_confirmations,
);
let state2 = event_loop_handle.execution_setup(state0).await?; let state2 = event_loop_handle.execution_setup(state0).await?;

View File

@ -12,7 +12,12 @@ use swap::{
execution_params, execution_params,
execution_params::{ExecutionParams, GetExecutionParams}, execution_params::{ExecutionParams, GetExecutionParams},
monero, monero,
protocol::{alice, alice::AliceState, bob, bob::BobState, SwapAmounts}, protocol::{
alice,
alice::{event_loop::RATE, AliceState},
bob,
bob::BobState,
},
seed::Seed, seed::Seed,
}; };
use tempfile::tempdir; use tempfile::tempdir;
@ -66,7 +71,8 @@ impl BobEventLoopJoinHandle {
pub struct AliceEventLoopJoinHandle(JoinHandle<()>); pub struct AliceEventLoopJoinHandle(JoinHandle<()>);
pub struct TestContext { pub struct TestContext {
swap_amounts: SwapAmounts, btc_amount: bitcoin::Amount,
xmr_amount: monero::Amount,
alice_starting_balances: StartingBalances, alice_starting_balances: StartingBalances,
alice_bitcoin_wallet: Arc<bitcoin::Wallet>, alice_bitcoin_wallet: Arc<bitcoin::Wallet>,
@ -84,7 +90,7 @@ impl TestContext {
let (swap, event_loop) = self let (swap, event_loop) = self
.bob_params .bob_params
.builder() .builder()
.with_init_params(self.swap_amounts) .with_init_params(self.btc_amount)
.build() .build()
.await .await
.unwrap(); .unwrap();
@ -116,7 +122,7 @@ impl TestContext {
let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap(); let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap();
assert_eq!( assert_eq!(
btc_balance_after_swap, btc_balance_after_swap,
self.alice_starting_balances.btc + self.swap_amounts.btc self.alice_starting_balances.btc + self.btc_amount
- bitcoin::Amount::from_sat(bitcoin::TX_FEE) - bitcoin::Amount::from_sat(bitcoin::TX_FEE)
); );
@ -126,7 +132,7 @@ impl TestContext {
.get_balance() .get_balance()
.await .await
.unwrap(); .unwrap();
assert!(xmr_balance_after_swap <= self.alice_starting_balances.xmr - self.swap_amounts.xmr); assert!(xmr_balance_after_swap <= self.alice_starting_balances.xmr - self.xmr_amount);
} }
pub async fn assert_alice_refunded(&mut self) { pub async fn assert_alice_refunded(&mut self) {
@ -155,7 +161,7 @@ impl TestContext {
.get_balance() .get_balance()
.await .await
.unwrap(); .unwrap();
assert_eq!(xmr_balance_after_swap, self.swap_amounts.xmr); assert_eq!(xmr_balance_after_swap, self.xmr_amount);
} }
pub async fn assert_alice_punished(&self, state: AliceState) { pub async fn assert_alice_punished(&self, state: AliceState) {
@ -164,7 +170,7 @@ impl TestContext {
let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap(); let btc_balance_after_swap = self.alice_bitcoin_wallet.as_ref().balance().await.unwrap();
assert_eq!( assert_eq!(
btc_balance_after_swap, btc_balance_after_swap,
self.alice_starting_balances.btc + self.swap_amounts.btc self.alice_starting_balances.btc + self.btc_amount
- bitcoin::Amount::from_sat(2 * bitcoin::TX_FEE) - bitcoin::Amount::from_sat(2 * bitcoin::TX_FEE)
); );
@ -174,7 +180,7 @@ impl TestContext {
.get_balance() .get_balance()
.await .await
.unwrap(); .unwrap();
assert!(xmr_balance_after_swap <= self.alice_starting_balances.xmr - self.swap_amounts.xmr); assert!(xmr_balance_after_swap <= self.alice_starting_balances.xmr - self.xmr_amount);
} }
pub async fn assert_bob_redeemed(&self, state: BobState) { pub async fn assert_bob_redeemed(&self, state: BobState) {
@ -193,7 +199,7 @@ impl TestContext {
let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap(); let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap();
assert_eq!( assert_eq!(
btc_balance_after_swap, btc_balance_after_swap,
self.bob_starting_balances.btc - self.swap_amounts.btc - lock_tx_bitcoin_fee self.bob_starting_balances.btc - self.btc_amount - lock_tx_bitcoin_fee
); );
// Ensure that Bob's balance is refreshed as we use a newly created wallet // Ensure that Bob's balance is refreshed as we use a newly created wallet
@ -206,7 +212,7 @@ impl TestContext {
let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap(); let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap();
assert_eq!( assert_eq!(
xmr_balance_after_swap, xmr_balance_after_swap,
self.bob_starting_balances.xmr + self.swap_amounts.xmr self.bob_starting_balances.xmr + self.xmr_amount
); );
} }
@ -258,7 +264,7 @@ impl TestContext {
let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap(); let btc_balance_after_swap = self.bob_bitcoin_wallet.as_ref().balance().await.unwrap();
assert_eq!( assert_eq!(
btc_balance_after_swap, btc_balance_after_swap,
self.bob_starting_balances.btc - self.swap_amounts.btc - lock_tx_bitcoin_fee self.bob_starting_balances.btc - self.btc_amount - lock_tx_bitcoin_fee
); );
let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap(); let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap();
@ -280,13 +286,11 @@ where
let (monero, containers) = testutils::init_containers(&cli).await; let (monero, containers) = testutils::init_containers(&cli).await;
let swap_amounts = SwapAmounts { let btc_amount = bitcoin::Amount::from_sat(1_000_000);
btc: bitcoin::Amount::from_sat(1_000_000), let xmr_amount = monero::Amount::from_monero(btc_amount.as_btc() * RATE as f64).unwrap();
xmr: monero::Amount::from_piconero(1_000_000_000_000),
};
let alice_starting_balances = StartingBalances { let alice_starting_balances = StartingBalances {
xmr: swap_amounts.xmr * 10, xmr: xmr_amount * 10,
btc: bitcoin::Amount::ZERO, btc: bitcoin::Amount::ZERO,
}; };
@ -311,7 +315,7 @@ where
let bob_starting_balances = StartingBalances { let bob_starting_balances = StartingBalances {
xmr: monero::Amount::ZERO, xmr: monero::Amount::ZERO,
btc: swap_amounts.btc * 10, btc: btc_amount * 10,
}; };
let (bob_bitcoin_wallet, bob_monero_wallet) = init_test_wallets( let (bob_bitcoin_wallet, bob_monero_wallet) = init_test_wallets(
@ -350,7 +354,8 @@ where
}; };
let test = TestContext { let test = TestContext {
swap_amounts, btc_amount,
xmr_amount,
alice_starting_balances, alice_starting_balances,
alice_bitcoin_wallet, alice_bitcoin_wallet,
alice_monero_wallet, alice_monero_wallet,