@@ -51,8 +51,8 @@ library Math {
5151 function tryAdd (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
5252 unchecked {
5353 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 );
5656 }
5757 }
5858
@@ -61,8 +61,9 @@ library Math {
6161 */
6262 function trySub (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
6363 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);
6667 }
6768 }
6869
@@ -71,13 +72,14 @@ library Math {
7172 */
7273 function tryMul (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
7374 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 );
7875 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);
8183 }
8284 }
8385
@@ -86,8 +88,11 @@ library Math {
8688 */
8789 function tryDiv (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
8890 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+ }
9196 }
9297 }
9398
@@ -96,11 +101,38 @@ library Math {
96101 */
97102 function tryMod (uint256 a , uint256 b ) internal pure returns (bool success , uint256 result ) {
98103 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+ }
101109 }
102110 }
103111
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+
104136 /**
105137 * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
106138 *
@@ -192,7 +224,7 @@ library Math {
192224
193225 // Make division exact by subtracting the remainder from [high low].
194226 uint256 remainder;
195- assembly {
227+ assembly ( "memory-safe" ) {
196228 // Compute remainder using mulmod.
197229 remainder := mulmod (x, y, denominator)
198230
@@ -205,7 +237,7 @@ library Math {
205237 // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
206238
207239 uint256 twos = denominator & (0 - denominator);
208- assembly {
240+ assembly ( "memory-safe" ) {
209241 // Divide denominator by twos.
210242 denominator := div (denominator, twos)
211243
0 commit comments