mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Merge #265
265: Replace quote with spot-price protocol r=thomaseizinger a=thomaseizinger This is essentially functionally equivalent but includes some cleanups by removing a layer of abstraction: `spot_price::Behaviour` is now just a type-alias for a request-response behaviour. Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
commit
d1363d130c
@ -1,5 +1,6 @@
|
|||||||
pub mod peer_tracker;
|
pub mod peer_tracker;
|
||||||
pub mod request_response;
|
pub mod request_response;
|
||||||
|
pub mod spot_price;
|
||||||
pub mod transport;
|
pub mod transport;
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
|
@ -13,21 +13,12 @@ pub const TIMEOUT: u64 = 3600; // One hour.
|
|||||||
/// Message receive buffer.
|
/// Message receive buffer.
|
||||||
pub const BUF_SIZE: usize = 1024 * 1024;
|
pub const BUF_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
|
||||||
pub struct Swap;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct TransferProofProtocol;
|
pub struct TransferProofProtocol;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct EncryptedSignatureProtocol;
|
pub struct EncryptedSignatureProtocol;
|
||||||
|
|
||||||
impl ProtocolName for Swap {
|
|
||||||
fn protocol_name(&self) -> &[u8] {
|
|
||||||
b"/comit/xmr/btc/swap/1.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProtocolName for TransferProofProtocol {
|
impl ProtocolName for TransferProofProtocol {
|
||||||
fn protocol_name(&self) -> &[u8] {
|
fn protocol_name(&self) -> &[u8] {
|
||||||
b"/comit/xmr/btc/transfer_proof/1.0.0"
|
b"/comit/xmr/btc/transfer_proof/1.0.0"
|
||||||
|
66
swap/src/network/spot_price.rs
Normal file
66
swap/src/network/spot_price.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use crate::{bitcoin, monero, network::request_response::CborCodec};
|
||||||
|
use libp2p::{
|
||||||
|
core::ProtocolName,
|
||||||
|
request_response::{
|
||||||
|
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub type OutEvent = RequestResponseEvent<SpotPriceRequest, SpotPriceResponse>;
|
||||||
|
|
||||||
|
/// The spot price protocol allows parties to **initiate** a trade by requesting
|
||||||
|
/// a spot price.
|
||||||
|
///
|
||||||
|
/// A spot price is binding for both parties, i.e. after the spot-price protocol
|
||||||
|
/// completes, both parties are expected to follow up with the `execution-setup`
|
||||||
|
/// protocol.
|
||||||
|
///
|
||||||
|
/// If a party wishes to only inquire about the current price, they should use
|
||||||
|
/// the `quote` protocol instead.
|
||||||
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
pub struct SpotPriceProtocol;
|
||||||
|
|
||||||
|
impl ProtocolName for SpotPriceProtocol {
|
||||||
|
fn protocol_name(&self) -> &[u8] {
|
||||||
|
b"/comit/xmr/btc/spot-price/1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct SpotPriceRequest {
|
||||||
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||||
|
pub btc: bitcoin::Amount,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct SpotPriceResponse {
|
||||||
|
pub xmr: monero::Amount,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Behaviour =
|
||||||
|
RequestResponse<CborCodec<SpotPriceProtocol, SpotPriceRequest, SpotPriceResponse>>;
|
||||||
|
|
||||||
|
/// Constructs a new instance of the `spot-price` behaviour to be used by Alice.
|
||||||
|
///
|
||||||
|
/// Alice only supports inbound connections, i.e. providing spot prices for BTC
|
||||||
|
/// in XMR.
|
||||||
|
pub fn alice() -> Behaviour {
|
||||||
|
Behaviour::new(
|
||||||
|
CborCodec::default(),
|
||||||
|
vec![(SpotPriceProtocol, ProtocolSupport::Inbound)],
|
||||||
|
RequestResponseConfig::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a new instance of the `spot-price` behaviour to be used by Bob.
|
||||||
|
///
|
||||||
|
/// Bob only supports outbound connections, i.e. requesting a spot price for a
|
||||||
|
/// given amount of BTC in XMR.
|
||||||
|
pub fn bob() -> Behaviour {
|
||||||
|
Behaviour::new(
|
||||||
|
CborCodec::default(),
|
||||||
|
vec![(SpotPriceProtocol, ProtocolSupport::Outbound)],
|
||||||
|
RequestResponseConfig::default(),
|
||||||
|
)
|
||||||
|
}
|
@ -8,7 +8,6 @@ pub use self::{
|
|||||||
behaviour::{Behaviour, OutEvent},
|
behaviour::{Behaviour, OutEvent},
|
||||||
event_loop::{EventLoop, EventLoopHandle},
|
event_loop::{EventLoop, EventLoopHandle},
|
||||||
execution_setup::Message1,
|
execution_setup::Message1,
|
||||||
quote_response::*,
|
|
||||||
state::*,
|
state::*,
|
||||||
swap::{run, run_until},
|
swap::{run, run_until},
|
||||||
transfer_proof::TransferProof,
|
transfer_proof::TransferProof,
|
||||||
@ -19,7 +18,6 @@ mod behaviour;
|
|||||||
mod encrypted_signature;
|
mod encrypted_signature;
|
||||||
pub mod event_loop;
|
pub mod event_loop;
|
||||||
mod execution_setup;
|
mod execution_setup;
|
||||||
mod quote_response;
|
|
||||||
pub mod state;
|
pub mod state;
|
||||||
mod steps;
|
mod steps;
|
||||||
pub mod swap;
|
pub mod swap;
|
||||||
|
@ -1,24 +1,35 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
network::{peer_tracker, peer_tracker::PeerTracker},
|
bitcoin,
|
||||||
|
execution_params::ExecutionParams,
|
||||||
|
monero,
|
||||||
|
network::{
|
||||||
|
peer_tracker,
|
||||||
|
peer_tracker::PeerTracker,
|
||||||
|
spot_price,
|
||||||
|
spot_price::{SpotPriceRequest, SpotPriceResponse},
|
||||||
|
},
|
||||||
protocol::{
|
protocol::{
|
||||||
alice::{
|
alice::{
|
||||||
encrypted_signature, execution_setup, quote_response, transfer_proof, QuoteResponse,
|
encrypted_signature, execution_setup, transfer_proof, State0, State3, TransferProof,
|
||||||
State0, State3, TransferProof,
|
|
||||||
},
|
},
|
||||||
bob::{EncryptedSignature, QuoteRequest},
|
bob::EncryptedSignature,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
use libp2p::{request_response::ResponseChannel, NetworkBehaviour, PeerId};
|
use libp2p::{
|
||||||
|
request_response::{RequestResponseMessage, ResponseChannel},
|
||||||
|
NetworkBehaviour, PeerId,
|
||||||
|
};
|
||||||
|
use rand::{CryptoRng, RngCore};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum OutEvent {
|
pub enum OutEvent {
|
||||||
ConnectionEstablished(PeerId),
|
ConnectionEstablished(PeerId),
|
||||||
QuoteRequest {
|
SpotPriceRequested {
|
||||||
msg: QuoteRequest,
|
msg: SpotPriceRequest,
|
||||||
channel: ResponseChannel<QuoteResponse>,
|
channel: ResponseChannel<SpotPriceResponse>,
|
||||||
bob_peer_id: PeerId,
|
peer: PeerId,
|
||||||
},
|
},
|
||||||
ExecutionSetupDone {
|
ExecutionSetupDone {
|
||||||
bob_peer_id: PeerId,
|
bob_peer_id: PeerId,
|
||||||
@ -43,21 +54,37 @@ impl From<peer_tracker::OutEvent> for OutEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<quote_response::OutEvent> for OutEvent {
|
impl From<spot_price::OutEvent> for OutEvent {
|
||||||
fn from(event: quote_response::OutEvent) -> Self {
|
fn from(event: spot_price::OutEvent) -> Self {
|
||||||
use crate::protocol::alice::quote_response::OutEvent::*;
|
|
||||||
match event {
|
match event {
|
||||||
MsgReceived {
|
spot_price::OutEvent::Message {
|
||||||
msg,
|
peer,
|
||||||
channel,
|
message:
|
||||||
bob_peer_id,
|
RequestResponseMessage::Request {
|
||||||
} => OutEvent::QuoteRequest {
|
channel,
|
||||||
msg,
|
request: msg,
|
||||||
channel,
|
..
|
||||||
bob_peer_id,
|
},
|
||||||
},
|
} => OutEvent::SpotPriceRequested { msg, channel, peer },
|
||||||
ResponseSent => OutEvent::ResponseSent,
|
spot_price::OutEvent::Message {
|
||||||
Failure(err) => OutEvent::Failure(err.context("Quote Request/Response failure")),
|
message: RequestResponseMessage::Response { .. },
|
||||||
|
..
|
||||||
|
} => OutEvent::Failure(anyhow!(
|
||||||
|
"Alice is only meant to hand out spot prices, not receive them"
|
||||||
|
)),
|
||||||
|
spot_price::OutEvent::ResponseSent { .. } => OutEvent::ResponseSent,
|
||||||
|
spot_price::OutEvent::InboundFailure { peer, error, .. } => OutEvent::Failure(anyhow!(
|
||||||
|
"spot_price protocol with peer {} failed due to {:?}",
|
||||||
|
peer,
|
||||||
|
error
|
||||||
|
)),
|
||||||
|
spot_price::OutEvent::OutboundFailure { peer, error, .. } => {
|
||||||
|
OutEvent::Failure(anyhow!(
|
||||||
|
"spot_price protocol with peer {} failed due to {:?}",
|
||||||
|
peer,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,29 +130,62 @@ impl From<encrypted_signature::OutEvent> for OutEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Alice.
|
/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Alice.
|
||||||
#[derive(NetworkBehaviour, Default)]
|
#[derive(NetworkBehaviour)]
|
||||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Behaviour {
|
pub struct Behaviour {
|
||||||
pt: PeerTracker,
|
pt: PeerTracker,
|
||||||
quote_response: quote_response::Behaviour,
|
spot_price: spot_price::Behaviour,
|
||||||
execution_setup: execution_setup::Behaviour,
|
execution_setup: execution_setup::Behaviour,
|
||||||
transfer_proof: transfer_proof::Behaviour,
|
transfer_proof: transfer_proof::Behaviour,
|
||||||
encrypted_signature: encrypted_signature::Behaviour,
|
encrypted_signature: encrypted_signature::Behaviour,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Behaviour {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
pt: Default::default(),
|
||||||
|
spot_price: spot_price::alice(),
|
||||||
|
execution_setup: Default::default(),
|
||||||
|
transfer_proof: Default::default(),
|
||||||
|
encrypted_signature: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Behaviour {
|
impl Behaviour {
|
||||||
pub fn send_quote_response(
|
pub fn send_spot_price(
|
||||||
&mut self,
|
&mut self,
|
||||||
channel: ResponseChannel<QuoteResponse>,
|
channel: ResponseChannel<SpotPriceResponse>,
|
||||||
quote_response: QuoteResponse,
|
response: SpotPriceResponse,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.quote_response.send(channel, quote_response)?;
|
self.spot_price
|
||||||
|
.send_response(channel, response)
|
||||||
|
.map_err(|_| anyhow!("failed to respond with spot price"))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_execution_setup(&mut self, bob_peer_id: PeerId, state0: State0) {
|
pub async fn start_execution_setup(
|
||||||
self.execution_setup.run(bob_peer_id, state0);
|
&mut self,
|
||||||
|
peer: PeerId,
|
||||||
|
btc: bitcoin::Amount,
|
||||||
|
xmr: monero::Amount,
|
||||||
|
execution_params: ExecutionParams,
|
||||||
|
bitcoin_wallet: &bitcoin::Wallet,
|
||||||
|
rng: &mut (impl RngCore + CryptoRng),
|
||||||
|
) -> Result<()> {
|
||||||
|
let state0 = State0::new(btc, xmr, execution_params, bitcoin_wallet, rng).await?;
|
||||||
|
|
||||||
|
tracing::info!(
|
||||||
|
%peer,
|
||||||
|
"Starting execution setup to sell {} for {}",
|
||||||
|
xmr, btc,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.execution_setup.run(peer, state0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send Transfer Proof to Bob.
|
/// Send Transfer Proof to Bob.
|
||||||
|
@ -5,25 +5,21 @@ use crate::{
|
|||||||
execution_params::ExecutionParams,
|
execution_params::ExecutionParams,
|
||||||
monero,
|
monero,
|
||||||
monero::BalanceTooLow,
|
monero::BalanceTooLow,
|
||||||
network::{transport, TokioExecutor},
|
network::{spot_price::SpotPriceResponse, transport, TokioExecutor},
|
||||||
protocol::{
|
protocol::{
|
||||||
alice,
|
alice,
|
||||||
alice::{
|
alice::{AliceState, Behaviour, OutEvent, State3, Swap, TransferProof},
|
||||||
AliceState, Behaviour, OutEvent, QuoteResponse, State0, State3, Swap, TransferProof,
|
bob::EncryptedSignature,
|
||||||
},
|
|
||||||
bob::{EncryptedSignature, QuoteRequest},
|
|
||||||
},
|
},
|
||||||
seed::Seed,
|
seed::Seed,
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use futures::future::RemoteHandle;
|
use futures::future::RemoteHandle;
|
||||||
use libp2p::{
|
use libp2p::{core::Multiaddr, futures::FutureExt, PeerId, Swarm};
|
||||||
core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm,
|
|
||||||
};
|
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{broadcast, mpsc, mpsc::error::SendError};
|
use tokio::sync::{broadcast, mpsc, mpsc::error::SendError};
|
||||||
use tracing::{debug, error, info, trace};
|
use tracing::{debug, error, trace};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
@ -166,9 +162,30 @@ where
|
|||||||
OutEvent::ConnectionEstablished(alice) => {
|
OutEvent::ConnectionEstablished(alice) => {
|
||||||
debug!("Connection Established with {}", alice);
|
debug!("Connection Established with {}", alice);
|
||||||
}
|
}
|
||||||
OutEvent::QuoteRequest { msg, channel, bob_peer_id } => {
|
OutEvent::SpotPriceRequested { msg, channel, peer } => {
|
||||||
if let Err(error) = self.handle_quote_request(msg, channel, bob_peer_id, self.monero_wallet.clone()).await {
|
let btc = msg.btc;
|
||||||
error!("Failed to handle quote request: {:#}", error);
|
let xmr = match self.handle_spot_price_request(btc, self.monero_wallet.clone()).await {
|
||||||
|
Ok(xmr) => xmr,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!(%peer, "failed to produce spot price for {}: {:#}", btc, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.swarm.send_spot_price(channel, SpotPriceResponse { xmr }) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
// if we can't respond, the peer probably just disconnected so it is not a huge deal, only log this on debug
|
||||||
|
debug!(%peer, "failed to respond with spot price: {:#}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.swarm.start_execution_setup(peer, btc, xmr, self.execution_params, self.bitcoin_wallet.as_ref(), &mut OsRng).await {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!(%peer, "failed to start execution setup: {:#}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OutEvent::ExecutionSetupDone{bob_peer_id, state3} => {
|
OutEvent::ExecutionSetupDone{bob_peer_id, state3} => {
|
||||||
@ -199,65 +216,34 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_quote_request(
|
async fn handle_spot_price_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
quote_request: QuoteRequest,
|
btc: bitcoin::Amount,
|
||||||
channel: ResponseChannel<QuoteResponse>,
|
|
||||||
bob_peer_id: PeerId,
|
|
||||||
monero_wallet: Arc<monero::Wallet>,
|
monero_wallet: Arc<monero::Wallet>,
|
||||||
) -> Result<()> {
|
) -> Result<monero::Amount> {
|
||||||
// 1. Check if acceptable request
|
|
||||||
// 2. Send response
|
|
||||||
|
|
||||||
let rate = self
|
let rate = self
|
||||||
.rate_service
|
.rate_service
|
||||||
.latest_rate()
|
.latest_rate()
|
||||||
.context("Failed to get latest rate")?;
|
.context("Failed to get latest rate")?;
|
||||||
|
|
||||||
let btc_amount = quote_request.btc_amount;
|
if btc > self.max_buy {
|
||||||
|
|
||||||
if btc_amount > self.max_buy {
|
|
||||||
bail!(MaximumBuyAmountExceeded {
|
bail!(MaximumBuyAmountExceeded {
|
||||||
actual: btc_amount,
|
actual: btc,
|
||||||
max: self.max_buy
|
max: self.max_buy
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let xmr_balance = monero_wallet.get_balance().await?;
|
let xmr_balance = monero_wallet.get_balance().await?;
|
||||||
let xmr_lock_fees = monero_wallet.static_tx_fee_estimate();
|
let xmr_lock_fees = monero_wallet.static_tx_fee_estimate();
|
||||||
let xmr_amount = rate.sell_quote(btc_amount)?;
|
let xmr = rate.sell_quote(btc)?;
|
||||||
|
|
||||||
if xmr_balance < xmr_amount + xmr_lock_fees {
|
if xmr_balance < xmr + xmr_lock_fees {
|
||||||
bail!(BalanceTooLow {
|
bail!(BalanceTooLow {
|
||||||
balance: xmr_balance
|
balance: xmr_balance
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let quote_response = QuoteResponse { xmr_amount };
|
Ok(xmr)
|
||||||
|
|
||||||
self.swarm
|
|
||||||
.send_quote_response(channel, quote_response)
|
|
||||||
.context("Failed to send quote response")?;
|
|
||||||
|
|
||||||
// 3. Start setup execution
|
|
||||||
|
|
||||||
let state0 = State0::new(
|
|
||||||
btc_amount,
|
|
||||||
xmr_amount,
|
|
||||||
self.execution_params,
|
|
||||||
self.bitcoin_wallet.as_ref(),
|
|
||||||
&mut OsRng,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
info!(
|
|
||||||
"Starting execution setup to sell {} for {} (rate of {}) with {}",
|
|
||||||
xmr_amount, btc_amount, rate, bob_peer_id
|
|
||||||
);
|
|
||||||
|
|
||||||
self.swarm.start_execution_setup(bob_peer_id, state0);
|
|
||||||
// Continues once the execution setup protocol is done
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_execution_setup_done(
|
async fn handle_execution_setup_done(
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
monero,
|
|
||||||
network::request_response::{CborCodec, Swap, TIMEOUT},
|
|
||||||
protocol::bob::QuoteRequest,
|
|
||||||
};
|
|
||||||
use anyhow::{anyhow, Error, Result};
|
|
||||||
use libp2p::{
|
|
||||||
request_response::{
|
|
||||||
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
|
||||||
RequestResponseMessage, ResponseChannel,
|
|
||||||
},
|
|
||||||
NetworkBehaviour, PeerId,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::time::Duration;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum OutEvent {
|
|
||||||
MsgReceived {
|
|
||||||
msg: QuoteRequest,
|
|
||||||
channel: ResponseChannel<QuoteResponse>,
|
|
||||||
bob_peer_id: PeerId,
|
|
||||||
},
|
|
||||||
ResponseSent,
|
|
||||||
Failure(Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct QuoteResponse {
|
|
||||||
pub xmr_amount: monero::Amount,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RequestResponseEvent<QuoteRequest, QuoteResponse>> for OutEvent {
|
|
||||||
fn from(event: RequestResponseEvent<QuoteRequest, QuoteResponse>) -> Self {
|
|
||||||
match event {
|
|
||||||
RequestResponseEvent::Message {
|
|
||||||
peer,
|
|
||||||
message:
|
|
||||||
RequestResponseMessage::Request {
|
|
||||||
request, channel, ..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
debug!("Received quote request from {}", peer);
|
|
||||||
OutEvent::MsgReceived {
|
|
||||||
msg: request,
|
|
||||||
channel,
|
|
||||||
bob_peer_id: peer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RequestResponseEvent::Message {
|
|
||||||
message: RequestResponseMessage::Response { .. },
|
|
||||||
..
|
|
||||||
} => OutEvent::Failure(anyhow!("Alice should not get a Response")),
|
|
||||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
|
||||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
|
||||||
}
|
|
||||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
|
||||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
|
||||||
}
|
|
||||||
RequestResponseEvent::ResponseSent { peer, .. } => {
|
|
||||||
tracing::debug!("successfully sent quote response to {}", peer);
|
|
||||||
OutEvent::ResponseSent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `NetworkBehaviour` that represents negotiate a swap using Swap
|
|
||||||
/// request/response.
|
|
||||||
#[derive(NetworkBehaviour)]
|
|
||||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
|
||||||
#[allow(missing_debug_implementations)]
|
|
||||||
pub struct Behaviour {
|
|
||||||
rr: RequestResponse<CborCodec<Swap, QuoteRequest, QuoteResponse>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Behaviour {
|
|
||||||
/// Alice always sends her messages as a response to a request from Bob.
|
|
||||||
pub fn send(
|
|
||||||
&mut self,
|
|
||||||
channel: ResponseChannel<QuoteResponse>,
|
|
||||||
msg: QuoteResponse,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.rr
|
|
||||||
.send_response(channel, msg)
|
|
||||||
.map_err(|_| anyhow!("failed to send quote response"))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Behaviour {
|
|
||||||
fn default() -> Self {
|
|
||||||
let timeout = Duration::from_secs(TIMEOUT);
|
|
||||||
|
|
||||||
let mut config = RequestResponseConfig::default();
|
|
||||||
config.set_request_timeout(timeout);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
rr: RequestResponse::new(
|
|
||||||
CborCodec::default(),
|
|
||||||
vec![(Swap, ProtocolSupport::Inbound)],
|
|
||||||
config,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,22 @@
|
|||||||
//! Run an XMR/BTC swap in the role of Bob.
|
|
||||||
//! Bob holds BTC and wishes receive XMR.
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bitcoin,
|
bitcoin,
|
||||||
database::Database,
|
database::Database,
|
||||||
execution_params::ExecutionParams,
|
execution_params::ExecutionParams,
|
||||||
monero,
|
monero,
|
||||||
network::peer_tracker::{self, PeerTracker},
|
network::{
|
||||||
protocol::{alice, alice::TransferProof, bob},
|
peer_tracker::{self, PeerTracker},
|
||||||
|
spot_price,
|
||||||
|
spot_price::{SpotPriceRequest, SpotPriceResponse},
|
||||||
|
},
|
||||||
|
protocol::{alice::TransferProof, bob},
|
||||||
|
};
|
||||||
|
use anyhow::{anyhow, Error, Result};
|
||||||
|
pub use execution_setup::{Message0, Message2, Message4};
|
||||||
|
use libp2p::{
|
||||||
|
core::Multiaddr,
|
||||||
|
request_response::{RequestResponseMessage, ResponseChannel},
|
||||||
|
NetworkBehaviour, PeerId,
|
||||||
};
|
};
|
||||||
use anyhow::{Error, Result};
|
|
||||||
use libp2p::{core::Multiaddr, NetworkBehaviour, PeerId};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -18,19 +25,15 @@ pub use self::{
|
|||||||
cancel::cancel,
|
cancel::cancel,
|
||||||
encrypted_signature::EncryptedSignature,
|
encrypted_signature::EncryptedSignature,
|
||||||
event_loop::{EventLoop, EventLoopHandle},
|
event_loop::{EventLoop, EventLoopHandle},
|
||||||
quote_request::*,
|
|
||||||
refund::refund,
|
refund::refund,
|
||||||
state::*,
|
state::*,
|
||||||
swap::{run, run_until},
|
swap::{run, run_until},
|
||||||
};
|
};
|
||||||
pub use execution_setup::{Message0, Message2, Message4};
|
|
||||||
use libp2p::request_response::ResponseChannel;
|
|
||||||
|
|
||||||
pub mod cancel;
|
pub mod cancel;
|
||||||
mod encrypted_signature;
|
mod encrypted_signature;
|
||||||
pub mod event_loop;
|
pub mod event_loop;
|
||||||
mod execution_setup;
|
mod execution_setup;
|
||||||
mod quote_request;
|
|
||||||
pub mod refund;
|
pub mod refund;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod swap;
|
pub mod swap;
|
||||||
@ -119,7 +122,7 @@ impl Builder {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum OutEvent {
|
pub enum OutEvent {
|
||||||
ConnectionEstablished(PeerId),
|
ConnectionEstablished(PeerId),
|
||||||
QuoteResponse(alice::QuoteResponse),
|
SpotPriceReceived(SpotPriceResponse),
|
||||||
ExecutionSetupDone(Result<Box<State2>>),
|
ExecutionSetupDone(Result<Box<State2>>),
|
||||||
TransferProof {
|
TransferProof {
|
||||||
msg: Box<TransferProof>,
|
msg: Box<TransferProof>,
|
||||||
@ -140,12 +143,34 @@ impl From<peer_tracker::OutEvent> for OutEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<quote_request::OutEvent> for OutEvent {
|
impl From<spot_price::OutEvent> for OutEvent {
|
||||||
fn from(event: quote_request::OutEvent) -> Self {
|
fn from(event: spot_price::OutEvent) -> Self {
|
||||||
use quote_request::OutEvent::*;
|
|
||||||
match event {
|
match event {
|
||||||
MsgReceived(quote_response) => OutEvent::QuoteResponse(quote_response),
|
spot_price::OutEvent::Message {
|
||||||
Failure(err) => OutEvent::CommunicationError(err.context("Failure with Quote Request")),
|
message: RequestResponseMessage::Response { response, .. },
|
||||||
|
..
|
||||||
|
} => OutEvent::SpotPriceReceived(response),
|
||||||
|
spot_price::OutEvent::Message {
|
||||||
|
message: RequestResponseMessage::Request { .. },
|
||||||
|
..
|
||||||
|
} => OutEvent::CommunicationError(anyhow!(
|
||||||
|
"Bob is only meant to receive spot prices, not hand them out"
|
||||||
|
)),
|
||||||
|
spot_price::OutEvent::ResponseSent { .. } => OutEvent::ResponseSent,
|
||||||
|
spot_price::OutEvent::InboundFailure { peer, error, .. } => {
|
||||||
|
OutEvent::CommunicationError(anyhow!(
|
||||||
|
"spot_price protocol with peer {} failed due to {:?}",
|
||||||
|
peer,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
}
|
||||||
|
spot_price::OutEvent::OutboundFailure { peer, error, .. } => {
|
||||||
|
OutEvent::CommunicationError(anyhow!(
|
||||||
|
"spot_price protocol with peer {} failed due to {:?}",
|
||||||
|
peer,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,21 +212,32 @@ impl From<encrypted_signature::OutEvent> for OutEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Bob.
|
/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Bob.
|
||||||
#[derive(NetworkBehaviour, Default)]
|
#[derive(NetworkBehaviour)]
|
||||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
#[behaviour(out_event = "OutEvent", event_process = false)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Behaviour {
|
pub struct Behaviour {
|
||||||
pt: PeerTracker,
|
pt: PeerTracker,
|
||||||
quote_request: quote_request::Behaviour,
|
spot_price: spot_price::Behaviour,
|
||||||
execution_setup: execution_setup::Behaviour,
|
execution_setup: execution_setup::Behaviour,
|
||||||
transfer_proof: transfer_proof::Behaviour,
|
transfer_proof: transfer_proof::Behaviour,
|
||||||
encrypted_signature: encrypted_signature::Behaviour,
|
encrypted_signature: encrypted_signature::Behaviour,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Behaviour {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
pt: Default::default(),
|
||||||
|
spot_price: spot_price::bob(),
|
||||||
|
execution_setup: Default::default(),
|
||||||
|
transfer_proof: Default::default(),
|
||||||
|
encrypted_signature: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Behaviour {
|
impl Behaviour {
|
||||||
/// Sends a quote request to Alice to retrieve the rate.
|
pub fn request_spot_price(&mut self, alice: PeerId, request: SpotPriceRequest) {
|
||||||
pub fn send_quote_request(&mut self, alice: PeerId, quote_request: QuoteRequest) {
|
let _ = self.spot_price.send_request(&alice, request);
|
||||||
let _ = self.quote_request.send(alice, quote_request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_execution_setup(
|
pub fn start_execution_setup(
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bitcoin,
|
bitcoin,
|
||||||
bitcoin::EncryptedSignature,
|
bitcoin::EncryptedSignature,
|
||||||
network::{transport, TokioExecutor},
|
monero,
|
||||||
|
network::{
|
||||||
|
spot_price::{SpotPriceRequest, SpotPriceResponse},
|
||||||
|
transport, TokioExecutor,
|
||||||
|
},
|
||||||
protocol::{
|
protocol::{
|
||||||
alice::{QuoteResponse, TransferProof},
|
alice::TransferProof,
|
||||||
bob::{Behaviour, OutEvent, QuoteRequest, State0, State2},
|
bob::{Behaviour, OutEvent, State0, State2},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
@ -35,24 +39,17 @@ impl<T> Default for Channels<T> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EventLoopHandle {
|
pub struct EventLoopHandle {
|
||||||
recv_quote_response: Receiver<QuoteResponse>,
|
recv_spot_price: Receiver<SpotPriceResponse>,
|
||||||
start_execution_setup: Sender<State0>,
|
start_execution_setup: Sender<State0>,
|
||||||
done_execution_setup: Receiver<Result<State2>>,
|
done_execution_setup: Receiver<Result<State2>>,
|
||||||
recv_transfer_proof: Receiver<TransferProof>,
|
recv_transfer_proof: Receiver<TransferProof>,
|
||||||
conn_established: Receiver<PeerId>,
|
conn_established: Receiver<PeerId>,
|
||||||
dial_alice: Sender<()>,
|
dial_alice: Sender<()>,
|
||||||
send_quote_request: Sender<QuoteRequest>,
|
request_spot_price: Sender<SpotPriceRequest>,
|
||||||
send_encrypted_signature: Sender<EncryptedSignature>,
|
send_encrypted_signature: Sender<EncryptedSignature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoopHandle {
|
impl EventLoopHandle {
|
||||||
pub async fn recv_quote_response(&mut self) -> Result<QuoteResponse> {
|
|
||||||
self.recv_quote_response
|
|
||||||
.recv()
|
|
||||||
.await
|
|
||||||
.ok_or_else(|| anyhow!("Failed to receive quote response from Alice"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn execution_setup(&mut self, state0: State0) -> Result<State2> {
|
pub async fn execution_setup(&mut self, state0: State0) -> Result<State2> {
|
||||||
let _ = self.start_execution_setup.send(state0).await?;
|
let _ = self.start_execution_setup.send(state0).await?;
|
||||||
|
|
||||||
@ -82,9 +79,19 @@ impl EventLoopHandle {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_quote_request(&mut self, quote_request: QuoteRequest) -> Result<()> {
|
pub async fn request_spot_price(&mut self, btc: bitcoin::Amount) -> Result<monero::Amount> {
|
||||||
let _ = self.send_quote_request.send(quote_request).await?;
|
let _ = self
|
||||||
Ok(())
|
.request_spot_price
|
||||||
|
.send(SpotPriceRequest { btc })
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let response = self
|
||||||
|
.recv_spot_price
|
||||||
|
.recv()
|
||||||
|
.await
|
||||||
|
.ok_or_else(|| anyhow!("Failed to receive spot price from Alice"))?;
|
||||||
|
|
||||||
|
Ok(response.xmr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_encrypted_signature(
|
pub async fn send_encrypted_signature(
|
||||||
@ -102,13 +109,13 @@ pub struct EventLoop {
|
|||||||
swarm: libp2p::Swarm<Behaviour>,
|
swarm: libp2p::Swarm<Behaviour>,
|
||||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||||
alice_peer_id: PeerId,
|
alice_peer_id: PeerId,
|
||||||
recv_quote_response: Sender<QuoteResponse>,
|
request_spot_price: Receiver<SpotPriceRequest>,
|
||||||
|
recv_spot_price: Sender<SpotPriceResponse>,
|
||||||
start_execution_setup: Receiver<State0>,
|
start_execution_setup: Receiver<State0>,
|
||||||
done_execution_setup: Sender<Result<State2>>,
|
done_execution_setup: Sender<Result<State2>>,
|
||||||
recv_transfer_proof: Sender<TransferProof>,
|
recv_transfer_proof: Sender<TransferProof>,
|
||||||
dial_alice: Receiver<()>,
|
dial_alice: Receiver<()>,
|
||||||
conn_established: Sender<PeerId>,
|
conn_established: Sender<PeerId>,
|
||||||
send_quote_request: Receiver<QuoteRequest>,
|
|
||||||
send_encrypted_signature: Receiver<EncryptedSignature>,
|
send_encrypted_signature: Receiver<EncryptedSignature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,24 +154,24 @@ impl EventLoop {
|
|||||||
swarm,
|
swarm,
|
||||||
alice_peer_id,
|
alice_peer_id,
|
||||||
bitcoin_wallet,
|
bitcoin_wallet,
|
||||||
recv_quote_response: quote_response.sender,
|
recv_spot_price: quote_response.sender,
|
||||||
start_execution_setup: start_execution_setup.receiver,
|
start_execution_setup: start_execution_setup.receiver,
|
||||||
done_execution_setup: done_execution_setup.sender,
|
done_execution_setup: done_execution_setup.sender,
|
||||||
recv_transfer_proof: recv_transfer_proof.sender,
|
recv_transfer_proof: recv_transfer_proof.sender,
|
||||||
conn_established: conn_established.sender,
|
conn_established: conn_established.sender,
|
||||||
dial_alice: dial_alice.receiver,
|
dial_alice: dial_alice.receiver,
|
||||||
send_quote_request: send_quote_request.receiver,
|
request_spot_price: send_quote_request.receiver,
|
||||||
send_encrypted_signature: send_encrypted_signature.receiver,
|
send_encrypted_signature: send_encrypted_signature.receiver,
|
||||||
};
|
};
|
||||||
|
|
||||||
let handle = EventLoopHandle {
|
let handle = EventLoopHandle {
|
||||||
recv_quote_response: quote_response.receiver,
|
recv_spot_price: quote_response.receiver,
|
||||||
start_execution_setup: start_execution_setup.sender,
|
start_execution_setup: start_execution_setup.sender,
|
||||||
done_execution_setup: done_execution_setup.receiver,
|
done_execution_setup: done_execution_setup.receiver,
|
||||||
recv_transfer_proof: recv_transfer_proof.receiver,
|
recv_transfer_proof: recv_transfer_proof.receiver,
|
||||||
conn_established: conn_established.receiver,
|
conn_established: conn_established.receiver,
|
||||||
dial_alice: dial_alice.sender,
|
dial_alice: dial_alice.sender,
|
||||||
send_quote_request: send_quote_request.sender,
|
request_spot_price: send_quote_request.sender,
|
||||||
send_encrypted_signature: send_encrypted_signature.sender,
|
send_encrypted_signature: send_encrypted_signature.sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,8 +186,8 @@ impl EventLoop {
|
|||||||
OutEvent::ConnectionEstablished(peer_id) => {
|
OutEvent::ConnectionEstablished(peer_id) => {
|
||||||
let _ = self.conn_established.send(peer_id).await;
|
let _ = self.conn_established.send(peer_id).await;
|
||||||
}
|
}
|
||||||
OutEvent::QuoteResponse(msg) => {
|
OutEvent::SpotPriceReceived(msg) => {
|
||||||
let _ = self.recv_quote_response.send(msg).await;
|
let _ = self.recv_spot_price.send(msg).await;
|
||||||
},
|
},
|
||||||
OutEvent::ExecutionSetupDone(res) => {
|
OutEvent::ExecutionSetupDone(res) => {
|
||||||
let _ = self.done_execution_setup.send(res.map(|state|*state)).await;
|
let _ = self.done_execution_setup.send(res.map(|state|*state)).await;
|
||||||
@ -213,9 +220,9 @@ impl EventLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
quote_request = self.send_quote_request.recv().fuse() => {
|
quote_request = self.request_spot_price.recv().fuse() => {
|
||||||
if let Some(quote_request) = quote_request {
|
if let Some(quote_request) = quote_request {
|
||||||
self.swarm.send_quote_request(self.alice_peer_id, quote_request);
|
self.swarm.request_spot_price(self.alice_peer_id, quote_request);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
option = self.start_execution_setup.recv().fuse() => {
|
option = self.start_execution_setup.recv().fuse() => {
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
network::request_response::{CborCodec, Swap, TIMEOUT},
|
|
||||||
protocol::alice::QuoteResponse,
|
|
||||||
};
|
|
||||||
use anyhow::{anyhow, Error, Result};
|
|
||||||
use libp2p::{
|
|
||||||
request_response::{
|
|
||||||
ProtocolSupport, RequestId, RequestResponse, RequestResponseConfig, RequestResponseEvent,
|
|
||||||
RequestResponseMessage,
|
|
||||||
},
|
|
||||||
NetworkBehaviour, PeerId,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::time::Duration;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct QuoteRequest {
|
|
||||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
|
||||||
pub btc_amount: bitcoin::Amount,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum OutEvent {
|
|
||||||
MsgReceived(QuoteResponse),
|
|
||||||
Failure(Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `NetworkBehaviour` that represents doing the negotiation of a swap.
|
|
||||||
#[derive(NetworkBehaviour)]
|
|
||||||
#[behaviour(out_event = "OutEvent", event_process = false)]
|
|
||||||
#[allow(missing_debug_implementations)]
|
|
||||||
pub struct Behaviour {
|
|
||||||
rr: RequestResponse<CborCodec<Swap, QuoteRequest, QuoteResponse>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Behaviour {
|
|
||||||
pub fn send(&mut self, alice: PeerId, quote_request: QuoteRequest) -> Result<RequestId> {
|
|
||||||
debug!("Requesting quote for {}", quote_request.btc_amount);
|
|
||||||
|
|
||||||
let id = self.rr.send_request(&alice, quote_request);
|
|
||||||
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Behaviour {
|
|
||||||
fn default() -> Self {
|
|
||||||
let timeout = Duration::from_secs(TIMEOUT);
|
|
||||||
|
|
||||||
let mut config = RequestResponseConfig::default();
|
|
||||||
config.set_request_timeout(timeout);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
rr: RequestResponse::new(
|
|
||||||
CborCodec::default(),
|
|
||||||
vec![(Swap, ProtocolSupport::Outbound)],
|
|
||||||
config,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RequestResponseEvent<QuoteRequest, QuoteResponse>> for OutEvent {
|
|
||||||
fn from(event: RequestResponseEvent<QuoteRequest, QuoteResponse>) -> Self {
|
|
||||||
match event {
|
|
||||||
RequestResponseEvent::Message {
|
|
||||||
message: RequestResponseMessage::Request { .. },
|
|
||||||
..
|
|
||||||
} => OutEvent::Failure(anyhow!("Bob should never get a request from Alice")),
|
|
||||||
RequestResponseEvent::Message {
|
|
||||||
message: RequestResponseMessage::Response { response, .. },
|
|
||||||
..
|
|
||||||
} => OutEvent::MsgReceived(response),
|
|
||||||
RequestResponseEvent::InboundFailure { error, .. } => {
|
|
||||||
OutEvent::Failure(anyhow!("Inbound failure: {:?}", error))
|
|
||||||
}
|
|
||||||
RequestResponseEvent::OutboundFailure { error, .. } => {
|
|
||||||
OutEvent::Failure(anyhow!("Outbound failure: {:?}", error))
|
|
||||||
}
|
|
||||||
RequestResponseEvent::ResponseSent { .. } => {
|
|
||||||
OutEvent::Failure(anyhow!("Bob does not send a quote response to Alice"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
execution_params::ExecutionParams,
|
execution_params::ExecutionParams,
|
||||||
monero,
|
monero,
|
||||||
monero::InsufficientFunds,
|
monero::InsufficientFunds,
|
||||||
protocol::bob::{self, event_loop::EventLoopHandle, state::*, QuoteRequest},
|
protocol::bob::{self, event_loop::EventLoopHandle, state::*},
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
@ -72,7 +72,7 @@ async fn run_until_internal(
|
|||||||
|
|
||||||
event_loop_handle.dial().await?;
|
event_loop_handle.dial().await?;
|
||||||
|
|
||||||
let state2 = request_quote_and_setup(
|
let state2 = request_price_and_setup(
|
||||||
btc_amount,
|
btc_amount,
|
||||||
&mut event_loop_handle,
|
&mut event_loop_handle,
|
||||||
execution_params,
|
execution_params,
|
||||||
@ -394,24 +394,20 @@ async fn run_until_internal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn request_quote_and_setup(
|
pub async fn request_price_and_setup(
|
||||||
btc_amount: bitcoin::Amount,
|
btc: bitcoin::Amount,
|
||||||
event_loop_handle: &mut EventLoopHandle,
|
event_loop_handle: &mut EventLoopHandle,
|
||||||
execution_params: ExecutionParams,
|
execution_params: ExecutionParams,
|
||||||
bitcoin_refund_address: bitcoin::Address,
|
bitcoin_refund_address: bitcoin::Address,
|
||||||
) -> Result<bob::state::State2> {
|
) -> Result<bob::state::State2> {
|
||||||
event_loop_handle
|
let xmr = event_loop_handle.request_spot_price(btc).await?;
|
||||||
.send_quote_request(QuoteRequest { btc_amount })
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let xmr_amount = event_loop_handle.recv_quote_response().await?.xmr_amount;
|
tracing::info!("Spot price for {} is {}", btc, xmr);
|
||||||
|
|
||||||
tracing::info!("Quote for {} is {}", btc_amount, xmr_amount);
|
|
||||||
|
|
||||||
let state0 = State0::new(
|
let state0 = State0::new(
|
||||||
&mut OsRng,
|
&mut OsRng,
|
||||||
btc_amount,
|
btc,
|
||||||
xmr_amount,
|
xmr,
|
||||||
execution_params.bitcoin_cancel_timelock,
|
execution_params.bitcoin_cancel_timelock,
|
||||||
execution_params.bitcoin_punish_timelock,
|
execution_params.bitcoin_punish_timelock,
|
||||||
bitcoin_refund_address,
|
bitcoin_refund_address,
|
||||||
|
Loading…
Reference in New Issue
Block a user