11use  bdk_coin_select:: { 
22    ChangePolicy ,  DrainWeights ,  InsufficientFunds ,  Replace ,  Target ,  TargetFee ,  TargetOutputs , 
33} ; 
4- use  bitcoin:: { Amount ,  FeeRate ,  Transaction ,  TxOut ,   Weight } ; 
4+ use  bitcoin:: { Amount ,  FeeRate ,  Transaction ,  Weight } ; 
55use  miniscript:: bitcoin; 
66
77use  crate :: { cs_feerate,  InputCandidates ,  InputGroup ,  Output ,  ScriptSource ,  Selection } ; 
@@ -15,7 +15,7 @@ pub struct Selector<'c> {
1515    target_outputs :  Vec < Output > , 
1616    target :  Target , 
1717    change_policy :  bdk_coin_select:: ChangePolicy , 
18-     change_source :  ScriptSource , 
18+     change_script :  ScriptSource , 
1919    inner :  bdk_coin_select:: CoinSelector < ' c > , 
2020} 
2121
@@ -42,11 +42,14 @@ pub struct SelectorParams {
4242    /// To derive change output. 
4343/// 
4444/// Will error if this is unsatisfiable descriptor. 
45- pub  change_source :  ScriptSource , 
45+ pub  change_script :  ScriptSource , 
4646
4747    /// The policy to determine whether we create a change output. 
4848pub  change_policy :  ChangePolicyType , 
4949
50+     /// Weight of the change output plus the future weight to spend the change 
51+ pub  change_weight :  DrainWeights , 
52+ 
5053    /// Params for replacing tx(s). 
5154pub  replace :  Option < RbfParams > , 
5255} 
@@ -140,14 +143,16 @@ impl SelectorParams {
140143pub  fn  new ( 
141144        target_feerate :  bitcoin:: FeeRate , 
142145        target_outputs :  Vec < Output > , 
143-         change_source :  ScriptSource , 
146+         change_script :  ScriptSource , 
144147        change_policy :  ChangePolicyType , 
148+         change_weight :  DrainWeights , 
145149    )  -> Self  { 
146150        Self  { 
147-             change_source, 
148-             change_policy, 
149151            target_feerate, 
150152            target_outputs, 
153+             change_script, 
154+             change_policy, 
155+             change_weight, 
151156            replace :  None , 
152157        } 
153158    } 
@@ -171,53 +176,14 @@ impl SelectorParams {
171176        } 
172177    } 
173178
174-     /// To change output weights. 
175- /// 
176- /// # Error 
177- /// 
178- /// Fails if `change_source` cannot be satisfied. 
179- pub  fn  to_cs_change_weights ( & self )  -> Result < bdk_coin_select:: DrainWeights ,  SelectorError >  { 
180-         let  ( script_pubkey,  spend_weight)  = match  & self . change_source  { 
181-             ScriptSource :: Script  { 
182-                 script_pubkey, 
183-                 max_weight_to_satisfy, 
184-             }  => { 
185-                 if  let  Some ( weight)  = max_weight_to_satisfy { 
186-                     ( script_pubkey. clone ( ) ,  weight. to_wu ( ) ) 
187-                 }  else  { 
188-                     return  Err ( SelectorError :: MissingChangeSatisfactionWeight ) ; 
189-                 } 
190-             } 
191-             ScriptSource :: Descriptor ( definite_descriptor)  => { 
192-                 let  script_pubkey = definite_descriptor. script_pubkey ( ) ; 
193-                 let  weight = definite_descriptor
194-                     . max_weight_to_satisfy ( ) 
195-                     . map ( |weight| weight. to_wu ( ) ) 
196-                     . map_err ( SelectorError :: Miniscript ) ?; 
197-                 ( script_pubkey,  weight) 
198-             } 
199-         } ; 
200-         let  drain_weight = DrainWeights  { 
201-             output_weight :  ( TxOut  { 
202-                 script_pubkey, 
203-                 value :  Amount :: ZERO , 
204-             } ) 
205-             . weight ( ) 
206-             . to_wu ( ) , 
207-             spend_weight, 
208-             n_outputs :  1 , 
209-         } ; 
210-         Ok ( drain_weight) 
211-     } 
212- 
213179    /// To change policy. 
214180/// 
215181/// # Error 
216182/// 
217- /// Fails if `change_source ` cannot be satisfied. 
218- pub  fn  to_cs_change_policy ( & self )  -> Result < bdk_coin_select:: ChangePolicy ,  SelectorError >  { 
219-         let  change_weights = self . to_cs_change_weights ( ) ? ; 
220-         let  dust_value = self . change_source . script ( ) . minimal_non_dust ( ) . to_sat ( ) ; 
183+ /// Fails if `change_descriptor ` cannot be satisfied. 
184+ pub  fn  to_cs_change_policy ( & self )  -> Result < bdk_coin_select:: ChangePolicy ,  miniscript :: Error >  { 
185+         let  change_weights = self . change_weight ; 
186+         let  dust_value = self . change_script . script ( ) . minimal_non_dust ( ) . to_sat ( ) ; 
221187        Ok ( match  self . change_policy  { 
222188            ChangePolicyType :: NoDust  => ChangePolicy :: min_value ( change_weights,  dust_value) , 
223189            ChangePolicyType :: NoDustAndLeastWaste  {  longterm_feerate }  => { 
@@ -255,19 +221,13 @@ pub enum SelectorError {
255221Miniscript ( miniscript:: Error ) , 
256222    /// meeting the target is not possible 
257223CannotMeetTarget ( CannotMeetTarget ) , 
258-     /// missing weight to satisfy change output 
259- MissingChangeSatisfactionWeight , 
260224} 
261225
262226impl  fmt:: Display  for  SelectorError  { 
263227    fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
264228        match  self  { 
265229            Self :: Miniscript ( err)  => write ! ( f,  "{err}" ) , 
266230            Self :: CannotMeetTarget ( err)  => write ! ( f,  "{err}" ) , 
267-             Self :: MissingChangeSatisfactionWeight  => write ! ( 
268-                 f, 
269-                 "Cannot determinate change policy without satisfaction weight" 
270-             ) , 
271231        } 
272232    } 
273233} 
@@ -287,9 +247,11 @@ impl<'c> Selector<'c> {
287247        params :  SelectorParams , 
288248    )  -> Result < Self ,  SelectorError >  { 
289249        let  target = params. to_cs_target ( ) ; 
290-         let  change_policy = params. to_cs_change_policy ( ) ?; 
250+         let  change_policy = params
251+             . to_cs_change_policy ( ) 
252+             . map_err ( SelectorError :: Miniscript ) ?; 
291253        let  target_outputs = params. target_outputs ; 
292-         let  change_source  = params. change_source ; 
254+         let  change_script  = params. change_script ; 
293255        if  target. value ( )  > candidates. groups ( ) . map ( |grp| grp. value ( ) . to_sat ( ) ) . sum ( )  { 
294256            return  Err ( SelectorError :: CannotMeetTarget ( CannotMeetTarget ) ) ; 
295257        } 
@@ -302,7 +264,7 @@ impl<'c> Selector<'c> {
302264            target, 
303265            target_outputs, 
304266            change_policy, 
305-             change_source , 
267+             change_script , 
306268            inner, 
307269        } ) 
308270    } 
@@ -379,16 +341,10 @@ impl<'c> Selector<'c> {
379341            outputs :  { 
380342                let  mut  outputs = self . target_outputs . clone ( ) ; 
381343                if  maybe_change. is_some ( )  { 
382-                     let  change_amount = Amount :: from_sat ( maybe_change. value ) ; 
383-                     let  change_output = match  & self . change_source  { 
384-                         ScriptSource :: Descriptor ( definite_descriptor)  => { 
385-                             Output :: with_descriptor ( * definite_descriptor. clone ( ) ,  change_amount) 
386-                         } 
387-                         ScriptSource :: Script  {  script_pubkey,  .. }  => { 
388-                             Output :: with_script ( script_pubkey. clone ( ) ,  change_amount) 
389-                         } 
390-                     } ; 
391-                     outputs. push ( change_output) ; 
344+                     outputs. push ( Output :: from ( ( 
345+                         self . change_script . clone ( ) , 
346+                         Amount :: from_sat ( maybe_change. value ) , 
347+                     ) ) ) ; 
392348                } 
393349                outputs
394350            } , 
0 commit comments