library WadRayMath {
  uint256 internal constant WAY = 1e9;
  uint256 internal constant halfWAY = WAY / 2;

  uint256 internal constant WAD = 1e18;
  uint256 internal constant halfWAD = WAD / 2;

  uint256 internal constant RAY = 1e27;
  uint256 internal constant halfRAY = RAY / 2;

  uint256 internal constant WAD_RAY_RATIO = 1e9;

  uint256 internal constant WAY_WAD_RATIO = 1e9;

  uint256 internal constant WAY_RAY_RATIO = 1e18;

  /**
   * @return One ray, 1e27
   **/
  function ray() internal pure returns (uint256) {
    return RAY;
  }

  /**
   * @return One wad, 1e18
   **/

  function wad() internal pure returns (uint256) {
    return WAD;
  }

  /**
 * @return One way, 1e9
 **/

  function way() internal pure returns (uint256) {
    return WAD;
  }

  /**
   * @return Half ray, 1e27/2
   **/
  function halfRay() internal pure returns (uint256) {
    return halfRAY;
  }

  /**
   * @return Half wad, 1e18/2
   **/
  function halfWad() internal pure returns (uint256) {
    return halfWAD;
  }

  /**
 * @return Half way, 1e9/2
 **/
  function halfWay() internal pure returns (uint256) {
    return halfWAY;
  }

  /**
 * @dev Multiplies two way, rounding half up to the nearest way
 * @param a Way
 * @param b Way
 * @return The result of a*b, in way
 **/
  function wayMul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0 || b == 0) {
      return 0;
    }

    require(a <= (type(uint256).max - halfWAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);

    return (a * b + halfWAY) / WAY;
  }

  /**
   * @dev Divides two way, rounding half up to the nearest way
   * @param a Way
   * @param b Way
   * @return The result of a/b, in way
   **/
  function wayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
    uint256 halfB = b / 2;

    require(a <= (type(uint256).max - halfB) / WAY, Errors.MATH_MULTIPLICATION_OVERFLOW);

    return (a * WAY + halfB) / b;
  }

  /**
   * @dev Multiplies two wad, rounding half up to the nearest wad
   * @param a Wad
   * @param b Wad
   * @return The result of a*b, in wad
   **/
  function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0 || b == 0) {
      return 0;
    }

    require(a <= (type(uint256).max - halfWAD) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);

    return (a * b + halfWAD) / WAD;
  }

  /**
   * @dev Divides two wad, rounding half up to the nearest wad
   * @param a Wad
   * @param b Wad
   * @return The result of a/b, in wad
   **/
  function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
    uint256 halfB = b / 2;

    require(a <= (type(uint256).max - halfB) / WAD, Errors.MATH_MULTIPLICATION_OVERFLOW);

    return (a * WAD + halfB) / b;
  }

  /**
   * @dev Multiplies two ray, rounding half up to the nearest ray
   * @param a Ray
   * @param b Ray
   * @return The result of a*b, in ray
   **/
  function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0 || b == 0) {
      return 0;
    }

    require(a <= (type(uint256).max - halfRAY) / b, Errors.MATH_MULTIPLICATION_OVERFLOW);

    return (a * b + halfRAY) / RAY;
  }

  /**
   * @dev Divides two ray, rounding half up to the nearest ray
   * @param a Ray
   * @param b Ray
   * @return The result of a/b, in ray
   **/
  function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
    uint256 halfB = b / 2;

    require(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW);

    return (a * RAY + halfB) / b;
  }

  /**
   * @dev Casts ray down to wad
   * @param a Ray
   * @return a casted to wad, rounded half up to the nearest wad
   **/
  function rayToWad(uint256 a) internal pure returns (uint256) {
    uint256 halfRatio = WAD_RAY_RATIO / 2;
    uint256 result = halfRatio + a;
    require(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW);

    return result / WAD_RAY_RATIO;
  }

  /**
   * @dev Converts wad up to ray
   * @param a Wad
   * @return a converted in ray
   **/
  function wadToRay(uint256 a) internal pure returns (uint256) {
    uint256 result = a * WAD_RAY_RATIO;
    require(result / WAD_RAY_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW);
    return result;
  }

  function rayToWay(uint256 a) internal pure returns (uint256) {
    uint256 halfRatio = WAY_RAY_RATIO / 2;
    uint256 result = halfRatio + a;
    require(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW);

    return result / WAY_RAY_RATIO;
  }

  /**
   * @dev Converts way up to ray
   * @param a Way
   * @return a converted in ray
   **/
  function wayToRay(uint256 a) internal pure returns (uint256) {
    uint256 result = a * WAY_RAY_RATIO;
    require(result / WAY_RAY_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW);
    return result;
  }

  /**
   * @dev Casts wad down to way
   * @param a Wad
   * @return a casted to way, rounded half up to the nearest way
   **/
  function wadToWay(uint256 a) internal pure returns (uint256) {
    uint256 halfRatio = WAY_WAD_RATIO / 2;
    uint256 result = halfRatio + a;
    require(result >= halfRatio, Errors.MATH_ADDITION_OVERFLOW);

    return result / WAY_WAD_RATIO;
  }

  /**
  * @dev Converts way up to wad
  * @param a Way
  * @return a converted in wad
  **/
  function wayToWad(uint256 a) internal pure returns (uint256) {
    uint256 result = a * WAY_WAD_RATIO;
    require(result / WAY_WAD_RATIO == a, Errors.MATH_MULTIPLICATION_OVERFLOW);
    return result;
  }

}
/**
 * @title WadRayMath library
 * @author Aave
 * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)
 **/
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
  require(b != 0, Errors.MATH_DIVISION_BY_ZERO);
  uint256 halfB = b / 2;

  require(a <= (type(uint256).max - halfB) / RAY, Errors.MATH_MULTIPLICATION_OVERFLOW);

  return (a * RAY + halfB) / b;
}

/**
 * @dev Divides two ray, rounding half up to the nearest ray
 * @param a Ray
 * @param b Ray
 * @return The result of a/b, in ray
 **/