@@ -51,8 +51,8 @@ library Math {
51
51
function tryAdd (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
52
52
unchecked {
53
53
uint256 c = a + b;
54
- if (c < a) return ( false , 0 ) ;
55
- return ( true , c );
54
+ success = c >= a ;
55
+ result = c * SafeCast. toUint (success );
56
56
}
57
57
}
58
58
@@ -61,8 +61,9 @@ library Math {
61
61
*/
62
62
function trySub (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
63
63
unchecked {
64
- if (b > a) return (false , 0 );
65
- return (true , a - b);
64
+ uint256 c = a - b;
65
+ success = c <= a;
66
+ result = c * SafeCast.toUint (success);
66
67
}
67
68
}
68
69
@@ -71,13 +72,14 @@ library Math {
71
72
*/
72
73
function tryMul (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
73
74
unchecked {
74
- // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
75
- // benefit is lost if 'b' is also tested.
76
- // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
77
- if (a == 0 ) return (true , 0 );
78
75
uint256 c = a * b;
79
- if (c / a != b) return (false , 0 );
80
- return (true , c);
76
+ assembly ("memory-safe" ) {
77
+ // Only true when the multiplication doesn't overflow
78
+ // (c / a == b) || (a == 0)
79
+ success := or (eq (div (c, a), b), iszero (a))
80
+ }
81
+ // equivalent to: success ? c : 0
82
+ result = c * SafeCast.toUint (success);
81
83
}
82
84
}
83
85
@@ -86,8 +88,11 @@ library Math {
86
88
*/
87
89
function tryDiv (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
88
90
unchecked {
89
- if (b == 0 ) return (false , 0 );
90
- return (true , a / b);
91
+ success = b > 0 ;
92
+ assembly ("memory-safe" ) {
93
+ // The `DIV` opcode returns zero when the denominator is 0.
94
+ result := div (a, b)
95
+ }
91
96
}
92
97
}
93
98
@@ -96,11 +101,38 @@ library Math {
96
101
*/
97
102
function tryMod (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
98
103
unchecked {
99
- if (b == 0 ) return (false , 0 );
100
- return (true , a % b);
104
+ success = b > 0 ;
105
+ assembly ("memory-safe" ) {
106
+ // The `MOD` opcode returns zero when the denominator is 0.
107
+ result := mod (a, b)
108
+ }
101
109
}
102
110
}
103
111
112
+ /**
113
+ * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
114
+ */
115
+ function saturatingAdd (uint256 a , uint256 b ) internal pure returns (uint256 ) {
116
+ (bool success , uint256 result ) = tryAdd (a, b);
117
+ return ternary (success, result, type (uint256 ).max);
118
+ }
119
+
120
+ /**
121
+ * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
122
+ */
123
+ function saturatingSub (uint256 a , uint256 b ) internal pure returns (uint256 ) {
124
+ (, uint256 result ) = trySub (a, b);
125
+ return result;
126
+ }
127
+
128
+ /**
129
+ * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
130
+ */
131
+ function saturatingMul (uint256 a , uint256 b ) internal pure returns (uint256 ) {
132
+ (bool success , uint256 result ) = tryMul (a, b);
133
+ return ternary (success, result, type (uint256 ).max);
134
+ }
135
+
104
136
/**
105
137
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
106
138
*
@@ -192,7 +224,7 @@ library Math {
192
224
193
225
// Make division exact by subtracting the remainder from [high low].
194
226
uint256 remainder;
195
- assembly {
227
+ assembly ( "memory-safe" ) {
196
228
// Compute remainder using mulmod.
197
229
remainder := mulmod (x, y, denominator)
198
230
@@ -205,7 +237,7 @@ library Math {
205
237
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
206
238
207
239
uint256 twos = denominator & (0 - denominator);
208
- assembly {
240
+ assembly ( "memory-safe" ) {
209
241
// Divide denominator by twos.
210
242
denominator := div (denominator, twos)
211
243
0 commit comments