zebra_chain/primitives/
address.rs
1use zcash_address::unified::{self, Container};
6use zcash_protocol::consensus::NetworkType;
7
8use crate::{parameters::NetworkKind, transparent, BoxError};
9
10pub enum Address {
12 Transparent(transparent::Address),
14
15 Sapling {
17 network: NetworkKind,
19
20 address: sapling_crypto::PaymentAddress,
22 },
23
24 Unified {
26 network: NetworkKind,
28
29 unified_address: zcash_address::unified::Address,
31
32 orchard: Option<orchard::Address>,
34
35 sapling: Option<sapling_crypto::PaymentAddress>,
37
38 transparent: Option<transparent::Address>,
40 },
41}
42
43impl zcash_address::TryFromAddress for Address {
44 type Error = BoxError;
46
47 fn try_from_transparent_p2pkh(
48 network: NetworkType,
49 data: [u8; 20],
50 ) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
51 Ok(Self::Transparent(transparent::Address::from_pub_key_hash(
52 network.into(),
53 data,
54 )))
55 }
56
57 fn try_from_transparent_p2sh(
58 network: NetworkType,
59 data: [u8; 20],
60 ) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
61 Ok(Self::Transparent(transparent::Address::from_script_hash(
62 network.into(),
63 data,
64 )))
65 }
66
67 fn try_from_sapling(
68 network: NetworkType,
69 data: [u8; 43],
70 ) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
71 let network = network.into();
72 sapling_crypto::PaymentAddress::from_bytes(&data)
73 .map(|address| Self::Sapling { address, network })
74 .ok_or_else(|| BoxError::from("not a valid sapling address").into())
75 }
76
77 fn try_from_unified(
78 network: NetworkType,
79 unified_address: zcash_address::unified::Address,
80 ) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
81 let network = network.into();
82 let mut orchard = None;
83 let mut sapling = None;
84 let mut transparent = None;
85
86 for receiver in unified_address.items().into_iter() {
87 match receiver {
88 unified::Receiver::Orchard(data) => {
89 orchard = orchard::Address::from_raw_address_bytes(&data).into();
90 if orchard.is_none() {
94 return Err(BoxError::from(
95 "Unified Address contains an invalid Orchard receiver.",
96 )
97 .into());
98 }
99 }
100 unified::Receiver::Sapling(data) => {
101 sapling = sapling_crypto::PaymentAddress::from_bytes(&data);
102 if sapling.is_none() {
106 return Err(BoxError::from(
107 "Unified Address contains an invalid Sapling receiver",
108 )
109 .into());
110 }
111 }
112 unified::Receiver::P2pkh(data) => {
113 transparent = Some(transparent::Address::from_pub_key_hash(network, data));
114 }
115 unified::Receiver::P2sh(data) => {
116 transparent = Some(transparent::Address::from_script_hash(network, data));
117 }
118 unified::Receiver::Unknown { .. } => {
119 return Err(BoxError::from("Unsupported receiver in a Unified Address.").into());
120 }
121 }
122 }
123
124 Ok(Self::Unified {
125 network,
126 unified_address,
127 orchard,
128 sapling,
129 transparent,
130 })
131 }
132
133 fn try_from_tex(
134 network: NetworkType,
135 data: [u8; 20],
136 ) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
137 Ok(Self::Transparent(transparent::Address::from_tex(
138 network.into(),
139 data,
140 )))
141 }
142}
143
144impl Address {
145 pub fn network(&self) -> NetworkKind {
147 match &self {
148 Self::Transparent(address) => address.network_kind(),
149 Self::Sapling { network, .. } | Self::Unified { network, .. } => *network,
150 }
151 }
152
153 pub fn is_script_hash(&self) -> bool {
156 match &self {
157 Self::Transparent(address) => address.is_script_hash(),
158 Self::Sapling { .. } | Self::Unified { .. } => false,
159 }
160 }
161
162 pub fn is_transparent(&self) -> bool {
165 matches!(self, Self::Transparent(_))
166 }
167
168 pub fn payment_address(&self) -> Option<String> {
170 use zcash_address::{ToAddress, ZcashAddress};
171
172 match &self {
173 Self::Transparent(address) => Some(address.to_string()),
174 Self::Sapling { address, network } => {
175 let data = address.to_bytes();
176 let address = ZcashAddress::from_sapling(network.into(), data);
177 Some(address.encode())
178 }
179 Self::Unified { .. } => None,
180 }
181 }
182}
183
184impl From<NetworkType> for NetworkKind {
185 fn from(network: NetworkType) -> Self {
186 match network {
187 NetworkType::Main => NetworkKind::Mainnet,
188 NetworkType::Test => NetworkKind::Testnet,
189 NetworkType::Regtest => NetworkKind::Regtest,
190 }
191 }
192}
193
194impl From<NetworkKind> for NetworkType {
195 fn from(network: NetworkKind) -> Self {
196 match network {
197 NetworkKind::Mainnet => NetworkType::Main,
198 NetworkKind::Testnet => NetworkType::Test,
199 NetworkKind::Regtest => NetworkType::Regtest,
200 }
201 }
202}
203
204impl From<&NetworkKind> for NetworkType {
205 fn from(network: &NetworkKind) -> Self {
206 (*network).into()
207 }
208}