casper_types/
motes.rs

1//! The `motes` module is used for working with Motes.
2
3use alloc::vec::Vec;
4use core::fmt;
5
6#[cfg(feature = "datasize")]
7use datasize::DataSize;
8use serde::{Deserialize, Serialize};
9
10use crate::{
11    bytesrepr::{self, FromBytes, ToBytes},
12    Gas, U512,
13};
14
15/// A struct representing a number of `Motes`.
16#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
17#[cfg_attr(feature = "datasize", derive(DataSize))]
18pub struct Motes(U512);
19
20impl Motes {
21    /// The maximum value of `Motes`.
22    pub const MAX: Motes = Motes(U512::MAX);
23
24    /// Constructs a new `Motes`.
25    pub fn new<T: Into<U512>>(value: T) -> Self {
26        Motes(value.into())
27    }
28
29    /// Constructs a new `Motes` with value `0`.
30    pub const fn zero() -> Self {
31        Motes(U512::zero())
32    }
33
34    /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred.
35    pub fn checked_add(&self, rhs: Self) -> Option<Self> {
36        self.0.checked_add(rhs.value()).map(Self::new)
37    }
38
39    /// Checked integer subtraction. Computes `self - rhs`, returning `None` if underflow occurred.
40    pub fn checked_sub(&self, rhs: Self) -> Option<Self> {
41        self.0.checked_sub(rhs.value()).map(Self::new)
42    }
43
44    /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow
45    /// occurred.
46    pub fn checked_mul(&self, rhs: Self) -> Option<Self> {
47        self.0.checked_mul(rhs.value()).map(Self::new)
48    }
49
50    /// Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`.
51    pub fn checked_div(&self, rhs: Self) -> Option<Self> {
52        self.0.checked_div(rhs.value()).map(Self::new)
53    }
54
55    /// Returns the inner `U512` value.
56    pub fn value(&self) -> U512 {
57        self.0
58    }
59
60    /// Converts the given `gas` to `Motes` by multiplying them by `conv_rate`.
61    ///
62    /// Returns `None` if an arithmetic overflow occurred.
63    pub fn from_gas(gas: Gas, conv_rate: u8) -> Option<Self> {
64        gas.value()
65            .checked_mul(U512::from(conv_rate))
66            .map(Self::new)
67    }
68
69    /// Converts the given `amount` to `Motes` by multiplying them by `price`.
70    ///
71    /// Returns `None` if an arithmetic overflow occurred.
72    pub fn from_price(amount: U512, price: u8) -> Option<Self> {
73        amount.checked_mul(U512::from(price)).map(Self::new)
74    }
75}
76
77impl fmt::Display for Motes {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        write!(f, "{:?}", self.0)
80    }
81}
82
83impl ToBytes for Motes {
84    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
85        self.0.to_bytes()
86    }
87
88    fn serialized_length(&self) -> usize {
89        self.0.serialized_length()
90    }
91}
92
93impl FromBytes for Motes {
94    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
95        let (value, remainder) = FromBytes::from_bytes(bytes)?;
96        Ok((Motes(value), remainder))
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use crate::U512;
103
104    use crate::{Gas, Motes};
105
106    #[test]
107    fn should_be_able_to_get_instance_of_motes() {
108        let initial_value = 1;
109        let motes = Motes::new(initial_value);
110        assert_eq!(
111            initial_value,
112            motes.value().as_u64(),
113            "should have equal value"
114        )
115    }
116
117    #[test]
118    fn should_be_able_to_compare_two_instances_of_motes() {
119        let left_motes = Motes::new(1);
120        let right_motes = Motes::new(1);
121        assert_eq!(left_motes, right_motes, "should be equal");
122        let right_motes = Motes::new(2);
123        assert_ne!(left_motes, right_motes, "should not be equal")
124    }
125
126    #[test]
127    fn should_be_able_to_add_two_instances_of_motes() {
128        let left_motes = Motes::new(1);
129        let right_motes = Motes::new(1);
130        let expected_motes = Motes::new(2);
131        assert_eq!(
132            left_motes.checked_add(right_motes),
133            Some(expected_motes),
134            "should be equal"
135        )
136    }
137
138    #[test]
139    fn should_be_able_to_subtract_two_instances_of_motes() {
140        let left_motes = Motes::new(1);
141        let right_motes = Motes::new(1);
142        let expected_motes = Motes::new(0);
143        assert_eq!(
144            left_motes.checked_sub(right_motes),
145            Some(expected_motes),
146            "should be equal"
147        )
148    }
149
150    #[test]
151    fn should_be_able_to_multiply_two_instances_of_motes() {
152        let left_motes = Motes::new(100);
153        let right_motes = Motes::new(10);
154        let expected_motes = Motes::new(1000);
155        assert_eq!(
156            left_motes.checked_mul(right_motes),
157            Some(expected_motes),
158            "should be equal"
159        )
160    }
161
162    #[test]
163    fn should_be_able_to_divide_two_instances_of_motes() {
164        let left_motes = Motes::new(1000);
165        let right_motes = Motes::new(100);
166        let expected_motes = Motes::new(10);
167        assert_eq!(
168            left_motes.checked_div(right_motes),
169            Some(expected_motes),
170            "should be equal"
171        )
172    }
173
174    #[test]
175    fn should_be_able_to_convert_from_motes() {
176        let gas = Gas::new(100);
177        let motes = Motes::from_gas(gas, 10).expect("should have value");
178        let expected_motes = Motes::new(1000);
179        assert_eq!(motes, expected_motes, "should be equal")
180    }
181
182    #[test]
183    fn should_be_able_to_default() {
184        let motes = Motes::default();
185        let expected_motes = Motes::new(0);
186        assert_eq!(motes, expected_motes, "should be equal")
187    }
188
189    #[test]
190    fn should_be_able_to_compare_relative_value() {
191        let left_motes = Motes::new(100);
192        let right_motes = Motes::new(10);
193        assert!(left_motes > right_motes, "should be gt");
194        let right_motes = Motes::new(100);
195        assert!(left_motes >= right_motes, "should be gte");
196        assert!(left_motes <= right_motes, "should be lte");
197        let left_motes = Motes::new(10);
198        assert!(left_motes < right_motes, "should be lt");
199    }
200
201    #[test]
202    fn should_default() {
203        let left_motes = Motes::new(0);
204        let right_motes = Motes::default();
205        assert_eq!(left_motes, right_motes, "should be equal");
206        let u512 = U512::zero();
207        assert_eq!(left_motes.value(), u512, "should be equal");
208    }
209
210    #[test]
211    fn should_support_checked_mul_from_gas() {
212        let gas = Gas::new(U512::MAX);
213        let conv_rate = 10;
214        let maybe = Motes::from_gas(gas, conv_rate);
215        assert!(maybe.is_none(), "should be none due to overflow");
216    }
217}