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