/* Copyright 2020 Set Labs Inc. 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. SPDX-License-Identifier: Apache License, Version 2.0 */ pragma solidity 0.6.10; pragma experimental ABIEncoderV2; import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol"; import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; import { SignedSafeMath } from "@openzeppelin/contracts/math/SignedSafeMath.sol"; /** * @title PreciseUnitMath * @author Set Protocol * * Arithmetic for fixed-point numbers with 18 decimals of precision. Some functions taken from * dYdX's BaseMath library. * * CHANGELOG: * - 9/21/20: Added safePower function * - 4/21/21: Added approximatelyEquals function * - 12/13/21: Added preciseDivCeil (int overloads) function * - 12/13/21: Added abs function */ library PreciseUnitMath { using SafeMath for uint256; using SignedSafeMath for int256; using SafeCast for int256; // The number One in precise units. uint256 constant internal PRECISE_UNIT = 10 ** 18; int256 constant internal PRECISE_UNIT_INT = 10 ** 18; // Max unsigned integer value uint256 constant internal MAX_UINT_256 = type(uint256).max; // Max and min signed integer value int256 constant internal MAX_INT_256 = type(int256).max; int256 constant internal MIN_INT_256 = type(int256).min; /** * @dev Getter function since constants can't be read directly from libraries. */ function preciseUnit() internal pure returns (uint256) { return PRECISE_UNIT; } /** * @dev Getter function since constants can't be read directly from libraries. */ function preciseUnitInt() internal pure returns (int256) { return PRECISE_UNIT_INT; } /** * @dev Getter function since constants can't be read directly from libraries. */ function maxUint256() internal pure returns (uint256) { return MAX_UINT_256; } /** * @dev Getter function since constants can't be read directly from libraries. */ function maxInt256() internal pure returns (int256) { return MAX_INT_256; } /** * @dev Getter function since constants can't be read directly from libraries. */ function minInt256() internal pure returns (int256) { return MIN_INT_256; } /** * @dev Multiplies value a by value b (result is rounded down). It's assumed that the value b is the significand * of a number with 18 decimals precision. */ function preciseMul(uint256 a, uint256 b) internal pure returns (uint256) { return a.mul(b).div(PRECISE_UNIT); } /** * @dev Multiplies value a by value b (result is rounded towards zero). It's assumed that the value b is the * significand of a number with 18 decimals precision. */ function preciseMul(int256 a, int256 b) internal pure returns (int256) { return a.mul(b).div(PRECISE_UNIT_INT); } /** * @dev Multiplies value a by value b (result is rounded up). It's assumed that the value b is the significand * of a number with 18 decimals precision. */ function preciseMulCeil(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0 || b == 0) { return 0; } return a.mul(b).sub(1).div(PRECISE_UNIT).add(1); } /** * @dev Divides value a by value b (result is rounded down). */ function preciseDiv(uint256 a, uint256 b) internal pure returns (uint256) { return a.mul(PRECISE_UNIT).div(b); } /** * @dev Divides value a by value b (result is rounded towards 0). */ function preciseDiv(int256 a, int256 b) internal pure returns (int256) { return a.mul(PRECISE_UNIT_INT).div(b); } /** * @dev Divides value a by value b (result is rounded up or away from 0). */ function preciseDivCeil(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "Cant divide by 0"); return a > 0 ? a.mul(PRECISE_UNIT).sub(1).div(b).add(1) : 0; } /** * @dev Divides value a by value b (result is rounded up or away from 0). When `a` is 0, 0 is * returned. When `b` is 0, method reverts with divide-by-zero error. */ function preciseDivCeil(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "Cant divide by 0"); a = a.mul(PRECISE_UNIT_INT); int256 c = a.div(b); if (a % b != 0) { // a ^ b == 0 case is covered by the previous if statement, hence it won't resolve to --c (a ^ b > 0) ? ++c : --c; } return c; } /** * @dev Divides value a by value b (result is rounded down - positive numbers toward 0 and negative away from 0). */ function divDown(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "Cant divide by 0"); require(a != MIN_INT_256 || b != -1, "Invalid input"); int256 result = a.div(b); if (a ^ b < 0 && a % b != 0) { result -= 1; } return result; } /** * @dev Multiplies value a by value b where rounding is towards the lesser number. * (positive values are rounded towards zero and negative values are rounded away from 0). */ function conservativePreciseMul(int256 a, int256 b) internal pure returns (int256) { return divDown(a.mul(b), PRECISE_UNIT_INT); } /** * @dev Divides value a by value b where rounding is towards the lesser number. * (positive values are rounded towards zero and negative values are rounded away from 0). */ function conservativePreciseDiv(int256 a, int256 b) internal pure returns (int256) { return divDown(a.mul(PRECISE_UNIT_INT), b); } /** * @dev Performs the power on a specified value, reverts on overflow. */ function safePower( uint256 a, uint256 pow ) internal pure returns (uint256) { require(a > 0, "Value must be positive"); uint256 result = 1; for (uint256 i = 0; i < pow; i++){ uint256 previousResult = result; // Using safemath multiplication prevents overflows result = previousResult.mul(a); } return result; } /** * @dev Returns true if a =~ b within range, false otherwise. */ function approximatelyEquals(uint256 a, uint256 b, uint256 range) internal pure returns (bool) { return a <= b.add(range) && a >= b.sub(range); } /** * Returns the absolute value of int256 `a` as a uint256 */ function abs(int256 a) internal pure returns (uint) { return a >= 0 ? a.toUint256() : a.mul(-1).toUint256(); } /** * Returns the negation of a */ function neg(int256 a) internal pure returns (int256) { require(a > MIN_INT_256, "Inversion overflow"); return -a; } }