zebra_rpc/methods/types/
z_validate_address.rs1use derive_getters::Getters;
4use derive_new::new;
5use jsonrpsee::core::RpcResult;
6
7use zebra_chain::{parameters::Network, primitives::Address};
8
9#[derive(
11 Clone, Default, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Getters, new,
12)]
13pub struct ZValidateAddressResponse {
14 #[serde(rename = "isvalid")]
18 pub(crate) is_valid: bool,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub(crate) address: Option<String>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 #[getter(copy)]
27 pub(crate) address_type: Option<ZValidateAddressType>,
28
29 #[serde(rename = "ismine")]
33 #[serde(skip_serializing_if = "Option::is_none")]
34 #[getter(copy)]
35 pub(crate) is_mine: Option<bool>,
36}
37
38impl ZValidateAddressResponse {
39 pub fn invalid() -> Self {
41 Self::default()
42 }
43}
44
45#[derive(Copy, Clone, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
48#[serde(rename_all = "lowercase")]
49pub enum ZValidateAddressType {
50 P2pkh,
52 P2sh,
54 Sapling,
56 Unified,
58}
59
60impl From<&Address> for ZValidateAddressType {
61 fn from(address: &Address) -> Self {
62 match address {
63 Address::Transparent(_) => {
64 if address.is_script_hash() {
65 Self::P2sh
66 } else {
67 Self::P2pkh
68 }
69 }
70 Address::Sapling { .. } => Self::Sapling,
71 Address::Unified { .. } => Self::Unified,
72 }
73 }
74}
75
76pub fn z_validate_address(
79 network: Network,
80 raw_address: String,
81) -> RpcResult<ZValidateAddressResponse> {
82 let Ok(address) = raw_address.parse::<zcash_address::ZcashAddress>() else {
83 return Ok(ZValidateAddressResponse::invalid());
84 };
85
86 let address = match address.convert::<Address>() {
87 Ok(address) => address,
88 Err(err) => {
89 tracing::debug!(?err, "conversion error");
90 return Ok(ZValidateAddressResponse::invalid());
91 }
92 };
93
94 if address.network() == network.kind() {
95 Ok(ZValidateAddressResponse {
96 is_valid: true,
97 address: Some(raw_address),
98 address_type: Some(ZValidateAddressType::from(&address)),
99 is_mine: Some(false),
100 })
101 } else {
102 tracing::info!(
103 ?network,
104 address_network = ?address.network(),
105 "invalid address network in z_validateaddress RPC: address is for {:?} but Zebra is on {:?}",
106 address.network(),
107 network
108 );
109
110 Ok(ZValidateAddressResponse::invalid())
111 }
112}