While the Solidity compiler automatically checks for underflows and overflows in arithmetic operations starting from version 0.8.x, there are instances where developers may choose to bypass these checks using unchecked math for the sake of gas optimization. However, using unchecked math comes with significant risks that must be carefully considered.
What is Unchecked Math?
Unchecked math refers to arithmetic operations in Solidity where the compiler does not automatically check for overflows and underflows. Normally, when an operation exceeds the maximum or minimum values that a data type can hold, Solidity will revert the transaction to prevent unexpected behavior. However, under certain circumstances, developers may choose to bypass these checks to reduce gas costs by using the unchecked {} block.
Unchecked math can be useful when developers are confident that overflows or underflows are impossible (or properly accounted for) within a specific block of code, as skipping these checks can save gas, especially in tight loops or frequent operations.
In some instances (like UniswapV3's fee implementation, this behavior is even desired)
However, the main reason remains gas efficiency.
The Problem: Overflows and Underflows
Unchecked math, however, comes with a serious risk: if an operation causes an overflow or underflow, it will not revert, potentially allowing incorrect and unintended results to propagate through your contract.
Overflow: When a value exceeds the maximum allowable size for a given data type (e.g., uint256), it wraps around to 0.
Underflow: When a value goes below 0, it wraps around to the maximum value for the type (e.g., uint256 underflow wraps to 2^256 - 1).
From a personal perspective - given the issues i have seen from this usage, I recommend developers to not use this technique if they are not 110% confident in their code.