Skip to content

Commit

Permalink
Fix fund output calculations
Browse files Browse the repository at this point in the history
We were doing a couple of things wrong with the `extra_fee`, which is
normally used to account for potential buffer transaction fees when
setting up a DLC channel:

- We were not splitting the cost of the `extra_fee` between both
parties. Instead, we were accounting for it _twice_, deducted in full
from both the change output of the offer party and the accept party.

- We were using the "extra" `extra_fee` to pay more transaction fees
for the funding transaction. This is usually a completely unnecessary
overpayment.
  • Loading branch information
luckysori committed Feb 14, 2024
1 parent a01f92b commit 1534c18
Showing 1 changed file with 19 additions and 7 deletions.
26 changes: 19 additions & 7 deletions dlc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,31 +402,43 @@ pub(crate) fn create_fund_transaction_with_fees(
) -> Result<(Transaction, Script), Error> {
let total_collateral = checked_add!(offer_params.collateral, accept_params.collateral)?;

let (offer_extra_fee, accept_extra_fee) = {
let half = extra_fee / 2;
let remainder = extra_fee % 2;

// The offer party has to pay an extra sat if there is a remainder.
(half + remainder, half)
};

let (offer_change_output, offer_fund_fee, offer_cet_fee) =
offer_params.get_change_output_and_fees(fee_rate_per_vb, extra_fee)?;
offer_params.get_change_output_and_fees(fee_rate_per_vb, offer_extra_fee)?;

let (accept_change_output, accept_fund_fee, accept_cet_fee) =
accept_params.get_change_output_and_fees(fee_rate_per_vb, extra_fee)?;
accept_params.get_change_output_and_fees(fee_rate_per_vb, accept_extra_fee)?;

let fund_output_value = checked_add!(offer_params.input_amount, accept_params.input_amount)?
- offer_change_output.value
- accept_change_output.value
- offer_fund_fee
- accept_fund_fee
- extra_fee;
- accept_fund_fee;

// The fund output has to cover: the total collateral being wagered and the fee reserve to pay
// for all transaction fees beyond the funding transaction. In the worst case, this is a buffer
// transaction (for DLC channels) and a CET or refund transaction.
assert_eq!(
total_collateral + offer_cet_fee + accept_cet_fee + extra_fee,
fund_output_value
fund_output_value,
total_collateral + offer_cet_fee + accept_cet_fee + offer_extra_fee + accept_extra_fee

This comment has been minimized.

Copy link
@holzeis

holzeis Feb 14, 2024

Collaborator

❓ I guess the *_cet_fee is also used for the refund transaction right? In the validation it's called cet_or_refund_fee.

This comment has been minimized.

Copy link
@luckysori

luckysori Feb 14, 2024

Author Collaborator

Yep, good catch!

);

// The sum of the inputs provided by both parties have to cover: the fund output; all the change
// outputs; and the funding TX fee.
assert_eq!(
offer_params.input_amount + accept_params.input_amount,
fund_output_value
+ offer_change_output.value
+ accept_change_output.value
+ offer_fund_fee
+ accept_fund_fee
+ extra_fee
);

let fund_sequence = util::get_sequence(fund_lock_time);
Expand Down

0 comments on commit 1534c18

Please sign in to comment.