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
2 changes: 1 addition & 1 deletion ddk-manager/benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ fn create_transactions(payouts: &[Payout]) -> DlcTransactions {
collateral: Amount::from_sat(100000000),
dlc_inputs: vec![],
};
create_dlc_transactions(&offer_params, &accept_params, payouts, 1000, 2, 0, 1000, 3).unwrap()
create_dlc_transactions(&offer_params, &accept_params, payouts, 1000, 2, 0, 1000, 3, 0).unwrap()
}

fn accept_seckey() -> SecretKey {
Expand Down
3 changes: 2 additions & 1 deletion ddk-manager/src/channel/offered_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl OfferedChannel {
let party_points = &self.party_points;
OfferChannel {
protocol_version: crate::conversion_utils::PROTOCOL_VERSION,
contract_flags: 0,
contract_flags: offered_contract.contract_flags,
chain_hash: crate::conversion_utils::BITCOIN_CHAINHASH,
temporary_contract_id: offered_contract.id,
temporary_channel_id: self.temporary_channel_id,
Expand Down Expand Up @@ -122,6 +122,7 @@ impl OfferedChannel {
fund_output_serial_id: offer_channel.fund_output_serial_id,
funding_inputs: offer_channel.funding_inputs.clone(),
total_collateral: offer_channel.contract_info.get_total_collateral(),
contract_flags: offer_channel.contract_flags,
keys_id,
};

Expand Down
5 changes: 5 additions & 0 deletions ddk-manager/src/channel_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ where
offered_contract.cet_locktime,
offered_contract.fund_output_serial_id,
Sequence(offered_channel.cet_nsequence),
offered_contract.contract_flags,
)?;

let own_base_secret_key =
Expand Down Expand Up @@ -368,6 +369,7 @@ where
offered_contract.cet_locktime,
offered_contract.fund_output_serial_id,
Sequence(cet_nsequence),
offered_contract.contract_flags,
)?;

let channel_id = crate::utils::compute_id(
Expand Down Expand Up @@ -1246,6 +1248,7 @@ where
fee_rate_per_vb: signed_channel.fee_rate_per_vb,
cet_locktime: renew_offer.cet_locktime,
refund_locktime: renew_offer.refund_locktime,
contract_flags: 0,
keys_id,
};

Expand Down Expand Up @@ -1338,6 +1341,7 @@ where
offered_contract.fee_rate_per_vb,
0,
Sequence(cet_nsequence),
offered_contract.contract_flags,
)?;

let own_secret_key = derive_private_key(secp, &accept_per_update_point, &own_base_secret_key);
Expand Down Expand Up @@ -1452,6 +1456,7 @@ where
offered_contract.fee_rate_per_vb,
0,
Sequence(cet_nsequence),
offered_contract.contract_flags,
)?;

let _offer_own_sk = derive_private_key(secp, &offer_per_update_point, &own_base_secret_key);
Expand Down
7 changes: 6 additions & 1 deletion ddk-manager/src/contract/offered_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ pub struct OfferedContract {
pub cet_locktime: u32,
/// The time at which the contract becomes refundable.
pub refund_locktime: u32,
/// Feature flags for the contract (bit 0: refund to accepter).
#[cfg_attr(feature = "use-serde", serde(default))]
pub contract_flags: u8,
/// Keys Id for generating the signers
pub(crate) keys_id: KeysId,
}
Expand Down Expand Up @@ -120,6 +123,7 @@ impl OfferedContract {
fee_rate_per_vb: contract.fee_rate,
cet_locktime,
refund_locktime: latest_maturity + refund_delay,
contract_flags: 0,
counter_party: *counter_party,
keys_id,
}
Expand Down Expand Up @@ -157,6 +161,7 @@ impl OfferedContract {
fund_output_serial_id: offer_dlc.fund_output_serial_id,
funding_inputs: offer_dlc.funding_inputs.clone(),
total_collateral: offer_dlc.contract_info.get_total_collateral(),
contract_flags: offer_dlc.contract_flags,
counter_party,
keys_id,
})
Expand All @@ -168,7 +173,7 @@ impl From<&OfferedContract> for OfferDlc {
OfferDlc {
protocol_version: PROTOCOL_VERSION,
temporary_contract_id: offered_contract.id,
contract_flags: 0,
contract_flags: offered_contract.contract_flags,
chain_hash: BITCOIN_CHAINHASH,
contract_info: offered_contract.into(),
funding_pubkey: offered_contract.offer_params.fund_pubkey,
Expand Down
1 change: 1 addition & 0 deletions ddk-manager/src/contract/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ impl_dlc_writeable!(OfferedContract, {
(fee_rate_per_vb, writeable),
(cet_locktime, writeable),
(refund_locktime, writeable),
(contract_flags, writeable),
(counter_party, writeable),
(keys_id, writeable)
});
Expand Down
4 changes: 4 additions & 0 deletions ddk-manager/src/contract_updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ where
0,
offered_contract.cet_locktime,
offered_contract.fund_output_serial_id,
offered_contract.contract_flags,
)?
} else {
log_debug!(logger, "Creating DLC transactions without splicing.");
Expand All @@ -187,6 +188,7 @@ where
0,
offered_contract.cet_locktime,
offered_contract.fund_output_serial_id,
offered_contract.contract_flags,
)?
};

Expand Down Expand Up @@ -404,6 +406,7 @@ where
0,
offered_contract.cet_locktime,
offered_contract.fund_output_serial_id,
offered_contract.contract_flags,
)?
} else {
log_debug!(logger, "Creating DLC transactions without splicing.");
Expand All @@ -416,6 +419,7 @@ where
0,
offered_contract.cet_locktime,
offered_contract.fund_output_serial_id,
offered_contract.contract_flags,
)?
};

Expand Down
2 changes: 2 additions & 0 deletions dlc-messages/src/compatibility_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ fn test_single(case: TestCase, secp: &secp256k1::Secp256k1<secp256k1::All>) {
0,
params.contract_maturity_bound,
0,
0,
)
.unwrap();

Expand Down Expand Up @@ -732,6 +733,7 @@ fn test_dlc_txs() {
0,
params.contract_maturity_bound,
0,
0,
)
.unwrap();
let test_txs = test_case.txs.unwrap();
Expand Down
4 changes: 4 additions & 0 deletions dlc/src/channel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ pub fn create_channel_transactions(
cet_lock_time: u32,
fund_output_serial_id: u64,
cet_nsequence: Sequence,
contract_flags: u8,
) -> Result<DlcChannelTransactions, Error> {
let extra_fee =
super::util::weight_to_fee(BUFFER_TX_WEIGHT + CET_EXTRA_WEIGHT, fee_rate_per_vb)?;
Expand All @@ -267,6 +268,7 @@ pub fn create_channel_transactions(
fee_rate_per_vb,
cet_lock_time,
cet_nsequence,
contract_flags,
)
}

