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
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17pub struct TransparentAddressId {
18 account_id: AccountId,
19 scope: TransparentScope,
20 address_index: NonHardenedChildIndex,
21}
22
23impl TransparentAddressId {
24 pub fn new(
26 account_id: zcash_primitives::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 pub fn account_id(&self) -> AccountId {
39 self.account_id
40 }
41
42 pub fn scope(&self) -> TransparentScope {
44 self.scope
45 }
46
47 pub fn address_index(&self) -> NonHardenedChildIndex {
49 self.address_index
50 }
51}
52
53#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
55pub enum TransparentScope {
56 External,
58 Internal,
60 Refund,
62}
63
64impl std::fmt::Display for TransparentScope {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 write!(
67 f,
68 "{}",
69 match self {
70 TransparentScope::External => "external",
71 TransparentScope::Internal => "internal",
72 TransparentScope::Refund => "refund",
73 }
74 )
75 }
76}
77
78impl From<TransparentScope> for TransparentKeyScope {
79 fn from(value: TransparentScope) -> Self {
80 match value {
81 TransparentScope::External => TransparentKeyScope::EXTERNAL,
82 TransparentScope::Internal => TransparentKeyScope::INTERNAL,
83 TransparentScope::Refund => TransparentKeyScope::EPHEMERAL,
84 }
85 }
86}
87
88impl TryFrom<u8> for TransparentScope {
89 type Error = std::io::Error;
90
91 fn try_from(value: u8) -> std::io::Result<Self> {
92 match value {
93 0 => Ok(TransparentScope::External),
94 1 => Ok(TransparentScope::Internal),
95 2 => Ok(TransparentScope::Refund),
96 _ => Err(std::io::Error::new(
97 std::io::ErrorKind::InvalidData,
98 "invalid scope value",
99 )),
100 }
101 }
102}
103
104pub(crate) fn derive_address(
105 consensus_parameters: &impl consensus::Parameters,
106 account_pubkey: &AccountPubKey,
107 address_id: TransparentAddressId,
108) -> Result<String, bip32::Error> {
109 let address = match address_id.scope() {
110 TransparentScope::External => {
111 derive_external_address(account_pubkey, address_id.address_index())?
112 }
113 TransparentScope::Internal => {
114 derive_internal_address(account_pubkey, address_id.address_index())?
115 }
116 TransparentScope::Refund => {
117 derive_refund_address(account_pubkey, address_id.address_index())?
118 }
119 };
120
121 Ok(encode_address(consensus_parameters, address))
122}
123
124fn derive_external_address(
125 account_pubkey: &AccountPubKey,
126 address_index: NonHardenedChildIndex,
127) -> Result<TransparentAddress, bip32::Error> {
128 account_pubkey
129 .derive_external_ivk()?
130 .derive_address(address_index)
131}
132
133fn derive_internal_address(
134 account_pubkey: &AccountPubKey,
135 address_index: NonHardenedChildIndex,
136) -> Result<TransparentAddress, bip32::Error> {
137 account_pubkey
138 .derive_internal_ivk()?
139 .derive_address(address_index)
140}
141
142fn derive_refund_address(
143 account_pubkey: &AccountPubKey,
144 address_index: NonHardenedChildIndex,
145) -> Result<TransparentAddress, bip32::Error> {
146 account_pubkey
147 .derive_ephemeral_ivk()?
148 .derive_ephemeral_address(address_index)
149}
150
151pub fn encode_address(
153 consensus_parameters: &impl consensus::Parameters,
154 address: TransparentAddress,
155) -> String {
156 let zcash_address = match address {
157 TransparentAddress::PublicKeyHash(data) => {
158 ZcashAddress::from_transparent_p2pkh(consensus_parameters.network_type(), data)
159 }
160 TransparentAddress::ScriptHash(data) => {
161 ZcashAddress::from_transparent_p2sh(consensus_parameters.network_type(), data)
162 }
163 };
164 zcash_address.to_string()
165}