763 lines
28 KiB
Solidity
763 lines
28 KiB
Solidity
// SPDX-License-Identifier: AGPL-3.0-only
|
|
pragma solidity ^0.8.0;
|
|
|
|
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
|
|
import "@openzeppelin/contracts/utils/math/SignedSafeMath.sol";
|
|
|
|
/**
|
|
* @title Library for fixed point arithmetic on uints
|
|
*/
|
|
library FixedPoint {
|
|
using SafeMath for uint256;
|
|
using SignedSafeMath for int256;
|
|
|
|
// Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
|
|
// For unsigned values:
|
|
// This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.
|
|
uint256 private constant FP_SCALING_FACTOR = 10**18;
|
|
|
|
// --------------------------------------- UNSIGNED -----------------------------------------------------------------------------
|
|
struct Unsigned {
|
|
uint256 rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.
|
|
* @param a uint to convert into a FixedPoint.
|
|
* @return the converted FixedPoint.
|
|
*/
|
|
function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {
|
|
return Unsigned(a.mul(FP_SCALING_FACTOR));
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is equal to `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return True if equal, or False.
|
|
*/
|
|
function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
|
|
return a.rawValue == fromUnscaledUint(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is equal to `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return True if equal, or False.
|
|
*/
|
|
function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
|
|
return a.rawValue == b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a > b`, or False.
|
|
*/
|
|
function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
|
|
return a.rawValue > b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return True if `a > b`, or False.
|
|
*/
|
|
function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
|
|
return a.rawValue > fromUnscaledUint(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than `b`.
|
|
* @param a a uint256.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a > b`, or False.
|
|
*/
|
|
function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
|
|
return fromUnscaledUint(a).rawValue > b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than or equal to `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a >= b`, or False.
|
|
*/
|
|
function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
|
|
return a.rawValue >= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than or equal to `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return True if `a >= b`, or False.
|
|
*/
|
|
function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
|
|
return a.rawValue >= fromUnscaledUint(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than or equal to `b`.
|
|
* @param a a uint256.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a >= b`, or False.
|
|
*/
|
|
function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
|
|
return fromUnscaledUint(a).rawValue >= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a < b`, or False.
|
|
*/
|
|
function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
|
|
return a.rawValue < b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return True if `a < b`, or False.
|
|
*/
|
|
function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
|
|
return a.rawValue < fromUnscaledUint(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than `b`.
|
|
* @param a a uint256.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a < b`, or False.
|
|
*/
|
|
function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
|
|
return fromUnscaledUint(a).rawValue < b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than or equal to `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a <= b`, or False.
|
|
*/
|
|
function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
|
|
return a.rawValue <= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than or equal to `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return True if `a <= b`, or False.
|
|
*/
|
|
function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
|
|
return a.rawValue <= fromUnscaledUint(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than or equal to `b`.
|
|
* @param a a uint256.
|
|
* @param b a FixedPoint.
|
|
* @return True if `a <= b`, or False.
|
|
*/
|
|
function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
|
|
return fromUnscaledUint(a).rawValue <= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice The minimum of `a` and `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the minimum of `a` and `b`.
|
|
*/
|
|
function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
return a.rawValue < b.rawValue ? a : b;
|
|
}
|
|
|
|
/**
|
|
* @notice The maximum of `a` and `b`.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the maximum of `a` and `b`.
|
|
*/
|
|
function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
return a.rawValue > b.rawValue ? a : b;
|
|
}
|
|
|
|
/**
|
|
* @notice Adds two `Unsigned`s, reverting on overflow.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the sum of `a` and `b`.
|
|
*/
|
|
function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
return Unsigned(a.rawValue.add(b.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return the sum of `a` and `b`.
|
|
*/
|
|
function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
|
|
return add(a, fromUnscaledUint(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Subtracts two `Unsigned`s, reverting on overflow.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the difference of `a` and `b`.
|
|
*/
|
|
function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
return Unsigned(a.rawValue.sub(b.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return the difference of `a` and `b`.
|
|
*/
|
|
function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
|
|
return sub(a, fromUnscaledUint(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.
|
|
* @param a a uint256.
|
|
* @param b a FixedPoint.
|
|
* @return the difference of `a` and `b`.
|
|
*/
|
|
function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
return sub(fromUnscaledUint(a), b);
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies two `Unsigned`s, reverting on overflow.
|
|
* @dev This will "floor" the product.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
// There are two caveats with this computation:
|
|
// 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
|
|
// stored internally as a uint256 ~10^59.
|
|
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
|
|
// would round to 3, but this computation produces the result 2.
|
|
// No need to use SafeMath because FP_SCALING_FACTOR != 0.
|
|
return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.
|
|
* @dev This will "floor" the product.
|
|
* @param a a FixedPoint.
|
|
* @param b a uint256.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
|
|
return Unsigned(a.rawValue.mul(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
uint256 mulRaw = a.rawValue.mul(b.rawValue);
|
|
uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;
|
|
uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);
|
|
if (mod != 0) {
|
|
return Unsigned(mulFloor.add(1));
|
|
} else {
|
|
return Unsigned(mulFloor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow.
|
|
* @param a a FixedPoint.
|
|
* @param b a FixedPoint.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
|
|
// Since b is an uint, there is no risk of truncation and we can just mul it normally
|
|
return Unsigned(a.rawValue.mul(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.
|
|
* @dev This will "floor" the quotient.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a FixedPoint denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
// There are two caveats with this computation:
|
|
// 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
|
|
// 10^41 is stored internally as a uint256 10^59.
|
|
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
|
|
// would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
|
|
return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.
|
|
* @dev This will "floor" the quotient.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a uint256 denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
|
|
return Unsigned(a.rawValue.div(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.
|
|
* @dev This will "floor" the quotient.
|
|
* @param a a uint256 numerator.
|
|
* @param b a FixedPoint denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
return div(fromUnscaledUint(a), b);
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a FixedPoint denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
|
|
uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);
|
|
uint256 divFloor = aScaled.div(b.rawValue);
|
|
uint256 mod = aScaled.mod(b.rawValue);
|
|
if (mod != 0) {
|
|
return Unsigned(divFloor.add(1));
|
|
} else {
|
|
return Unsigned(divFloor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a uint256 denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
|
|
// Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))"
|
|
// similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.
|
|
// This creates the possibility of overflow if b is very large.
|
|
return divCeil(a, fromUnscaledUint(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
|
|
* @dev This will "floor" the result.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a uint256 denominator.
|
|
* @return output is `a` to the power of `b`.
|
|
*/
|
|
function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {
|
|
output = fromUnscaledUint(1);
|
|
for (uint256 i = 0; i < b; i = i.add(1)) {
|
|
output = mul(output, a);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------- SIGNED -------------------------------------------------------------
|
|
// Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
|
|
// For signed values:
|
|
// This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.
|
|
int256 private constant SFP_SCALING_FACTOR = 10**18;
|
|
|
|
struct Signed {
|
|
int256 rawValue;
|
|
}
|
|
|
|
function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {
|
|
require(a.rawValue >= 0, "Negative value provided");
|
|
return Unsigned(uint256(a.rawValue));
|
|
}
|
|
|
|
function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {
|
|
require(a.rawValue <= uint256(type(int256).max), "Unsigned too large");
|
|
return Signed(int256(a.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.
|
|
* @param a int to convert into a FixedPoint.Signed.
|
|
* @return the converted FixedPoint.Signed.
|
|
*/
|
|
function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {
|
|
return Signed(a.mul(SFP_SCALING_FACTOR));
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is equal to `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a int256.
|
|
* @return True if equal, or False.
|
|
*/
|
|
function isEqual(Signed memory a, int256 b) internal pure returns (bool) {
|
|
return a.rawValue == fromUnscaledInt(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is equal to `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if equal, or False.
|
|
*/
|
|
function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
|
|
return a.rawValue == b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a > b`, or False.
|
|
*/
|
|
function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {
|
|
return a.rawValue > b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return True if `a > b`, or False.
|
|
*/
|
|
function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {
|
|
return a.rawValue > fromUnscaledInt(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than `b`.
|
|
* @param a an int256.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a > b`, or False.
|
|
*/
|
|
function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {
|
|
return fromUnscaledInt(a).rawValue > b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than or equal to `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a >= b`, or False.
|
|
*/
|
|
function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
|
|
return a.rawValue >= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than or equal to `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return True if `a >= b`, or False.
|
|
*/
|
|
function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
|
|
return a.rawValue >= fromUnscaledInt(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is greater than or equal to `b`.
|
|
* @param a an int256.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a >= b`, or False.
|
|
*/
|
|
function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
|
|
return fromUnscaledInt(a).rawValue >= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a < b`, or False.
|
|
*/
|
|
function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {
|
|
return a.rawValue < b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return True if `a < b`, or False.
|
|
*/
|
|
function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {
|
|
return a.rawValue < fromUnscaledInt(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than `b`.
|
|
* @param a an int256.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a < b`, or False.
|
|
*/
|
|
function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {
|
|
return fromUnscaledInt(a).rawValue < b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than or equal to `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a <= b`, or False.
|
|
*/
|
|
function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
|
|
return a.rawValue <= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than or equal to `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return True if `a <= b`, or False.
|
|
*/
|
|
function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
|
|
return a.rawValue <= fromUnscaledInt(b).rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice Whether `a` is less than or equal to `b`.
|
|
* @param a an int256.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return True if `a <= b`, or False.
|
|
*/
|
|
function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
|
|
return fromUnscaledInt(a).rawValue <= b.rawValue;
|
|
}
|
|
|
|
/**
|
|
* @notice The minimum of `a` and `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the minimum of `a` and `b`.
|
|
*/
|
|
function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
return a.rawValue < b.rawValue ? a : b;
|
|
}
|
|
|
|
/**
|
|
* @notice The maximum of `a` and `b`.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the maximum of `a` and `b`.
|
|
*/
|
|
function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
return a.rawValue > b.rawValue ? a : b;
|
|
}
|
|
|
|
/**
|
|
* @notice Adds two `Signed`s, reverting on overflow.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the sum of `a` and `b`.
|
|
*/
|
|
function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
return Signed(a.rawValue.add(b.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Adds an `Signed` to an unscaled int, reverting on overflow.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return the sum of `a` and `b`.
|
|
*/
|
|
function add(Signed memory a, int256 b) internal pure returns (Signed memory) {
|
|
return add(a, fromUnscaledInt(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Subtracts two `Signed`s, reverting on overflow.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the difference of `a` and `b`.
|
|
*/
|
|
function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
return Signed(a.rawValue.sub(b.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return the difference of `a` and `b`.
|
|
*/
|
|
function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {
|
|
return sub(a, fromUnscaledInt(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.
|
|
* @param a an int256.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the difference of `a` and `b`.
|
|
*/
|
|
function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {
|
|
return sub(fromUnscaledInt(a), b);
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies two `Signed`s, reverting on overflow.
|
|
* @dev This will "floor" the product.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
// There are two caveats with this computation:
|
|
// 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
|
|
// stored internally as an int256 ~10^59.
|
|
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
|
|
// would round to 3, but this computation produces the result 2.
|
|
// No need to use SafeMath because SFP_SCALING_FACTOR != 0.
|
|
return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.
|
|
* @dev This will "floor" the product.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b an int256.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {
|
|
return Signed(a.rawValue.mul(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
int256 mulRaw = a.rawValue.mul(b.rawValue);
|
|
int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;
|
|
// Manual mod because SignedSafeMath doesn't support it.
|
|
int256 mod = mulRaw % SFP_SCALING_FACTOR;
|
|
if (mod != 0) {
|
|
bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
|
|
int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
|
|
return Signed(mulTowardsZero.add(valueToAdd));
|
|
} else {
|
|
return Signed(mulTowardsZero);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a FixedPoint.Signed.
|
|
* @return the product of `a` and `b`.
|
|
*/
|
|
function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
|
|
// Since b is an int, there is no risk of truncation and we can just mul it normally
|
|
return Signed(a.rawValue.mul(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.
|
|
* @dev This will "floor" the quotient.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a FixedPoint denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
// There are two caveats with this computation:
|
|
// 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
|
|
// 10^41 is stored internally as an int256 10^59.
|
|
// 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
|
|
// would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
|
|
return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.
|
|
* @dev This will "floor" the quotient.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b an int256 denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function div(Signed memory a, int256 b) internal pure returns (Signed memory) {
|
|
return Signed(a.rawValue.div(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.
|
|
* @dev This will "floor" the quotient.
|
|
* @param a an int256 numerator.
|
|
* @param b a FixedPoint denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function div(int256 a, Signed memory b) internal pure returns (Signed memory) {
|
|
return div(fromUnscaledInt(a), b);
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b a FixedPoint denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
|
|
int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);
|
|
int256 divTowardsZero = aScaled.div(b.rawValue);
|
|
// Manual mod because SignedSafeMath doesn't support it.
|
|
int256 mod = aScaled % b.rawValue;
|
|
if (mod != 0) {
|
|
bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
|
|
int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
|
|
return Signed(divTowardsZero.add(valueToAdd));
|
|
} else {
|
|
return Signed(divTowardsZero);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0.
|
|
* @param a a FixedPoint numerator.
|
|
* @param b an int256 denominator.
|
|
* @return the quotient of `a` divided by `b`.
|
|
*/
|
|
function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
|
|
// Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))"
|
|
// similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.
|
|
// This creates the possibility of overflow if b is very large.
|
|
return divAwayFromZero(a, fromUnscaledInt(b));
|
|
}
|
|
|
|
/**
|
|
* @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
|
|
* @dev This will "floor" the result.
|
|
* @param a a FixedPoint.Signed.
|
|
* @param b a uint256 (negative exponents are not allowed).
|
|
* @return output is `a` to the power of `b`.
|
|
*/
|
|
function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {
|
|
output = fromUnscaledInt(1);
|
|
for (uint256 i = 0; i < b; i = i.add(1)) {
|
|
output = mul(output, a);
|
|
}
|
|
}
|
|
} |