nautilus_model/defi/types/
quantity.rs1use alloy_primitives::U256;
19
20use crate::types::quantity::Quantity;
21
22impl Quantity {
23 #[must_use]
32 pub fn from_wei<U>(raw_wei: U) -> Self
33 where
34 U: Into<U256>,
35 {
36 let raw_u256: U256 = raw_wei.into();
37 let raw_u128: u128 = raw_u256
38 .try_into()
39 .expect("raw wei value exceeds unsigned 128-bit range");
40
41 Self::from_raw(raw_u128, 18)
42 }
43
44 #[must_use]
52 pub fn as_wei(&self) -> U256 {
53 assert!(
54 self.precision == 18,
55 "Failed to convert quantity with precision {} to wei (requires precision 18)",
56 self.precision
57 );
58
59 U256::from(self.raw)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use rstest::rstest;
66 use rust_decimal_macros::dec;
67
68 use super::*;
69
70 #[rstest]
71 fn test_from_wei_basic() {
72 let quantity = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128)); assert_eq!(quantity.precision, 18);
74 assert_eq!(quantity.as_decimal(), dec!(1.0));
75 }
76
77 #[rstest]
78 fn test_as_wei_basic() {
79 let quantity = Quantity::from_raw(1_000_000_000_000_000_000_u128, 18);
80 let wei = quantity.as_wei();
81 assert_eq!(wei, U256::from(1_000_000_000_000_000_000_u128));
82 }
83
84 #[rstest]
85 #[should_panic(
86 expected = "Failed to convert quantity with precision 2 to wei (requires precision 18)"
87 )]
88 fn test_as_wei_wrong_precision() {
89 let quantity = Quantity::new(1.23, 2);
90 let _ = quantity.as_wei();
91 }
92
93 #[rstest]
94 fn test_wei_round_trip() {
95 let original_wei = U256::from(1_500_000_000_000_000_000_u128); let quantity = Quantity::from_wei(original_wei);
97 let converted_wei = quantity.as_wei();
98 assert_eq!(original_wei, converted_wei);
99 assert_eq!(quantity.as_decimal(), dec!(1.5));
100 }
101
102 #[rstest]
103 fn test_checked_arith_accepts_wei_precision() {
104 let a = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128));
105 let b = Quantity::from_wei(U256::from(2_000_000_000_000_000_000_u128));
106 let sum = a
107 .checked_add(b)
108 .expect("checked_add must accept wei quantities");
109 assert_eq!(sum.as_decimal(), dec!(3));
110 let diff = b
111 .checked_sub(a)
112 .expect("checked_sub must accept wei quantities");
113 assert_eq!(diff.as_decimal(), dec!(1));
114 }
115
116 #[rstest]
117 fn test_checked_arith_rejects_mixed_scale() {
118 let wei = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128));
121 let standard = Quantity::new(1.0, 0);
122 assert_eq!(wei.checked_add(standard), None);
123 assert_eq!(standard.checked_add(wei), None);
124 assert_eq!(wei.checked_sub(standard), None);
125 assert_eq!(standard.checked_sub(wei), None);
126 }
127
128 #[rstest]
129 fn test_checked_arith_rejects_mixed_defi_scales() {
130 let q17 = Quantity::from_raw(100_000_000_000_000_000_u128, 17);
133 let q18 = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128));
134 assert_eq!(q17.checked_add(q18), None);
135 assert_eq!(q18.checked_add(q17), None);
136 assert_eq!(q17.checked_sub(q18), None);
137 assert_eq!(q18.checked_sub(q17), None);
138 }
139
140 #[rstest]
141 fn test_from_wei_large_value() {
142 let large_wei = U256::from(1_000_000_000_000_000_000_000_u128); let quantity = Quantity::from_wei(large_wei);
145 assert_eq!(quantity.precision, 18);
146 assert_eq!(quantity.as_decimal(), dec!(1000.0));
147 }
148
149 #[rstest]
150 fn test_from_wei_small_value() {
151 let small_wei = U256::from(1_000_000_u128);
154 let quantity = Quantity::from_wei(small_wei);
155 assert_eq!(quantity.precision, 18);
156 assert_eq!(quantity.as_decimal(), dec!(0.000000000001));
157 }
158
159 #[rstest]
160 fn test_from_wei_zero() {
161 let quantity = Quantity::from_wei(U256::ZERO);
162 assert_eq!(quantity.precision, 18);
163 assert_eq!(quantity.as_decimal(), dec!(0));
164 assert_eq!(quantity.as_wei(), U256::ZERO);
165 }
166
167 #[rstest]
168 fn test_from_wei_very_large_value() {
169 let large_wei = U256::from(1_000_000_000_000_000_000_000_000_000_u128);
171 let quantity = Quantity::from_wei(large_wei);
172 assert_eq!(quantity.precision, 18);
173 assert_eq!(quantity.as_wei(), large_wei);
174 assert_eq!(quantity.as_decimal(), dec!(1000000000));
175 }
176
177 #[rstest]
178 #[should_panic(expected = "raw wei value exceeds unsigned 128-bit range")]
179 fn test_from_wei_overflow() {
180 let overflow_wei = U256::from(u128::MAX) + U256::from(1_u64);
181 let _ = Quantity::from_wei(overflow_wei);
182 }
183
184 #[rstest]
185 fn test_from_wei_various_amounts() {
186 let test_cases = vec![
188 (1_u128, dec!(0.000000000000000001)), (1000_u128, dec!(0.000000000000001)), (1_000_000_u128, dec!(0.000000000001)), (1_000_000_000_u128, dec!(0.000000001)), (1_000_000_000_000_u128, dec!(0.000001)), (1_000_000_000_000_000_u128, dec!(0.001)), (1_000_000_000_000_000_000_u128, dec!(1)), (10_000_000_000_000_000_000_u128, dec!(10)), ];
197
198 for (wei_amount, expected_decimal) in test_cases {
199 let quantity = Quantity::from_wei(U256::from(wei_amount));
200 assert_eq!(quantity.precision, 18);
201 assert_eq!(quantity.as_decimal(), expected_decimal);
202 assert_eq!(quantity.as_wei(), U256::from(wei_amount));
203 }
204 }
205
206 #[rstest]
207 fn test_as_wei_precision_validation() {
208 for precision in [2, 6, 8, 16] {
210 let quantity = Quantity::new(123.45, precision);
211 let result = std::panic::catch_unwind(|| quantity.as_wei());
212 assert!(
213 result.is_err(),
214 "as_wei() should panic for precision {precision}"
215 );
216 }
217 }
218
219 #[rstest]
220 fn test_arithmetic_operations_with_wei() {
221 let quantity1 = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128)); let quantity2 = Quantity::from_wei(U256::from(500_000_000_000_000_000_u128)); let sum = quantity1 + quantity2;
226 assert_eq!(sum.precision, 18);
227 assert_eq!(sum.as_decimal(), dec!(1.5));
228 assert_eq!(sum.as_wei(), U256::from(1_500_000_000_000_000_000_u128));
229
230 let diff = quantity1 - quantity2;
232 assert_eq!(diff.precision, 18);
233 assert_eq!(diff.as_decimal(), dec!(0.5));
234 assert_eq!(diff.as_wei(), U256::from(500_000_000_000_000_000_u128));
235 }
236
237 #[rstest]
238 fn test_comparison_operations_with_wei() {
239 let quantity1 = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128)); let quantity2 = Quantity::from_wei(U256::from(2_000_000_000_000_000_000_u128)); let quantity3 = Quantity::from_wei(U256::from(1_000_000_000_000_000_000_u128)); assert!(quantity1 < quantity2);
244 assert!(quantity2 > quantity1);
245 assert_eq!(quantity1, quantity3);
246 assert!(quantity1 <= quantity3);
247 assert!(quantity1 >= quantity3);
248 }
249}