mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-06 21:44:49 -04:00
wip: Process swap request in event loop
This commit is contained in:
parent
815ef90c9f
commit
6b1443b570
6 changed files with 86 additions and 23 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -2917,10 +2917,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_decimal"
|
name = "rust_decimal"
|
||||||
version = "1.8.1"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9e81662973c7a8d9663e64a0de4cd642b89a21d64966e3d99606efdc5fb0cc6"
|
checksum = "04d1fde955d206c00af1eb529d8ebfca3b505921820a0436566dbcc6c4d4ffb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
|
@ -40,7 +40,7 @@ pem = "0.8"
|
||||||
prettytable-rs = "0.8"
|
prettytable-rs = "0.8"
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
reqwest = { version = "0.11", default-features = false }
|
reqwest = { version = "0.11", default-features = false }
|
||||||
rust_decimal = "1.8"
|
rust_decimal = "1.10"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_cbor = "0.11"
|
serde_cbor = "0.11"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
|
|
@ -15,6 +15,7 @@ use rust_decimal::{
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
ops::{Add, Mul, Sub},
|
ops::{Add, Mul, Sub},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
@ -88,13 +89,22 @@ impl Amount {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_monero(amount: f64) -> Result<Self> {
|
||||||
|
let decimal = Decimal::try_from(amount)?;
|
||||||
|
Self::from_decimal(decimal)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_monero(amount: &str) -> Result<Self> {
|
pub fn parse_monero(amount: &str) -> Result<Self> {
|
||||||
let decimal = Decimal::from_str(amount)?;
|
let decimal = Decimal::from_str(amount)?;
|
||||||
|
Self::from_decimal(decimal)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_decimal(amount: Decimal) -> Result<Self> {
|
||||||
let piconeros_dec =
|
let piconeros_dec =
|
||||||
decimal.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64"));
|
amount.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64"));
|
||||||
let piconeros = piconeros_dec
|
let piconeros = piconeros_dec
|
||||||
.to_u64()
|
.to_u64()
|
||||||
.ok_or_else(|| OverflowError(amount.to_owned()))?;
|
.ok_or_else(|| OverflowError(amount.to_string()))?;
|
||||||
Ok(Amount(piconeros))
|
Ok(Amount(piconeros))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,9 @@ impl Builder {
|
||||||
alice_behaviour,
|
alice_behaviour,
|
||||||
self.listen_address(),
|
self.listen_address(),
|
||||||
self.peer_id,
|
self.peer_id,
|
||||||
|
self.execution_params.bitcoin_cancel_timelock,
|
||||||
|
self.execution_params.bitcoin_punish_timelock,
|
||||||
|
self.bitcoin_wallet.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
bitcoin,
|
||||||
|
bitcoin::Timelock,
|
||||||
|
monero,
|
||||||
network::{request_response::Response, transport::SwapTransport, TokioExecutor},
|
network::{request_response::Response, transport::SwapTransport, TokioExecutor},
|
||||||
protocol::{
|
protocol::{
|
||||||
alice::{Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof},
|
alice::{swap_response, Behaviour, OutEvent, State0, State3, SwapResponse, TransferProof},
|
||||||
bob::EncryptedSignature,
|
bob::EncryptedSignature,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -9,9 +12,14 @@ use anyhow::{anyhow, Context, Result};
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm,
|
core::Multiaddr, futures::FutureExt, request_response::ResponseChannel, PeerId, Swarm,
|
||||||
};
|
};
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::{Receiver, Sender};
|
use tokio::sync::mpsc::{Receiver, Sender};
|
||||||
use tracing::{debug, error, trace};
|
use tracing::{debug, error, trace};
|
||||||
|
|
||||||
|
// TODO: Use dynamic
|
||||||
|
const RATE: u32 = 100;
|
||||||
|
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Channels<T> {
|
pub struct Channels<T> {
|
||||||
sender: Sender<T>,
|
sender: Sender<T>,
|
||||||
|
@ -35,7 +43,6 @@ impl<T> Default for Channels<T> {
|
||||||
pub struct EventLoopHandle {
|
pub struct EventLoopHandle {
|
||||||
done_execution_setup: Receiver<Result<State3>>,
|
done_execution_setup: Receiver<Result<State3>>,
|
||||||
recv_encrypted_signature: Receiver<EncryptedSignature>,
|
recv_encrypted_signature: Receiver<EncryptedSignature>,
|
||||||
request: Receiver<crate::protocol::alice::swap_response::OutEvent>,
|
|
||||||
send_swap_response: Sender<(ResponseChannel<Response>, SwapResponse)>,
|
send_swap_response: Sender<(ResponseChannel<Response>, SwapResponse)>,
|
||||||
start_execution_setup: Sender<(PeerId, State0)>,
|
start_execution_setup: Sender<(PeerId, State0)>,
|
||||||
send_transfer_proof: Sender<(PeerId, TransferProof)>,
|
send_transfer_proof: Sender<(PeerId, TransferProof)>,
|
||||||
|
@ -62,15 +69,6 @@ impl EventLoopHandle {
|
||||||
.ok_or_else(|| anyhow!("Failed to receive Bitcoin encrypted signature from Bob"))
|
.ok_or_else(|| anyhow!("Failed to receive Bitcoin encrypted signature from Bob"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv_request(
|
|
||||||
&mut self,
|
|
||||||
) -> Result<crate::protocol::alice::swap_response::OutEvent> {
|
|
||||||
self.request
|
|
||||||
.recv()
|
|
||||||
.await
|
|
||||||
.ok_or_else(|| anyhow!("Failed to receive amounts request from Bob"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_swap_response(
|
pub async fn send_swap_response(
|
||||||
&mut self,
|
&mut self,
|
||||||
channel: ResponseChannel<Response>,
|
channel: ResponseChannel<Response>,
|
||||||
|
@ -100,10 +98,12 @@ pub struct EventLoop {
|
||||||
start_execution_setup: Receiver<(PeerId, State0)>,
|
start_execution_setup: Receiver<(PeerId, State0)>,
|
||||||
done_execution_setup: Sender<Result<State3>>,
|
done_execution_setup: Sender<Result<State3>>,
|
||||||
recv_encrypted_signature: Sender<EncryptedSignature>,
|
recv_encrypted_signature: Sender<EncryptedSignature>,
|
||||||
request: Sender<crate::protocol::alice::swap_response::OutEvent>,
|
|
||||||
send_swap_response: Receiver<(ResponseChannel<Response>, SwapResponse)>,
|
send_swap_response: Receiver<(ResponseChannel<Response>, SwapResponse)>,
|
||||||
send_transfer_proof: Receiver<(PeerId, TransferProof)>,
|
send_transfer_proof: Receiver<(PeerId, TransferProof)>,
|
||||||
recv_transfer_proof_ack: Sender<()>,
|
recv_transfer_proof_ack: Sender<()>,
|
||||||
|
cancel_timelock: Timelock,
|
||||||
|
punish_timelock: Timelock,
|
||||||
|
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
|
@ -112,6 +112,10 @@ impl EventLoop {
|
||||||
behaviour: Behaviour,
|
behaviour: Behaviour,
|
||||||
listen: Multiaddr,
|
listen: Multiaddr,
|
||||||
peer_id: PeerId,
|
peer_id: PeerId,
|
||||||
|
// TODO(Franck): Have the timelocks in a struct so they don't get swap by mistake
|
||||||
|
cancel_timelock: Timelock,
|
||||||
|
punish_timelock: Timelock,
|
||||||
|
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||||
) -> Result<(Self, EventLoopHandle)> {
|
) -> Result<(Self, EventLoopHandle)> {
|
||||||
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, peer_id)
|
let mut swarm = libp2p::swarm::SwarmBuilder::new(transport, behaviour, peer_id)
|
||||||
.executor(Box::new(TokioExecutor {
|
.executor(Box::new(TokioExecutor {
|
||||||
|
@ -125,7 +129,6 @@ impl EventLoop {
|
||||||
let start_execution_setup = Channels::new();
|
let start_execution_setup = Channels::new();
|
||||||
let done_execution_setup = Channels::new();
|
let done_execution_setup = Channels::new();
|
||||||
let recv_encrypted_signature = Channels::new();
|
let recv_encrypted_signature = Channels::new();
|
||||||
let request = Channels::new();
|
|
||||||
let send_swap_response = Channels::new();
|
let send_swap_response = Channels::new();
|
||||||
let send_transfer_proof = Channels::new();
|
let send_transfer_proof = Channels::new();
|
||||||
let recv_transfer_proof_ack = Channels::new();
|
let recv_transfer_proof_ack = Channels::new();
|
||||||
|
@ -135,17 +138,18 @@ impl EventLoop {
|
||||||
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_encrypted_signature: recv_encrypted_signature.sender,
|
recv_encrypted_signature: recv_encrypted_signature.sender,
|
||||||
request: request.sender,
|
|
||||||
send_swap_response: send_swap_response.receiver,
|
send_swap_response: send_swap_response.receiver,
|
||||||
send_transfer_proof: send_transfer_proof.receiver,
|
send_transfer_proof: send_transfer_proof.receiver,
|
||||||
recv_transfer_proof_ack: recv_transfer_proof_ack.sender,
|
recv_transfer_proof_ack: recv_transfer_proof_ack.sender,
|
||||||
|
cancel_timelock,
|
||||||
|
punish_timelock,
|
||||||
|
bitcoin_wallet,
|
||||||
};
|
};
|
||||||
|
|
||||||
let handle = EventLoopHandle {
|
let handle = EventLoopHandle {
|
||||||
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_encrypted_signature: recv_encrypted_signature.receiver,
|
recv_encrypted_signature: recv_encrypted_signature.receiver,
|
||||||
request: request.receiver,
|
|
||||||
send_swap_response: send_swap_response.sender,
|
send_swap_response: send_swap_response.sender,
|
||||||
send_transfer_proof: send_transfer_proof.sender,
|
send_transfer_proof: send_transfer_proof.sender,
|
||||||
recv_transfer_proof_ack: recv_transfer_proof_ack.receiver,
|
recv_transfer_proof_ack: recv_transfer_proof_ack.receiver,
|
||||||
|
@ -173,7 +177,7 @@ impl EventLoop {
|
||||||
let _ = self.recv_encrypted_signature.send(*msg).await;
|
let _ = self.recv_encrypted_signature.send(*msg).await;
|
||||||
}
|
}
|
||||||
OutEvent::Request(event) => {
|
OutEvent::Request(event) => {
|
||||||
let _ = self.request.send(*event).await;
|
let _ = self.handle_swap_request(*event).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -200,4 +204,43 @@ impl EventLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_swap_request(&mut self, event: swap_response::OutEvent) -> Result<()> {
|
||||||
|
let swap_response::OutEvent {
|
||||||
|
msg,
|
||||||
|
bob_peer_id,
|
||||||
|
channel,
|
||||||
|
} = event;
|
||||||
|
// 1. Check if acceptable request
|
||||||
|
// 2. Send response
|
||||||
|
|
||||||
|
let btc_amount = msg.btc_amount;
|
||||||
|
let xmr_amount = btc_amount.as_btc() * RATE as f64;
|
||||||
|
let xmr_amount = monero::Amount::from_monero(xmr_amount)?;
|
||||||
|
let swap_response = SwapResponse { xmr_amount };
|
||||||
|
|
||||||
|
self.swarm
|
||||||
|
.send_swap_response(channel, swap_response)
|
||||||
|
.context("Failed to send swap response")?;
|
||||||
|
|
||||||
|
// 3. Start setup execution
|
||||||
|
|
||||||
|
let state0 = State0::new(
|
||||||
|
btc_amount,
|
||||||
|
xmr_amount,
|
||||||
|
self.cancel_timelock,
|
||||||
|
self.punish_timelock,
|
||||||
|
self.bitcoin_wallet.as_ref(),
|
||||||
|
&mut OsRng,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.swarm.execution_setup.run(bob_peer_id, state0);
|
||||||
|
|
||||||
|
// 4. Trigger swap
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use libp2p::{
|
||||||
RequestResponseEvent, RequestResponseMessage, ResponseChannel,
|
RequestResponseEvent, RequestResponseMessage, ResponseChannel,
|
||||||
},
|
},
|
||||||
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters},
|
||||||
NetworkBehaviour,
|
NetworkBehaviour, PeerId,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -23,6 +23,7 @@ use tracing::{debug, error};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OutEvent {
|
pub struct OutEvent {
|
||||||
pub msg: bob::SwapRequest,
|
pub msg: bob::SwapRequest,
|
||||||
|
pub bob_peer_id: PeerId,
|
||||||
pub channel: ResponseChannel<Response>,
|
pub channel: ResponseChannel<Response>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +87,7 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for B
|
||||||
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
|
fn inject_event(&mut self, event: RequestResponseEvent<Request, Response>) {
|
||||||
match event {
|
match event {
|
||||||
RequestResponseEvent::Message {
|
RequestResponseEvent::Message {
|
||||||
|
peer,
|
||||||
message:
|
message:
|
||||||
RequestResponseMessage::Request {
|
RequestResponseMessage::Request {
|
||||||
request, channel, ..
|
request, channel, ..
|
||||||
|
@ -94,7 +96,11 @@ impl NetworkBehaviourEventProcess<RequestResponseEvent<Request, Response>> for B
|
||||||
} => {
|
} => {
|
||||||
if let Request::SwapRequest(msg) = request {
|
if let Request::SwapRequest(msg) = request {
|
||||||
debug!("Received swap request");
|
debug!("Received swap request");
|
||||||
self.events.push_back(OutEvent { msg: *msg, channel })
|
self.events.push_back(OutEvent {
|
||||||
|
bob_peer_id: peer,
|
||||||
|
msg: *msg,
|
||||||
|
channel,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RequestResponseEvent::Message {
|
RequestResponseEvent::Message {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue