@@ -5977,13 +5977,8 @@ pub(super) struct FundingNegotiationContext {
5977
5977
/// The input spending the previous funding output, if this is a splice.
5978
5978
#[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
5979
5979
pub shared_funding_input: Option<SharedOwnedInput>,
5980
- /// The funding inputs we will be contributing to the channel.
5981
- #[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.
5982
- pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
5983
- /// The change output script. This will be used if needed or -- if not set -- generated using
5984
- /// `SignerProvider::get_destination_script`.
5985
- #[allow(dead_code)] // TODO(splicing): Remove once splicing is enabled.
5986
- pub change_script: Option<ScriptBuf>,
5980
+ /// The components of the funding transaction that we will contribute.
5981
+ pub funding_tx_contributions: FundingTxContributions,
5987
5982
}
5988
5983
5989
5984
impl FundingNegotiationContext {
@@ -6019,35 +6014,43 @@ impl FundingNegotiationContext {
6019
6014
script_pubkey: funding.get_funding_redeemscript().to_p2wsh(),
6020
6015
};
6021
6016
6022
- // Optionally add change output
6023
- if self.our_funding_contribution > SignedAmount::ZERO {
6024
- let change_value_opt = calculate_change_output_value(
6017
+ let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6018
+ calculate_change_output_value(
6025
6019
&self,
6026
6020
self.shared_funding_input.is_some(),
6027
6021
&shared_funding_output.script_pubkey,
6028
6022
&funding_outputs,
6029
6023
context.holder_dust_limit_satoshis,
6030
- )?;
6031
- if let Some(change_value) = change_value_opt {
6032
- let change_script = if let Some(script) = self.change_script {
6033
- script
6034
- } else {
6035
- signer_provider
6036
- .get_destination_script(context.channel_keys_id)
6037
- .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6038
- };
6039
- let mut change_output =
6040
- TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
6041
- let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
6042
- let change_output_fee =
6043
- fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
6044
- let change_value_decreased_with_fee =
6045
- change_value.saturating_sub(change_output_fee);
6046
- // Check dust limit again
6047
- if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6048
- change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6049
- funding_outputs.push(change_output);
6050
- }
6024
+ )?
6025
+ } else {
6026
+ None
6027
+ };
6028
+
6029
+ let (inputs_to_contribute, change_script) = match self.funding_tx_contributions {
6030
+ FundingTxContributions::InputsOnly { inputs, change_script } => (inputs, change_script),
6031
+ };
6032
+
6033
+ // Add change output if necessary
6034
+ if let Some(change_value) = change_value_opt {
6035
+ let change_script = if let Some(script) = change_script {
6036
+ script
6037
+ } else {
6038
+ signer_provider
6039
+ .get_destination_script(context.channel_keys_id)
6040
+ .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6041
+ };
6042
+
6043
+ let mut change_output =
6044
+ TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
6045
+ let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
6046
+ let change_output_fee =
6047
+ fee_for_weight(self.funding_feerate_sat_per_1000_weight, change_output_weight);
6048
+ let change_value_decreased_with_fee = change_value.saturating_sub(change_output_fee);
6049
+
6050
+ // Check dust limit again
6051
+ if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6052
+ change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6053
+ funding_outputs.push(change_output);
6051
6054
}
6052
6055
}
6053
6056
@@ -6059,7 +6062,7 @@ impl FundingNegotiationContext {
6059
6062
feerate_sat_per_kw: self.funding_feerate_sat_per_1000_weight,
6060
6063
is_initiator: self.is_initiator,
6061
6064
funding_tx_locktime: self.funding_tx_locktime,
6062
- inputs_to_contribute: self.our_funding_inputs ,
6065
+ inputs_to_contribute,
6063
6066
shared_funding_input: self.shared_funding_input,
6064
6067
shared_funding_output: SharedOwnedOutput::new(
6065
6068
shared_funding_output,
@@ -6071,6 +6074,30 @@ impl FundingNegotiationContext {
6071
6074
}
6072
6075
}
6073
6076
6077
+ /// The components of a funding transaction that are contributed by one party.
6078
+ pub enum FundingTxContributions {
6079
+ /// When only inputs -- except for a possible change output -- are contributed to the funding
6080
+ /// transaction. This must correspond to a positive contribution amount.
6081
+ InputsOnly {
6082
+ /// The inputs used to meet the contributed amount. Any excess amount will be sent to a
6083
+ /// change output.
6084
+ inputs: Vec<(TxIn, TransactionU16LenLimited)>,
6085
+
6086
+ /// An optional change output script. This will be used if needed or, if not set, generated
6087
+ /// using `SignerProvider::get_destination_script`.
6088
+ change_script: Option<ScriptBuf>,
6089
+ },
6090
+ }
6091
+
6092
+ impl FundingTxContributions {
6093
+ /// Returns an inputs to be contributed to the funding transaction.
6094
+ pub fn inputs(&self) -> &[(TxIn, TransactionU16LenLimited)] {
6095
+ match self {
6096
+ FundingTxContributions::InputsOnly { inputs, .. } => &inputs[..],
6097
+ }
6098
+ }
6099
+ }
6100
+
6074
6101
// Holder designates channel data owned for the benefit of the user client.
6075
6102
// Counterparty designates channel data owned by the another channel participant entity.
6076
6103
pub(super) struct FundedChannel<SP: Deref>
@@ -10684,15 +10711,17 @@ where
10684
10711
funding_inputs.push((tx_in, tx16));
10685
10712
}
10686
10713
10714
+ let funding_tx_contributions =
10715
+ FundingTxContributions::InputsOnly { inputs: funding_inputs, change_script };
10716
+
10687
10717
let prev_funding_input = self.funding.to_splice_funding_input();
10688
10718
let funding_negotiation_context = FundingNegotiationContext {
10689
10719
is_initiator: true,
10690
10720
our_funding_contribution,
10691
10721
funding_tx_locktime: LockTime::from_consensus(locktime),
10692
10722
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
10693
10723
shared_funding_input: Some(prev_funding_input),
10694
- our_funding_inputs: funding_inputs,
10695
- change_script,
10724
+ funding_tx_contributions,
10696
10725
};
10697
10726
10698
10727
self.pending_splice = Some(PendingSplice {
@@ -10806,15 +10835,17 @@ where
10806
10835
self.funding.get_value_satoshis(),
10807
10836
);
10808
10837
10838
+ let funding_tx_contributions =
10839
+ FundingTxContributions::InputsOnly { inputs: vec![], change_script: None };
10840
+
10809
10841
let prev_funding_input = self.funding.to_splice_funding_input();
10810
10842
let funding_negotiation_context = FundingNegotiationContext {
10811
10843
is_initiator: false,
10812
10844
our_funding_contribution,
10813
10845
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
10814
10846
funding_feerate_sat_per_1000_weight: msg.funding_feerate_per_kw,
10815
10847
shared_funding_input: Some(prev_funding_input),
10816
- our_funding_inputs: Vec::new(),
10817
- change_script: None,
10848
+ funding_tx_contributions,
10818
10849
};
10819
10850
10820
10851
let mut interactive_tx_constructor = funding_negotiation_context
@@ -12505,14 +12536,17 @@ where
12505
12536
unfunded_channel_age_ticks: 0,
12506
12537
holder_commitment_point: HolderCommitmentPoint::new(&context.holder_signer, &context.secp_ctx),
12507
12538
};
12539
+ let funding_tx_contributions = FundingTxContributions::InputsOnly {
12540
+ inputs: funding_inputs,
12541
+ change_script: None,
12542
+ };
12508
12543
let funding_negotiation_context = FundingNegotiationContext {
12509
12544
is_initiator: true,
12510
12545
our_funding_contribution: SignedAmount::from_sat(funding_satoshis as i64),
12511
12546
funding_tx_locktime,
12512
12547
funding_feerate_sat_per_1000_weight,
12513
12548
shared_funding_input: None,
12514
- our_funding_inputs: funding_inputs,
12515
- change_script: None,
12549
+ funding_tx_contributions,
12516
12550
};
12517
12551
let chan = Self {
12518
12552
funding,
@@ -12659,14 +12693,17 @@ where
12659
12693
&funding.get_counterparty_pubkeys().revocation_basepoint);
12660
12694
context.channel_id = channel_id;
12661
12695
12696
+ let funding_tx_contributions = FundingTxContributions::InputsOnly {
12697
+ inputs: our_funding_inputs.clone(),
12698
+ change_script: None,
12699
+ };
12662
12700
let funding_negotiation_context = FundingNegotiationContext {
12663
12701
is_initiator: false,
12664
12702
our_funding_contribution,
12665
12703
funding_tx_locktime: LockTime::from_consensus(msg.locktime),
12666
12704
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
12667
12705
shared_funding_input: None,
12668
- our_funding_inputs: our_funding_inputs.clone(),
12669
- change_script: None,
12706
+ funding_tx_contributions,
12670
12707
};
12671
12708
let shared_funding_output = TxOut {
12672
12709
value: Amount::from_sat(funding.get_value_satoshis()),
0 commit comments