Expand All @@ -285,6 +287,7 @@ pub fn create_renewal_channel_transactions(
fee_rate_per_vb: u64,
cet_lock_time: u32,
cet_nsequence: Sequence,
contract_flags: u8,
) -> Result<DlcChannelTransactions, Error> {
let extra_fee =
super::util::weight_to_fee(BUFFER_TX_WEIGHT + CET_EXTRA_WEIGHT, fee_rate_per_vb)?;
Expand Down Expand Up @@ -327,6 +330,7 @@ pub fn create_renewal_channel_transactions(
refund_lock_time,
cet_lock_time,
Some(cet_nsequence),
contract_flags,
)?;

Ok(DlcChannelTransactions {
Expand Down
89 changes: 87 additions & 2 deletions dlc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ pub mod util;
/// See: https://github.com/discreetlogcontracts/dlcspecs/blob/master/Transactions.md#change-outputs
const DUST_LIMIT: Amount = Amount::from_sat(1000);

/// Bit 0 of `contract_flags`: redirect all refund proceeds to the accepter.
pub const REFUND_TO_ACCEPTER_FLAG: u8 = 0x01;

/// The transaction version
/// See: https://github.com/discreetlogcontracts/dlcspecs/blob/master/Transactions.md#funding-transaction
const TX_VERSION: Version = Version::TWO;
Expand Down Expand Up @@ -436,6 +439,7 @@ pub fn create_spliced_dlc_transactions(
fund_lock_time: u32,
cet_lock_time: u32,
fund_output_serial_id: u64,
contract_flags: u8,
) -> Result<DlcTransactions, Error> {
// Create enhanced party parameters that include DLC inputs as regular inputs
let mut enhanced_offer_params = offer_params.clone();
Expand Down Expand Up @@ -480,6 +484,7 @@ pub fn create_spliced_dlc_transactions(
fund_lock_time,
cet_lock_time,
fund_output_serial_id,
contract_flags,
)
}

Expand All @@ -494,6 +499,7 @@ pub fn create_dlc_transactions(
fund_lock_time: u32,
cet_lock_time: u32,
fund_output_serial_id: u64,
contract_flags: u8,
) -> Result<DlcTransactions, Error> {
let (fund_tx, funding_script_pubkey) = create_fund_transaction_with_fees(
offer_params,
Expand All @@ -517,6 +523,7 @@ pub fn create_dlc_transactions(
refund_lock_time,
cet_lock_time,
None,
contract_flags,
)?;

Ok(DlcTransactions {
Expand Down Expand Up @@ -594,6 +601,7 @@ pub fn create_fund_transaction_with_fees(
}

/// Create the contract execution transactions and refund transaction.
#[allow(clippy::too_many_arguments)]
pub fn create_cets_and_refund_tx(
offer_params: &PartyParams,
accept_params: &PartyParams,
Expand All @@ -602,6 +610,7 @@ pub fn create_cets_and_refund_tx(
refund_lock_time: u32,
cet_lock_time: u32,
cet_nsequence: Option<Sequence>,
contract_flags: u8,
) -> Result<(Vec<Transaction>, Transaction), Error> {
let total_collateral = checked_add!(offer_params.collateral, accept_params.collateral)?;

Expand Down Expand Up @@ -637,13 +646,23 @@ pub fn create_cets_and_refund_tx(
cet_lock_time,
);

let (offer_refund_value, accept_refund_value) =
if contract_flags & REFUND_TO_ACCEPTER_FLAG != 0 {
(
Amount::ZERO,
checked_add!(offer_params.collateral, accept_params.collateral)?,
)
} else {
(offer_params.collateral, accept_params.collateral)
};

let offer_refund_output = TxOut {
value: offer_params.collateral,
value: offer_refund_value,
script_pubkey: offer_params.payout_script_pubkey.clone(),
};

let accept_refund_ouput = TxOut {
value: accept_params.collateral,
value: accept_refund_value,
script_pubkey: accept_params.payout_script_pubkey.clone(),
};

Expand Down Expand Up @@ -1495,6 +1514,7 @@ mod tests {
10,
10,
0,
0,
)
.unwrap();

Expand Down Expand Up @@ -1532,6 +1552,7 @@ mod tests {
10,
10,
0,
0,
)
.unwrap();

Expand Down Expand Up @@ -1716,6 +1737,7 @@ mod tests {
10,
10,
case.serials[0],
0,
)
.unwrap();

Expand Down Expand Up @@ -1760,4 +1782,67 @@ mod tests {
.expect("Could not find fund output");
}
}

#[test]
fn refund_to_accepter_flag_redirects_all_funds() {
let secp = Secp256k1::new();
let mut rng = secp256k1_zkp::rand::thread_rng();

let offer_collateral = Amount::from_sat(100000000);
let accept_collateral = Amount::ZERO;
let total_collateral = offer_collateral + accept_collateral;

let (offer_party_params, _) = get_party_params(
Amount::from_sat(1000000000),
offer_collateral,
None,
);

let accept_fund_privkey = SecretKey::new(&mut rng);
let accept_party_params = PartyParams {
fund_pubkey: PublicKey::from_secret_key(&secp, &accept_fund_privkey),
change_script_pubkey: get_p2wpkh_script_pubkey(&secp, &mut rng),
change_serial_id: 2,
payout_script_pubkey: get_p2wpkh_script_pubkey(&secp, &mut rng),
payout_serial_id: 2,
input_amount: Amount::ZERO,
collateral: accept_collateral,
inputs: vec![],
dlc_inputs: vec![],
};

let dlc_txs = create_dlc_transactions(
&offer_party_params,
&accept_party_params,
&[Payout {
offer: total_collateral,
accept: Amount::ZERO,
}],
100,
4,
10,
10,
0,
REFUND_TO_ACCEPTER_FLAG,
)
.unwrap();

let refund_tx = &dlc_txs.refund;

assert_eq!(
refund_tx.output.len(),
1,
"Refund TX should have exactly one output when flag is set"
);
assert_eq!(
refund_tx.output[0].value,
total_collateral,
"The single output should receive total collateral"
);
assert_eq!(
refund_tx.output[0].script_pubkey,
accept_party_params.payout_script_pubkey,
"Output should pay to the accepter's payout SPK"
);
}
}
Loading