1use std::collections::{BTreeSet, HashMap};
24use std::fmt::{self, Display, Formatter};
25use std::iter;
26
27use derive::{
28 Derive, DeriveCompr, DerivedScript, KeyOrigin, Keychain, LegacyPk, NormalIndex, ScriptPubkey,
29 SigScript, TapDerivation, Terminal, WPubkeyHash, Witness, XOnlyPk, XpubAccount, XpubDerivable,
30};
31use indexmap::IndexMap;
32
33use crate::{Descriptor, LegacyKeySig, SpkClass, TaprootKeySig};
34
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Clone, Eq, PartialEq, Hash, Debug, From)]
37pub struct Wpkh<K: DeriveCompr = XpubDerivable>(K);
38
39impl<K: DeriveCompr> Wpkh<K> {
40 pub fn as_key(&self) -> &K { &self.0 }
41 pub fn into_key(self) -> K { self.0 }
42}
43
44impl<K: DeriveCompr> Derive<DerivedScript> for Wpkh<K> {
45 #[inline]
46 fn default_keychain(&self) -> Keychain { self.0.default_keychain() }
47
48 #[inline]
49 fn keychains(&self) -> BTreeSet<Keychain> { self.0.keychains() }
50
51 fn derive(
52 &self,
53 keychain: impl Into<Keychain>,
54 index: impl Into<NormalIndex>,
55 ) -> impl Iterator<Item = DerivedScript> {
56 self.0
57 .derive(keychain, index)
58 .map(|key| DerivedScript::Bare(ScriptPubkey::p2wpkh(WPubkeyHash::from(key))))
59 }
60}
61
62impl<K: DeriveCompr> Descriptor<K> for Wpkh<K> {
63 fn class(&self) -> SpkClass { SpkClass::P2wpkh }
64
65 fn keys<'a>(&'a self) -> impl Iterator<Item = &'a K>
66 where K: 'a {
67 iter::once(&self.0)
68 }
69 fn vars<'a>(&'a self) -> impl Iterator<Item = &'a ()>
70 where (): 'a {
71 iter::empty()
72 }
73 fn xpubs(&self) -> impl Iterator<Item = &XpubAccount> { iter::once(self.0.xpub_spec()) }
74
75 fn legacy_keyset(&self, terminal: Terminal) -> IndexMap<LegacyPk, KeyOrigin> {
76 self.0
77 .derive(terminal.keychain, terminal.index)
78 .map(|key| (key.into(), KeyOrigin::with(self.0.xpub_spec().origin().clone(), terminal)))
79 .collect()
80 }
81
82 fn xonly_keyset(&self, _terminal: Terminal) -> IndexMap<XOnlyPk, TapDerivation> {
83 IndexMap::new()
84 }
85
86 fn legacy_witness(
87 &self,
88 keysigs: HashMap<&KeyOrigin, LegacyKeySig>,
89 ) -> Option<(SigScript, Witness)> {
90 let our_origin = self.0.xpub_spec().origin();
91 let keysig =
92 keysigs.iter().find(|(origin, _)| our_origin.is_subset_of(origin)).map(|(_, ks)| ks)?;
93 let witness = Witness::from_consensus_stack([keysig.sig.to_vec(), keysig.key.to_vec()]);
94 Some((empty!(), witness))
95 }
96
97 fn taproot_witness(&self, _keysigs: HashMap<&KeyOrigin, TaprootKeySig>) -> Option<Witness> {
98 None
99 }
100}
101
102impl<K: DeriveCompr> Display for Wpkh<K> {
103 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "wpkh({})", self.0) }
104}