diff --git a/lib/archethic/contracts/interpreter/library/common/math.ex b/lib/archethic/contracts/interpreter/library/common/math.ex index 2c3952f6f..426422c12 100644 --- a/lib/archethic/contracts/interpreter/library/common/math.ex +++ b/lib/archethic/contracts/interpreter/library/common/math.ex @@ -4,6 +4,7 @@ defmodule Archethic.Contracts.Interpreter.Library.Common.Math do alias Archethic.Tag alias Archethic.Contracts.Interpreter.ASTHelper, as: AST + alias Archethic.Contracts.Interpreter.Library use Tag import Bitwise @@ -127,6 +128,50 @@ defmodule Archethic.Contracts.Interpreter.Library.Common.Math do to_number(res, is_integer(num1) and is_integer(num2)) end + @doc """ + + ## Example + + iex> Math.bigint(49.85024327, 18) + 49_850_243_270_000_000_000 + + iex> Math.bigint(1.994e-4, 18) + 199_400_000_000_000 + + iex> Math.bigint(0.19941234, 18) + 199_412_340_000_000_000 + + iex> Math.bigint(0.10000006, 18) + 100_000_060_000_000_000 + + iex> Math.bigint(0.002, 18) + 2_000_000_000_000_000 + + iex> Math.bigint(1.2390131, 18) + 1_239_013_100_000_000_000 + + iex> Math.bigint(10, 18) + 10_000_000_000_000_000_000 + + iex> Math.bigint(1, 8) + 100_000_000 + + """ + @spec bigint(num :: number(), decimals :: number()) :: number() + def bigint(num, decimals) do + num + |> to_string() + |> Decimal.new() + |> Decimal.mult(Decimal.new(10 ** decimals)) + |> then(fn dec -> + if Decimal.integer?(dec) do + Decimal.to_integer(dec) + else + raise Library.Error, message: "Number exceeds decimals" + end + end) + end + @spec check_types(atom(), list()) :: boolean() def check_types(:trunc, [first]) do AST.is_number?(first) || AST.is_variable_or_function_call?(first) @@ -146,6 +191,11 @@ defmodule Archethic.Contracts.Interpreter.Library.Common.Math do (AST.is_number?(second) || AST.is_variable_or_function_call?(second)) end + def check_types(:bigint, [first, second]) do + (AST.is_number?(first) || AST.is_variable_or_function_call?(first)) && + (AST.is_number?(second) || AST.is_variable_or_function_call?(second)) + end + def check_types(_, _), do: false defp to_decimal(num) when is_integer(num), do: Decimal.new(num) diff --git a/test/archethic/contracts/interpreter/library/common/math_test.exs b/test/archethic/contracts/interpreter/library/common/math_test.exs index b7023589d..107a3144e 100644 --- a/test/archethic/contracts/interpreter/library/common/math_test.exs +++ b/test/archethic/contracts/interpreter/library/common/math_test.exs @@ -1,7 +1,18 @@ defmodule Archethic.Contracts.Interpreter.Library.Common.MathTest do use ArchethicCase + alias Archethic.Contracts.Interpreter.Library alias Archethic.Contracts.Interpreter.Library.Common.Math doctest Math + + test "exceed decimals raise" do + assert_raise Library.Error, "Number exceeds decimals", fn -> + Math.bigint(0.1234, 2) + end + + assert_raise Library.Error, "Number exceeds decimals", fn -> + Math.bigint(0.12345874564, 8) + end + end end