Browse Source

Merge #316

316: Provide more feedback to the user during collaborative settlement r=klochowicz a=klochowicz

Fixes #309

Co-authored-by: Mariusz Klochowicz <mariusz@klochowicz.com>
refactor/no-log-handler
bors[bot] 3 years ago
committed by GitHub
parent
commit
cb38e617b3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      daemon/src/maker_cfd.rs
  2. 48
      daemon/src/model/cfd.rs
  3. 6
      daemon/src/monitor.rs
  4. 1
      daemon/src/oracle.rs
  5. 41
      daemon/src/to_sse_event.rs
  6. 5
      frontend/src/components/Types.tsx

8
daemon/src/maker_cfd.rs

@ -307,6 +307,8 @@ impl Actor {
TimestampedTransaction::new(tx.clone(), dlc.script_pubkey_for(cfd.role())), TimestampedTransaction::new(tx.clone(), dlc.script_pubkey_for(cfd.role())),
))?; ))?;
insert_new_cfd_state_by_order_id(cfd.order.id, &cfd.state, &mut conn).await?; insert_new_cfd_state_by_order_id(cfd.order.id, &cfd.state, &mut conn).await?;
self.cfd_feed_actor_inbox
.send(load_all_cfds(&mut conn).await?)?;
let spend_tx = dlc.finalize_spend_transaction((tx, sig_maker), sig_taker)?; let spend_tx = dlc.finalize_spend_transaction((tx, sig_maker), sig_taker)?;
@ -317,12 +319,6 @@ impl Actor {
.context("Broadcasting spend transaction")?; .context("Broadcasting spend transaction")?;
tracing::info!("Close transaction published with txid {}", txid); tracing::info!("Close transaction published with txid {}", txid);
cfd.handle(CfdStateChangeEvent::CloseSent(TimestampedTransaction::new(
spend_tx,
dlc.script_pubkey_for(cfd.role()),
)))?;
insert_new_cfd_state_by_order_id(cfd.order.id, &cfd.state, &mut conn).await?;
self.current_agreed_proposals self.current_agreed_proposals
.remove(&order_id) .remove(&order_id)
.context("remove accepted proposal after signing")?; .context("remove accepted proposal after signing")?;

48
daemon/src/model/cfd.rs

@ -253,17 +253,6 @@ pub enum CfdState {
attestation: Attestation, attestation: Attestation,
}, },
/// The collaborative close transaction was published but is not final yet.
///
/// This state applies to taker and maker.
/// This state is needed, because otherwise the user does not get any feedback.
PendingClose {
common: CfdStateCommon,
dlc: Dlc,
attestation: Option<Attestation>,
collaborative_close: TimestampedTransaction,
},
/// The position was closed collaboratively or non-collaboratively /// The position was closed collaboratively or non-collaboratively
/// ///
/// This state applies to taker and maker. /// This state applies to taker and maker.
@ -408,7 +397,6 @@ impl CfdState {
CfdState::SetupFailed { common, .. } => common, CfdState::SetupFailed { common, .. } => common,
CfdState::PendingCommit { common, .. } => common, CfdState::PendingCommit { common, .. } => common,
CfdState::PendingCet { common, .. } => common, CfdState::PendingCet { common, .. } => common,
CfdState::PendingClose { common, .. } => common,
CfdState::Closed { common, .. } => common, CfdState::Closed { common, .. } => common,
}; };
@ -425,10 +413,6 @@ impl CfdState {
collaborative_close, collaborative_close,
.. ..
} => collaborative_close.clone(), } => collaborative_close.clone(),
CfdState::PendingClose {
collaborative_close,
..
} => Some(collaborative_close.clone()),
_ => None, _ => None,
} }
} }
@ -476,9 +460,6 @@ impl fmt::Display for CfdState {
CfdState::PendingCet { .. } => { CfdState::PendingCet { .. } => {
write!(f, "Pending CET") write!(f, "Pending CET")
} }
CfdState::PendingClose { .. } => {
write!(f, "Pending Close")
}
CfdState::Closed { .. } => { CfdState::Closed { .. } => {
write!(f, "Closed") write!(f, "Closed")
} }
@ -584,7 +565,6 @@ impl Cfd {
Ok((p_n_l, p_n_l_percent)) Ok((p_n_l, p_n_l_percent))
} }
#[allow(dead_code)] // Not used by all binaries.
pub fn calculate_settlement(&self, current_price: Usd) -> Result<SettlementProposal> { pub fn calculate_settlement(&self, current_price: Usd) -> Result<SettlementProposal> {
let payout_curve = let payout_curve =
payout_curve::calculate(self.order.price, self.quantity_usd, self.order.leverage)?; payout_curve::calculate(self.order.price, self.quantity_usd, self.order.leverage)?;
@ -946,26 +926,6 @@ impl Cfd {
self.state self.state
), ),
}, },
CfdStateChangeEvent::CloseSent(collaborative_close) => match self.state.clone() {
CfdState::Open {
common,
dlc,
attestation,
collaborative_close : Some(_),
} => CfdState::PendingClose {
common,
dlc,
attestation,
collaborative_close,
},
CfdState::Open {
collaborative_close : None,
..
} => bail!("Cannot transition to PendingClose because Open state did not record a settlement proposal beforehand"),
_ => bail!(
"Cannot transition to PendingClose because of unexpected state {}",
self.state)
}
}; };
self.state = new_state.clone(); self.state = new_state.clone();
@ -1161,7 +1121,6 @@ impl Cfd {
| CfdState::Accepted { .. } | CfdState::Accepted { .. }
| CfdState::Rejected { .. } | CfdState::Rejected { .. }
| CfdState::ContractSetup { .. } | CfdState::ContractSetup { .. }
| CfdState::PendingClose { .. }
| CfdState::Closed { .. } | CfdState::Closed { .. }
| CfdState::MustRefund { .. } | CfdState::MustRefund { .. }
| CfdState::Refunded { .. } | CfdState::Refunded { .. }
@ -1201,7 +1160,6 @@ impl Cfd {
| CfdState::PendingOpen { .. } | CfdState::PendingOpen { .. }
| CfdState::Open { .. } | CfdState::Open { .. }
| CfdState::PendingCommit { .. } | CfdState::PendingCommit { .. }
| CfdState::PendingClose { .. }
| CfdState::Closed { .. } | CfdState::Closed { .. }
| CfdState::OpenCommitted { .. } | CfdState::OpenCommitted { .. }
| CfdState::MustRefund { .. } | CfdState::MustRefund { .. }
@ -1216,10 +1174,6 @@ impl Cfd {
collaborative_close: Some(collaborative_close), collaborative_close: Some(collaborative_close),
.. ..
} }
| CfdState::PendingClose {
collaborative_close,
..
}
| CfdState::Closed { | CfdState::Closed {
payout: Payout::CollaborativeClose(collaborative_close), payout: Payout::CollaborativeClose(collaborative_close),
.. ..
@ -1282,8 +1236,6 @@ pub enum CfdStateChangeEvent {
CetSent, CetSent,
/// Settlement proposal was signed by the taker and sent to the maker /// Settlement proposal was signed by the taker and sent to the maker
ProposalSigned(TimestampedTransaction), ProposalSigned(TimestampedTransaction),
/// Maker signed and finalized the close transaction with both signatures
CloseSent(TimestampedTransaction),
} }
/// Returns the Profit/Loss (P/L) as Bitcoin. Losses are capped by the provided margin /// Returns the Profit/Loss (P/L) as Bitcoin. Losses are capped by the provided margin

6
daemon/src/monitor.rs

@ -126,12 +126,6 @@ impl Actor<bdk::electrum_client::Client> {
actor.monitor_commit_refund_timelock(&params, cfd.order.id); actor.monitor_commit_refund_timelock(&params, cfd.order.id);
actor.monitor_refund_finality(&params,cfd.order.id); actor.monitor_refund_finality(&params,cfd.order.id);
} }
CfdState::PendingClose { collaborative_close, .. } => {
let transaction = collaborative_close.tx;
let close_params = (transaction.txid(),
transaction.output.first().expect("have output").script_pubkey.clone());
actor.monitor_close_finality(close_params,cfd.order.id);
}
CfdState::MustRefund { dlc, .. } => { CfdState::MustRefund { dlc, .. } => {
let params = MonitorParams::from_dlc_and_timelocks(dlc.clone(), cfd.refund_timelock_in_blocks()); let params = MonitorParams::from_dlc_and_timelocks(dlc.clone(), cfd.refund_timelock_in_blocks());
actor.cfds.insert(cfd.order.id, params.clone()); actor.cfds.insert(cfd.order.id, params.clone());

1
daemon/src/oracle.rs

@ -88,7 +88,6 @@ impl Actor {
| CfdState::Accepted { .. } | CfdState::Accepted { .. }
| CfdState::Rejected { .. } | CfdState::Rejected { .. }
| CfdState::ContractSetup { .. } | CfdState::ContractSetup { .. }
| CfdState::PendingClose { .. }
// Final states // Final states
| CfdState::Closed { .. } | CfdState::Closed { .. }

41
daemon/src/to_sse_event.rs

@ -326,7 +326,21 @@ fn to_cfd_state(
direction: SettlementKind::Incoming, direction: SettlementKind::Incoming,
.. ..
}) => CfdState::IncomingSettlementProposal, }) => CfdState::IncomingSettlementProposal,
Some(UpdateCfdProposal::RollOverProposal {
direction: SettlementKind::Outgoing,
..
}) => CfdState::OutgoingRollOverProposal,
Some(UpdateCfdProposal::RollOverProposal {
direction: SettlementKind::Incoming,
..
}) => CfdState::IncomingRollOverProposal,
None => match cfd_state { None => match cfd_state {
// Filled in collaborative close in Open means that we're awaiting
// a collaborative closure
model::cfd::CfdState::Open {
collaborative_close: Some(_),
..
} => CfdState::PendingClose,
model::cfd::CfdState::OutgoingOrderRequest { .. } => CfdState::OutgoingOrderRequest, model::cfd::CfdState::OutgoingOrderRequest { .. } => CfdState::OutgoingOrderRequest,
model::cfd::CfdState::IncomingOrderRequest { .. } => CfdState::IncomingOrderRequest, model::cfd::CfdState::IncomingOrderRequest { .. } => CfdState::IncomingOrderRequest,
model::cfd::CfdState::Accepted { .. } => CfdState::Accepted, model::cfd::CfdState::Accepted { .. } => CfdState::Accepted,
@ -340,17 +354,8 @@ fn to_cfd_state(
model::cfd::CfdState::SetupFailed { .. } => CfdState::SetupFailed, model::cfd::CfdState::SetupFailed { .. } => CfdState::SetupFailed,
model::cfd::CfdState::PendingCommit { .. } => CfdState::PendingCommit, model::cfd::CfdState::PendingCommit { .. } => CfdState::PendingCommit,
model::cfd::CfdState::PendingCet { .. } => CfdState::PendingCet, model::cfd::CfdState::PendingCet { .. } => CfdState::PendingCet,
model::cfd::CfdState::PendingClose { .. } => CfdState::PendingClose,
model::cfd::CfdState::Closed { .. } => CfdState::Closed, model::cfd::CfdState::Closed { .. } => CfdState::Closed,
}, },
Some(UpdateCfdProposal::RollOverProposal {
direction: SettlementKind::Outgoing,
..
}) => CfdState::OutgoingRollOverProposal,
Some(UpdateCfdProposal::RollOverProposal {
direction: SettlementKind::Incoming,
..
}) => CfdState::IncomingRollOverProposal,
} }
} }
@ -360,11 +365,22 @@ fn to_tx_url_list(state: model::cfd::CfdState, network: Network) -> Vec<TxUrl> {
let tx_ub = TxUrlBuilder::new(network); let tx_ub = TxUrlBuilder::new(network);
match state { match state {
PendingOpen { dlc, .. } | Open { dlc, .. } => { PendingOpen { dlc, .. } => {
vec![tx_ub.lock(&dlc)] vec![tx_ub.lock(&dlc)]
} }
PendingCommit { dlc, .. } => vec![tx_ub.lock(&dlc), tx_ub.commit(&dlc)], PendingCommit { dlc, .. } => vec![tx_ub.lock(&dlc), tx_ub.commit(&dlc)],
OpenCommitted { dlc, .. } => vec![tx_ub.lock(&dlc), tx_ub.commit(&dlc)], OpenCommitted { dlc, .. } => vec![tx_ub.lock(&dlc), tx_ub.commit(&dlc)],
Open {
dlc,
collaborative_close,
..
} => {
let mut tx_urls = vec![tx_ub.lock(&dlc)];
if let Some(collaborative_close) = collaborative_close {
tx_urls.push(tx_ub.collaborative_close(collaborative_close.tx.txid()));
}
tx_urls
}
PendingCet { PendingCet {
dlc, attestation, .. dlc, attestation, ..
} => vec![ } => vec![
@ -386,7 +402,6 @@ fn to_tx_url_list(state: model::cfd::CfdState, network: Network) -> Vec<TxUrl> {
Refunded { dlc, .. } => vec![tx_ub.refund(&dlc)], Refunded { dlc, .. } => vec![tx_ub.refund(&dlc)],
OutgoingOrderRequest { .. } OutgoingOrderRequest { .. }
| IncomingOrderRequest { .. } | IncomingOrderRequest { .. }
| PendingClose { .. }
| Accepted { .. } | Accepted { .. }
| Rejected { .. } | Rejected { .. }
| ContractSetup { .. } | ContractSetup { .. }
@ -435,6 +450,10 @@ fn available_actions(state: CfdState, role: Role) -> Vec<CfdAction> {
(CfdState::OutgoingSettlementProposal { .. }, Role::Maker) => { (CfdState::OutgoingSettlementProposal { .. }, Role::Maker) => {
vec![CfdAction::Commit] vec![CfdAction::Commit]
} }
// User is awaiting collaborative close, commit is left as a safeguard
(CfdState::PendingClose { .. }, _) => {
vec![CfdAction::Commit]
}
(CfdState::Open { .. }, Role::Taker) => { (CfdState::Open { .. }, Role::Taker) => {
vec![CfdAction::RollOver, CfdAction::Commit, CfdAction::Settle] vec![CfdAction::RollOver, CfdAction::Commit, CfdAction::Settle]
} }

5
frontend/src/components/Types.tsx

@ -82,6 +82,8 @@ export class State {
return "Open"; return "Open";
case StateKey.PENDING_COMMIT: case StateKey.PENDING_COMMIT:
return "Pending Commit"; return "Pending Commit";
case StateKey.PENDING_CLOSE:
return "Pending Close";
case StateKey.OPEN_COMMITTED: case StateKey.OPEN_COMMITTED:
return "Open (commit-tx published)"; return "Open (commit-tx published)";
case StateKey.INCOMING_SETTLEMENT_PROPOSAL: case StateKey.INCOMING_SETTLEMENT_PROPOSAL:
@ -123,6 +125,7 @@ export class State {
case StateKey.OPEN_COMMITTED: case StateKey.OPEN_COMMITTED:
case StateKey.MUST_REFUND: case StateKey.MUST_REFUND:
case StateKey.PENDING_CET: case StateKey.PENDING_CET:
case StateKey.PENDING_CLOSE:
return orange; return orange;
case StateKey.OUTGOING_ORDER_REQUEST: case StateKey.OUTGOING_ORDER_REQUEST:
@ -158,6 +161,7 @@ export class State {
case StateKey.OUTGOING_SETTLEMENT_PROPOSAL: case StateKey.OUTGOING_SETTLEMENT_PROPOSAL:
case StateKey.OUTGOING_ROLL_OVER_PROPOSAL: case StateKey.OUTGOING_ROLL_OVER_PROPOSAL:
case StateKey.PENDING_CET: case StateKey.PENDING_CET:
case StateKey.PENDING_CLOSE:
return StateGroupKey.OPEN; return StateGroupKey.OPEN;
case StateKey.INCOMING_SETTLEMENT_PROPOSAL: case StateKey.INCOMING_SETTLEMENT_PROPOSAL:
@ -195,6 +199,7 @@ const enum StateKey {
CONTRACT_SETUP = "ContractSetup", CONTRACT_SETUP = "ContractSetup",
PENDING_OPEN = "PendingOpen", PENDING_OPEN = "PendingOpen",
OPEN = "Open", OPEN = "Open",
PENDING_CLOSE = "PendingClose",
PENDING_COMMIT = "PendingCommit", PENDING_COMMIT = "PendingCommit",
PENDING_CET = "PendingCet", PENDING_CET = "PendingCet",
OPEN_COMMITTED = "OpenCommitted", OPEN_COMMITTED = "OpenCommitted",

Loading…
Cancel
Save