use alloy_primitives::U256;
use crate::types::{Currency, Money};
impl Money {
pub fn from_wei<U>(raw_wei: U, currency: Currency) -> 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, currency)
}
pub fn to_wei(&self) -> U256 {
U256::from(self.raw as u128)
}
}
#[cfg(test)]
mod tests {
use alloy_primitives::U256;
use rstest::rstest;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use super::*;
use crate::enums::CurrencyType;
#[rstest]
fn test_from_wei_one_eth() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let one_eth_wei = U256::from(1_000_000_000_000_000_000_u64);
let money = Money::from_wei(one_eth_wei, eth);
assert_eq!(money.as_decimal(), dec!(1));
assert_eq!(money.currency.precision, 18);
}
#[rstest]
fn test_from_wei_small_amount() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let small_wei = U256::from(1_000_000_000_000_u64); let money = Money::from_wei(small_wei, eth);
assert_eq!(money.as_decimal(), dec!(0.000001)); }
#[rstest]
fn test_to_wei_one_eth() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let money = Money::from_wei(U256::from(1_000_000_000_000_000_000_u64), eth);
let wei_value = money.to_wei();
assert_eq!(wei_value, U256::from(1_000_000_000_000_000_000_u64));
}
#[rstest]
fn test_to_wei_small_amount() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let money = Money::from_wei(U256::from(1_000_000_000_000_u64), eth);
let wei_value = money.to_wei();
assert_eq!(wei_value, U256::from(1_000_000_000_000_u64));
}
#[rstest]
fn test_wei_roundtrip() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let original_wei = U256::from(1_234_567_890_123_456_789_u64);
let money = Money::from_wei(original_wei, eth);
let roundtrip_wei = money.to_wei();
assert_eq!(original_wei, roundtrip_wei);
}
#[rstest]
fn test_from_wei_zero() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let money = Money::from_wei(U256::ZERO, eth);
assert!(money.is_zero());
assert_eq!(money.as_decimal(), Decimal::ZERO);
assert_eq!(money.to_wei(), U256::ZERO);
}
#[rstest]
#[should_panic(expected = "raw wei value exceeds signed 128-bit range")]
fn test_from_wei_maximum_u128() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let max_wei = U256::from(u128::MAX);
let _ = Money::from_wei(max_wei, eth);
}
#[rstest]
#[should_panic(expected = "raw wei value exceeds 128-bit range")]
fn test_from_wei_overflow() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
let overflow_wei = U256::from(u128::MAX) + U256::from(1u64);
Money::from_wei(overflow_wei, eth);
}
#[rstest]
fn test_from_wei_different_tokens() {
let usdc = Currency::new("USDC", 18, 0, "USD Coin", CurrencyType::Crypto);
let dai = Currency::new("DAI", 18, 0, "Dai Stablecoin", CurrencyType::Crypto);
let wei_amount = U256::from(500_000_000_000_000_000_u64); let usdc_money = Money::from_wei(wei_amount, usdc);
let dai_money = Money::from_wei(wei_amount, dai);
assert_eq!(usdc_money.as_decimal(), dai_money.as_decimal());
assert_eq!(usdc_money.to_wei(), dai_money.to_wei());
assert_ne!(usdc_money.currency, dai_money.currency);
}
#[rstest]
fn test_arithmetic_with_wei_values() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
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;
assert_eq!(sum.as_decimal(), dec!(1.5)); assert_eq!(sum.to_wei(), U256::from(1_500_000_000_000_000_000_u64));
let diff = money1 - money2;
assert_eq!(diff.as_decimal(), dec!(0.5)); assert_eq!(diff.to_wei(), U256::from(500_000_000_000_000_000_u64));
}
#[rstest]
fn test_comparison_with_wei_values() {
let eth = Currency::new("ETH", 18, 0, "Ethereum", CurrencyType::Crypto);
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);
assert!(money2 > money1);
assert_eq!(money1, money3);
assert!(money1 <= money3);
assert!(money1 >= money3);
}
}