brk_structs/structs/
sats.rs1use std::{
2 iter::Sum,
3 ops::{Add, AddAssign, Div, Mul, SubAssign},
4};
5
6use bitcoin::Amount;
7use derive_deref::Deref;
8use serde::{Deserialize, Serialize};
9use vecdb::{CheckedSub, StoredCompressed};
10use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
11
12use crate::StoredF64;
13
14use super::{Bitcoin, Cents, Dollars, Height};
15
16#[derive(
17 Debug,
18 PartialEq,
19 Eq,
20 PartialOrd,
21 Ord,
22 Clone,
23 Copy,
24 Deref,
25 Default,
26 FromBytes,
27 Immutable,
28 IntoBytes,
29 KnownLayout,
30 Serialize,
31 Deserialize,
32 StoredCompressed,
33)]
34pub struct Sats(u64);
35
36#[allow(clippy::inconsistent_digit_grouping)]
37impl Sats {
38 pub const ZERO: Self = Self(0);
39 pub const _1: Self = Self(1);
40 pub const _10: Self = Self(10);
41 pub const _100: Self = Self(100);
42 pub const _1K: Self = Self(1_000);
43 pub const _10K: Self = Self(10_000);
44 pub const _100K: Self = Self(100_000);
45 pub const _1M: Self = Self(1_000_000);
46 pub const _10M: Self = Self(10_000_000);
47 pub const _1BTC: Self = Self::ONE_BTC;
48 pub const _10BTC: Self = Self(10_00_000_000);
49 pub const _100BTC: Self = Self(100_00_000_000);
50 pub const _1K_BTC: Self = Self(1_000_00_000_000);
51 pub const _10K_BTC: Self = Self(10_000_00_000_000);
52 pub const _100K_BTC: Self = Self(100_000_00_000_000);
53 pub const ONE_BTC: Self = Self(1_00_000_000);
54 pub const MAX: Self = Self(u64::MAX);
55 pub const FIFTY_BTC: Self = Self(50_00_000_000);
56 pub const ONE_BTC_U128: u128 = 1_00_000_000;
57
58 pub fn new(sats: u64) -> Self {
59 Self(sats)
60 }
61
62 pub fn is_zero(&self) -> bool {
63 *self == Self::ZERO
64 }
65
66 pub fn is_not_zero(&self) -> bool {
67 *self != Self::ZERO
68 }
69}
70
71impl Add for Sats {
72 type Output = Self;
73 fn add(self, rhs: Self) -> Self::Output {
74 Self::from(self.0 + rhs.0)
75 }
76}
77
78impl AddAssign for Sats {
79 fn add_assign(&mut self, rhs: Self) {
80 *self = *self + rhs;
81 }
82}
83
84impl CheckedSub<Sats> for Sats {
85 fn checked_sub(self, rhs: Self) -> Option<Self> {
86 self.0.checked_sub(rhs.0).map(Self::from)
87 }
88}
89
90impl CheckedSub<usize> for Sats {
91 fn checked_sub(self, rhs: usize) -> Option<Self> {
92 self.0.checked_sub(rhs as u64).map(Self::from)
93 }
94}
95
96impl SubAssign for Sats {
97 fn sub_assign(&mut self, rhs: Self) {
98 *self = self.checked_sub(rhs).unwrap();
99 }
104}
105
106impl Mul<Sats> for Sats {
107 type Output = Self;
108 fn mul(self, rhs: Sats) -> Self::Output {
109 Sats::from(self.0.checked_mul(rhs.0).unwrap())
110 }
111}
112
113impl Mul<usize> for Sats {
114 type Output = Self;
115 fn mul(self, rhs: usize) -> Self::Output {
116 Sats::from(self.0.checked_mul(rhs as u64).unwrap())
117 }
118}
119
120impl Mul<u64> for Sats {
121 type Output = Self;
122 fn mul(self, rhs: u64) -> Self::Output {
123 Sats::from(self.0.checked_mul(rhs).unwrap())
124 }
125}
126
127impl Mul<Height> for Sats {
128 type Output = Self;
129 fn mul(self, rhs: Height) -> Self::Output {
130 Sats::from(self.0.checked_mul(u64::from(rhs)).unwrap())
131 }
132}
133
134impl Mul<StoredF64> for Sats {
135 type Output = Self;
136 fn mul(self, rhs: StoredF64) -> Self::Output {
137 Sats::from((self.0 as f64 * f64::from(rhs)) as u64)
138 }
139}
140
141impl Sum for Sats {
142 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
143 let sats: u64 = iter.map(|sats| sats.0).sum();
144 Self::from(sats)
145 }
146}
147
148impl Div<Dollars> for Sats {
149 type Output = Self;
150 fn div(self, rhs: Dollars) -> Self::Output {
151 let raw_cents = u64::from(Cents::from(rhs));
152 if raw_cents != 0 {
153 Self(self.0 * 100 / raw_cents)
154 } else {
155 Self::MAX
156 }
157 }
158}
159
160impl Div<Sats> for Sats {
161 type Output = Self;
162 fn div(self, rhs: Sats) -> Self::Output {
163 if rhs.0 == 0 {
164 Self(0)
165 } else {
166 Self(self.0 / rhs.0)
167 }
168 }
169}
170
171impl Div<usize> for Sats {
172 type Output = Self;
173 fn div(self, rhs: usize) -> Self::Output {
174 Self(self.0 / rhs as u64)
175 }
176}
177
178impl From<u64> for Sats {
179 fn from(value: u64) -> Self {
180 Self(value)
181 }
182}
183
184impl From<usize> for Sats {
185 fn from(value: usize) -> Self {
186 Self(value as u64)
187 }
188}
189
190impl From<f64> for Sats {
191 fn from(value: f64) -> Self {
192 Self(value.round() as u64)
193 }
194}
195
196impl From<Sats> for f64 {
197 fn from(value: Sats) -> Self {
198 value.0 as f64
199 }
200}
201
202impl From<Sats> for usize {
203 fn from(value: Sats) -> Self {
204 value.0 as usize
205 }
206}
207
208impl From<Amount> for Sats {
209 fn from(value: Amount) -> Self {
210 Self(value.to_sat())
211 }
212}
213impl From<Sats> for Amount {
214 fn from(value: Sats) -> Self {
215 Self::from_sat(value.0)
216 }
217}
218
219impl From<Bitcoin> for Sats {
220 fn from(value: Bitcoin) -> Self {
221 Self((f64::from(value) * (Sats::ONE_BTC.0 as f64)).round() as u64)
222 }
223}
224
225impl From<Sats> for u64 {
226 fn from(value: Sats) -> Self {
227 value.0
228 }
229}
230
231impl From<u128> for Sats {
232 fn from(value: u128) -> Self {
233 if value > u64::MAX as u128 {
234 panic!("u128 bigger than u64")
235 }
236 Self(value as u64)
237 }
238}
239
240impl From<Sats> for u128 {
241 fn from(value: Sats) -> Self {
242 value.0 as u128
243 }
244}
245
246impl Mul<Sats> for usize {
247 type Output = Sats;
248 fn mul(self, rhs: Sats) -> Self::Output {
249 Self::Output::from(rhs.0 * self as u64)
250 }
251}