aboutsummaryrefslogtreecommitdiffstats
path: root/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol
diff options
context:
space:
mode:
Diffstat (limited to 'contracts/core/contracts/protocol/Exchange/libs/LibMath.sol')
-rw-r--r--contracts/core/contracts/protocol/Exchange/libs/LibMath.sol253
1 files changed, 253 insertions, 0 deletions
diff --git a/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol b/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol
new file mode 100644
index 000000000..c0b85ea10
--- /dev/null
+++ b/contracts/core/contracts/protocol/Exchange/libs/LibMath.sol
@@ -0,0 +1,253 @@
+/*
+
+ Copyright 2018 ZeroEx Intl.
+
+ 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.
+
+*/
+
+pragma solidity 0.4.24;
+
+import "../../../utils/SafeMath/SafeMath.sol";
+
+
+contract LibMath is
+ SafeMath
+{
+ /// @dev Calculates partial value given a numerator and denominator rounded down.
+ /// Reverts if rounding error is >= 0.1%
+ /// @param numerator Numerator.
+ /// @param denominator Denominator.
+ /// @param target Value to calculate partial of.
+ /// @return Partial value of target rounded down.
+ function safeGetPartialAmountFloor(
+ uint256 numerator,
+ uint256 denominator,
+ uint256 target
+ )
+ internal
+ pure
+ returns (uint256 partialAmount)
+ {
+ require(
+ denominator > 0,
+ "DIVISION_BY_ZERO"
+ );
+
+ require(
+ !isRoundingErrorFloor(
+ numerator,
+ denominator,
+ target
+ ),
+ "ROUNDING_ERROR"
+ );
+
+ partialAmount = safeDiv(
+ safeMul(numerator, target),
+ denominator
+ );
+ return partialAmount;
+ }
+
+ /// @dev Calculates partial value given a numerator and denominator rounded down.
+ /// Reverts if rounding error is >= 0.1%
+ /// @param numerator Numerator.
+ /// @param denominator Denominator.
+ /// @param target Value to calculate partial of.
+ /// @return Partial value of target rounded up.
+ function safeGetPartialAmountCeil(
+ uint256 numerator,
+ uint256 denominator,
+ uint256 target
+ )
+ internal
+ pure
+ returns (uint256 partialAmount)
+ {
+ require(
+ denominator > 0,
+ "DIVISION_BY_ZERO"
+ );
+
+ require(
+ !isRoundingErrorCeil(
+ numerator,
+ denominator,
+ target
+ ),
+ "ROUNDING_ERROR"
+ );
+
+ // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
+ // ceil(a / b) = floor((a + b - 1) / b)
+ // To implement `ceil(a / b)` using safeDiv.
+ partialAmount = safeDiv(
+ safeAdd(
+ safeMul(numerator, target),
+ safeSub(denominator, 1)
+ ),
+ denominator
+ );
+ return partialAmount;
+ }
+
+ /// @dev Calculates partial value given a numerator and denominator rounded down.
+ /// @param numerator Numerator.
+ /// @param denominator Denominator.
+ /// @param target Value to calculate partial of.
+ /// @return Partial value of target rounded down.
+ function getPartialAmountFloor(
+ uint256 numerator,
+ uint256 denominator,
+ uint256 target
+ )
+ internal
+ pure
+ returns (uint256 partialAmount)
+ {
+ require(
+ denominator > 0,
+ "DIVISION_BY_ZERO"
+ );
+
+ partialAmount = safeDiv(
+ safeMul(numerator, target),
+ denominator
+ );
+ return partialAmount;
+ }
+
+ /// @dev Calculates partial value given a numerator and denominator rounded down.
+ /// @param numerator Numerator.
+ /// @param denominator Denominator.
+ /// @param target Value to calculate partial of.
+ /// @return Partial value of target rounded up.
+ function getPartialAmountCeil(
+ uint256 numerator,
+ uint256 denominator,
+ uint256 target
+ )
+ internal
+ pure
+ returns (uint256 partialAmount)
+ {
+ require(
+ denominator > 0,
+ "DIVISION_BY_ZERO"
+ );
+
+ // safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
+ // ceil(a / b) = floor((a + b - 1) / b)
+ // To implement `ceil(a / b)` using safeDiv.
+ partialAmount = safeDiv(
+ safeAdd(
+ safeMul(numerator, target),
+ safeSub(denominator, 1)
+ ),
+ denominator
+ );
+ return partialAmount;
+ }
+
+ /// @dev Checks if rounding error >= 0.1% when rounding down.
+ /// @param numerator Numerator.
+ /// @param denominator Denominator.
+ /// @param target Value to multiply with numerator/denominator.
+ /// @return Rounding error is present.
+ function isRoundingErrorFloor(
+ uint256 numerator,
+ uint256 denominator,
+ uint256 target
+ )
+ internal
+ pure
+ returns (bool isError)
+ {
+ require(
+ denominator > 0,
+ "DIVISION_BY_ZERO"
+ );
+
+ // The absolute rounding error is the difference between the rounded
+ // value and the ideal value. The relative rounding error is the
+ // absolute rounding error divided by the absolute value of the
+ // ideal value. This is undefined when the ideal value is zero.
+ //
+ // The ideal value is `numerator * target / denominator`.
+ // Let's call `numerator * target % denominator` the remainder.
+ // The absolute error is `remainder / denominator`.
+ //
+ // When the ideal value is zero, we require the absolute error to
+ // be zero. Fortunately, this is always the case. The ideal value is
+ // zero iff `numerator == 0` and/or `target == 0`. In this case the
+ // remainder and absolute error are also zero.
+ if (target == 0 || numerator == 0) {
+ return false;
+ }
+
+ // Otherwise, we want the relative rounding error to be strictly
+ // less than 0.1%.
+ // The relative error is `remainder / (numerator * target)`.
+ // We want the relative error less than 1 / 1000:
+ // remainder / (numerator * denominator) < 1 / 1000
+ // or equivalently:
+ // 1000 * remainder < numerator * target
+ // so we have a rounding error iff:
+ // 1000 * remainder >= numerator * target
+ uint256 remainder = mulmod(
+ target,
+ numerator,
+ denominator
+ );
+ isError = safeMul(1000, remainder) >= safeMul(numerator, target);
+ return isError;
+ }
+
+ /// @dev Checks if rounding error >= 0.1% when rounding up.
+ /// @param numerator Numerator.
+ /// @param denominator Denominator.
+ /// @param target Value to multiply with numerator/denominator.
+ /// @return Rounding error is present.
+ function isRoundingErrorCeil(
+ uint256 numerator,
+ uint256 denominator,
+ uint256 target
+ )
+ internal
+ pure
+ returns (bool isError)
+ {
+ require(
+ denominator > 0,
+ "DIVISION_BY_ZERO"
+ );
+
+ // See the comments in `isRoundingError`.
+ if (target == 0 || numerator == 0) {
+ // When either is zero, the ideal value and rounded value are zero
+ // and there is no rounding error. (Although the relative error
+ // is undefined.)
+ return false;
+ }
+ // Compute remainder as before
+ uint256 remainder = mulmod(
+ target,
+ numerator,
+ denominator
+ );
+ remainder = safeSub(denominator, remainder) % denominator;
+ isError = safeMul(1000, remainder) >= safeMul(numerator, target);
+ return isError;
+ }
+}