Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions dlc-manager/src/channel_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1770,6 +1770,7 @@ pub fn offer_collaborative_close<C: Signing, SP: Deref, T: Deref>(
secp: &Secp256k1<C>,
signed_channel: &mut SignedChannel,
counter_payout: Amount,
additional_inputs: Vec<OutPoint>,
signer_provider: &SP,
time: &T,
) -> Result<(CollaborativeCloseOffer, Transaction), Error>
Expand Down Expand Up @@ -1800,6 +1801,7 @@ where
vout: signed_channel.fund_output_index as u32,
},
fund_output_value,
&additional_inputs,
);

let keys_id = signed_channel
Expand Down Expand Up @@ -1875,6 +1877,7 @@ where
vout: signed_channel.fund_output_index as u32,
},
fund_output_value,
&[], // TODO: Add additional inputs parameter to prevent free option problem
);

let mut state = SignedChannelState::CollaborativeCloseOffered {
Expand Down
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
124 changes: 123 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,124 @@ 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,
&[], // No additional inputs for contract cooperative close
);

// Get our private key and sign the transaction
let signer = signer_provider.derive_contract_signer(offered_contract.keys_id)?;
let fund_private_key = signer.get_secret_key()?;

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,
accept_payout: counter_payout,
fee_rate_per_vb: offered_contract.fee_rate_per_vb,
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();

let total_collateral = offered_contract.total_collateral;
let offer_payout = total_collateral - close_message.accept_payout;

// Recreate the close transaction to verify
let mut close_tx = dlc::channel::create_collaborative_close_transaction(
&offered_contract.offer_params,
offer_payout,
&accepted_contract.accept_params,
close_message.accept_payout,
fund_outpoint,
fund_output_value,
&[], // No additional inputs for contract cooperative close verification
);

// Get our private key
let signer = signer_provider.derive_contract_signer(offered_contract.keys_id)?;
let fund_private_key = signer.get_secret_key()?;

// 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