Integer overflow and underflow vulnerabilities in Solidity contracts
unchecked { } blocks, ORassembly { } / Yul blocks, ORuint8(uint256Var)), OR<<, >>) on values near type boundaries// Pre-0.8.0: wraps silently
uint256 balance = 0;
balance -= 1; // Underflows to 2^256 - 1
// Post-0.8.0 bypass via unchecked block
unchecked {
uint256 x = type(uint256).max;
x += 1; // Wraps to 0, no revert
}
// Type downcast truncation (all versions)
uint256 big = 256;
uint8 small = uint8(big); // Silently truncates to 0
// Assembly arithmetic (all versions)
assembly {
let x := sub(0, 1) // Underflows to max uint256
}
unchecked blocks and audit every arithmetic operation inside themassembly blocks and audit all add, sub, mul, div, shl, shr operations withinuint8(, uint16(, int8(, etc. — verify the source value is bounds-checked before casting<<, >>) and verify the operand cannot overflow the target typeunchecked and assembly blocks (automatically checked)unchecked blocks used only for loop counter increments (i++) where overflow is impossible due to bounded looprequire(x <= type(uint8).max))SafeMath for all arithmeticunchecked blocks to only provably safe operations (e.g., bounded loop counters)SafeCast library for all type downcasts// Safe downcast
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
uint8 small = SafeCast.toUint8(big); // Reverts if big > 255