contract Exponential is CarefulMath {
	uint256 constant expScale = 1e18;
	uint256 constant halfExpScale = expScale / 2;
	uint256 constant mantissaOne = expScale;

	struct Exp {
		uint256 mantissa;
	}

	/**
	 * @dev Creates an exponential from numerator and denominator values.
	 *      Note: Returns an error if (`num` * 10e18) > MAX_INT,
	 *            or if `denom` is zero.
	 */
	function getExp(uint256 num, uint256 denom)
		internal
		pure
		returns (MathError, Exp memory)
	{
		(MathError err0, uint256 scaledNumerator) = mulUInt(num, expScale);
		if (err0 != MathError.NO_ERROR) {
			return (err0, Exp({ mantissa: 0 }));
		}

		(MathError err1, uint256 rational) = divUInt(scaledNumerator, denom);
		if (err1 != MathError.NO_ERROR) {
			return (err1, Exp({ mantissa: 0 }));
		}

		return (MathError.NO_ERROR, Exp({ mantissa: rational }));
	}

	/**
	 * @dev Adds two exponentials, returning a new exponential.
	 */
	function addExp(Exp memory a, Exp memory b)
		internal
		pure
		returns (MathError, Exp memory)
	{
		(MathError error, uint256 result) = addUInt(a.mantissa, b.mantissa);

		return (error, Exp({ mantissa: result }));
	}

	/**
	 * @dev Subtracts two exponentials, returning a new exponential.
	 */
	function subExp(Exp memory a, Exp memory b)
		internal
		pure
		returns (MathError, Exp memory)
	{
		(MathError error, uint256 result) = subUInt(a.mantissa, b.mantissa);

		return (error, Exp({ mantissa: result }));
	}

	/**
	 * @dev Multiply an Exp by a scalar, returning a new Exp.
	 */
	function mulScalar(Exp memory a, uint256 scalar)
		internal
		pure
		returns (MathError, Exp memory)
	{
		(MathError err0, uint256 scaledMantissa) = mulUInt(a.mantissa, scalar);
		if (err0 != MathError.NO_ERROR) {
			return (err0, Exp({ mantissa: 0 }));
		}

		return (MathError.NO_ERROR, Exp({ mantissa: scaledMantissa }));
	}

	/**
	 * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
	 */
	function mulScalarTruncate(Exp memory a, uint256 scalar)
		internal
		pure
		returns (MathError, uint256)
	{
		(MathError err, Exp memory product) = mulScalar(a, scalar);
		if (err != MathError.NO_ERROR) {
			return (err, 0);
		}

		return (MathError.NO_ERROR, truncate(product));
	}

	/**
	 * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
	 */
	function mulScalarTruncateAddUInt(
		Exp memory a,
		uint256 scalar,
		uint256 addend
	) internal pure returns (MathError, uint256) {
		(MathError err, Exp memory product) = mulScalar(a, scalar);
		if (err != MathError.NO_ERROR) {
			return (err, 0);
		}

		return addUInt(truncate(product), addend);
	}

	/**
	 * @dev Divide an Exp by a scalar, returning a new Exp.
	 */
	function divScalar(Exp memory a, uint256 scalar)
		internal
		pure
		returns (MathError, Exp memory)
	{
		(MathError err0, uint256 descaledMantissa) =
			divUInt(a.mantissa, scalar);
		if (err0 != MathError.NO_ERROR) {
			return (err0, Exp({ mantissa: 0 }));
		}

		return (MathError.NO_ERROR, Exp({ mantissa: descaledMantissa }));
	}

	/**
	 * @dev Divide a scalar by an Exp, returning a new Exp.
	 */
	function divScalarByExp(uint256 scalar, Exp memory divisor)
		internal
		pure
		returns (MathError, Exp memory)
	{
		/*
          We are doing this as:
          getExp(mulUInt(expScale, scalar), divisor.mantissa)

          How it works:
          Exp = a / b;
          Scalar = s;
          `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
        */
		(MathError err0, uint256 numerator) = mulUInt(expScale, scalar);
		if (err0 != MathError.NO_ERROR) {
			return (err0, Exp({ mantissa: 0 }));
		}
		return getExp(numerator, divisor.mantissa);
	}

	/**
	 * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
	 */
	function divScalarByExpTruncate(uint256 scalar, Exp memory divisor)
		internal
		pure
		returns (MathError, uint256)
	{
		(MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
		if (err != MathError.NO_ERROR) {
			return (err, 0);
		}

		return (MathError.NO_ERROR, truncate(fraction));
	}

	/**
	 * @dev Multiplies two exponentials, returning a new exponential.
	 */
	function mulExp(Exp memory a, Exp memory b)
		internal
		pure
		returns (MathError, Exp memory)
	{
		(MathError err0, uint256 doubleScaledProduct) =
			mulUInt(a.mantissa, b.mantissa);
		if (err0 != MathError.NO_ERROR) {
			return (err0, Exp({ mantissa: 0 }));
		}

		// We add half the scale before dividing so that we get rounding instead of truncation.
		//  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
		// Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
		(MathError err1, uint256 doubleScaledProductWithHalfScale) =
			addUInt(halfExpScale, doubleScaledProduct);
		if (err1 != MathError.NO_ERROR) {
			return (err1, Exp({ mantissa: 0 }));
		}

		(MathError err2, uint256 product) =
			divUInt(doubleScaledProductWithHalfScale, expScale);
		// The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
		assert(err2 == MathError.NO_ERROR);

		return (MathError.NO_ERROR, Exp({ mantissa: product }));
	}

	/**
	 * @dev Multiplies two exponentials given their mantissas, returning a new exponential.
	 */
	function mulExp(uint256 a, uint256 b)
		internal
		pure
		returns (MathError, Exp memory)
	{
		return mulExp(Exp({ mantissa: a }), Exp({ mantissa: b }));
	}

	/**
	 * @dev Multiplies three exponentials, returning a new exponential.
	 */
	function mulExp3(
		Exp memory a,
		Exp memory b,
		Exp memory c
	) internal pure returns (MathError, Exp memory) {
		(MathError err, Exp memory ab) = mulExp(a, b);
		if (err != MathError.NO_ERROR) {
			return (err, ab);
		}
		return mulExp(ab, c);
	}

	/**
	 * @dev Divides two exponentials, returning a new exponential.
	 *     (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
	 *  which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
	 */
	function divExp(Exp memory a, Exp memory b)
		internal
		pure
		returns (MathError, Exp memory)
	{
		return getExp(a.mantissa, b.mantissa);
	}

	/**
	 * @dev Truncates the given exp to a whole number value.
	 *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
	 */
	function truncate(Exp memory exp) internal pure returns (uint256) {
		// Note: We are not using careful math here as we're performing a division that cannot fail
		return exp.mantissa / expScale;
	}

	/**
	 * @dev Checks if first Exp is less than second Exp.
	 */
	function lessThanExp(Exp memory left, Exp memory right)
		internal
		pure
		returns (bool)
	{
		return left.mantissa < right.mantissa; //TODO: Add some simple tests and this in another PR yo.
	}

	/**
	 * @dev Checks if left Exp <= right Exp.
	 */
	function lessThanOrEqualExp(Exp memory left, Exp memory right)
		internal
		pure
		returns (bool)
	{
		return left.mantissa <= right.mantissa;
	}

	/**
	 * @dev Checks if left Exp > right Exp.
	 */
	function greaterThanExp(Exp memory left, Exp memory right)
		internal
		pure
		returns (bool)
	{
		return left.mantissa > right.mantissa;
	}

	/**
	 * @dev returns true if Exp is exactly zero
	 */
	function isZeroExp(Exp memory value) internal pure returns (bool) {
		return value.mantissa == 0;
	}
}
/**
 * @title Exponential module for storing fixed-decision decimals
 * @author Compound
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
function addExp(Exp memory a, Exp memory b)
	internal
	pure
	returns (MathError, Exp memory)
{
	(MathError error, uint256 result) = addUInt(a.mantissa, b.mantissa);

	return (error, Exp({ mantissa: result }));
}

/**
 	 * @dev Adds two exponentials, returning a new exponential.
 	 */