@@ -353,6 +353,19 @@ where
353353 }
354354}
355355
356+ pub fn checked_as_f64 < T > ( arg : T ) -> Result < f64 >
357+ where
358+ T : Display + num_traits:: ToPrimitive + Clone ,
359+ {
360+ let option: Option < f64 > = num_traits:: NumCast :: from ( arg. clone ( ) ) ;
361+ if let Some ( res) = option {
362+ Ok ( res)
363+ } else {
364+ msg ! ( "Error: Overflow in {} as f64" , arg) ;
365+ err ! ( PerpetualsError :: MathOverflow )
366+ }
367+ }
368+
356369pub fn scale_to_exponent ( arg : u64 , exponent : i32 , target_exponent : i32 ) -> Result < u64 > {
357370 if target_exponent == exponent {
358371 return Ok ( arg) ;
@@ -366,7 +379,10 @@ pub fn scale_to_exponent(arg: u64, exponent: i32, target_exponent: i32) -> Resul
366379}
367380
368381pub fn to_ui_amount ( amount : u64 , decimals : u8 ) -> Result < f64 > {
369- checked_float_div ( amount as f64 , checked_powi ( 10.0 , decimals as i32 ) ?)
382+ checked_float_div (
383+ checked_as_f64 ( amount) ?,
384+ checked_powi ( 10.0 , decimals as i32 ) ?,
385+ )
370386}
371387
372388pub fn to_token_amount ( ui_amount : f64 , decimals : u8 ) -> Result < u64 > {
@@ -375,3 +391,69 @@ pub fn to_token_amount(ui_amount: f64, decimals: u8) -> Result<u64> {
375391 checked_powi ( 10.0 , decimals as i32 ) ?,
376392 ) ?)
377393}
394+
395+ #[ cfg( test) ]
396+ mod tests {
397+ use super :: * ;
398+
399+ #[ test]
400+ fn test_checked_decimal_div_ok ( ) {
401+ // Nominal test
402+ assert_eq ! (
403+ 2_000_000 ,
404+ checked_decimal_div( 1_000 , -6 , 500 , -6 , -6 ) . unwrap( )
405+ ) ;
406+
407+ // Different exponents
408+ assert_eq ! (
409+ 2_000_000_000 ,
410+ checked_decimal_div( 1_000 , -6 , 500 , -9 , -6 ) . unwrap( )
411+ ) ;
412+
413+ // Different exponents
414+ assert_eq ! ( 2_000 , checked_decimal_div( 1_000 , -9 , 500 , -6 , -6 ) . unwrap( ) ) ;
415+
416+ // MAX coefficient values
417+ assert_eq ! (
418+ 1_000_000 ,
419+ checked_decimal_div( u64 :: MAX , -6 , u64 :: MAX , -6 , -6 ) . unwrap( )
420+ ) ;
421+
422+ assert_eq ! ( 0 , checked_decimal_div( 0 , -6 , u64 :: MAX , -6 , -6 ) . unwrap( ) ) ;
423+
424+ // Maximum coefficients delta depends on target exponent
425+ assert_eq ! (
426+ 18_446_744_073_709_000_000 ,
427+ checked_decimal_div(
428+ checked_div( u64 :: MAX , checked_pow( 10u64 , 6 ) . unwrap( ) ) . unwrap( ) ,
429+ -6 ,
430+ 1 ,
431+ -6 ,
432+ -6 ,
433+ )
434+ . unwrap( )
435+ ) ;
436+
437+ // Maximum coefficients delta depends on target exponent
438+ assert_eq ! (
439+ 18_446_744_073_000_000_000 ,
440+ checked_decimal_div(
441+ checked_div( u64 :: MAX , checked_pow( 10u64 , 9 ) . unwrap( ) ) . unwrap( ) ,
442+ -6 ,
443+ 1 ,
444+ -6 ,
445+ -9 ,
446+ )
447+ . unwrap( )
448+ ) ;
449+ }
450+
451+ #[ test]
452+ fn test_checked_decimal_div_ko ( ) {
453+ // Division by zero
454+ assert ! ( checked_decimal_div( 1_000_000 , -6 , 0 , -6 , -6 ) . is_err( ) ) ;
455+
456+ // Overflowing result
457+ assert ! ( checked_decimal_div( u64 :: MAX , -6 , 1 , -6 , -6 ) . is_err( ) ) ;
458+ }
459+ }
0 commit comments