Repository navigation
Added functions for multipath descriptors. #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -124,6 +124,13 @@ impl ElectrumExtendedKey for ElectrumExtendedPrivKey { | |
| self.xprv.to_string() | ||
| } | ||
|
|
||
| /// Returns multipath descriptor | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. miniscript 12 and BDK 2.x reject multipath xprv. Please note that in the doc comment so callers know. |
||
| fn to_descriptor(&self) -> String { | ||
| let xprv = self.xprv.to_string(); | ||
| let closing_parenthesis = if self.kind.contains('(') { ")" } else { "" }; | ||
| format!("{}({}/<0;1>/*){}", self.kind, xprv, closing_parenthesis) | ||
| } | ||
|
|
||
| /// Returns internal and external descriptor | ||
| fn to_descriptors(&self) -> Descriptors { | ||
| let xprv = self.xprv.to_string(); | ||
|
|
@@ -151,7 +158,7 @@ impl ElectrumExtendedPrivKey { | |
| let sentinel = sentinels | ||
| .iter() | ||
| .find(|sent| NetworkKind::from(sent.1) == self.xprv.network && sent.2 == self.kind) | ||
| .ok_or_else(|| Electrum2DescriptorError::UnknownType)?; | ||
| .ok_or(Electrum2DescriptorError::UnknownType)?; | ||
| let mut data = Vec::from(&sentinel.0[..]); | ||
| data.push(self.xprv.depth); | ||
| data.extend(self.xprv.parent_fingerprint.as_bytes()); | ||
|
|
@@ -188,13 +195,30 @@ mod tests { | |
| #[test] | ||
| fn test_vprv_from_electrum() { | ||
| let electrum_xprv = ElectrumExtendedPrivKey::from_str("yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF").unwrap(); | ||
| assert_eq!(electrum_xprv.xprv.to_string(),"xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD"); | ||
| assert_eq!( | ||
| electrum_xprv.xprv.to_string(), | ||
| "xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD" | ||
| ); | ||
| assert_eq!(electrum_xprv.kind, "sh(wpkh"); | ||
| let descriptor = electrum_xprv.to_descriptor(); | ||
| assert_eq!( | ||
| descriptor, | ||
| "sh(wpkh(xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD/<0;1>/*))" | ||
| ); | ||
| let descriptors = electrum_xprv.to_descriptors(); | ||
| assert_eq!(descriptors.external, "sh(wpkh(xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD/0/*))"); | ||
| assert_eq!(descriptors.change, "sh(wpkh(xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD/1/*))"); | ||
| assert_eq!( | ||
| descriptors.external, | ||
| "sh(wpkh(xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD/0/*))" | ||
| ); | ||
| assert_eq!( | ||
| descriptors.change, | ||
| "sh(wpkh(xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD/1/*))" | ||
| ); | ||
| let xprv = electrum_xprv.xprv(); | ||
| assert_eq!(xprv.to_string(), "xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD"); | ||
| assert_eq!( | ||
| xprv.to_string(), | ||
| "xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
@@ -203,7 +227,10 @@ mod tests { | |
| Xpriv::from_str("xprv9y7S1RkggDtZnP1RSzJ7PwUR4MUfF66Wz2jGv9TwJM52WLGmnnrQLLzBSTi7rNtBk4SGeQHBj5G4CuQvPXSn58BmhvX9vk6YzcMm37VuNYD").unwrap(), | ||
| "sh(wpkh".to_string(), | ||
| ); | ||
| assert_eq!(electrum_xprv.electrum_xprv().unwrap(), "yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF"); | ||
| assert_eq!( | ||
| electrum_xprv.electrum_xprv().unwrap(), | ||
| "yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -131,6 +131,13 @@ impl ElectrumExtendedKey for ElectrumExtendedPubKey { | |
| [0, 1].map(|i| format!("{}({}/{}/*){}", self.kind, xpub, i, closing_parenthesis)); | ||
| Descriptors { external, change } | ||
| } | ||
|
|
||
| /// Returns multipath descriptor | ||
| fn to_descriptor(&self) -> String { | ||
| let xpub = self.xpub.to_string(); | ||
| let closing_parenthesis = if self.kind.contains('(') { ")" } else { "" }; | ||
| format!("{}({}/<0;1>/*){}", self.kind, xpub, closing_parenthesis) | ||
| } | ||
| } | ||
|
|
||
| impl ElectrumExtendedPubKey { | ||
|
|
@@ -150,7 +157,7 @@ impl ElectrumExtendedPubKey { | |
| let sentinel = sentinels | ||
| .iter() | ||
| .find(|sent| NetworkKind::from(sent.1) == self.xpub.network && sent.2 == self.kind) | ||
| .ok_or_else(|| Electrum2DescriptorError::UnknownType)?; | ||
| .ok_or(Electrum2DescriptorError::UnknownType)?; | ||
| let mut data = Vec::from(&sentinel.0[..]); | ||
| data.push(self.xpub.depth); | ||
| data.extend(self.xpub.parent_fingerprint.as_bytes()); | ||
|
|
@@ -188,13 +195,30 @@ mod tests { | |
| #[test] | ||
| fn test_vpub_from_electrum() { | ||
| let electrum_xpub = ElectrumExtendedPubKey::from_str("vpub5VXaSncXqxLbdmvrC4Y8z9CszPwuEscADoetWhfrxDFzPUbL5nbVtanYDkrVEutkv9n5A5aCcvRC9swbjDKgHjCZ2tAeae8VsBuPbS8KpXv").unwrap(); | ||
| assert_eq!(electrum_xpub.xpub.to_string(),"tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp"); | ||
| assert_eq!( | ||
| electrum_xpub.xpub.to_string(), | ||
| "tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp" | ||
| ); | ||
| assert_eq!(electrum_xpub.kind, "wpkh"); | ||
| let descriptor = electrum_xpub.to_descriptor(); | ||
| assert_eq!( | ||
| descriptor, | ||
| "wpkh(tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp/<0;1>/*)" | ||
| ); | ||
| let descriptors = electrum_xpub.to_descriptors(); | ||
| assert_eq!(descriptors.external, "wpkh(tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp/0/*)"); | ||
| assert_eq!(descriptors.change, "wpkh(tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp/1/*)"); | ||
| assert_eq!( | ||
| descriptors.external, | ||
| "wpkh(tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp/0/*)" | ||
| ); | ||
| assert_eq!( | ||
| descriptors.change, | ||
| "wpkh(tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp/1/*)" | ||
| ); | ||
| let xpub = electrum_xpub.xpub(); | ||
| assert_eq!(xpub.to_string(), "tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp"); | ||
| assert_eq!( | ||
| xpub.to_string(), | ||
| "tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
@@ -203,9 +227,15 @@ mod tests { | |
| Xpub::from_str("tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp").unwrap(), | ||
| "wpkh".to_string(), | ||
| ); | ||
| assert_eq!(electrum_xpub.xpub.to_string(),"tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp"); | ||
| assert_eq!( | ||
| electrum_xpub.xpub.to_string(), | ||
| "tpubD9ZjaMn3rbP1cAVwJy6UcEjFfTLT7W6DbfHdS3Wn48meExtVfKmiH9meWCrSmE9qXLYbGcHC5LxLcdfLZTzwme23qAJoRzRhzbd68dHeyjp" | ||
| ); | ||
| assert_eq!(electrum_xpub.kind, "wpkh"); | ||
| assert_eq!(electrum_xpub.electrum_xpub().unwrap(), "vpub5VXaSncXqxLbdmvrC4Y8z9CszPwuEscADoetWhfrxDFzPUbL5nbVtanYDkrVEutkv9n5A5aCcvRC9swbjDKgHjCZ2tAeae8VsBuPbS8KpXv"); | ||
| assert_eq!( | ||
| electrum_xpub.electrum_xpub().unwrap(), | ||
| "vpub5VXaSncXqxLbdmvrC4Y8z9CszPwuEscADoetWhfrxDFzPUbL5nbVtanYDkrVEutkv9n5A5aCcvRC9swbjDKgHjCZ2tAeae8VsBuPbS8KpXv" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
@@ -219,9 +249,18 @@ mod tests { | |
| #[test] | ||
| fn test_slip121_vectors() { | ||
| // from https://github.com/satoshilabs/slips/blob/master/slip-0132.md | ||
| test_first_address("xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj","1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"); | ||
| test_first_address("ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP","37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"); | ||
| test_first_address("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs","bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"); | ||
| test_first_address( | ||
| "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", | ||
| "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", | ||
| ); | ||
| test_first_address( | ||
| "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", | ||
| "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", | ||
| ); | ||
| test_first_address( | ||
| "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", | ||
| "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", | ||
| ); | ||
| } | ||
|
|
||
| fn test_first_address(electrum_xpub: &str, expected_first_address: &str) { | ||
|
|
@@ -241,4 +280,39 @@ mod tests { | |
| .to_string(); | ||
| assert_eq!(expected_first_address, first_address); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_slip121_vectors_multipath() { | ||
| // from https://github.com/satoshilabs/slips/blob/master/slip-0132.md | ||
| test_first_address_multipath( | ||
| "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", | ||
| "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", | ||
| ); | ||
| test_first_address_multipath( | ||
| "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", | ||
| "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", | ||
| ); | ||
| test_first_address_multipath( | ||
| "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", | ||
| "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", | ||
| ); | ||
| } | ||
|
|
||
| fn test_first_address_multipath(electrum_xpub: &str, expected_first_address: &str) { | ||
| let electrum_xpub = ElectrumExtendedPubKey::from_str(electrum_xpub).unwrap(); | ||
| assert_eq!(electrum_xpub.xpub.network, Network::Bitcoin.into()); | ||
| let descriptor = electrum_xpub.to_descriptor(); | ||
| let descriptor = descriptor.replace("<0;1>", "0"); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replacing |
||
| let descriptor: miniscript::Descriptor<DescriptorPublicKey> = descriptor.parse().unwrap(); | ||
| let secp = Secp256k1::verification_only(); | ||
| let first_address = descriptor | ||
| .at_derivation_index(0) | ||
| .unwrap() | ||
| .derived_descriptor(&secp) | ||
| .unwrap() | ||
| .address(miniscript::bitcoin::Network::Bitcoin) | ||
| .unwrap() | ||
| .to_string(); | ||
| assert_eq!(expected_first_address, first_address); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ use crate::{ | |
| }; | ||
| use bitcoin::bip32::{Xpriv, Xpub}; | ||
| use regex::Regex; | ||
| use serde::{de, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; | ||
| use serde::{Deserialize, Deserializer, Serialize, Serializer, de, ser::SerializeMap}; | ||
| use std::{fmt, io::BufReader, path::Path, str::FromStr, string::ToString}; | ||
|
|
||
| /// Representation of an electrum wallet file. Has custom serialization and de-serialization routines to more accurately represent what we need, and the electrum wallet file format. | ||
|
|
@@ -82,8 +82,9 @@ impl ElectrumWalletFile { | |
|
|
||
| /// Construct from a single signature output descriptor. Only the external descriptor is needed, the change descriptor is implied. | ||
| fn from_descriptor_singlesig(desc: &str) -> Result<Self, Electrum2DescriptorError> { | ||
| let re = | ||
| Regex::new(r#"(pkh|sh\(wpkh|sh\(wsh|wpkh|wsh)\((([tx]p(ub|rv)[0-9A-Za-z]+)/0/\*)\)+"#)?; | ||
| let re = Regex::new( | ||
| r#"(pkh|sh\(wpkh|sh\(wsh|wpkh|wsh)\((([tx]p(ub|rv)[0-9A-Za-z]+)/.*/\*)\)+"#, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| )?; | ||
| let captures = re.captures(desc).map(|captures| { | ||
| captures | ||
| .iter() | ||
|
|
@@ -99,7 +100,7 @@ impl ElectrumWalletFile { | |
| return Err(Electrum2DescriptorError::UnknownDescriptorFormat(format!( | ||
| "{:?}", | ||
| captures | ||
| ))) | ||
| ))); | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -113,7 +114,7 @@ impl ElectrumWalletFile { | |
| /// Construct from a multisig output descriptor. Only the external descriptor is needed, the change descriptor is implied. | ||
| fn from_descriptor_multisig(desc: &str) -> Result<Self, Electrum2DescriptorError> { | ||
| let re = Regex::new( | ||
| r#"(sh|sh\(wsh|wsh)\(sortedmulti\((\d),([tx]p(ub|rv)[0-9A-Za-z]+/0/\*,?)+\)+"#, | ||
| r#"(sh|sh\(wsh|wsh)\(sortedmulti\((\d),([tx]p(ub|rv)[0-9A-Za-z]+/.*/\*,?)+\)+"#, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. A multisig with |
||
| )?; | ||
| let captures = re.captures(desc).map(|captures| { | ||
| captures | ||
|
|
@@ -132,7 +133,7 @@ impl ElectrumWalletFile { | |
| _ => { | ||
| return Err(Electrum2DescriptorError::UnknownScriptKind( | ||
| kind.to_string(), | ||
| )) | ||
| )); | ||
| } | ||
| }; | ||
| let re = Regex::new(r#"[tx]p[ur][bv][0-9A-Za-z]+"#)?; | ||
|
|
@@ -203,6 +204,12 @@ impl ElectrumWalletFile { | |
| } | ||
| } | ||
|
|
||
| /// Generate multipath output descriptor matching the electrum wallet | ||
| pub fn to_descriptor(&self) -> Result<String, Electrum2DescriptorError> { | ||
| let desc = self.to_descriptors()?; | ||
| Ok(desc.external.replace("/0/*", "/<0;1>/*")) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: building the string directly would be more robust than |
||
| } | ||
|
|
||
| /// validate the internal structure | ||
| fn validate(&self) -> Result<(), Electrum2DescriptorError> { | ||
| let expected_keystores: usize = match self.wallet_type { | ||
|
|
@@ -217,6 +224,7 @@ impl ElectrumWalletFile { | |
| )); | ||
| } | ||
|
|
||
| #[allow(clippy::collapsible_if)] | ||
| if let WalletType::Multisig(x, _y) = self.wallet_type { | ||
| if x as usize > expected_keystores { | ||
| return Err(Electrum2DescriptorError::NumberSignaturesKeyStores( | ||
|
|
@@ -294,7 +302,7 @@ impl<'de> Deserialize<'de> for ElectrumWalletFile { | |
| { | ||
| struct FieldVisitor; | ||
|
|
||
| impl<'de> de::Visitor<'de> for FieldVisitor { | ||
| impl de::Visitor<'_> for FieldVisitor { | ||
| type Value = Field; | ||
|
|
||
| fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,9 @@ pub trait ElectrumExtendedKey { | |
| /// Returns internal and external descriptor | ||
| fn to_descriptors(&self) -> Descriptors; | ||
|
|
||
| /// Returns multipath descriptor | ||
| fn to_descriptor(&self) -> String; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be a default method using |
||
|
|
||
| /// Returns the bitcoin extended key (xpub or xprv) as String | ||
| fn xkey_str(&self) -> String; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For private keys this prints a descriptor that BDK can't load. Maybe keep
to_descriptors()for xprv until BDK supports it? Also,{:?}at line 32 now prints a quoted string, and the README examples still show the old list.