Skip to content

Commit

Permalink
Add ability to handle external closures of contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman committed Nov 28, 2023
1 parent e183feb commit 099bbb0
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
55 changes: 54 additions & 1 deletion dlc-manager/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::utils::same_nonces;
use crate::Signer;
use crate::{ChannelId, ContractId};
use bitcoin::Transaction;
use bitcoin::{locktime, Address, LockTime};
use bitcoin::{locktime, Address, LockTime, OutPoint};
use dlc_messages::channel::{
AcceptChannel, CollaborativeCloseOffer, OfferChannel, Reject, RenewAccept, RenewConfirm,
RenewFinalize, RenewOffer, SettleAccept, SettleConfirm, SettleFinalize, SettleOffer,
Expand Down Expand Up @@ -361,6 +361,22 @@ where
Ok(())
}

/// Outputs to watch for on the blockchain. This is used to detect when a contract is closed
/// by our counter party.
///
/// If a contract is closed by our counter party, the [`on_counterparty_close`] method should
/// be called.
pub fn outputs_to_watch(&self) -> Result<Vec<(OutPoint, SignedContract)>, Error> {
let contracts: Vec<SignedContract> = self.store.get_confirmed_contracts()?;

let outpoints = contracts
.into_iter()
.map(|c| (c.accepted_contract.dlc_transactions.get_fund_outpoint(), c))
.collect();

Ok(outpoints)
}

fn on_offer_message(
&mut self,
offered_message: &OfferDlc,
Expand Down Expand Up @@ -802,6 +818,43 @@ where

Ok(())
}

/// Function to call when we detect that a contract was closed by our counter party.
/// This will update the state of the contract and return the [`Contract`] object.
pub fn on_counterparty_close(
&mut self,
contract: &SignedContract,
closing_tx: Transaction,
confirmations: u32,
) -> Result<Contract, Error> {
// check if it is the refund tx (easy case)
if contract.accepted_contract.dlc_transactions.refund.txid() == closing_tx.txid() {
let refunded = Contract::Refunded(contract.clone());
self.store.update_contract(&refunded)?;
return Ok(refunded);
}

let contract = if confirmations < NB_CONFIRMATIONS {
Contract::PreClosed(PreClosedContract {
signed_contract: contract.clone(),
attestations: None, // todo in some cases we can get the attestations from the closing tx
signed_cet: closing_tx,
})
} else {
Contract::Closed(ClosedContract {
attestations: None, // todo in some cases we can get the attestations from the closing tx
pnl: contract.accepted_contract.compute_pnl(&closing_tx),
signed_cet: Some(closing_tx),
contract_id: contract.accepted_contract.get_contract_id(),
temporary_contract_id: contract.accepted_contract.offered_contract.id,
counter_party_id: contract.accepted_contract.offered_contract.counter_party,
})
};

self.store.update_contract(&contract)?;

Ok(contract)
}
}

impl<W: Deref, B: Deref, S: Deref, O: Deref, T: Deref, F: Deref> Manager<W, B, S, O, T, F>
Expand Down
8 changes: 8 additions & 0 deletions dlc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ impl DlcTransactions {
.unwrap()
.0
}

/// Get the outpoint for the fund output in the fund transaction
pub fn get_fund_outpoint(&self) -> OutPoint {
OutPoint {
txid: self.fund.txid(),
vout: self.get_fund_output_index() as u32,
}
}
}

/// Contains info about a utxo used for funding a DLC contract
Expand Down

0 comments on commit 099bbb0

Please sign in to comment.