fermat_core/lib.rs
1//! # fermat-core
2//!
3//! 128-bit fixed-point decimal arithmetic for Solana's sBPF runtime.
4//!
5//! ## Design Goals
6//!
7//! - **`no_std`**: Works on Solana sBPF without any OS dependencies.
8//! - **Zero external dependencies**: Only `proptest` appears as a dev-dependency.
9//! - **Panic-free**: Every fallible operation returns `Result<_, ArithmeticError>`.
10//! - **`#![forbid(unsafe_code)]`**: No unsafe blocks anywhere in the crate.
11//! - **Overflow-safe `mul_div`**: Uses a 256-bit intermediate (`U256`) to prevent
12//! the class of bugs where `(a × b) / c` silently wraps when `a × b` overflows `i128`.
13//!
14//! ## Core Type
15//!
16//! ```text
17//! Decimal { mantissa: i128, scale: u8 }
18//! value = mantissa × 10^(-scale)
19//! ```
20//!
21//! The `scale` is bounded to `[0, 28]` (`MAX_SCALE`). On-chain Borsh encoding is
22//! exactly 17 bytes (16 bytes mantissa LE + 1 byte scale).
23//!
24//! ## Quick Start
25//!
26//! ```rust
27//! use fermat_core::{Decimal, RoundingMode};
28//!
29//! let price = Decimal::new(150_000_000, 6).unwrap(); // 150.000000
30//! let amount = Decimal::new(2_500_000, 6).unwrap(); // 2.500000
31//! let total = price.checked_mul(amount).unwrap(); // 375.000000...
32//! let result = total.round(6, RoundingMode::HalfEven).unwrap();
33//! ```
34
35#![no_std]
36#![forbid(unsafe_code)]
37#![deny(missing_docs)]
38#![deny(clippy::all)]
39
40extern crate alloc;
41
42pub mod arithmetic;
43pub mod compare;
44pub mod convert;
45pub mod decimal;
46pub mod display;
47pub mod error;
48pub mod rounding;
49
50pub use decimal::{Decimal, MAX_SCALE, SOL_SCALE, USDC_SCALE};
51pub use error::ArithmeticError;
52pub use rounding::RoundingMode;
53
54#[cfg(test)]
55mod tests_arithmetic;
56#[cfg(test)]
57mod tests_rounding;