11use crate :: error:: WasmMiniscriptError ;
22use crate :: try_into_js_value:: TryIntoJsValue ;
3- use miniscript:: bitcoin:: secp256k1:: Secp256k1 ;
3+ use miniscript:: bitcoin:: secp256k1:: { Context , Secp256k1 , Signing } ;
44use miniscript:: bitcoin:: ScriptBuf ;
55use miniscript:: descriptor:: KeyMap ;
66use miniscript:: { DefiniteDescriptorKey , Descriptor , DescriptorPublicKey } ;
@@ -71,7 +71,9 @@ impl WrapDescriptor {
7171 pub fn script_pubkey ( & self ) -> Result < Vec < u8 > , WasmMiniscriptError > {
7272 match & self . 0 {
7373 WrapDescriptorEnum :: Definite ( desc) => Ok ( desc. script_pubkey ( ) . to_bytes ( ) ) ,
74- _ => Err ( WasmMiniscriptError :: new ( "Cannot derive from a non-definite descriptor" ) ) ,
74+ _ => Err ( WasmMiniscriptError :: new (
75+ "Cannot encode a derivable descriptor" ,
76+ ) ) ,
7577 }
7678 }
7779
@@ -109,8 +111,10 @@ impl WrapDescriptor {
109111 . map_err ( |_| WasmMiniscriptError :: new ( "Weight exceeds u32" ) )
110112 }
111113
112- fn from_string_derivable ( descriptor : & str ) -> Result < WrapDescriptor , WasmMiniscriptError > {
113- let secp = Secp256k1 :: new ( ) ;
114+ fn from_string_derivable < C : Signing > (
115+ secp : & Secp256k1 < C > ,
116+ descriptor : & str ,
117+ ) -> Result < WrapDescriptor , WasmMiniscriptError > {
114118 let ( desc, keys) = Descriptor :: parse_descriptor ( & secp, descriptor) ?;
115119 Ok ( WrapDescriptor ( WrapDescriptorEnum :: Derivable ( desc, keys) ) )
116120 }
@@ -120,13 +124,35 @@ impl WrapDescriptor {
120124 Ok ( WrapDescriptor ( WrapDescriptorEnum :: Definite ( desc) ) )
121125 }
122126
127+ /// Parse a descriptor string with an explicit public key type.
128+ ///
129+ /// Note that this function permits parsing a non-derivable descriptor with a derivable key type.
130+ /// Use `from_string_detect_type` to automatically detect the key type.
131+ ///
132+ /// # Arguments
133+ /// * `descriptor` - A string containing the descriptor to parse
134+ /// * `pk_type` - The type of public key to expect:
135+ /// - "derivable": For descriptors containing derivation paths (eg. xpubs)
136+ /// - "definite": For descriptors with fully specified keys
137+ /// - "string": For descriptors with string placeholders
138+ ///
139+ /// # Returns
140+ /// * `Result<WrapDescriptor, WasmMiniscriptError>` - The parsed descriptor or an error
141+ ///
142+ /// # Example
143+ /// ```
144+ /// let desc = WrapDescriptor::from_string(
145+ /// "pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/*)",
146+ /// "derivable"
147+ /// );
148+ /// ```
123149 #[ wasm_bindgen( js_name = fromString, skip_typescript) ]
124150 pub fn from_string (
125151 descriptor : & str ,
126152 pk_type : & str ,
127153 ) -> Result < WrapDescriptor , WasmMiniscriptError > {
128154 match pk_type {
129- "derivable" => WrapDescriptor :: from_string_derivable ( descriptor) ,
155+ "derivable" => WrapDescriptor :: from_string_derivable ( & Secp256k1 :: new ( ) , descriptor) ,
130156 "definite" => WrapDescriptor :: from_string_definite ( descriptor) ,
131157 "string" => {
132158 let desc = Descriptor :: < String > :: from_str ( descriptor) ?;
@@ -135,4 +161,71 @@ impl WrapDescriptor {
135161 _ => Err ( WasmMiniscriptError :: new ( "Invalid descriptor type" ) ) ,
136162 }
137163 }
138- }
164+
165+ /// Parse a descriptor string, automatically detecting the appropriate public key type.
166+ /// This will check if the descriptor contains wildcards to determine if it should be
167+ /// parsed as derivable or definite.
168+ ///
169+ /// # Arguments
170+ /// * `descriptor` - A string containing the descriptor to parse
171+ ///
172+ /// # Returns
173+ /// * `Result<WrapDescriptor, WasmMiniscriptError>` - The parsed descriptor or an error
174+ ///
175+ /// # Example
176+ /// ```
177+ /// // Will be parsed as definite since it has no wildcards
178+ /// let desc = WrapDescriptor::from_string_detect_type(
179+ /// "pk(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)"
180+ /// );
181+ ///
182+ /// // Will be parsed as derivable since it contains a wildcard (*)
183+ /// let desc = WrapDescriptor::from_string_detect_type(
184+ /// "pk(xpub.../0/*)"
185+ /// );
186+ /// ```
187+ #[ wasm_bindgen( js_name = fromStringDetectType, skip_typescript) ]
188+ pub fn from_string_detect_type (
189+ descriptor : & str ,
190+ ) -> Result < WrapDescriptor , WasmMiniscriptError > {
191+ let secp = Secp256k1 :: new ( ) ;
192+ let ( descriptor, _key_map) = Descriptor :: parse_descriptor ( & secp, descriptor)
193+ . map_err ( |_| WasmMiniscriptError :: new ( "Invalid descriptor" ) ) ?;
194+ if descriptor. has_wildcard ( ) {
195+ WrapDescriptor :: from_string_derivable ( & secp, & descriptor. to_string ( ) )
196+ } else {
197+ WrapDescriptor :: from_string_definite ( & descriptor. to_string ( ) )
198+ }
199+ }
200+ }
201+
202+ impl FromStr for WrapDescriptor {
203+ type Err = WasmMiniscriptError ;
204+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
205+ WrapDescriptor :: from_string_detect_type ( s)
206+ }
207+ }
208+
209+ #[ cfg( test) ]
210+ mod tests {
211+ use crate :: WrapDescriptor ;
212+
213+ #[ test]
214+ fn test_detect_type ( ) {
215+ let desc = WrapDescriptor :: from_string_detect_type (
216+ "pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)" ,
217+ )
218+ . unwrap ( ) ;
219+
220+ assert_eq ! ( desc. has_wildcard( ) , false ) ;
221+ assert_eq ! (
222+ match desc {
223+ WrapDescriptor {
224+ 0 : crate :: descriptor:: WrapDescriptorEnum :: Definite ( _) ,
225+ } => true ,
226+ _ => false ,
227+ } ,
228+ true
229+ ) ;
230+ }
231+ }
0 commit comments