pepper_sync/keys/
transparent.rs1use zcash_address::{ToAddress as _, ZcashAddress};
4use zcash_protocol::consensus;
5use zcash_transparent::address::TransparentAddress;
6use zcash_transparent::keys::{NonHardenedChildIndex, TransparentKeyScope};
7use zip32::AccountId;
8
9#[cfg(not(feature = "darkside_test"))]
10use zcash_transparent::keys::{AccountPubKey, IncomingViewingKey as _};
11
12use crate::wallet::KeyIdInterface;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16pub struct TransparentAddressId {
17 account_id: AccountId,
18 scope: TransparentScope,
19 address_index: NonHardenedChildIndex,
20}
21
22impl TransparentAddressId {
23 #[must_use]
25 pub fn new(
26 account_id: zip32::AccountId,
27 scope: TransparentScope,
28 address_index: NonHardenedChildIndex,
29 ) -> Self {
30 Self {
31 account_id,
32 scope,
33 address_index,
34 }
35 }
36
37 #[must_use]
39 pub fn address_index(&self) -> NonHardenedChildIndex {
40 self.address_index
41 }
42
43 #[must_use]
45 pub fn scope(&self) -> TransparentScope {
46 self.scope
47 }
48}
49
50impl KeyIdInterface for TransparentAddressId {
51 fn account_id(&self) -> AccountId {
52 self.account_id
53 }
54}
55
56#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
58pub enum TransparentScope {
59 External,
61 Internal,
63 Refund,
65}
66
67impl std::fmt::Display for TransparentScope {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(
70 f,
71 "{}",
72 match self {
73 TransparentScope::External => "external",
74 TransparentScope::Internal => "internal",
75 TransparentScope::Refund => "refund",
76 }
77 )
78 }
79}
80
81impl From<TransparentScope> for TransparentKeyScope {
82 fn from(value: TransparentScope) -> Self {
83 match value {
84 TransparentScope::External => TransparentKeyScope::EXTERNAL,
85 TransparentScope::Internal => TransparentKeyScope::INTERNAL,
86 TransparentScope::Refund => TransparentKeyScope::EPHEMERAL,
87 }
88 }
89}
90
91impl TryFrom<u8> for TransparentScope {
92 type Error = std::io::Error;
93
94 fn try_from(value: u8) -> std::io::Result<Self> {
95 match value {
96 0 => Ok(TransparentScope::External),
97 1 => Ok(TransparentScope::Internal),
98 2 => Ok(TransparentScope::Refund),
99 _ => Err(std::io::Error::new(
100 std::io::ErrorKind::InvalidData,
101 "invalid scope value",
102 )),
103 }
104 }
105}
106
107#[cfg(not(feature = "darkside_test"))]
108pub(crate) fn derive_address(
109 consensus_parameters: &impl consensus::Parameters,
110 account_pubkey: &AccountPubKey,
111 address_id: TransparentAddressId,
112) -> Result<String, bip32::Error> {
113 let address = match address_id.scope() {
114 TransparentScope::External => {
115 derive_external_address(account_pubkey, address_id.address_index())?
116 }
117 TransparentScope::Internal => {
118 derive_internal_address(account_pubkey, address_id.address_index())?
119 }
120 TransparentScope::Refund => {
121 derive_refund_address(account_pubkey, address_id.address_index())?
122 }
123 };
124
125 Ok(encode_address(consensus_parameters, address))
126}
127
128#[cfg(not(feature = "darkside_test"))]
129fn derive_external_address(
130 account_pubkey: &AccountPubKey,
131 address_index: NonHardenedChildIndex,
132) -> Result<TransparentAddress, bip32::Error> {
133 account_pubkey
134 .derive_external_ivk()?
135 .derive_address(address_index)
136}
137
138#[cfg(not(feature = "darkside_test"))]
139fn derive_internal_address(
140 account_pubkey: &AccountPubKey,
141 address_index: NonHardenedChildIndex,
142) -> Result<TransparentAddress, bip32::Error> {
143 account_pubkey
144 .derive_internal_ivk()?
145 .derive_address(address_index)
146}
147
148#[cfg(not(feature = "darkside_test"))]
149fn derive_refund_address(
150 account_pubkey: &AccountPubKey,
151 address_index: NonHardenedChildIndex,
152) -> Result<TransparentAddress, bip32::Error> {
153 account_pubkey
154 .derive_ephemeral_ivk()?
155 .derive_ephemeral_address(address_index)
156}
157
158pub fn encode_address(
160 consensus_parameters: &impl consensus::Parameters,
161 address: TransparentAddress,
162) -> String {
163 let zcash_address = match address {
164 TransparentAddress::PublicKeyHash(data) => {
165 ZcashAddress::from_transparent_p2pkh(consensus_parameters.network_type(), data)
166 }
167 TransparentAddress::ScriptHash(data) => {
168 ZcashAddress::from_transparent_p2sh(consensus_parameters.network_type(), data)
169 }
170 };
171 zcash_address.to_string()
172}