Integer types in Solidity have fixed size. For example, uint8 is 8-bit long, so the number with type uint8 is in the range from 0 to 2**8 - 1 (255).
Imagine there’s a number valued 255 with type uint8, what will happen when we add it by 1, or the number is 0 and we sub it by 1. So when we do arithmetic operations, we will run into two exceptions: the former is called overflow and the latter is called underflow.
There are two modes when performing arithmetic operations: wrapping (or unchecked) and checked. And checked mode is the default.
checked - Will revert on over- and underflow
unchecked - Will wrap on over- and underflow
Here, wrapping means we add a number valued 255 with type uint8 by 1, it will go down to value 0, like a clock goes from 23:59 to 00:00.
All arithmetic operations revert on over- and underflow by default. If you want to wrap the operation results, you can use unchecked :
contract A {
function test(uint x, uint y) public returns (uint) {
// This will revert on overflow
uint a = x + y;
// This will revert on underflow
uint b = x - y;
// This will wrap on overflow
uint c;
unchecked {
c = x + y;
}
return c;
}
}
Bitwise operators do not perform over- and underflow checks.
You can call functions in unchecked block, but these functions don’t inherit the property.
Before Solidity version 0.8, the compiler won’t check over- and underflow, instead of wrapping it, so we need to do the checks by manual. e.g.
library SafeMath {
function add(uint a, uint b) internal returns (uint) {
unchecked {
uint c = a + b;
require(c >= a, 'err: overflow');
return c;
}
}
}
After Solidity 0.8, the compiler will check over- and underflow, so we don’t need SafeMath library anymore.

