Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions dlc-manager/src/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ pub enum Contract {
Signed(signed_contract::SignedContract),
/// A contract whose funding transaction was included in the blockchain.
Confirmed(signed_contract::SignedContract),
/// A contract for which a CET was broadcasted, but not neccesarily confirmed to blockchain
/// A contract for which a CET was broadcasted, but not fully confirmed to blockchain
PreClosed(PreClosedContract),
/// A contract for which a CET was confirmed to blockchain
/// A contract for which a CET was confirmed to blockchain with sufficient confirmations
Closed(ClosedContract),
/// A contract whose refund transaction was broadcast.
Refunded(signed_contract::SignedContract),
Expand Down
3 changes: 2 additions & 1 deletion dlc-manager/src/contract/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ impl_dlc_writeable_external!(
{ (fund, writeable),
(cets, vec),
(refund, writeable),
(funding_script_pubkey, writeable) }
(funding_script_pubkey, writeable),
(pending_close_txs, vec) }
);
impl_dlc_writeable!(AcceptedContract, {
(offered_contract, writeable),
Expand Down
127 changes: 126 additions & 1 deletion dlc-manager/src/contract_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use dlc::{DlcTransactions, PartyParams};
use dlc_messages::FundingInput;
use dlc_messages::{
oracle_msgs::{OracleAnnouncement, OracleAttestation},
AcceptDlc, FundingSignature, FundingSignatures, OfferDlc, SignDlc, WitnessElement,
AcceptDlc, CloseDlc, FundingSignature, FundingSignatures, OfferDlc, SignDlc, WitnessElement,
};
use secp256k1_zkp::{
ecdsa::Signature, All, EcdsaAdaptorSignature, PublicKey, Secp256k1, SecretKey, Signing,
Expand Down Expand Up @@ -165,6 +165,7 @@ pub(crate) fn accept_contract_internal(
cets,
refund,
funding_script_pubkey,
pending_close_txs: _,
} = dlc_transactions;

let mut cets = cets.clone();
Expand Down Expand Up @@ -212,6 +213,7 @@ pub(crate) fn accept_contract_internal(
cets,
refund: refund.clone(),
funding_script_pubkey: funding_script_pubkey.clone(),
pending_close_txs: vec![],
};

let accepted_contract = AcceptedContract {
Expand Down Expand Up @@ -340,6 +342,7 @@ where
cets,
refund,
funding_script_pubkey,
pending_close_txs: _,
} = dlc_transactions;

let mut fund_psbt = Psbt::from_unsigned_tx(fund.clone())
Expand Down Expand Up @@ -492,6 +495,7 @@ where
cets,
refund: refund.clone(),
funding_script_pubkey: funding_script_pubkey.clone(),
pending_close_txs: vec![],
};

let accepted_contract = AcceptedContract {
Expand Down Expand Up @@ -754,6 +758,127 @@ where
Ok(refund)
}

/// Creates a cooperative close transaction and signs it with the local party's key.
pub fn create_cooperative_close<C: Signing, SP: Deref>(
secp: &Secp256k1<C>,
signed_contract: &SignedContract,
counter_payout: Amount,
signer_provider: &SP,
) -> Result<(CloseDlc, Transaction), Error>
where
SP::Target: ContractSignerProvider,
{
let accepted_contract = &signed_contract.accepted_contract;
let offered_contract = &accepted_contract.offered_contract;
let total_collateral = offered_contract.total_collateral;

if counter_payout > total_collateral {
return Err(Error::InvalidParameters(
"Counter payout is greater than total collateral".to_string(),
));
}

let offer_payout = total_collateral - counter_payout;
let fund_output_value = accepted_contract.dlc_transactions.get_fund_output().value;
let fund_outpoint = accepted_contract.dlc_transactions.get_fund_outpoint();

// Create the cooperative close transaction
let close_tx = dlc::channel::create_collaborative_close_transaction(
&offered_contract.offer_params,
offer_payout,
&accepted_contract.accept_params,
counter_payout,
fund_outpoint,
fund_output_value,
);

// Get our private key and sign the transaction
let fund_private_key =
Comment thread
matthewjablack marked this conversation as resolved.
Outdated
signer_provider.get_secret_key_for_pubkey(if offered_contract.is_offer_party {
&offered_contract.offer_params.fund_pubkey
} else {
&accepted_contract.accept_params.fund_pubkey
})?;

let close_signature = dlc::util::get_raw_sig_for_tx_input(
secp,
&close_tx,
0,
&accepted_contract.dlc_transactions.funding_script_pubkey,
fund_output_value,
&fund_private_key,
)?;

// Create the CloseDlc message
let close_message = CloseDlc {
protocol_version: crate::conversion_utils::PROTOCOL_VERSION,
contract_id: accepted_contract.get_contract_id(),
close_signature,
offer_payout,
accept_payout: counter_payout,
fund_input_serial_id: offered_contract.fund_output_serial_id,
funding_inputs: accepted_contract.funding_inputs.clone(),
funding_signatures: signed_contract.funding_signatures.clone(),
};

Ok((close_message, close_tx))
}

/// Verifies and completes a cooperative close transaction using the counter party's signature.
pub fn complete_cooperative_close<C: Signing, SP: Deref>(
secp: &Secp256k1<C>,
signed_contract: &SignedContract,
close_message: &CloseDlc,
signer_provider: &SP,
) -> Result<Transaction, Error>
where
SP::Target: ContractSignerProvider,
{
let accepted_contract = &signed_contract.accepted_contract;
let offered_contract = &accepted_contract.offered_contract;
let fund_output_value = accepted_contract.dlc_transactions.get_fund_output().value;
let fund_outpoint = accepted_contract.dlc_transactions.get_fund_outpoint();

// Recreate the close transaction to verify
let mut close_tx = dlc::channel::create_collaborative_close_transaction(
&offered_contract.offer_params,
close_message.offer_payout,
&accepted_contract.accept_params,
close_message.accept_payout,
fund_outpoint,
fund_output_value,
);

// Get our private key
let fund_private_key =
signer_provider.get_secret_key_for_pubkey(if offered_contract.is_offer_party {
&offered_contract.offer_params.fund_pubkey
} else {
&accepted_contract.accept_params.fund_pubkey
})?;

// Get counter party's pubkey
let counter_pubkey = if offered_contract.is_offer_party {
&accepted_contract.accept_params.fund_pubkey
} else {
&offered_contract.offer_params.fund_pubkey
};

// Sign and combine signatures
dlc::util::sign_multi_sig_input(
secp,
&mut close_tx,
&close_message.close_signature,
counter_pubkey,
&fund_private_key,
&accepted_contract.dlc_transactions.funding_script_pubkey,
fund_output_value,
0,
)?;

Ok(close_tx)
}

#[cfg(test)]
mod tests {
use std::rc::Rc;
Expand Down
Loading
Loading