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