Skip to main content

precolator/
utils.rs

1// Utility functions and helpers
2
3use crate::errors::{ProgramError, Result};
4use solana_program::pubkey::Pubkey;
5
6/// Calculate percentage with basis points
7pub fn calculate_bps_amount(amount: u64, bps: u16) -> Result<u64> {
8    let result = (amount as u128 * bps as u128) / 10_000;
9    Ok(result as u64)
10}
11
12/// Check if account is valid
13pub fn validate_account(account: &Pubkey) -> Result<()> {
14    if account == &Pubkey::default() {
15        return Err(ProgramError::Unauthorized);
16    }
17    Ok(())
18}
19
20/// Safe multiplication
21pub fn safe_mul(a: u64, b: u64) -> Result<u64> {
22    a.checked_mul(b).ok_or(ProgramError::Overflow)
23}
24
25/// Safe division
26pub fn safe_div(a: u64, b: u64) -> Result<u64> {
27    if b == 0 {
28        return Err(ProgramError::InvalidAmount);
29    }
30    Ok(a / b)
31}
32
33/// Safe subtraction
34pub fn safe_sub(a: u64, b: u64) -> Result<u64> {
35    a.checked_sub(b).ok_or(ProgramError::Overflow)
36}
37
38/// Safe addition
39pub fn safe_add(a: u64, b: u64) -> Result<u64> {
40    a.checked_add(b).ok_or(ProgramError::Overflow)
41}
42
43/// Format lamports to SOL string
44pub fn format_lamports_to_sol(lamports: u64) -> String {
45    let sol = lamports as f64 / 1_000_000_000.0;
46    format!("{:.9}", sol)
47}
48
49/// Parse SOL string to lamports
50pub fn parse_sol_to_lamports(sol_str: &str) -> Result<u64> {
51    let sol: f64 = sol_str.parse().map_err(|_| ProgramError::InvalidAmount)?;
52    Ok((sol * 1_000_000_000.0) as u64)
53}
54
55/// Calculate percentage change
56pub fn calculate_percentage_change(from: u64, to: u64) -> Result<i32> {
57    if from == 0 {
58        return Ok(0);
59    }
60
61    if to >= from {
62        let change = ((to - from) as i128 * 10_000) / from as i128;
63        Ok(change as i32)
64    } else {
65        let change = -((from - to) as i128 * 10_000) as i32 / from as i32;
66        Ok(change)
67    }
68}
69
70/// Round up to next power of 2
71pub fn next_power_of_2(mut n: u64) -> u64 {
72    if n == 0 {
73        return 1;
74    }
75    n -= 1;
76    n |= n >> 1;
77    n |= n >> 2;
78    n |= n >> 4;
79    n |= n >> 8;
80    n |= n >> 16;
81    n |= n >> 32;
82    n + 1
83}
84
85/// Clamp value between min and max
86pub fn clamp<T: PartialOrd>(value: T, min: T, max: T) -> T {
87    if value < min {
88        min
89    } else if value > max {
90        max
91    } else {
92        value
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_calculate_bps_amount() {
102        let result = calculate_bps_amount(1_000_000, 500);
103        assert!(result.is_ok());
104        assert_eq!(result.unwrap(), 50_000);
105    }
106
107    #[test]
108    fn test_safe_mul() {
109        let result = safe_mul(1000, 2000);
110        assert!(result.is_ok());
111        assert_eq!(result.unwrap(), 2_000_000);
112    }
113
114    #[test]
115    fn test_percentage_change() {
116        let result = calculate_percentage_change(100, 110);
117        assert!(result.is_ok());
118        assert_eq!(result.unwrap(), 1000); // 10%
119    }
120}