nautilus_model/defi/types/
money.rs1use alloy_primitives::U256;
19
20use crate::types::{Currency, Money};
21
22impl Money {
23 pub fn from_wei<U>(raw_wei: U, currency: Currency) -> Self
32 where
33 U: Into<U256>,
34 {
35 let raw_u256: U256 = raw_wei.into();
36 let raw_u128: u128 = raw_u256
37 .try_into()
38 .expect("raw wei value exceeds 128-bit range");
39
40 assert!(
41 raw_u128 <= i128::MAX as u128,
42 "raw wei value exceeds signed 128-bit range"
43 );
44
45 let raw_i128: i128 = raw_u128 as i128;
46 Self::from_raw(raw_i128, currency)
47 }
48
49 pub fn to_wei(&self) -> U256 {
57 U256::from(self.raw as u128)
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use alloy_primitives::U256;
64 use rstest::rstest;
65 use rust_decimal::Decimal;
66 use rust_decimal_macros::dec;
67
68 use super::*;
69 use crate::enums::CurrencyType;
70
71 #[rstest]
72 fn test_from_wei_one_eth() {
73 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
74 let one_eth_wei = U256::from(1_000_000_000_000_000_000_u64);
75 let money = Money::from_wei(one_eth_wei, eth);
76
77 assert_eq!(money.as_decimal(), dec!(1));
79 assert_eq!(money.currency.precision, 18);
80 }
81
82 #[rstest]
83 fn test_from_wei_small_amount() {
84 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
85 let small_wei = U256::from(1_000_000_000_000_u64); let money = Money::from_wei(small_wei, eth);
87
88 assert_eq!(money.as_decimal(), dec!(0.000001)); }
91
92 #[rstest]
93 fn test_to_wei_one_eth() {
94 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
95 let money = Money::from_wei(U256::from(1_000_000_000_000_000_000_u64), eth);
96 let wei_value = money.to_wei();
97
98 assert_eq!(wei_value, U256::from(1_000_000_000_000_000_000_u64));
99 }
100
101 #[rstest]
102 fn test_to_wei_small_amount() {
103 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
104 let money = Money::from_wei(U256::from(1_000_000_000_000_u64), eth);
105 let wei_value = money.to_wei();
106
107 assert_eq!(wei_value, U256::from(1_000_000_000_000_u64));
108 }
109
110 #[rstest]
111 fn test_wei_roundtrip() {
112 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
113 let original_wei = U256::from(1_234_567_890_123_456_789_u64);
114 let money = Money::from_wei(original_wei, eth);
115 let roundtrip_wei = money.to_wei();
116
117 assert_eq!(original_wei, roundtrip_wei);
118 }
119
120 #[rstest]
121 fn test_from_wei_zero() {
122 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
123 let money = Money::from_wei(U256::ZERO, eth);
124
125 assert!(money.is_zero());
126 assert_eq!(money.as_decimal(), Decimal::ZERO);
127 assert_eq!(money.to_wei(), U256::ZERO);
128 }
129
130 #[rstest]
133 #[should_panic(expected = "raw wei value exceeds signed 128-bit range")]
134 fn test_from_wei_maximum_u128() {
135 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
136 let max_wei = U256::from(u128::MAX);
137 let _ = Money::from_wei(max_wei, eth);
138 }
139
140 #[rstest]
141 #[should_panic(expected = "raw wei value exceeds 128-bit range")]
142 fn test_from_wei_overflow() {
143 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
144 let overflow_wei = U256::from(u128::MAX) + U256::from(1u64);
145 Money::from_wei(overflow_wei, eth);
146 }
147
148 #[rstest]
149 fn test_from_wei_different_tokens() {
150 let usdc = Currency::new("USDC", 18, 0, "USD Coin", CurrencyType::Crypto);
151 let dai = Currency::new("DAI", 18, 0, "Dai Stablecoin", CurrencyType::Crypto);
152
153 let wei_amount = U256::from(500_000_000_000_000_000_u64); let usdc_money = Money::from_wei(wei_amount, usdc);
155 let dai_money = Money::from_wei(wei_amount, dai);
156
157 assert_eq!(usdc_money.as_decimal(), dai_money.as_decimal());
158 assert_eq!(usdc_money.to_wei(), dai_money.to_wei());
159 assert_ne!(usdc_money.currency, dai_money.currency);
160 }
161
162 #[rstest]
163 fn test_arithmetic_with_wei_values() {
164 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
165 let money1 = Money::from_wei(U256::from(1_000_000_000_000_000_000_u64), eth); let money2 = Money::from_wei(U256::from(500_000_000_000_000_000_u64), eth); let sum = money1 + money2;
169 assert_eq!(sum.as_decimal(), dec!(1.5)); assert_eq!(sum.to_wei(), U256::from(1_500_000_000_000_000_000_u64));
171
172 let diff = money1 - money2;
173 assert_eq!(diff.as_decimal(), dec!(0.5)); assert_eq!(diff.to_wei(), U256::from(500_000_000_000_000_000_u64));
175 }
176
177 #[rstest]
178 fn test_comparison_with_wei_values() {
179 let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
180 let money1 = Money::from_wei(U256::from(1_000_000_000_000_000_000_u64), eth); let money2 = Money::from_wei(U256::from(2_000_000_000_000_000_000_u64), eth); let money3 = Money::from_wei(U256::from(1_000_000_000_000_000_000_u64), eth); assert!(money1 < money2);
185 assert!(money2 > money1);
186 assert_eq!(money1, money3);
187 assert!(money1 <= money3);
188 assert!(money1 >= money3);
189 }
190}