diff --git a/src/contract/split.rs b/src/contract/split.rs index 4d3ce0c..3358079 100644 --- a/src/contract/split.rs +++ b/src/contract/split.rs @@ -1,4 +1,4 @@ -use bitcoin::{absolute::LockTime, Amount, OutPoint, Sequence, Transaction, TxIn, TxOut}; +use bitcoin::{absolute::LockTime, OutPoint, Sequence, Transaction, TxIn, TxOut}; use musig2::{AggNonce, CompactSignature, PartialSignature, PubNonce, SecNonce}; use secp::Scalar; diff --git a/src/spend_info/outcome.rs b/src/spend_info/outcome.rs index 3cdc9ce..9b585e0 100644 --- a/src/spend_info/outcome.rs +++ b/src/spend_info/outcome.rs @@ -6,10 +6,10 @@ use bitcoin::{ LeafVersion, TaprootSpendInfo, TAPROOT_CONTROL_BASE_SIZE, TAPROOT_CONTROL_NODE_SIZE, }, transaction::InputWeightPrediction, - Amount, ScriptBuf, TapLeafHash, TapSighash, TapSighashType, Transaction, TxOut, + Amount, ScriptBuf, TapLeafHash, TapSighash, TapSighashType, Transaction, TxOut, Witness, }; -use musig2::KeyAggContext; -use secp::Point; +use musig2::{CompactSignature, KeyAggContext}; +use secp::{Point, Scalar}; use crate::{ errors::Error, @@ -17,7 +17,7 @@ use crate::{ parties::{MarketMaker, Player}, }; -use std::collections::BTreeMap; +use std::{borrow::Borrow, collections::BTreeMap}; /// Represents a taproot contract which encodes spending conditions for /// the given outcome index's outcome TX. This tree is meant to encumber joint @@ -221,21 +221,43 @@ impl OutcomeSpendInfo { Ok(sighash) } - /// Compute the signature hash for a given split transaction. - pub(crate) fn sighash_tx_reclaim(&self, split_tx: &Transaction) -> Result { - let outcome_prevouts = [TxOut { - script_pubkey: self.script_pubkey(), - value: self.outcome_value, - }]; - + /// Compute a witness for a reclaim transaction which spends from the outcome transaction. + /// + /// This would only be used if none of the attested DLC outcome winners actually paid for + /// their ticket preimage. It allows the market maker to sweep their on-chain money back + /// without splitting it into multiple payout contracts and recombining the outputs unnecessarily. + pub(crate) fn witness_tx_reclaim>( + &self, + split_tx: &Transaction, + input_index: usize, + prevouts: &Prevouts, + market_maker_secret_key: Scalar, + nonce_seed: impl Into, + ) -> Result { let leaf_hash = TapLeafHash::from_script(&self.reclaim_script, LeafVersion::TapScript); let sighash = SighashCache::new(split_tx).taproot_script_spend_signature_hash( - 0, - &Prevouts::All(&outcome_prevouts), + input_index, + prevouts, leaf_hash, TapSighashType::Default, )?; - Ok(sighash) + + let signature: CompactSignature = + musig2::sign_solo(market_maker_secret_key, sighash, nonce_seed); + + let reclaim_control_block = self + .spend_info + .control_block(&(self.reclaim_script.clone(), LeafVersion::TapScript)) + .expect("reclaim script cannot be missing"); + + // The witness stack for a reclaim TX which spends an outcome TX is: + //