openzeppelin-contracts
openzeppelin-contracts copied to clipboard
Support Saturation Arithmetic Operations
Description
Adds gas efficient saturating arithmetic operators, those operators are useful when both overflow and revert are not desired. This PR also optimizes and remove unnecessary branching from various Math methods.
Motivation
If you want to write some formula, but don't want neither wrapping and reverts, the only option is using the Math.try*
methods, which can't be used in chain and make the code less readable.
Ex: Make sure there're at least 100_000
gas units left before calling an external contract, otherwise revert.
// “all but one 64th", reference: https://eips.ethereum.org/EIPS/eip-150
uint256 gasAvailable = gasleft().saturatingSub(5000).saturatingMul(63) / 64;
require(gasAvailable >= 100_000, "not enough gas left to call contract");
// ... call contract
The equivalent code using Math.try*
is less readable and less efficient.
(bool success, uint256 gasAvailable) = gasleft().trySub(5000);
gasAvailable = Math.ternary(success, gasAvailable, 0);
// “all but one 64th", reference: https://eips.ethereum.org/EIPS/eip-150
(success, gasAvailable) = gasAvailable.tryMul(63);
gasAvailable = Math.ternary(success, gasAvailable, type(uint256).max);
gasAvailable /= 64;
require(gasAvailable >= 100_000, "not enough gas left to call contract");
// ... call contract