zebra_rpc/methods/types/
zec.rs1use std::{
7 fmt,
8 hash::{Hash, Hasher},
9 ops,
10 str::FromStr,
11};
12
13use zebra_chain::amount::{self, Amount, Constraint, COIN};
14
15use zebra_node_services::BoxError;
16
17#[allow(unused_imports)]
19use zebra_chain::amount::MAX_MONEY;
20
21#[cfg(test)]
22mod tests;
23
24pub const MAX_ZEC_FORMAT_PRECISION: usize = 8;
30
31#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, Default)]
44#[serde(try_from = "f64")]
45#[serde(into = "f64")]
46#[serde(bound = "C: Constraint + Clone")]
47pub struct Zec<C: Constraint>(Amount<C>);
48
49impl<C: Constraint> Zec<C> {
50 pub fn lossy_zec(&self) -> f64 {
55 let zats = self.zatoshis();
56 let zats = zats as f64;
59 let coin = COIN as f64;
60
61 zats / coin
64 }
65
66 pub fn from_lossy_zec(lossy_zec: f64) -> Result<Self, BoxError> {
71 let coin = COIN as f64;
73
74 let zats = lossy_zec * coin;
77
78 if !zats.is_finite() {
79 return Err("invalid ZEC value: floating point is not finite".into());
80 }
81
82 let zats = Amount::try_from(zats.round() as i64)?;
85
86 Ok(Self(zats))
87 }
88}
89
90impl<C: Constraint> From<Zec<C>> for f64 {
92 fn from(zec: Zec<C>) -> f64 {
93 zec.lossy_zec()
94 }
95}
96
97impl<C: Constraint> TryFrom<f64> for Zec<C> {
98 type Error = BoxError;
99
100 fn try_from(value: f64) -> Result<Self, Self::Error> {
101 Self::from_lossy_zec(value)
102 }
103}
104
105impl<C: Constraint> fmt::Display for Zec<C> {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 let zec = self.lossy_zec();
109
110 let decimals = f.precision().unwrap_or(MAX_ZEC_FORMAT_PRECISION);
112 let string = format!("{zec:.decimals$}");
113 f.pad_integral(zec >= 0.0, "", &string)
114 }
115}
116
117impl<C: Constraint> FromStr for Zec<C> {
119 type Err = BoxError;
120
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 let lossy_zec: f64 = s.parse()?;
123
124 Self::from_lossy_zec(lossy_zec)
125 }
126}
127
128impl<C: Constraint> std::fmt::Debug for Zec<C> {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 f.debug_struct(&format!("Zec<{}>", std::any::type_name::<C>()))
131 .field("ZEC", &self.to_string())
132 .field("zat", &self.0)
133 .finish()
134 }
135}
136
137impl<C: Constraint> ops::Deref for Zec<C> {
138 type Target = Amount<C>;
139
140 fn deref(&self) -> &Self::Target {
141 &self.0
142 }
143}
144
145impl<C: Constraint> ops::DerefMut for Zec<C> {
146 fn deref_mut(&mut self) -> &mut Self::Target {
147 &mut self.0
148 }
149}
150
151impl<C: Constraint> From<Amount<C>> for Zec<C> {
152 fn from(amount: Amount<C>) -> Self {
153 Self(amount)
154 }
155}
156
157impl<C: Constraint> From<Zec<C>> for Amount<C> {
158 fn from(zec: Zec<C>) -> Amount<C> {
159 zec.0
160 }
161}
162
163impl<C: Constraint> From<Zec<C>> for i64 {
164 fn from(zec: Zec<C>) -> i64 {
165 zec.0.into()
166 }
167}
168
169impl<C: Constraint> TryFrom<i64> for Zec<C> {
170 type Error = amount::Error;
171
172 fn try_from(value: i64) -> Result<Self, Self::Error> {
173 Ok(Self(Amount::try_from(value)?))
174 }
175}
176
177impl<C: Constraint> Hash for Zec<C> {
178 fn hash<H: Hasher>(&self, state: &mut H) {
180 self.0.hash(state);
181 }
182}
183
184impl<C1: Constraint, C2: Constraint> PartialEq<Zec<C2>> for Zec<C1> {
185 fn eq(&self, other: &Zec<C2>) -> bool {
186 self.0.eq(&other.0)
187 }
188}
189
190impl<C: Constraint> PartialEq<i64> for Zec<C> {
191 fn eq(&self, other: &i64) -> bool {
192 self.0.eq(other)
193 }
194}
195
196impl<C: Constraint> PartialEq<Zec<C>> for i64 {
197 fn eq(&self, other: &Zec<C>) -> bool {
198 self.eq(&other.0)
199 }
200}
201
202impl<C1: Constraint, C2: Constraint> PartialEq<Amount<C2>> for Zec<C1> {
203 fn eq(&self, other: &Amount<C2>) -> bool {
204 self.0.eq(other)
205 }
206}
207
208impl<C1: Constraint, C2: Constraint> PartialEq<Zec<C2>> for Amount<C1> {
209 fn eq(&self, other: &Zec<C2>) -> bool {
210 self.eq(&other.0)
211 }
212}
213
214impl<C: Constraint> Eq for Zec<C> {}