soroban_fixed_point_math/
u256.rs1use soroban_sdk::{Env, U256};
2
3use crate::soroban_fixed_point::SorobanFixedPoint;
4
5impl SorobanFixedPoint for U256 {
6    fn fixed_mul_floor(&self, _env: &Env, y: &U256, denominator: &U256) -> U256 {
7        mul_div_floor(self, y, denominator)
8    }
9
10    fn fixed_mul_ceil(&self, env: &Env, y: &U256, denominator: &U256) -> U256 {
11        mul_div_ceil(env, self, y, denominator)
12    }
13
14    fn fixed_div_floor(&self, _env: &Env, y: &U256, denominator: &U256) -> U256 {
15        mul_div_floor(self, denominator, y)
16    }
17
18    fn fixed_div_ceil(&self, env: &Env, y: &U256, denominator: &U256) -> U256 {
19        mul_div_ceil(env, self, denominator, y)
20    }
21}
22
23pub(crate) fn mul_div_floor(x: &U256, y: &U256, z: &U256) -> U256 {
25    x.mul(&y).div(&z)
27}
28
29pub(crate) fn mul_div_ceil(env: &Env, x: &U256, y: &U256, z: &U256) -> U256 {
31    let r = x.mul(&y);
32    let remainder = r.rem_euclid(&z);
33    let zero = U256::from_u32(env, 0);
34    let one = U256::from_u32(env, 1);
35    r.div(&z).add(if remainder > zero { &one } else { &zero })
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
45    fn test_fixed_mul_floor_rounds_down() {
46        let env = Env::default();
47        let x: U256 = U256::from_u128(&env, 1_5391283);
48        let y: U256 = U256::from_u128(&env, 314_1592653);
49        let denominator: U256 = U256::from_u128(&env, 1_0000001);
50
51        let result = x.fixed_mul_floor(&env, &y, &denominator);
52
53        assert_eq!(result, U256::from_u128(&env, 483_5313675));
54    }
55
56    #[test]
57    fn test_fixed_mul_floor_large_number() {
58        let env = Env::default();
59        let x: U256 = U256::from_u128(&env, u128::MAX);
60        let y: U256 = U256::from_u128(&env, 10u128.pow(38));
61        let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
62
63        let result = x.clone().fixed_mul_floor(&env, &y, &denominator);
64
65        let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(20)));
66        assert_eq!(result, expected_result);
67    }
68
69    #[test]
70    #[should_panic(expected = "attempt to multiply with overflow")]
71    fn test_fixed_mul_floor_phantom_overflow() {
72        let env = Env::default();
73        let x: U256 = U256::from_u128(&env, u128::MAX);
74        let y: U256 = U256::from_u128(&env, 10u128.pow(39));
76        let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
77
78        x.fixed_mul_floor(&env, &y, &denominator);
79    }
80
81    #[test]
84    fn test_fixed_mul_ceil_rounds_up() {
85        let env = Env::default();
86        let x: U256 = U256::from_u128(&env, 1_5391283);
87        let y: U256 = U256::from_u128(&env, 314_1592653);
88        let denominator: U256 = U256::from_u128(&env, 1_0000001);
89
90        let result = x.fixed_mul_ceil(&env, &y, &denominator);
91
92        assert_eq!(result, U256::from_u128(&env, 483_5313676));
93    }
94
95    #[test]
96    fn test_fixed_mul_ceil_large_number() {
97        let env = Env::default();
98        let x: U256 = U256::from_u128(&env, u128::MAX);
99        let y: U256 = U256::from_u128(&env, 10u128.pow(38));
100        let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
101
102        let result = x.clone().fixed_mul_ceil(&env, &y, &denominator);
103
104        let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(20)));
105        assert_eq!(result, expected_result);
106    }
107
108    #[test]
109    #[should_panic(expected = "attempt to multiply with overflow")]
110    fn test_fixed_mul_ceil_phantom_overflow() {
111        let env = Env::default();
112        let x: U256 = U256::from_u128(&env, u128::MAX);
113        let y: U256 = U256::from_u128(&env, 10u128.pow(39));
115        let denominator: U256 = U256::from_u128(&env, 10u128.pow(18));
116
117        x.fixed_mul_ceil(&env, &y, &denominator);
118    }
119
120    #[test]
123    fn test_fixed_div_floor_rounds_down() {
124        let env = Env::default();
125        let x: U256 = U256::from_u128(&env, 314_1592653);
126        let y: U256 = U256::from_u128(&env, 1_5391280);
127        let denominator: U256 = U256::from_u128(&env, 1_0000000);
128
129        let result = x.fixed_div_floor(&env, &y, &denominator);
130
131        assert_eq!(result, U256::from_u128(&env, 204_1150997));
132    }
133
134    #[test]
135    fn test_fixed_div_floor_large_number() {
136        let env = Env::default();
137        let x: U256 = U256::from_u128(&env, u128::MAX);
138        let y: U256 = U256::from_u128(&env, 10u128.pow(27));
139        let denominator: U256 = U256::from_u128(&env, 10u128.pow(38));
140
141        let result = x.clone().fixed_div_floor(&env, &y, &denominator);
142
143        let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(11)));
144        assert_eq!(result, expected_result);
145    }
146
147    #[test]
148    #[should_panic(expected = "attempt to multiply with overflow")]
149    fn test_fixed_div_floor_phantom_overflow() {
150        let env = Env::default();
151        let x: U256 = U256::from_u128(&env, u128::MAX);
152        let y: U256 = U256::from_u128(&env, 10u128.pow(27));
153        let denominator: U256 = U256::from_u128(&env, 10u128.pow(39));
155
156        x.fixed_div_floor(&env, &y, &denominator);
157    }
158
159    #[test]
162    fn test_fixed_div_ceil_rounds_down() {
163        let env = Env::default();
164        let x: U256 = U256::from_u128(&env, 314_1592653);
165        let y: U256 = U256::from_u128(&env, 1_5391280);
166        let denominator: U256 = U256::from_u128(&env, 1_0000000);
167
168        let result = x.fixed_div_ceil(&env, &y, &denominator);
169
170        assert_eq!(result, U256::from_u128(&env, 204_1150998));
171    }
172
173    #[test]
174    fn test_fixed_div_ceil_large_number() {
175        let env = Env::default();
176        let x: U256 = U256::from_u128(&env, u128::MAX);
177        let y: U256 = U256::from_u128(&env, 10u128.pow(27));
178        let denominator: U256 = U256::from_u128(&env, 10u128.pow(38));
179
180        let result = x.clone().fixed_div_ceil(&env, &y, &denominator);
181
182        let expected_result = x.mul(&U256::from_u128(&env, 10u128.pow(11)));
183        assert_eq!(result, expected_result);
184    }
185
186    #[test]
187    #[should_panic(expected = "attempt to multiply with overflow")]
188    fn test_fixed_div_ceil_phantom_overflow() {
189        let env = Env::default();
190        let x: U256 = U256::from_u128(&env, u128::MAX);
191        let y: U256 = U256::from_u128(&env, 10u128.pow(27));
192        let denominator: U256 = U256::from_u128(&env, 10u128.pow(39));
194
195        x.fixed_div_ceil(&env, &y, &denominator);
196    }
197}