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 , ScriptBuf , Transaction , TxOut , Weight } ;
55use miniscript:: bitcoin;
66
77use crate :: { cs_feerate, DefiniteDescriptor , InputCandidates , InputGroup , Output , Selection } ;
@@ -15,10 +15,51 @@ pub struct Selector<'c> {
1515 target_outputs : Vec < Output > ,
1616 target : Target ,
1717 change_policy : bdk_coin_select:: ChangePolicy ,
18- change_descriptor : DefiniteDescriptor ,
18+ change_descriptor : ChangeDescriptor ,
1919 inner : bdk_coin_select:: CoinSelector < ' c > ,
2020}
2121
22+ /// Data source to create a change output if needed
23+ #[ derive( Debug , Clone ) ]
24+ pub enum ChangeDescriptor {
25+ /// Build change output from descriptor
26+ Definite ( DefiniteDescriptor ) ,
27+ /// Build change output without descriptor
28+ Manual {
29+ /// The final script pubkey the change output should have
30+ script_pubkey : ScriptBuf ,
31+ /// The maximum weight to satisfy the script pubkey
32+ max_weight_to_satisfy_wu : u64 ,
33+ } ,
34+ }
35+
36+ /// Wrapper methods to unify interface for change outputs
37+ impl ChangeDescriptor {
38+ /// Get the maximum weight to satisfy the script pubkey of the resultant output
39+ pub fn get_max_weight_to_satisfy_wu ( & self ) -> Result < u64 , miniscript:: Error > {
40+ use ChangeDescriptor :: * ;
41+
42+ match self {
43+ Definite ( definite_descriptor) => definite_descriptor
44+ . max_weight_to_satisfy ( )
45+ . map ( |weight| weight. to_wu ( ) ) ,
46+ Manual {
47+ max_weight_to_satisfy_wu,
48+ ..
49+ } => Ok ( * max_weight_to_satisfy_wu) ,
50+ }
51+ }
52+
53+ /// Get the script pubkey the change output should have
54+ pub fn get_script_pubkey ( & self ) -> ScriptBuf {
55+ use ChangeDescriptor :: * ;
56+ match self {
57+ Definite ( definite_descriptor) => definite_descriptor. script_pubkey ( ) ,
58+ Manual { script_pubkey, .. } => script_pubkey. clone ( ) ,
59+ }
60+ }
61+ }
62+
2263/// Parameters for creating tx.
2364///
2465/// TODO: Create a builder interface on this that does checks. I.e.
@@ -42,7 +83,7 @@ pub struct SelectorParams {
4283 /// To derive change output.
4384 ///
4485 /// Will error if this is unsatisfiable descriptor.
45- pub change_descriptor : DefiniteDescriptor ,
86+ pub change_descriptor : ChangeDescriptor ,
4687
4788 /// The policy to determine whether we create a change output.
4889 pub change_policy : ChangePolicyType ,
@@ -140,7 +181,7 @@ impl SelectorParams {
140181 pub fn new (
141182 target_feerate : bitcoin:: FeeRate ,
142183 target_outputs : Vec < Output > ,
143- change_descriptor : DefiniteDescriptor ,
184+ change_descriptor : ChangeDescriptor ,
144185 change_policy : ChangePolicyType ,
145186 ) -> Self {
146187 Self {
@@ -179,12 +220,12 @@ impl SelectorParams {
179220 pub fn to_cs_change_weights ( & self ) -> Result < bdk_coin_select:: DrainWeights , miniscript:: Error > {
180221 Ok ( DrainWeights {
181222 output_weight : ( TxOut {
182- script_pubkey : self . change_descriptor . script_pubkey ( ) ,
223+ script_pubkey : self . change_descriptor . get_script_pubkey ( ) ,
183224 value : Amount :: ZERO ,
184225 } )
185226 . weight ( )
186227 . to_wu ( ) ,
187- spend_weight : self . change_descriptor . max_weight_to_satisfy ( ) ?. to_wu ( ) ,
228+ spend_weight : self . change_descriptor . get_max_weight_to_satisfy_wu ( ) ?,
188229 n_outputs : 1 ,
189230 } )
190231 }
@@ -198,7 +239,7 @@ impl SelectorParams {
198239 let change_weights = self . to_cs_change_weights ( ) ?;
199240 let dust_value = self
200241 . change_descriptor
201- . script_pubkey ( )
242+ . get_script_pubkey ( )
202243 . minimal_non_dust ( )
203244 . to_sat ( ) ;
204245 Ok ( match self . change_policy {
@@ -358,8 +399,8 @@ impl<'c> Selector<'c> {
358399 outputs : {
359400 let mut outputs = self . target_outputs . clone ( ) ;
360401 if maybe_change. is_some ( ) {
361- outputs. push ( Output :: with_descriptor (
362- self . change_descriptor . clone ( ) ,
402+ outputs. push ( Output :: with_script (
403+ self . change_descriptor . get_script_pubkey ( ) ,
363404 Amount :: from_sat ( maybe_change. value ) ,
364405 ) ) ;
365406 }
0 commit comments