use alloy_primitives::U256;
use rust_decimal::{
Decimal,
prelude::{FromPrimitive, ToPrimitive},
};
use crate::error::{PricingError, Result};
pub const PRICING_SCALE_PLACES: u32 = 9;
pub fn pricing_scale() -> Decimal {
let scale = 10u128.pow(PRICING_SCALE_PLACES);
Decimal::from_u128(scale).expect("invalid pricing scale")
}
pub fn decimal_to_scaled_amount(value: Decimal) -> Result<U256> {
let scaled = (value * pricing_scale()).trunc();
if scaled.is_sign_negative() {
return Err(PricingError::Pricing(
"Negative prices are not supported".to_string(),
));
}
if scaled.is_zero() {
return Err(PricingError::Pricing(
"Zero price not supported; use explicit free-tier logic".to_string(),
));
}
let int_value = scaled
.to_u128()
.ok_or_else(|| PricingError::Pricing("Failed to scale price into u128".to_string()))?;
Ok(U256::from(int_value))
}
pub fn percent_to_bps(percent: u32) -> Result<u16> {
if percent > 100 {
return Err(PricingError::Pricing(format!(
"Exposure percent {percent}% exceeds 100%"
)));
}
Ok(u16::try_from(percent * 100).expect("percent <= 100 guarantees fit"))
}