From 851daf9ebce438627bfd71ca566e919957414b11 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 13 Sep 2023 16:19:47 -0400 Subject: [PATCH 1/6] add round to FPDecimal, fix a bug in must_from_str --- .../injective-math/src/fp_decimal/from_str.rs | 7 +- .../injective-math/src/fp_decimal/round.rs | 3 + packages/injective-math/src/utils.rs | 96 +++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 packages/injective-math/src/fp_decimal/round.rs diff --git a/packages/injective-math/src/fp_decimal/from_str.rs b/packages/injective-math/src/fp_decimal/from_str.rs index 85636d72..29c25525 100644 --- a/packages/injective-math/src/fp_decimal/from_str.rs +++ b/packages/injective-math/src/fp_decimal/from_str.rs @@ -45,7 +45,12 @@ impl FromStr for FPDecimal { impl FPDecimal { pub fn must_from_str(input: &str) -> Self { - Self::from_str(input).unwrap() + let i = Self::from_str(input).unwrap(); + // to handle must_from_str("-0") + if i.num == U256([0, 0, 0, 0]) { + return FPDecimal::ZERO; + } + i } } diff --git a/packages/injective-math/src/fp_decimal/round.rs b/packages/injective-math/src/fp_decimal/round.rs new file mode 100644 index 00000000..8c20393a --- /dev/null +++ b/packages/injective-math/src/fp_decimal/round.rs @@ -0,0 +1,3 @@ +use crate::fp_decimal::{FPDecimal, U256}; +use std::iter; +use std::ops; diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index 28f49fac..61f321e3 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -75,6 +75,32 @@ pub fn div_dec(num: FPDecimal, denom: FPDecimal) -> FPDecimal { } } +pub fn floor(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { + // min_tick has to be a positive number + //FIXME min_tick has to be 1, 0.1,0.01, etc + assert!(min_tick >= FPDecimal::ZERO); + if num.is_zero() { + return num; + } + let remainder = num % min_tick; + num - remainder +} + +pub fn round(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { + //FIXME min_tick has to be 1, 0.1,0.01, etc + let num_floor = floor(num, min_tick); + let diff = num - num_floor; + if diff < (min_tick / FPDecimal::TWO) { + return num_floor; + } else if diff > (min_tick / FPDecimal::TWO) { + return num_floor + min_tick; + } + if num_floor / (min_tick * FPDecimal::TWO) == FPDecimal::ZERO { + return num_floor; + } + return num_floor + min_tick; +} + pub fn round_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { if num < min_tick { FPDecimal::zero() @@ -115,6 +141,76 @@ pub fn round_up_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { mod tests { use super::*; + #[test] + fn test_floor() { + assert_eq!(floor(FPDecimal::must_from_str("0"), FPDecimal::must_from_str("0.1")), FPDecimal::ZERO); + assert_eq!( + floor(FPDecimal::must_from_str("0.13"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("0.1") + ); + assert_eq!( + floor(FPDecimal::must_from_str("0.19"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("0.1") + ); + assert_eq!( + floor(FPDecimal::must_from_str("1.19"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("1.1") + ); + assert_eq!(floor(FPDecimal::must_from_str("2.19"), FPDecimal::ONE), FPDecimal::TWO); + + assert_eq!(floor(FPDecimal::must_from_str("-0"), FPDecimal::must_from_str("0.1")), FPDecimal::ZERO); + assert_eq!( + floor(FPDecimal::must_from_str("-0.13"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("-0.2") + ); + assert_eq!( + floor(FPDecimal::must_from_str("-0.19"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("-0.2") + ); + assert_eq!( + floor(FPDecimal::must_from_str("-1.19"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("-1.2") + ); + assert_eq!( + floor(FPDecimal::must_from_str("-2.19"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("-2.2") + ); + + assert_eq!(floor(FPDecimal::must_from_str("-2.19"), FPDecimal::ONE), FPDecimal::must_from_str("-3")); + } + + #[test] + fn test_round() { + assert_eq!(round(FPDecimal::must_from_str("0"), FPDecimal::must_from_str("0.1")), FPDecimal::ZERO); + assert_eq!( + round(FPDecimal::must_from_str("0.13"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("0.1") + ); + assert_eq!(round(FPDecimal::must_from_str("0.13"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("0.49"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("0.5"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("0.50009"), FPDecimal::ONE), FPDecimal::ONE); + assert_eq!( + round(FPDecimal::must_from_str("0.50009"), FPDecimal::must_from_str("0.0001")), + FPDecimal::must_from_str("0.5001") + ); + + assert_eq!(round(FPDecimal::must_from_str("-0"), FPDecimal::must_from_str("0.1")), FPDecimal::ZERO); + assert_eq!( + round(FPDecimal::must_from_str("-0.13"), FPDecimal::must_from_str("0.1")), + FPDecimal::must_from_str("-0.1") + ); + assert_eq!(round(FPDecimal::must_from_str("-0.13"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("-0.49"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("-0.5"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("-0.51"), FPDecimal::ONE), -FPDecimal::ONE); + assert_eq!( + round(FPDecimal::must_from_str("-0.50009"), FPDecimal::must_from_str("0.0001")), + FPDecimal::must_from_str("-0.5001") + ); + assert_eq!(round(FPDecimal::must_from_str("-1.50009"), FPDecimal::ONE), -FPDecimal::TWO); + } + #[test] fn test_div_dec() { assert_eq!( From 4a68105fbc9162648b89e1acf90ca756c6fca7ad Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 13 Sep 2023 16:31:01 -0400 Subject: [PATCH 2/6] bumped version, fixed clippy warnings --- packages/injective-math/Cargo.toml | 2 +- packages/injective-math/src/utils.rs | 29 ++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/injective-math/Cargo.toml b/packages/injective-math/Cargo.toml index a3859433..b4a9e5df 100644 --- a/packages/injective-math/Cargo.toml +++ b/packages/injective-math/Cargo.toml @@ -6,7 +6,7 @@ license = "Apache-2.0" name = "injective-math" readme = "README.md" repository = "https://github.com/InjectiveLabs/cw-injective/tree/master/packages/injective-math" -version = "0.1.20" +version = "0.1.21" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index 61f321e3..16397693 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -1,6 +1,7 @@ use crate::FPDecimal; use bigint::U256; use cosmwasm_std::StdError; +use std::cmp::Ordering; use std::{fmt::Display, str::FromStr}; #[derive(Default)] @@ -90,15 +91,27 @@ pub fn round(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { //FIXME min_tick has to be 1, 0.1,0.01, etc let num_floor = floor(num, min_tick); let diff = num - num_floor; - if diff < (min_tick / FPDecimal::TWO) { - return num_floor; - } else if diff > (min_tick / FPDecimal::TWO) { - return num_floor + min_tick; - } - if num_floor / (min_tick * FPDecimal::TWO) == FPDecimal::ZERO { - return num_floor; + match diff.cmp(&(min_tick / FPDecimal::TWO)) { + Ordering::Less => num_floor, + Ordering::Equal => { + if num_floor / (min_tick * FPDecimal::TWO) == FPDecimal::ZERO { + num_floor + } else { + num_floor + min_tick + } + } + Ordering::Greater => num_floor + min_tick, } - return num_floor + min_tick; + // if diff < (min_tick / FPDecimal::TWO) { + // num_floor + // } else if diff > (min_tick / FPDecimal::TWO) { + // num_floor + min_tick + // } else { + // if num_floor / (min_tick * FPDecimal::TWO) == FPDecimal::ZERO { + // return num_floor; + // } + // return num_floor + min_tick; + // } } pub fn round_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { From ffb03630864b0d30bc3fb2f0ef7e29f4e8e3f970 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 13 Sep 2023 16:32:47 -0400 Subject: [PATCH 3/6] updated Cargo.lock --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d15a294..98ecb43e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -763,7 +763,7 @@ dependencies = [ "cw-storage-plus 0.15.1", "ethereum-types", "hex", - "injective-math 0.1.20", + "injective-math 0.1.21", "schemars", "serde 1.0.164", "serde-json-wasm 0.4.1", @@ -790,7 +790,7 @@ dependencies = [ [[package]] name = "injective-math" -version = "0.1.20" +version = "0.1.21" dependencies = [ "bigint", "cosmwasm-schema", @@ -840,7 +840,7 @@ dependencies = [ "cosmwasm-std", "cw-multi-test", "injective-cosmwasm 0.2.12", - "injective-math 0.1.20", + "injective-math 0.1.21", "rand 0.4.6", "secp256k1", "serde 1.0.164", From 2f1708a4b5ed429ef62b9ddf8820ead4c6b1b9d0 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Wed, 13 Sep 2023 16:57:31 -0400 Subject: [PATCH 4/6] cleaned up codes --- packages/injective-math/src/utils.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index 16397693..0a7179a3 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -102,16 +102,6 @@ pub fn round(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { } Ordering::Greater => num_floor + min_tick, } - // if diff < (min_tick / FPDecimal::TWO) { - // num_floor - // } else if diff > (min_tick / FPDecimal::TWO) { - // num_floor + min_tick - // } else { - // if num_floor / (min_tick * FPDecimal::TWO) == FPDecimal::ZERO { - // return num_floor; - // } - // return num_floor + min_tick; - // } } pub fn round_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { From f309a24d8a90c4bc1ff1b81df0c067df8c222766 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 14 Sep 2023 12:30:14 -0400 Subject: [PATCH 5/6] add more unit tests --- packages/injective-math/src/utils.rs | 35 +++++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index 0a7179a3..8ebbd80a 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -143,6 +143,7 @@ pub fn round_up_to_min_tick(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { #[cfg(test)] mod tests { use super::*; + use crate::fp_decimal::scale::Scaled; #[test] fn test_floor() { @@ -184,15 +185,25 @@ mod tests { #[test] fn test_round() { + assert_eq!(round(FPDecimal::must_from_str("0.13"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("0.49"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("0.5"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("0.50009"), FPDecimal::ONE), FPDecimal::ONE); + + assert_eq!(round(FPDecimal::must_from_str("-0.13"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("-0.49"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("-0.5"), FPDecimal::ONE), FPDecimal::ZERO); + assert_eq!(round(FPDecimal::must_from_str("-0.51"), FPDecimal::ONE), -FPDecimal::ONE); + assert_eq!(round(FPDecimal::must_from_str("-1.50009"), FPDecimal::ONE), -FPDecimal::TWO); + } + + #[test] + fn test_round_with_scaled_numbers() { assert_eq!(round(FPDecimal::must_from_str("0"), FPDecimal::must_from_str("0.1")), FPDecimal::ZERO); assert_eq!( round(FPDecimal::must_from_str("0.13"), FPDecimal::must_from_str("0.1")), FPDecimal::must_from_str("0.1") ); - assert_eq!(round(FPDecimal::must_from_str("0.13"), FPDecimal::ONE), FPDecimal::ZERO); - assert_eq!(round(FPDecimal::must_from_str("0.49"), FPDecimal::ONE), FPDecimal::ZERO); - assert_eq!(round(FPDecimal::must_from_str("0.5"), FPDecimal::ONE), FPDecimal::ZERO); - assert_eq!(round(FPDecimal::must_from_str("0.50009"), FPDecimal::ONE), FPDecimal::ONE); assert_eq!( round(FPDecimal::must_from_str("0.50009"), FPDecimal::must_from_str("0.0001")), FPDecimal::must_from_str("0.5001") @@ -203,15 +214,21 @@ mod tests { round(FPDecimal::must_from_str("-0.13"), FPDecimal::must_from_str("0.1")), FPDecimal::must_from_str("-0.1") ); - assert_eq!(round(FPDecimal::must_from_str("-0.13"), FPDecimal::ONE), FPDecimal::ZERO); - assert_eq!(round(FPDecimal::must_from_str("-0.49"), FPDecimal::ONE), FPDecimal::ZERO); - assert_eq!(round(FPDecimal::must_from_str("-0.5"), FPDecimal::ONE), FPDecimal::ZERO); - assert_eq!(round(FPDecimal::must_from_str("-0.51"), FPDecimal::ONE), -FPDecimal::ONE); assert_eq!( round(FPDecimal::must_from_str("-0.50009"), FPDecimal::must_from_str("0.0001")), FPDecimal::must_from_str("-0.5001") ); - assert_eq!(round(FPDecimal::must_from_str("-1.50009"), FPDecimal::ONE), -FPDecimal::TWO); + + assert_eq!(round(FPDecimal::must_from_str("-1.50009"), FPDecimal::ONE.scaled(1)), FPDecimal::ZERO); + assert_eq!( + round(FPDecimal::must_from_str("-1.50009").scaled(1), FPDecimal::ONE.scaled(1)), + -FPDecimal::TWO.scaled(1) + ); + assert_eq!(round(FPDecimal::must_from_str("-1.50009"), FPDecimal::ONE.scaled(1)), FPDecimal::ZERO); + assert_eq!( + round(FPDecimal::must_from_str("-1.50009").scaled(1), FPDecimal::ONE.scaled(1)), + -FPDecimal::TWO.scaled(1) + ); } #[test] From 741ba12c5bf99ef7c6d41bdfefbe2d7ae2e28a77 Mon Sep 17 00:00:00 2001 From: DrunkRandomWalker Date: Thu, 14 Sep 2023 15:35:44 -0400 Subject: [PATCH 6/6] delete outdated comments --- packages/injective-math/src/utils.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/injective-math/src/utils.rs b/packages/injective-math/src/utils.rs index 8ebbd80a..d208b8d3 100644 --- a/packages/injective-math/src/utils.rs +++ b/packages/injective-math/src/utils.rs @@ -78,7 +78,6 @@ pub fn div_dec(num: FPDecimal, denom: FPDecimal) -> FPDecimal { pub fn floor(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { // min_tick has to be a positive number - //FIXME min_tick has to be 1, 0.1,0.01, etc assert!(min_tick >= FPDecimal::ZERO); if num.is_zero() { return num; @@ -88,7 +87,6 @@ pub fn floor(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { } pub fn round(num: FPDecimal, min_tick: FPDecimal) -> FPDecimal { - //FIXME min_tick has to be 1, 0.1,0.01, etc let num_floor = floor(num, min_tick); let diff = num - num_floor; match diff.cmp(&(min_tick / FPDecimal::TWO)) {