Remove use of Deref with CoinSelectionSource
What changed, and why it matters
This commit is a code cleanup in the Lightning Dev Kit's Rust library. It changes how a wallet interface called CoinSelectionSource is used in function signatures. Instead of requiring that a wallet type be a pointer-like wrapper (Deref) around something that implements CoinSelectionSource, the commit makes CoinSelectionSource directly implementable for any pointer-like wrapper. This simplifies the API and removes an internal wrapper struct, but it does not fix a security bug or change runtime behavior in a way that would affect funds or network safety.
No security action required. Treat as a normal API refactor. Reviewers may want to verify downstream code still compiles and that the blanket impl does not introduce ambiguity with other trait impls, but this is a type-system concern, not a security concern.
Security signals we found
No security-relevant logic changes observed
Refactor only: trait bound simplification and blanket implementation
No changes to cryptographic operations, fee calculations, or transaction validation
No mention of vulnerability, CVE, security fix, or bug in commit message
Evidence from the diff
The patch refactors trait bounds from C: Deref where C::Target: CoinSelectionSource to C: CoinSelectionSource in BumpTransactionEventHandler and FundingTemplate methods. It then adds blanket impls impl<C: Deref> CoinSelectionSource for C where C::Target: CoinSelectionSource and similarly for CoinSelectionSourceSync, forwarding methods through deref(). It also removes the internal CoinSelectionSourceSyncWrapper’s manual Deref hack. This is an API ergonomics refactor using Rust’s newer impl-trait-in-trait (return-position impl Future) support; it does not alter transaction construction logic, coin-selection algorithms, signature handling, or any security-critical behavior.
Changed components
lightning/src/events/bump_transaction/mod.rslightning/src/ln/funding.rslightning/src/util/wallet_utils.rsInspect captured patch +57 / −55
diff --git a/lightning/src/events/bump_transaction/mod.rs b/lightning/src/events/bump_transaction/mod.rs
index f1ba1fc..6a5e994 100644
--- a/lightning/src/events/bump_transaction/mod.rs
+++ b/lightning/src/events/bump_transaction/mod.rs
@@ -14,7 +14,6 @@
pub mod sync;
use alloc::collections::BTreeMap;
-use core::ops::Deref;
use crate::chain::chaininterface::{
compute_feerate_sat_per_1000_weight, fee_for_weight, BroadcasterInterface, TransactionType,
@@ -257,12 +256,10 @@ pub enum BumpTransactionEvent {
// Note that updates to documentation on this struct should be copied to the synchronous version.
pub struct BumpTransactionEventHandler<
B: BroadcasterInterface,
- C: Deref,
+ C: CoinSelectionSource,
SP: SignerProvider,
L: Logger,
-> where
- C::Target: CoinSelectionSource,
-{
+> {
broadcaster: B,
utxo_source: C,
signer_provider: SP,
@@ -270,10 +267,8 @@ pub struct BumpTransactionEventHandler<
secp: Secp256k1<secp256k1::All>,
}
-impl<B: BroadcasterInterface, C: Deref, SP: SignerProvider, L: Logger>
+impl<B: BroadcasterInterface, C: CoinSelectionSource, SP: SignerProvider, L: Logger>
BumpTransactionEventHandler<B, C, SP, L>
-where
- C::Target: CoinSelectionSource,
{
/// Returns a new instance capable of handling [`Event::BumpTransaction`] events.
///
diff --git a/lightning/src/ln/funding.rs b/lightning/src/ln/funding.rs
index 4e7cc12..d18aca9 100644
--- a/lightning/src/ln/funding.rs
+++ b/lightning/src/ln/funding.rs
@@ -13,8 +13,6 @@ use bitcoin::hashes::Hash;
use bitcoin::secp256k1::PublicKey;
use bitcoin::{Amount, FeeRate, OutPoint, ScriptBuf, SignedAmount, TxOut, WScriptHash, Weight};
-use core::ops::Deref;
-
use crate::ln::chan_utils::{
make_funding_redeemscript, BASE_INPUT_WEIGHT, EMPTY_SCRIPT_SIG_WEIGHT,
FUNDING_TRANSACTION_WITNESS_WEIGHT,
@@ -125,12 +123,9 @@ macro_rules! build_funding_contribution {
impl FundingTemplate {
/// Creates a [`FundingContribution`] for adding funds to a channel using `wallet` to perform
/// coin selection.
- pub async fn splice_in<W: Deref + MaybeSend>(
+ pub async fn splice_in<W: CoinSelectionSource + MaybeSend>(
self, value_added: Amount, wallet: W,
- ) -> Result<FundingContribution, ()>
- where
- W::Target: CoinSelectionSource + MaybeSend,
- {
+ ) -> Result<FundingContribution, ()> {
if value_added == Amount::ZERO {
return Err(());
}
@@ -140,12 +135,9 @@ impl FundingTemplate {
/// Creates a [`FundingContribution`] for adding funds to a channel using `wallet` to perform
/// coin selection.
- pub fn splice_in_sync<W: Deref>(
+ pub fn splice_in_sync<W: CoinSelectionSourceSync>(
self, value_added: Amount, wallet: W,
- ) -> Result<FundingContribution, ()>
- where
- W::Target: CoinSelectionSourceSync,
- {
+ ) -> Result<FundingContribution, ()> {
if value_added == Amount::ZERO {
return Err(());
}
@@ -162,12 +154,9 @@ impl FundingTemplate {
/// Creates a [`FundingContribution`] for removing funds from a channel using `wallet` to
/// perform coin selection.
- pub async fn splice_out<W: Deref + MaybeSend>(
+ pub async fn splice_out<W: CoinSelectionSource + MaybeSend>(
self, outputs: Vec<TxOut>, wallet: W,
- ) -> Result<FundingContribution, ()>
- where
- W::Target: CoinSelectionSource + MaybeSend,
- {
+ ) -> Result<FundingContribution, ()> {
if outputs.is_empty() {
return Err(());
}
@@ -177,12 +166,9 @@ impl FundingTemplate {
/// Creates a [`FundingContribution`] for removing funds from a channel using `wallet` to
/// perform coin selection.
- pub fn splice_out_sync<W: Deref>(
+ pub fn splice_out_sync<W: CoinSelectionSourceSync>(
self, outputs: Vec<TxOut>, wallet: W,
- ) -> Result<FundingContribution, ()>
- where
- W::Target: CoinSelectionSourceSync,
- {
+ ) -> Result<FundingContribution, ()> {
if outputs.is_empty() {
return Err(());
}
@@ -199,12 +185,9 @@ impl FundingTemplate {
/// Creates a [`FundingContribution`] for both adding and removing funds from a channel using
/// `wallet` to perform coin selection.
- pub async fn splice_in_and_out<W: Deref + MaybeSend>(
+ pub async fn splice_in_and_out<W: CoinSelectionSource + MaybeSend>(
self, value_added: Amount, outputs: Vec<TxOut>, wallet: W,
- ) -> Result<FundingContribution, ()>
- where
- W::Target: CoinSelectionSource + MaybeSend,
- {
+ ) -> Result<FundingContribution, ()> {
if value_added == Amount::ZERO && outputs.is_empty() {
return Err(());
}
@@ -214,12 +197,9 @@ impl FundingTemplate {
/// Creates a [`FundingContribution`] for both adding and removing funds from a channel using
/// `wallet` to perform coin selection.
- pub fn splice_in_and_out_sync<W: Deref>(
+ pub fn splice_in_and_out_sync<W: CoinSelectionSourceSync>(
self, value_added: Amount, outputs: Vec<TxOut>, wallet: W,
- ) -> Result<FundingContribution, ()>
- where
- W::Target: CoinSelectionSourceSync,
- {
+ ) -> Result<FundingContribution, ()> {
if value_added == Amount::ZERO && outputs.is_empty() {
return Err(());
}
diff --git a/lightning/src/util/wallet_utils.rs b/lightning/src/util/wallet_utils.rs
index 54c6f54..b82437c 100644
--- a/lightning/src/util/wallet_utils.rs
+++ b/lightning/src/util/wallet_utils.rs
@@ -400,6 +400,29 @@ pub trait CoinSelectionSource {
) -> impl Future<Output = Result<Transaction, ()>> + MaybeSend + 'a;
}
+impl<C: Deref> CoinSelectionSource for C
+where
+ C::Target: CoinSelectionSource,
+{
+ fn select_confirmed_utxos<'a>(
+ &'a self, claim_id: Option<ClaimId>, must_spend: Vec<Input>, must_pay_to: &'a [TxOut],
+ target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
+ ) -> impl Future<Output = Result<CoinSelection, ()>> + MaybeSend + 'a {
+ self.deref().select_confirmed_utxos(
+ claim_id,
+ must_spend,
+ must_pay_to,
+ target_feerate_sat_per_1000_weight,
+ max_tx_weight,
+ )
+ }
+ fn sign_psbt<'a>(
+ &'a self, psbt: Psbt,
+ ) -> impl Future<Output = Result<Transaction, ()>> + MaybeSend + 'a {
+ self.deref().sign_psbt(psbt)
+ }
+}
+
/// An alternative to [`CoinSelectionSource`] that can be implemented and used along [`Wallet`] to
/// provide a default implementation to [`CoinSelectionSource`].
///
@@ -908,26 +931,30 @@ pub trait CoinSelectionSourceSync {
fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()>;
}
-pub(crate) struct CoinSelectionSourceSyncWrapper<T: Deref>(pub(crate) T)
-where
- T::Target: CoinSelectionSourceSync;
-
-// Implement `Deref` directly on CoinSelectionSourceSyncWrapper so that it can be used directly
-// below, rather than via a wrapper.
-impl<T: Deref> Deref for CoinSelectionSourceSyncWrapper<T>
+impl<C: Deref> CoinSelectionSourceSync for C
where
- T::Target: CoinSelectionSourceSync,
+ C::Target: CoinSelectionSourceSync,
{
- type Target = Self;
- fn deref(&self) -> &Self {
- self
+ fn select_confirmed_utxos(
+ &self, claim_id: Option<ClaimId>, must_spend: Vec<Input>, must_pay_to: &[TxOut],
+ target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
+ ) -> Result<CoinSelection, ()> {
+ self.deref().select_confirmed_utxos(
+ claim_id,
+ must_spend,
+ must_pay_to,
+ target_feerate_sat_per_1000_weight,
+ max_tx_weight,
+ )
+ }
+ fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()> {
+ self.deref().sign_psbt(psbt)
}
}
-impl<T: Deref> CoinSelectionSource for CoinSelectionSourceSyncWrapper<T>
-where
- T::Target: CoinSelectionSourceSync,
-{
+pub(crate) struct CoinSelectionSourceSyncWrapper<T: CoinSelectionSourceSync>(pub(crate) T);
+
+impl<T: CoinSelectionSourceSync> CoinSelectionSource for CoinSelectionSourceSyncWrapper<T> {
fn select_confirmed_utxos<'a>(
&'a self, claim_id: Option<ClaimId>, must_spend: Vec<Input>, must_pay_to: &'a [TxOut],
target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.