Branch data Line data Source code
1 : : // SPDX-License-Identifier: BUSL-1.1
2 : : pragma solidity ^0.8.0;
3 : :
4 : : /**
5 : : * @title WadRayMath library
6 : : * @author Aave
7 : : * @notice Provides functions to perform calculations with Wad and Ray units
8 : : * @dev Provides mul and div function for wads (decimal numbers with 18 digits of precision) and rays (decimal numbers
9 : : * with 27 digits of precision)
10 : : * @dev Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down.
11 : : */
12 : : library WadRayMath {
13 : : // HALF_WAD and HALF_RAY expressed with extended notation as constant with operations are not supported in Yul assembly
14 : : uint256 internal constant WAD = 1e18;
15 : : uint256 internal constant HALF_WAD = 0.5e18;
16 : :
17 : : uint256 internal constant RAY = 1e27;
18 : : uint256 internal constant HALF_RAY = 0.5e27;
19 : :
20 : : uint256 internal constant WAD_RAY_RATIO = 1e9;
21 : :
22 : : /**
23 : : * @dev Multiplies two wad, rounding half up to the nearest wad
24 : : * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
25 : : * @param a Wad
26 : : * @param b Wad
27 : : * @return c = a*b, in wad
28 : : */
29 : : function wadMul(uint256 a, uint256 b) internal pure returns (uint256 c) {
30 : : // to avoid overflow, a <= (type(uint256).max - HALF_WAD) / b
31 : : assembly {
32 : 1006 : if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_WAD), b))))) {
33 : 314 : revert(0, 0)
34 : : }
35 : :
36 : 692 : c := div(add(mul(a, b), HALF_WAD), WAD)
37 : : }
38 : : }
39 : :
40 : : /**
41 : : * @dev Divides two wad, rounding half up to the nearest wad
42 : : * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
43 : : * @param a Wad
44 : : * @param b Wad
45 : : * @return c = a/b, in wad
46 : : */
47 : : function wadDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
48 : : // to avoid overflow, a <= (type(uint256).max - halfB) / WAD
49 : : assembly {
50 : 23533 : if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), WAD))))) {
51 : 169 : revert(0, 0)
52 : : }
53 : :
54 : 23364 : c := div(add(mul(a, WAD), div(b, 2)), b)
55 : : }
56 : : }
57 : :
58 : : /**
59 : : * @notice Multiplies two ray, rounding half up to the nearest ray
60 : : * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
61 : : * @param a Ray
62 : : * @param b Ray
63 : : * @return c = a raymul b
64 : : */
65 : : function rayMul(uint256 a, uint256 b) internal pure returns (uint256 c) {
66 : : // to avoid overflow, a <= (type(uint256).max - HALF_RAY) / b
67 : : assembly {
68 : 719133 : if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_RAY), b))))) {
69 : 0 : revert(0, 0)
70 : : }
71 : :
72 : 719133 : c := div(add(mul(a, b), HALF_RAY), RAY)
73 : : }
74 : : }
75 : :
76 : : /**
77 : : * @notice Divides two ray, rounding half up to the nearest ray
78 : : * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
79 : : * @param a Ray
80 : : * @param b Ray
81 : : * @return c = a raydiv b
82 : : */
83 : : function rayDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
84 : : // to avoid overflow, a <= (type(uint256).max - halfB) / RAY
85 : : assembly {
86 : 280644 : if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), RAY))))) {
87 : 0 : revert(0, 0)
88 : : }
89 : :
90 : 280644 : c := div(add(mul(a, RAY), div(b, 2)), b)
91 : : }
92 : : }
93 : :
94 : : /**
95 : : * @dev Casts ray down to wad
96 : : * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
97 : : * @param a Ray
98 : : * @return b = a converted to wad, rounded half up to the nearest wad
99 : : */
100 : : function rayToWad(uint256 a) internal pure returns (uint256 b) {
101 : : assembly {
102 : 2003 : b := div(a, WAD_RAY_RATIO)
103 : 2003 : let remainder := mod(a, WAD_RAY_RATIO)
104 : 2003 : if iszero(lt(remainder, div(WAD_RAY_RATIO, 2))) {
105 : 558 : b := add(b, 1)
106 : : }
107 : : }
108 : : }
109 : :
110 : : /**
111 : : * @dev Converts wad up to ray
112 : : * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
113 : : * @param a Wad
114 : : * @return b = a converted in ray
115 : : */
116 : : function wadToRay(uint256 a) internal pure returns (uint256 b) {
117 : : // to avoid overflow, b/WAD_RAY_RATIO == a
118 : : assembly {
119 : 1945 : b := mul(a, WAD_RAY_RATIO)
120 : :
121 : 1945 : if iszero(eq(div(b, WAD_RAY_RATIO), a)) {
122 : 112 : revert(0, 0)
123 : : }
124 : : }
125 : : }
126 : : }
|