Crate ra_solana_math

Crate ra_solana_math 

Source
Expand description

ยง๐Ÿงฎ Solana Fixed-Point Math Library

Crates.io Documentation License CircleCI Build & Test Status

A high-performance, fixed-point arithmetic library optimized for Solana smart contracts. Provides safe, deterministic mathematical operations with 18 decimal places of precision, designed to minimize compute units while maximizing accuracy.

ยงโœจ Features

  • ๐ŸŽฏ High Precision: 18 decimal places (1e18 scale factor) for accurate financial calculations
  • โšก Optimized for Solana: Minimal compute units, no dynamic loops, small stack footprint
  • ๐Ÿ›ก๏ธ Safe by Design: Comprehensive overflow/underflow protection with Anchor error handling
  • ๐Ÿ”ข Large Number Support: U256 backing for handling massive values safely
  • ๐Ÿ“ Advanced Math: Power functions (including fractional exponents), logarithms, square roots, and exponentials
  • ๐Ÿ’ฏ Well-Tested: 60+ comprehensive unit tests with 100% code coverage
  • ๐Ÿ“š Fully Documented: Complete API documentation with examples

ยง๐Ÿ“ฆ Installation

Add to your Cargo.toml:

[dependencies]
ra-solana-math = "0.1.0"
anchor-lang = "0.29"

Or using cargo:

cargo add ra-solana-math

ยง๐Ÿš€ Quick Start

use ra_solana_math::FixedPoint;

// Create fixed-point numbers
let price = FixedPoint::from_int(100);           // 100
let fee = FixedPoint::from_percent(5)?;          // 5% = 0.05
let multiplier = FixedPoint::from_ratio(3, 2)?;  // 3/2 = 1.5

// Perform calculations
let fee_amount = price.mul(&fee)?;               // 100 * 0.05 = 5.0
let adjusted = price.mul(&multiplier)?;          // 100 * 1.5 = 150.0

// Advanced operations
let sqrt_price = price.sqrt()?;                  // โˆš100 = 10.0
let compound = price.pow(&multiplier)?;          // 100^1.5 โ‰ˆ 1000.0
let log_price = price.ln()?;                     // ln(100) โ‰ˆ 4.605

ยง๐Ÿ“– Usage Examples

ยงBasic Arithmetic

use ra_solana_math::FixedPoint;

let a = FixedPoint::from_int(10);
let b = FixedPoint::from_int(3);

// Addition and subtraction
let sum = a.add(&b)?;        // 13.0
let diff = a.sub(&b)?;       // 7.0

// Multiplication and division
let product = a.mul(&b)?;    // 30.0
let quotient = a.div(&b)?;   // 3.333...

// Convert back to integers
assert_eq!(sum.to_u64()?, 13);

ยงFinancial Calculations

// Calculate compound interest: A = P(1 + r)^n
let principal = FixedPoint::from_int(1000);           // $1000
let rate = FixedPoint::from_percent(5)?;              // 5% annual
let years = FixedPoint::from_int(10);                 // 10 years
let one = FixedPoint::from_int(1);

let growth_factor = one.add(&rate)?.pow(&years)?;     // (1.05)^10
let final_amount = principal.mul(&growth_factor)?;    // โ‰ˆ $1628.89

println!("Final amount: ${:.2}", final_amount.to_f64()?);

ยงDeFi Price Calculations

// Constant product AMM (x * y = k)
let reserve_x = FixedPoint::from_int(1_000_000);      // 1M tokens
let reserve_y = FixedPoint::from_int(500_000);        // 500K tokens

let k = reserve_x.mul(&reserve_y)?;                   // Constant product

// Calculate price impact for a swap
let amount_in = FixedPoint::from_int(10_000);         // 10K tokens in
let new_x = reserve_x.add(&amount_in)?;
let new_y = k.div(&new_x)?;
let amount_out = reserve_y.sub(&new_y)?;

println!("Amount out: {}", amount_out.to_u64()?);

ยงPercentage and Basis Points

// Working with percentages
let total = FixedPoint::from_int(10_000);
let fee_rate = FixedPoint::from_bps(250)?;            // 250 bps = 2.5%
let fee = total.mul(&fee_rate)?;                      // $250

// Discounts
let discount = FixedPoint::from_percent(15)?;         // 15% off
let discount_amount = total.mul(&discount)?;          // $1,500
let final_price = total.sub(&discount_amount)?;      // $8,500

ยงAdvanced Math Operations

// Power functions
let base = FixedPoint::from_int(2);
let exp = FixedPoint::from_int(10);
let result = base.pow(&exp)?;                         // 2^10 = 1024

// Fractional exponents (roots)
let number = FixedPoint::from_int(27);
let cube_root_exp = FixedPoint::from_ratio(1, 3)?;
let cube_root = number.pow(&cube_root_exp)?;         // 27^(1/3) โ‰ˆ 3

