Skip to content

feat: single funded contracts - #256

Open
bennyhodl wants to merge 3 commits into
p2pderivatives:masterfrom
bennyhodl:single-funded-dlc
Open

feat: single funded contracts#256
bennyhodl wants to merge 3 commits into
p2pderivatives:masterfrom
bennyhodl:single-funded-dlc

Conversation

@bennyhodl

Copy link
Copy Markdown
Contributor

This PR implements single-funded DLCs where only one party provides collateral and covers all transaction fees, while the other party contributes no inputs or fees.

Problem

The current implementation requires both parties to split transaction fees (funding, CET, and refund), even when one party provides zero collateral. This prevents true single-funded DLCs where the acceptor contributes nothing.

Solution

Fee calculation is now dynamic based on collateral contribution:

  • Zero collateral: Party pays no fees, provides no inputs
  • Full collateral: Party pays all fees (single-funded)
  • Partial collateral: Fees split between parties (existing dual-funded behavior)

Additional Changes

Contract Input Validation: Added dust limit checks per DLC specifications - offer collateral and total collateral must be above dust limit when non-zero. Follow spec for offer collateral

Code Quality: Fixed clippy warnings throughout the codebase.

Backward Compatibility

Existing dual-funded DLCs work unchanged. API changes are additive with no breaking changes to existing functionality.

@Tibo-lg Tibo-lg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a nice feature to have! I feel the implementation and usage could be made a bit clearer, and also please add an integration test to make sure it's working as expected.

Comment thread dlc-manager/src/contract/contract_input.rs Outdated
Comment thread dlc-manager/src/utils.rs
}

// If own_collateral is zero, appr_required_amount is zero.
// If own_collateral is equal to total_collateral, appr_required_amount is the common fee.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like it would be easier to just pass a bool like pay_all_fee to this method

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, to flag pay_all_fee then we still need to do the same check if they are paying all or zero collateral

Comment thread dlc/src/lib.rs

// first check if a party does not need to fund the contract if so, then it is zero
if self.collateral == Amount::ZERO {
// We use a zero value output to indicate that the party does not need to fund the contract

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be clearer to return an option so that it can be None in that case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, making it an Option requires extra checks in the callers that I think is cleaner to set to just Amount::ZERO

Comment thread dlc/src/lib.rs

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(total_collateral, fee_rate_per_vb, extra_fee)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe just don't call this method when it's not needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need to include the accept_change to create_fund_transaction even if it is dust which is then discarded

@bennyhodl
bennyhodl force-pushed the single-funded-dlc branch from e389637 to d215bc7 Compare July 14, 2025 13:52
@Tibo-lg

Tibo-lg commented Aug 4, 2025

Copy link
Copy Markdown
Contributor

The current implementation requires both parties to split transaction fees (funding, CET, and refund)

Going through this PR again, I wonder if it would make more sense to just have a setting that enables setting a single party to pay the entire fee regardless of the collateral values. It would also make things more explicit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants