|
|
@ -15,6 +15,7 @@ use crate::{maker_inc_connections, monitor, oracle, setup_contract, wire}; |
|
|
|
use anyhow::{bail, Context as _, Result}; |
|
|
|
use async_trait::async_trait; |
|
|
|
use bdk::bitcoin::secp256k1::schnorrsig; |
|
|
|
use cfd_protocol::secp256k1_zkp::Signature; |
|
|
|
use futures::channel::mpsc; |
|
|
|
use futures::{future, SinkExt}; |
|
|
|
use std::collections::HashMap; |
|
|
@ -91,6 +92,10 @@ pub struct Actor { |
|
|
|
oracle_actor: Address<oracle::Actor<Actor, monitor::Actor<Actor>>>, |
|
|
|
// Maker needs to also store TakerId to be able to send a reply back
|
|
|
|
current_pending_proposals: HashMap<OrderId, (UpdateCfdProposal, TakerId)>, |
|
|
|
// TODO: Persist instead of using an in-memory hashmap for resiliency?
|
|
|
|
// (not a huge deal, as in the worst case taker will fall back to
|
|
|
|
// noncollaborative settlement)
|
|
|
|
current_agreed_proposals: HashMap<OrderId, (SettlementProposal, TakerId)>, |
|
|
|
} |
|
|
|
|
|
|
|
enum SetupState { |
|
|
@ -136,6 +141,7 @@ impl Actor { |
|
|
|
roll_over_state: RollOverState::None, |
|
|
|
oracle_actor, |
|
|
|
current_pending_proposals: HashMap::new(), |
|
|
|
current_agreed_proposals: HashMap::new(), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -168,6 +174,21 @@ impl Actor { |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
|
|
|
|
fn get_settlement_proposal(&self, order_id: OrderId) -> Result<(SettlementProposal, TakerId)> { |
|
|
|
let (update_proposal, taker_id) = self |
|
|
|
.current_pending_proposals |
|
|
|
.get(&order_id) |
|
|
|
.context("have a proposal that is about to be accepted")?; |
|
|
|
|
|
|
|
let proposal = match update_proposal { |
|
|
|
UpdateCfdProposal::Settlement { proposal, .. } => proposal, |
|
|
|
UpdateCfdProposal::RollOverProposal { .. } => { |
|
|
|
anyhow::bail!("did not expect a rollover proposal"); |
|
|
|
} |
|
|
|
}; |
|
|
|
Ok((proposal.clone(), *taker_id)) |
|
|
|
} |
|
|
|
|
|
|
|
async fn handle_new_order( |
|
|
|
&mut self, |
|
|
|
price: Usd, |
|
|
@ -246,6 +267,53 @@ impl Actor { |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
|
|
|
|
async fn handle_initiate_settlement( |
|
|
|
&mut self, |
|
|
|
taker_id: TakerId, |
|
|
|
order_id: OrderId, |
|
|
|
sig_taker: Signature, |
|
|
|
) -> Result<()> { |
|
|
|
tracing::info!( |
|
|
|
"Taker {} initiated collab settlement for order { } by sending their signature", |
|
|
|
taker_id, |
|
|
|
order_id, |
|
|
|
); |
|
|
|
|
|
|
|
let (proposal, agreed_taker_id) = self |
|
|
|
.current_agreed_proposals |
|
|
|
.get(&order_id) |
|
|
|
.context("maker should have data matching the agreed settlement")?; |
|
|
|
|
|
|
|
if taker_id != *agreed_taker_id { |
|
|
|
anyhow::bail!( |
|
|
|
"taker Id mismatch. Expected: {}, received: {}", |
|
|
|
agreed_taker_id, |
|
|
|
taker_id |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
let mut conn = self.db.acquire().await?; |
|
|
|
|
|
|
|
let cfd = load_cfd_by_order_id(order_id, &mut conn).await?; |
|
|
|
let dlc = cfd.open_dlc().context("CFD was in wrong state")?; |
|
|
|
|
|
|
|
let (tx, sig_maker) = dlc.close_transaction(proposal)?; |
|
|
|
let spend_tx = dlc.finalize_spend_transaction((tx, sig_maker), sig_taker)?; |
|
|
|
|
|
|
|
self.wallet |
|
|
|
.try_broadcast_transaction(spend_tx) |
|
|
|
.await |
|
|
|
.context("Broadcasting spend transaction")?; |
|
|
|
|
|
|
|
self.current_agreed_proposals |
|
|
|
.remove(&order_id) |
|
|
|
.context("remove accepted proposal after signing")?; |
|
|
|
|
|
|
|
// TODO: Monitor for the transaction
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
|
|
|
|
async fn handle_propose_roll_over( |
|
|
|
&mut self, |
|
|
|
proposal: RollOverProposal, |
|
|
@ -631,9 +699,6 @@ impl Actor { |
|
|
|
|
|
|
|
let taker_id = self.get_taker_id_of_proposal(&order_id)?; |
|
|
|
|
|
|
|
// TODO: Initiate the settlement - should we start calculating the
|
|
|
|
// signature here?
|
|
|
|
|
|
|
|
self.takers |
|
|
|
.do_send_async(maker_inc_connections::TakerMessage { |
|
|
|
taker_id, |
|
|
@ -641,6 +706,8 @@ impl Actor { |
|
|
|
}) |
|
|
|
.await?; |
|
|
|
|
|
|
|
self.current_agreed_proposals |
|
|
|
.insert(order_id, self.get_settlement_proposal(order_id)?); |
|
|
|
self.remove_pending_proposal(&order_id) |
|
|
|
.context("accepted settlement")?; |
|
|
|
Ok(()) |
|
|
@ -997,6 +1064,12 @@ impl Handler<TakerStreamMessage> for Actor { |
|
|
|
} |
|
|
|
)) |
|
|
|
} |
|
|
|
wire::TakerToMaker::InitiateSettlement { |
|
|
|
order_id, |
|
|
|
sig_taker, |
|
|
|
} => { |
|
|
|
log_error!(self.handle_initiate_settlement(taker_id, order_id, sig_taker)) |
|
|
|
} |
|
|
|
wire::TakerToMaker::Protocol(msg) => { |
|
|
|
log_error!(self.handle_inc_protocol_msg(taker_id, msg)) |
|
|
|
} |
|
|
|