// Logarithms
let value = FixedPoint::from_int(100);
let ln_value = value.ln()?;                          // ln(100) โ‰ˆ 4.605
let log10_value = value.log10()?;                    // logโ‚โ‚€(100) = 2
let log2_value = value.log2()?;                      // logโ‚‚(100) โ‰ˆ 6.644

// Square root
let number = FixedPoint::from_int(144);
let sqrt = number.sqrt()?;                           // โˆš144 = 12

ยงUtility Functions

let value = FixedPoint::from_fraction(5, 7, 10)?;    // 5.7

// Floor and ceiling
let floor = value.floor();                           // 5.0
let ceil = value.ceil()?;                            // 6.0

// Get fractional part
let frac = value.frac()?;                            // 0.7

// Min and max
let a = FixedPoint::from_int(5);
let b = FixedPoint::from_int(3);
let min = a.min(&b);                                 // 3.0
let max = a.max(&b);                                 // 5.0

ยง๐Ÿ—๏ธ Solana Program Integration

ยงIn Your Anchor Program

use anchor_lang::prelude::*;
use ra_solana_math::FixedPoint;

#[program]
pub mod my_defi_protocol {
    use super::*;

    pub fn calculate_swap(
        ctx: Context<Swap>,
        amount_in: u64,
    ) -> Result<()> {
        let pool = &mut ctx.accounts.pool;
        
        // Convert to fixed-point
        let amount_in_fp = FixedPoint::from_int(amount_in);
        let reserve_in_fp = FixedPoint::from_int(pool.reserve_in);
        let reserve_out_fp = FixedPoint::from_int(pool.reserve_out);
        
        // Calculate constant product
        let k = reserve_in_fp.mul(&reserve_out_fp)?;
        
        // Calculate output amount with 0.3% fee
        let fee = FixedPoint::from_bps(30)?;  // 30 bps = 0.3%
        let one = FixedPoint::from_int(1);
        let amount_in_after_fee = amount_in_fp.mul(&one.sub(&fee)?)?;
        
        let new_reserve_in = reserve_in_fp.add(&amount_in_after_fee)?;
        let new_reserve_out = k.div(&new_reserve_in)?;
        let amount_out = reserve_out_fp.sub(&new_reserve_out)?;
        
        pool.reserve_in = new_reserve_in.to_u64()?;
        pool.reserve_out = new_reserve_out.to_u64()?;
        
        msg!("Swap: {} in, {} out", amount_in, amount_out.to_u64()?);
        
        Ok(())
    }
}

#[account]
pub struct Pool {
    pub reserve_in: u64,
    pub reserve_out: u64,
}

#[derive(Accounts)]
pub struct Swap<'info> {
    #[account(mut)]
    pub pool: Account<'info, Pool>,
}

ยงPrecision

  • Scale Factor: 10^18 (18 decimal places)
  • Basic Operations: Exact (no rounding errors)
  • Square Root: โ‰ˆ 0.01% error (Newtonโ€™s method, 4 iterations)
  • Logarithms: โ‰ˆ 0.1% error (Taylor series, 5 terms)
  • Exponentials: โ‰ˆ 1% error (range reduction + Taylor series)
  • Powers: โ‰ˆ 1-5% error (depends on base and exponent)

ยง๐Ÿงช Testing

Run the comprehensive test suite:

# Run all tests
cargo test

# Run tests with output
cargo test -- --nocapture

# Run specific test
cargo test test_compound_interest

# Run with coverage
cargo tarpaulin --out Html

The library includes 60+ tests covering:

  • โœ… All constructor and conversion methods
  • โœ… Arithmetic operations and identities
  • โœ… Advanced mathematical functions
  • โœ… Edge cases and error handling
  • โœ… Complex real-world scenarios
  • โœ… Mathematical properties (commutativity, associativity, etc.)

ยง๐Ÿ“ API Reference

ยงConstructors

MethodDescriptionExample
from_int(n)Create from integerFixedPoint::from_int(100)
from_u128(n)Create from u128FixedPoint::from_u128(1_000_000)
from_f64(n)Create from float (testing)FixedPoint::from_f64(3.14)?
from_fraction(w, n, d)w + n/dFixedPoint::from_fraction(5, 1, 2)? โ†’ 5.5
from_ratio(n, d)n/dFixedPoint::from_ratio(3, 4)? โ†’ 0.75
from_percent(p)PercentageFixedPoint::from_percent(25)? โ†’ 0.25
from_bps(b)Basis pointsFixedPoint::from_bps(250)? โ†’ 0.025
from_scaled(u256)From raw scaled valueFixedPoint::from_scaled(value)

ยงConversions

MethodDescription
to_u64()Convert to u64 (truncates decimals)
to_u128()Convert to u128 (truncates decimals)
to_f64()Convert to f64 (for testing/display)

