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
134impl Address {
135 pub fn network(&self) -> NetworkKind {
137 match &self {
138 Self::Transparent(address) => address.network_kind(),
139 Self::Sapling { network, .. } | Self::Unified { network, .. } => *network,
140 }
141 }
142
143 pub fn is_script_hash(&self) -> bool {
146 match &self {
147 Self::Transparent(address) => address.is_script_hash(),
148 Self::Sapling { .. } | Self::Unified { .. } => false,
149 }
150 }
151
152 pub fn is_transparent(&self) -> bool {
155 matches!(self, Self::Transparent(_))
156 }
157
158 pub fn payment_address(&self) -> Option<String> {
160 use zcash_address::{ToAddress, ZcashAddress};
161
162 match &self {
163 Self::Transparent(address) => Some(address.to_string()),
164 Self::Sapling { address, network } => {
165 let data = address.to_bytes();
166 let address = ZcashAddress::from_sapling(network.into(), data);
167 Some(address.encode())
168 }
169 Self::Unified { .. } => None,
170 }
171 }
172}
173
174impl From<NetworkType> for NetworkKind {
175 fn from(network: NetworkType) -> Self {
176 match network {
177 NetworkType::Main => NetworkKind::Mainnet,
178 NetworkType::Test => NetworkKind::Testnet,
179 NetworkType::Regtest => NetworkKind::Regtest,
180 }
181 }
182}
183
184impl From<NetworkKind> for NetworkType {
185 fn from(network: NetworkKind) -> Self {
186 match network {
187 NetworkKind::Mainnet => NetworkType::Main,
188 NetworkKind::Testnet => NetworkType::Test,
189 NetworkKind::Regtest => NetworkType::Regtest,
190 }
191 }
192}
193
194impl From<&NetworkKind> for NetworkType {
195 fn from(network: &NetworkKind) -> Self {
196 (*network).into()
197 }
198}