use alloy_primitives::U256;
use crate::types::price::Price;
impl Price {
#[must_use]
pub fn from_wei<U>(raw_wei: U) -> Self
where
U: Into<U256>,
{
let raw_u256: U256 = raw_wei.into();
let raw_u128: u128 = raw_u256
.try_into()
.expect("raw wei value exceeds 128-bit range");
assert!(
raw_u128 <= i128::MAX as u128,
"raw wei value exceeds signed 128-bit range"
);
let raw_i128: i128 = raw_u128 as i128;
Self::from_raw(raw_i128, 18)
}
#[must_use]
pub fn as_wei(&self) -> U256 {
assert!(
self.precision == 18,
"Failed to convert price with precision {} to wei (requires precision 18)",
self.precision
);
assert!(self.raw >= 0, "Failed to convert negative price to wei");
U256::from(self.raw as u128)
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use rust_decimal_macros::dec;
use super::*;
#[rstest]
fn test_from_wei_basic() {
let price = Price::from_wei(U256::from(1_000_000_000_000_000_000_u128)); assert_eq!(price.precision, 18);
assert_eq!(price.as_decimal(), dec!(1.0));
}
#[rstest]
fn test_precision_18_requires_from_wei() {
let result = Price::new_checked(1.0, 18);
assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("use `Price::from_wei()` for wei values")
);
let price = Price::from_wei(U256::from(1_000_000_000_000_000_000_u128));
assert_eq!(price.precision, 18);
assert_eq!(price.as_decimal(), dec!(1.0));
}
#[rstest]
fn test_as_wei_basic() {
let price = Price::from_raw(1_000_000_000_000_000_000_i128, 18);
let wei = price.as_wei();
assert_eq!(wei, U256::from(1_000_000_000_000_000_000_u128));
}
#[rstest]
#[should_panic(
expected = "Failed to convert price with precision 2 to wei (requires precision 18)"
)]
fn test_as_wei_wrong_precision() {
let price = Price::new(1.23, 2);
let _ = price.as_wei();
}
#[rstest]
#[should_panic(expected = "Failed to convert negative price")]
fn test_as_wei_negative_price() {
let price = Price::from_raw(-1_000_000_000_000_000_000_i128, 18);
let _ = price.as_wei();
}
#[rstest]
fn test_wei_round_trip() {
let original_wei = U256::from(1_500_000_000_000_000_000_u128); let price = Price::from_wei(original_wei);
let converted_wei = price.as_wei();
assert_eq!(original_wei, converted_wei);
assert_eq!(price.as_decimal(), dec!(1.5));
}
#[rstest]
fn test_from_wei_zero() {
let price = Price::from_wei(U256::ZERO);
assert_eq!(price.precision, 18);
assert_eq!(price.as_decimal(), dec!(0));
assert_eq!(price.as_wei(), U256::ZERO);
}
#[rstest]
fn test_from_wei_very_large_value() {
let large_wei = U256::from(1_000_000_000_000_000_000_000_000_000_u128);
let price = Price::from_wei(large_wei);
assert_eq!(price.precision, 18);
assert_eq!(price.as_wei(), large_wei);
assert_eq!(price.as_decimal(), dec!(1000000000));
}
#[rstest]
#[should_panic(expected = "raw wei value exceeds 128-bit range")]
fn test_from_wei_overflow() {
let overflow_wei = U256::from(u128::MAX) + U256::from(1u64);
let _ = Price::from_wei(overflow_wei);
}
#[rstest]
fn test_from_wei_small_amounts() {
let test_cases = vec![
(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)), ];
for (wei_amount, expected_decimal) in test_cases {
let price = Price::from_wei(U256::from(wei_amount));
assert_eq!(price.precision, 18);
assert_eq!(price.as_decimal(), expected_decimal);
assert_eq!(price.as_wei(), U256::from(wei_amount));
}
}
#[rstest]
fn test_from_wei_large_amounts() {
let test_cases = vec![
(1_000_000_000_000_000_000_u128, dec!(1)), (10_000_000_000_000_000_000_u128, dec!(10)), (100_000_000_000_000_000_000_u128, dec!(100)), (1_000_000_000_000_000_000_000_u128, dec!(1000)), ];
for (wei_amount, expected_decimal) in test_cases {
let price = Price::from_wei(U256::from(wei_amount));
assert_eq!(price.precision, 18);
assert_eq!(price.as_decimal(), expected_decimal);
assert_eq!(price.as_wei(), U256::from(wei_amount));
}
}
#[rstest]
fn test_as_wei_precision_validation() {
for precision in [2, 6, 8, 16] {
let price = Price::new(123.45, precision);
let result = std::panic::catch_unwind(|| price.as_wei());
assert!(
result.is_err(),
"as_wei() should panic for precision {precision}"
);
}
}
#[rstest]
fn test_arithmetic_operations_with_wei() {
let price1 = Price::from_wei(U256::from(1_000_000_000_000_000_000_u128)); let price2 = Price::from_wei(U256::from(500_000_000_000_000_000_u128));
let sum = price1 + price2;
assert_eq!(sum.precision, 18);
assert_eq!(sum.as_decimal(), dec!(1.5));
let diff = price1 - price2;
assert_eq!(diff.precision, 18);
assert_eq!(diff.as_decimal(), dec!(0.5));
}
#[rstest]
fn test_comparison_operations_with_wei() {
let price1 = Price::from_wei(U256::from(1_000_000_000_000_000_000_u128)); let price2 = Price::from_wei(U256::from(2_000_000_000_000_000_000_u128)); let price3 = Price::from_wei(U256::from(1_000_000_000_000_000_000_u128));
assert!(price1 < price2);
assert!(price2 > price1);
assert_eq!(price1, price3);
assert!(price1 <= price3);
assert!(price1 >= price3);
}
}