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