lwk/
desc.rs

1use std::{fmt, str::FromStr, sync::Arc};
2
3use crate::{types::SecretKey, Chain, LwkError, Script};
4
5/// The output descriptors, wrapper over [`lwk_wollet::WolletDescriptor`]
6#[derive(uniffi::Object)]
7#[uniffi::export(Display)]
8pub struct WolletDescriptor {
9    inner: lwk_wollet::WolletDescriptor,
10}
11
12impl AsRef<lwk_wollet::WolletDescriptor> for WolletDescriptor {
13    fn as_ref(&self) -> &lwk_wollet::WolletDescriptor {
14        &self.inner
15    }
16}
17
18impl From<lwk_wollet::WolletDescriptor> for WolletDescriptor {
19    fn from(inner: lwk_wollet::WolletDescriptor) -> Self {
20        Self { inner }
21    }
22}
23
24impl From<&WolletDescriptor> for lwk_wollet::WolletDescriptor {
25    fn from(desc: &WolletDescriptor) -> Self {
26        desc.inner.clone()
27    }
28}
29
30#[uniffi::export]
31impl WolletDescriptor {
32    /// Create a new descriptor from its string representation.
33    #[uniffi::constructor]
34    pub fn new(descriptor: &str) -> Result<Arc<Self>, LwkError> {
35        let inner = lwk_wollet::WolletDescriptor::from_str(descriptor)?;
36        Ok(Arc::new(WolletDescriptor { inner }))
37    }
38
39    /// Whether the descriptor is on the mainnet
40    pub fn is_mainnet(&self) -> bool {
41        self.inner.is_mainnet()
42    }
43
44    /// Derive the private blinding key
45    pub fn derive_blinding_key(&self, script_pubkey: &Script) -> Option<Arc<SecretKey>> {
46        lwk_common::derive_blinding_key(self.inner.as_ref(), &script_pubkey.into())
47            .map(Into::into)
48            .map(Arc::new)
49    }
50
51    /// Derive a scriptpubkey
52    pub fn script_pubkey(&self, ext_int: Chain, index: u32) -> Result<Arc<Script>, LwkError> {
53        self.inner
54            .script_pubkey(ext_int.into(), index)
55            .map_err(Into::into)
56            .map(Into::into)
57            .map(Arc::new)
58    }
59
60    /// Whether the descriptor is AMP0
61    pub fn is_amp0(&self) -> bool {
62        self.inner.is_amp0()
63    }
64}
65
66impl fmt::Display for WolletDescriptor {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        write!(f, "{}", self.inner)
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use lwk_wollet::ElementsNetwork;
75
76    use crate::{Chain, Mnemonic, Signer, WolletDescriptor};
77    use std::str::FromStr;
78
79    #[test]
80    fn wpkh_slip77_descriptor() {
81        let mnemonic_str = lwk_test_util::TEST_MNEMONIC;
82        let mnemonic = Mnemonic::new(mnemonic_str).unwrap();
83        let network: crate::Network = ElementsNetwork::default_regtest().into();
84
85        let signer = Signer::new(&mnemonic, &network).unwrap();
86        let exp = "ct(slip77(9c8e4f05c7711a98c838be228bcb84924d4570ca53f35fa1c793e58841d47023),elwpkh([73c5da0a/84'/1'/0']tpubDC8msFGeGuwnKG9Upg7DM2b4DaRqg3CUZa5g8v2SRQ6K4NSkxUgd7HsL2XVWbVm39yBA4LAxysQAm397zwQSQoQgewGiYZqrA9DsP4zbQ1M/<0;1>/*))#2e4n992d";
87        assert_eq!(signer.wpkh_slip77_descriptor().unwrap().to_string(), exp);
88
89        let wollet_desc = lwk_wollet::WolletDescriptor::from_str(exp).unwrap();
90        let desc: WolletDescriptor = wollet_desc.into();
91        assert_eq!(desc.to_string(), exp);
92
93        assert!(!desc.is_mainnet());
94
95        assert_eq!(
96            desc.script_pubkey(Chain::External, 0).unwrap().to_string(),
97            "0014d0c4a3ef09e997b6e99e397e518fe3e41a118ca1"
98        );
99
100        assert_eq!(
101            desc.script_pubkey(Chain::Internal, 0).unwrap().to_string(),
102            "00142f34aa1cf00a53b055a291a03a7d45f0a6988b52"
103        );
104    }
105}