Answer 1) We never want behavior that leads to over/underflow*. The reason the "unchecked" keyword exists is to allow Solidity developers to write more efficient programs. The default "checked" behavior costs more gas when adding/diving/multiplying, because under-the-hood those checks are implemented as a series of opcodes that, prior to performing the actual arithmetic, check for under/overflow and revert if it is detected. So if you're a Solidity developer who needs to do some math in 0.8.0 or greater, and you can statically determine there is no possible way for your arithmetic to under/overflow (maybe because you have your own "if" statement which checks that the numbers being added are never greater than, say, 100), then you can surround the arithmetic in an "unchecked" block.
tl;dr: "unchecked" exists in order to save gas
Answer 2) Correct. You do not need to include SafeMath in any of your contracts compiled using version 0.8.0 and above, because now the compiler implements what SafeMath does.
*The only reason I can think of for wanting this behavior is for educational reasons: If I'm writing an intro to Solidity book and I'd like to show how modular arithmetic works, I would like under/overflow to occur so I can show students how it works.
Solidity has no concept of floating-point numbers, so you need to work on an integer representation of your number.
Your idea is good, but the order of operations won't work on integers.
result = ((x - low) / (high - low))
Will always return a number between 0 and 1 by definition (unless you allow x < low
or x > high
but it wouldn't make any sense). Solidity only deals with integers, so it will return either 0 or 1, nothing in between. When you multiply this value by 100, you get either 0 or 100...
You need to multiply before doing the division, to immediately generate a number between 0 and 100 (or more depending on the precision that you are looking for).
This code returns the percentage that you are looking for when given 544386085
as parameter : 72
.
pragma solidity ^0.7.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/math/SafeMath.sol";
contract Percentage {
using SafeMath for uint256;
uint256 high = 632885842;
uint256 low = 316442921;
uint256 precision = 2;
function getPercentage(uint256 x) public view returns (uint256) {
require(x >= low, "Number too low");
require(x <= high, "Number too high");
return x.sub(low).mul(10 ** precision) / high.sub(low);
}
}
Btw, SafeMath is superfluous here, since if you know that x >= low
and x <= high
(due to the require statements) there is no overflow / undeflow possible.
Best Answer
The Solidity v0.8.0 Breaking Changes Docs says:
And Checking the GitHub commits for SafeMath.sol I found this commit made on February 2021 were they added the comment:
The comment was later Reviewed in this other commit, with the title Review wording of SafeMath need in Solidity 0.8, and changed to:
Checking the first commit linked, we can also see a comment made in the SignedSafeMath.sol contract that said:
I think that's like saying they are checking for overflows.
Also, the wording changes seems to be aligned with the other answer here, noticing that you may reuse safemath as library to improve operation cost for example, as the default one is more expensive now according to the docs, or to improve the ** operator for bases different to 2 or 10.
But it does seems that SafeMath is indeed generally not needed starting with Solidity 0.8
Also the top comment in the safemath library now says:
Now the add function is :
And an earlier implementation was: