diff --git a/zrml/neo-swaps/src/consts.rs b/zrml/neo-swaps/src/consts.rs
index cab971b4b..7e7948f0b 100644
--- a/zrml/neo-swaps/src/consts.rs
+++ b/zrml/neo-swaps/src/consts.rs
@@ -25,13 +25,22 @@ pub(crate) const _2: u128 = 2 * _1;
pub(crate) const _3: u128 = 3 * _1;
pub(crate) const _4: u128 = 4 * _1;
pub(crate) const _5: u128 = 5 * _1;
+pub(crate) const _7: u128 = 7 * _1;
+pub(crate) const _8: u128 = 8 * _1;
pub(crate) const _9: u128 = 9 * _1;
pub(crate) const _10: u128 = 10 * _1;
+pub(crate) const _11: u128 = 11 * _1;
+pub(crate) const _17: u128 = 17 * _1;
pub(crate) const _20: u128 = 20 * _1;
+pub(crate) const _30: u128 = 30 * _1;
pub(crate) const _70: u128 = 70 * _1;
pub(crate) const _80: u128 = 80 * _1;
pub(crate) const _100: u128 = 100 * _1;
pub(crate) const _101: u128 = 101 * _1;
+pub(crate) const _444: u128 = 444 * _1;
+pub(crate) const _500: u128 = 500 * _1;
+pub(crate) const _777: u128 = 777 * _1;
+pub(crate) const _1000: u128 = 1_000 * _1;
pub(crate) const _1_2: u128 = _1 / 2;
@@ -45,3 +54,8 @@ pub(crate) const _1_5: u128 = _1 / 5;
pub(crate) const _1_6: u128 = _1 / 6;
pub(crate) const _5_6: u128 = _5 / 6;
+
+pub(crate) const _1_10: u128 = _1 / 10;
+pub(crate) const _2_10: u128 = _2 / 10;
+pub(crate) const _3_10: u128 = _3 / 10;
+pub(crate) const _4_10: u128 = _4 / 10;
diff --git a/zrml/neo-swaps/src/math.rs b/zrml/neo-swaps/src/math.rs
index f0978deb6..3b83b1dff 100644
--- a/zrml/neo-swaps/src/math.rs
+++ b/zrml/neo-swaps/src/math.rs
@@ -14,12 +14,37 @@
//
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+//
+// This file incorporates work covered by the following copyright and
+// permission notice:
+//
+// Copyright (c) 2019 Alain Brenzikofer, modified by GalacticCouncil(2021)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Original source: https://github.com/encointer/substrate-fixed
+//
+// The changes applied are: 1) Used same design for definition of `exp`
+// as in the source. 2) Re-used and extended tests for `exp` and other
+// functions.
-use crate::{BalanceOf, Config, Error};
+use crate::{
+ math::transcendental::{exp, ln},
+ BalanceOf, Config, Error,
+};
use alloc::vec::Vec;
use core::marker::PhantomData;
use fixed::FixedU128;
-use hydra_dx_math::transcendental::{exp, ln};
use sp_runtime::{DispatchError, SaturatedConversion};
use typenum::U80;
@@ -102,6 +127,88 @@ impl MathOps for Math {
}
}
+mod transcendental {
+ use fixed::traits::FixedUnsigned;
+ pub(crate) use hydra_dx_math::transcendental::{exp as inner_exp, ln};
+ use sp_runtime::traits::One;
+
+ pub(crate) fn exp(operand: S, neg: bool) -> Result
+ where
+ S: FixedUnsigned + PartialOrd + One,
+ D: FixedUnsigned + PartialOrd + From + One,
+ {
+ if operand == S::one() && neg {
+ let e_inverse =
+ S::from_str("0.367879441171442321595523770161460867445").map_err(|_| ())?;
+ return Ok(D::from(e_inverse));
+ }
+ inner_exp(operand, neg)
+ }
+
+ #[cfg(test)]
+ mod tests {
+ use super::*;
+ use alloc::str::FromStr;
+ use fixed::types::U64F64;
+ use test_case::test_case;
+
+ type S = U64F64;
+ type D = U64F64;
+
+ #[test_case("0", false, "1")]
+ #[test_case("0", true, "1")]
+ #[test_case("1", false, "2.718281828459045235360287471352662497757")]
+ #[test_case("1", true, "0.367879441171442321595523770161460867445")]
+ #[test_case("2", false, "7.3890560989306502265")]
+ #[test_case("2", true, "0.13533528323661269186")]
+ #[test_case("0.1", false, "1.1051709180756476246")]
+ #[test_case("0.1", true, "0.9048374180359595733")]
+ #[test_case("0.9", false, "2.4596031111569496633")]
+ #[test_case("0.9", true, "0.40656965974059911195")]
+ #[test_case("1.5", false, "4.481689070338064822")]
+ #[test_case("1.5", true, "0.22313016014842982894")]
+ #[test_case("3.3", false, "27.1126389206578874259")]
+ #[test_case("3.3", true, "0.03688316740124000543")]
+ #[test_case("7.3456", false, "1549.3643050275008503592")]
+ #[test_case("7.3456", true, "0.00064542599616831253")]
+ #[test_case("12.3456789", false, "229964.194569082134542849")]
+ #[test_case("12.3456789", true, "0.00000434850304358833")]
+ #[test_case("13", false, "442413.39200892050332603603")]
+ #[test_case("13", true, "0.0000022603294069810542")]
+ fn exp_works(operand: &str, neg: bool, expected: &str) {
+ let o = U64F64::from_str(operand).unwrap();
+ let e = U64F64::from_str(expected).unwrap();
+ assert_eq!(exp::(o, neg).unwrap(), e);
+ }
+
+ #[test_case("1", "0", false)]
+ #[test_case("2", "0.69314718055994530943", false)]
+ #[test_case("3", "1.09861228866810969136", false)]
+ #[test_case("2.718281828459045235360287471352662497757", "1", false)]
+ #[test_case("1.1051709180756476246", "0.09999999999999999975", false)]
+ #[test_case("2.4596031111569496633", "0.89999999999999999976", false)]
+ #[test_case("4.481689070338064822", "1.49999999999999999984", false)]
+ #[test_case("27.1126389206578874261", "3.3", false)]
+ #[test_case("1549.3643050275008503592", "7.34560000000000000003", false)]
+ #[test_case("229964.194569082134542849", "12.3456789000000000002", false)]
+ #[test_case("442413.39200892050332603603", "13.0000000000000000002", false)]
+ #[test_case("0.9048374180359595733", "0.09999999999999999975", true)]
+ #[test_case("0.40656965974059911195", "0.8999999999999999998", true)]
+ #[test_case("0.22313016014842982894", "1.4999999999999999999", true)]
+ #[test_case("0.03688316740124000543", "3.3000000000000000005", true)]
+ #[test_case("0.00064542599616831253", "7.34560000000000002453", true)]
+ #[test_case("0.00000434850304358833", "12.34567890000000711117", true)]
+ #[test_case("0.0000022603294069810542", "13.0000000000000045352", true)]
+ fn ln_works(operand: &str, expected_abs: &str, expected_neg: bool) {
+ let o = U64F64::from_str(operand).unwrap();
+ let e = U64F64::from_str(expected_abs).unwrap();
+ let (a, n) = ln::(o).unwrap();
+ assert_eq!(a, e);
+ assert_eq!(n, expected_neg);
+ }
+ }
+}
+
mod detail {
use super::*;
use zeitgeist_primitives::{
@@ -225,58 +332,112 @@ mod detail {
tmp_reserves.iter().map(|&r| r.checked_mul(liquidity)).collect::