ยงArithmetic Operations

MethodDescriptionErrors
add(&self, other)AdditionOverflow
sub(&self, other)SubtractionUnderflow
mul(&self, other)MultiplicationOverflow
div(&self, other)DivisionDivisionByZero, Overflow

ยงAdvanced Math

MethodDescriptionPrecision
pow(&self, exp)Power (x^y)~1-5%
sqrt(&self)Square root~0.01%
ln(&self)Natural logarithm~0.1%
log10(&self)Base-10 logarithm~0.1%
log2(&self)Base-2 logarithm~0.1%
log(&self, base)Custom base logarithm~0.1%
exp(&self)Exponential (e^x)~1%

ยงUtility Functions

MethodDescription
floor()Round down to integer
ceil()Round up to integer
frac()Get fractional part
abs()Absolute value
min(&self, other)Minimum of two values
max(&self, other)Maximum of two values
is_zero()Check if zero

ยงโš ๏ธ Important Notes

ยงError Handling

All fallible operations return Result<FixedPoint, MathError>:

pub enum MathError {
    Overflow,        // Result exceeds U256::MAX
    Underflow,       // Result is negative (unsigned type)
    DivisionByZero,  // Division by zero
    InvalidInput,    // Invalid input (e.g., ln(0))
}

Always handle errors in your Solana programs:

let result = a.div(&b).map_err(|_| ErrorCode::MathError)?;

ยงPrecision Considerations

  1. Basic operations (add, sub, mul, div) are exact
  2. Square root uses Newtonโ€™s method (4 iterations)
  3. Logarithms and exponentials use Taylor series approximations
  4. Powers use logarithm-based computation for fractional exponents

For critical financial calculations, test edge cases thoroughly.

ยงCompute Unit Optimization

To minimize CU usage:

  • Use integer operations when possible (from_int, to_u64)
  • Prefer sqrt() over pow(x, 0.5) for square roots
  • Cache repeated calculations
  • Use pow2_fast() for powers of 2

ยง๐Ÿค Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for new functionality
  4. Ensure all tests pass (cargo test)
  5. Format code (cargo fmt)
  6. Lint code (cargo clippy)
  7. Commit changes (git commit -m 'Add amazing feature')
  8. Push to branch (git push origin feature/amazing-feature)
  9. Open a Pull Request

ยงDevelopment Setup

# Clone the repository
git clone https://github.com/ra-sun-god/ra-solana-math.git
cd ra-solana-math

# Install dependencies
cargo build

# Run tests
cargo test

# Run clippy
cargo clippy -- -D warnings

# Format code
cargo fmt

ยง๐Ÿ› Known Limitations

  1. Unsigned Only: Only handles non-negative numbers (use separate sign tracking if needed)
  2. Approximation Errors: Complex operations (ln, exp, pow) have ~0.1-5% error
  3. Range Limits: Maximum value is U256::MAX / 10^18 โ‰ˆ 1.15 ร— 10^59
  4. Compute Units: Advanced operations consume more CU than basic arithmetic

ยง๐Ÿ“„ License

This project is licensed under either of:

  • MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

ยง๐Ÿ™ Acknowledgments

ยง๐Ÿ“ž Support

Made with โค๏ธ for the Solana ecosystem

If this library helps your project, consider giving it a โญ on GitHub!

ยงSolana Fixed-Point Math Library

A high-performance fixed-point arithmetic library optimized for Solana programs. Uses 18 decimal places of precision (1e18 scale factor) with U256 for large number support.

ยงFeatures

  • Fixed-point arithmetic: Add, subtract, multiply, divide with overflow protection
  • Advanced math: Power (including fractional exponents), logarithms, square root, exponentials
  • Optimized for Solana: Minimal compute units, no dynamic loops, small stack footprint
  • Large number support: U256 backing for handling massive values safely
  • Type-safe: Comprehensive error handling with Anchor integration

ยงExamples

โ“˜
use fixed_point_math::FixedPoint;

// Create a fixed-point number from an integer
let x = FixedPoint::from_int(5);
let y = FixedPoint::from_int(2);

// Perform arithmetic operations
let sum = x.add(&y)?;       // 7.0
let product = x.mul(&y)?;    // 10.0
let quotient = x.div(&y)?;   // 2.5

// Advanced operations
let power = x.pow(&y)?;      // 5^2 = 25.0
let sqrt = x.sqrt()?;        // โˆš5 โ‰ˆ 2.236
let log = x.ln()?;           // ln(5) โ‰ˆ 1.609

Structsยง

FixedPoint
A fixed-point number with 18 decimal places of precision.
U256
Little-endian large integer type

Enumsยง

MathError
Error types for fixed-point math operations.

Constantsยง

SCALE
Fixed-point math library optimized for Solana compute units.