11use crate :: try_into_js_value:: TryIntoJsValue ;
2- use miniscript:: bitcoin:: secp256k1:: Secp256k1 ;
2+ use miniscript:: bitcoin:: secp256k1:: { Context , Secp256k1 , Signing } ;
33use miniscript:: bitcoin:: ScriptBuf ;
44use miniscript:: descriptor:: KeyMap ;
55use miniscript:: { DefiniteDescriptorKey , Descriptor , DescriptorPublicKey } ;
@@ -69,7 +69,7 @@ impl WrapDescriptor {
6969 pub fn script_pubkey ( & self ) -> Result < Vec < u8 > , WasmMiniscriptError > {
7070 match & self . 0 {
7171 WrapDescriptorEnum :: Definite ( desc) => Ok ( desc. script_pubkey ( ) . to_bytes ( ) ) ,
72- _ => Err ( WasmMiniscriptError :: new ( "Cannot derive from a non-definite descriptor" ) ) ,
72+ _ => Err ( WasmMiniscriptError :: new ( "Cannot encode a derivable descriptor" ) ) ,
7373 }
7474 }
7575
@@ -105,8 +105,7 @@ impl WrapDescriptor {
105105 . map_err ( |_| WasmMiniscriptError :: new ( "Weight exceeds u32" ) )
106106 }
107107
108- fn from_string_derivable ( descriptor : & str ) -> Result < WrapDescriptor , WasmMiniscriptError > {
109- let secp = Secp256k1 :: new ( ) ;
108+ fn from_string_derivable < C : Signing > ( secp : & Secp256k1 < C > , descriptor : & str ) -> Result < WrapDescriptor , WasmMiniscriptError > {
110109 let ( desc, keys) = Descriptor :: parse_descriptor ( & secp, descriptor) ?;
111110 Ok ( WrapDescriptor ( WrapDescriptorEnum :: Derivable ( desc, keys) ) )
112111 }
@@ -116,10 +115,32 @@ impl WrapDescriptor {
116115 Ok ( WrapDescriptor ( WrapDescriptorEnum :: Definite ( desc) ) )
117116 }
118117
118+ /// Parse a descriptor string with an explicit public key type.
119+ ///
120+ /// Note that this function permits parsing a non-derivable descriptor with a derivable key type.
121+ /// Use `from_string_detect_type` to automatically detect the key type.
122+ ///
123+ /// # Arguments
124+ /// * `descriptor` - A string containing the descriptor to parse
125+ /// * `pk_type` - The type of public key to expect:
126+ /// - "derivable": For descriptors containing derivation paths (eg. xpubs)
127+ /// - "definite": For descriptors with fully specified keys
128+ /// - "string": For descriptors with string placeholders
129+ ///
130+ /// # Returns
131+ /// * `Result<WrapDescriptor, WasmMiniscriptError>` - The parsed descriptor or an error
132+ ///
133+ /// # Example
134+ /// ```
135+ /// let desc = WrapDescriptor::from_string(
136+ /// "pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/*)",
137+ /// "derivable"
138+ /// );
139+ /// ```
119140 #[ wasm_bindgen( js_name = fromString, skip_typescript) ]
120141 pub fn from_string ( descriptor : & str , pk_type : & str ) -> Result < WrapDescriptor , WasmMiniscriptError > {
121142 match pk_type {
122- "derivable" => WrapDescriptor :: from_string_derivable ( descriptor) ,
143+ "derivable" => WrapDescriptor :: from_string_derivable ( & Secp256k1 :: new ( ) , descriptor) ,
123144 "definite" => WrapDescriptor :: from_string_definite ( descriptor) ,
124145 "string" => {
125146 let desc = Descriptor :: < String > :: from_str ( descriptor) ?;
@@ -128,4 +149,60 @@ impl WrapDescriptor {
128149 _ => Err ( WasmMiniscriptError :: new ( "Invalid descriptor type" ) ) ,
129150 }
130151 }
131- }
152+
153+ /// Parse a descriptor string, automatically detecting the appropriate public key type.
154+ /// This will check if the descriptor contains wildcards to determine if it should be
155+ /// parsed as derivable or definite.
156+ ///
157+ /// # Arguments
158+ /// * `descriptor` - A string containing the descriptor to parse
159+ ///
160+ /// # Returns
161+ /// * `Result<WrapDescriptor, WasmMiniscriptError>` - The parsed descriptor or an error
162+ ///
163+ /// # Example
164+ /// ```
165+ /// // Will be parsed as definite since it has no wildcards
166+ /// let desc = WrapDescriptor::from_string_detect_type(
167+ /// "pk(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)"
168+ /// );
169+ ///
170+ /// // Will be parsed as derivable since it contains a wildcard (*)
171+ /// let desc = WrapDescriptor::from_string_detect_type(
172+ /// "pk(xpub.../0/*)"
173+ /// );
174+ /// ```
175+ #[ wasm_bindgen( js_name = fromStringDetectType, skip_typescript) ]
176+ pub fn from_string_detect_type ( descriptor : & str ) -> Result < WrapDescriptor , WasmMiniscriptError > {
177+ let secp = Secp256k1 :: new ( ) ;
178+ let ( descriptor, _key_map) = Descriptor :: parse_descriptor ( & secp, descriptor) . map_err ( |_| WasmMiniscriptError :: new ( "Invalid descriptor" ) ) ?;
179+ if descriptor. has_wildcard ( ) {
180+ WrapDescriptor :: from_string_derivable ( & secp, & descriptor. to_string ( ) )
181+ } else {
182+ WrapDescriptor :: from_string_definite ( & descriptor. to_string ( ) )
183+ }
184+ }
185+ }
186+
187+ impl FromStr for WrapDescriptor {
188+ type Err = WasmMiniscriptError ;
189+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
190+ WrapDescriptor :: from_string_detect_type ( s)
191+ }
192+ }
193+
194+ #[ cfg( test) ]
195+ mod tests {
196+ use crate :: WrapDescriptor ;
197+
198+ #[ test]
199+ fn test_detect_type ( ) {
200+ let desc = WrapDescriptor :: from_string_detect_type ( "pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)" ) . unwrap ( ) ;
201+
202+ assert_eq ! ( desc. has_wildcard( ) , false ) ;
203+ assert_eq ! ( match desc {
204+ WrapDescriptor { 0 : crate :: descriptor:: WrapDescriptorEnum :: Definite ( _) } => true ,
205+ _ => false ,
206+ } , true ) ;
207+ }
208+ }
0 commit comments