<100 subscribers
How I Learned to Stop Worrying and Love the Compiler
Back in the dark ages of Solidity (before version 0.8.0), numbers in smart contracts behaved like toddlers with no adult supervision. Add uint256
+ uint256
? Sure, no problem — even if it wraps around like a cursed clock and silently goes from 2^256 - 1
to 0
.
Let me paint a scene:
“Behold! My function mints 1000 tokens. Simple math:
balance += 1000
.
But oh no — balance was already at max uint256. And now… it’s ZERO!?”
Overflow.
Its evil twin? Underflow.
Try subtracting 1
from 0
, and you just summoned a new god of unintended consequences.
This wasn’t just annoying. It was disastrous. Millions of dollars could be lost to what was essentially bad accounting. Enter: SafeMath, OpenZeppelin’s gift to Ethereum-kind.
OpenZeppelin's SafeMath
was like the Gandalf of Solidity math. It stood between you and ruin, shouting, "YOU SHALL NOT UNDERFLOW!"
It worked like this:
SafeMath for uint256;
uint256 safeAmount = balance.sub(1); // Throws if balance < 1
No more silent errors. If something shady happened, it would revert like a responsible adult.
SafeMath became so iconic, it was almost a rite of passage to write:
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
If your contract didn’t use SafeMath, it basically had a death wish.
Then came Solidity 0.8.0 and everything changed. Overflow? Underflow?
“I gotchu fam.” – The Compiler
The Solidity team built checked arithmetic directly into the language. Now:
uint256 a = type(uint256).max;
a += 1; // Reverts automatically. No SafeMath needed.
Suddenly, using SafeMath was like carrying a giant umbrella indoors — technically not harmful, but kinda redundant and slightly awkward.
Even OpenZeppelin acknowledged the change and began phasing SafeMath out for uint256
.
While SafeMath (or now the compiler) handles overflows and underflows, there’s one sneaky villain that still roams free: rounding errors in division.
uint256 result = 5 / 2; // equals 2, not 2.5
Solidity doesn’t do floating points. So, it rounds down like a ruthless landlord.
This can break DeFi protocols, reward distributions, and even DAO votes.
Use point-math libraries like ABDKMath64x64 or FixedPoint
from Uniswap.
Apply BODMAS rules religiously. Yes, math order matters.
Introduce minimums in calculations, e.g., require that denominator > 0
, or use:
require(x >= y, "Underflow");
When splitting tokens or shares, design the logic with dust handling (i.e., leftovers) in mind.
Use SafeCast
to prevent dangerous downcasting (e.g., from uint256
to uint8
).
The "Oops, We’re All Billionaires" Bug – A token contract without SafeMath minted 2^256
tokens to one address.
The “Why Is My Balance Negative?” Mystery – A DeFi lending pool returned negative interest. Spoiler: It was an underflow.
The DAO that Paid Everyone but Kept No Dust – A community split funds using division and lost hundreds of tokens to rounding.
SafeMath is no longer mandatory thanks to Solidity’s maturing compiler, but the lessons it taught us remain critical. Don't trust arithmetic blindly. Handle your rounding like a responsible adult. And never, ever forget that numbers are cold, uncaring beasts unless you tame them with logic.
Pre-0.8.0 Solidity: Use SafeMath
or risk disasters.
Post-0.8.0 Solidity: Compiler protects against over/underflow.
Rounding: Still dangerous. Use fixed-point math libraries.
Best practice today: Write safe, clear, math-aware code. And maybe light a candle in memory of SafeMath
.
Fabian Owuor