Skip to content

Commit 1223805

Browse files
authored
sol_to_lamports(): convert negative and NaN to 0, clip positive value… (#149)
* sol_to_lamports(): convert negative and NaN to 0, clip positive values to u64::MAX, round float lamports to int rather than truncate. add test cases. * Suppress clippy warnings about excessive precision in floating point constants. Rely on Rust type cast logic for float to unsigned int conversion which saturates and handles NaNs as desired; unit tests will fail if the language changes in future. https://doc.rust-lang.org/reference/expressions/operator-expr.html#r-expr.as.numeric.float-as-int
1 parent ac11e3e commit 1223805

File tree

1 file changed

+78
-2
lines changed

1 file changed

+78
-2
lines changed

native-token/src/lib.rs

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44

55
/// There are 10^9 lamports in one SOL
66
pub const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
7+
const LAMPORTS_PER_SOL_F64: f64 = LAMPORTS_PER_SOL as f64;
78

89
/// Approximately convert fractional native tokens (lamports) into native tokens (SOL)
910
pub fn lamports_to_sol(lamports: u64) -> f64 {
10-
lamports as f64 / LAMPORTS_PER_SOL as f64
11+
lamports as f64 / LAMPORTS_PER_SOL_F64
1112
}
1213

1314
/// Approximately convert native tokens (SOL) into fractional native tokens (lamports)
1415
pub fn sol_to_lamports(sol: f64) -> u64 {
15-
(sol * LAMPORTS_PER_SOL as f64) as u64
16+
// NaNs return zero, negative values saturate to u64::MIN (i.e. zero), positive values saturate to u64::MAX
17+
// https://doc.rust-lang.org/reference/expressions/operator-expr.html#r-expr.as.numeric.float-as-int
18+
(sol * LAMPORTS_PER_SOL_F64).round() as u64
1619
}
1720

1821
use std::fmt::{Debug, Display, Formatter, Result};
@@ -40,3 +43,76 @@ impl Debug for Sol {
4043
self.write_in_sol(f)
4144
}
4245
}
46+
47+
#[cfg(test)]
48+
mod tests {
49+
use super::*;
50+
51+
#[test]
52+
#[allow(clippy::excessive_precision)]
53+
fn test_lamports_to_sol() {
54+
assert_eq!(0.0, lamports_to_sol(0));
55+
assert_eq!(0.000000001, lamports_to_sol(1));
56+
assert_eq!(0.00000001, lamports_to_sol(10));
57+
assert_eq!(0.0000001, lamports_to_sol(100));
58+
assert_eq!(0.000001, lamports_to_sol(1000));
59+
assert_eq!(0.00001, lamports_to_sol(10000));
60+
assert_eq!(0.0001, lamports_to_sol(100000));
61+
assert_eq!(0.001, lamports_to_sol(1000000));
62+
assert_eq!(0.01, lamports_to_sol(10000000));
63+
assert_eq!(0.1, lamports_to_sol(100000000));
64+
assert_eq!(1., lamports_to_sol(1000000000));
65+
assert_eq!(4.1, lamports_to_sol(4_100_000_000));
66+
assert_eq!(8.2, lamports_to_sol(8_200_000_000));
67+
assert_eq!(8.50228288, lamports_to_sol(8_502_282_880));
68+
assert_eq!(18446744073.70955276489257812500, lamports_to_sol(u64::MAX));
69+
assert_eq!(
70+
18446744073.70955276489257812500,
71+
lamports_to_sol(u64::MAX - 1023)
72+
);
73+
assert_eq!(
74+
18446744073.70954895019531250000,
75+
lamports_to_sol(u64::MAX - 1024)
76+
);
77+
assert_eq!(
78+
18446744073.70954895019531250000,
79+
lamports_to_sol(u64::MAX - 5119)
80+
);
81+
assert_eq!(
82+
18446744073.70954513549804687500,
83+
lamports_to_sol(u64::MAX - 5120)
84+
);
85+
}
86+
87+
#[test]
88+
#[allow(clippy::excessive_precision)]
89+
fn test_sol_to_lamports() {
90+
assert_eq!(0, sol_to_lamports(0.0));
91+
assert_eq!(1, sol_to_lamports(0.000000001));
92+
assert_eq!(10, sol_to_lamports(0.00000001));
93+
assert_eq!(100, sol_to_lamports(0.0000001));
94+
assert_eq!(1000, sol_to_lamports(0.000001));
95+
assert_eq!(10000, sol_to_lamports(0.00001));
96+
assert_eq!(100000, sol_to_lamports(0.0001));
97+
assert_eq!(1000000, sol_to_lamports(0.001));
98+
assert_eq!(10000000, sol_to_lamports(0.01));
99+
assert_eq!(100000000, sol_to_lamports(0.1));
100+
assert_eq!(1000000000, sol_to_lamports(1.));
101+
assert_eq!(4_100_000_000, sol_to_lamports(4.1));
102+
assert_eq!(8_200_000_000, sol_to_lamports(8.2));
103+
assert_eq!(8_502_282_880, sol_to_lamports(8.50228288));
104+
assert_eq!(0, sol_to_lamports(-1.0));
105+
assert_eq!(0, sol_to_lamports(f64::NEG_INFINITY));
106+
assert_eq!(0, sol_to_lamports(f64::NAN));
107+
assert_eq!(u64::MAX, sol_to_lamports(f64::INFINITY));
108+
assert_eq!(u64::MAX, sol_to_lamports(18446744073.70955276489257812500));
109+
assert_eq!(
110+
u64::MAX - 2047,
111+
sol_to_lamports(18446744073.70954895019531250000)
112+
);
113+
assert_eq!(
114+
u64::MAX - 6143,
115+
sol_to_lamports(18446744073.70954513549804687500)
116+
);
117+
}
118+
}

0 commit comments

Comments
 (0)