There are two usual ways to handle error in Solidity: require
and assert
.
To summarise, the biggest difference between require
and assert
is that what developes expect that condition should be.
If developes expect a condition to be normal errors and be safe to be handled, require
comes in.
If they do not expect that condition to be false, meaning it should never happen (in a bug-free world), assert
is necessary.
key | require |
assert |
---|---|---|
return | Error(string) |
Panic(uint256) |
expectation | expected errors that can be handled | unexpected errors that shold not be present |
is it a bug? | maybe not, handle it well ✅ | yes, should fix it 👊 |
Then, which would be raised, Error(string)
or Panic(uint256)
, when developers divide by zero?
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0 <0.9.0;
contract C {
function test() public pure {
uint num = 5 / 0;
}
}
This is apparently a bug, and there does not make sense at all to divide numbers with zero (under most of our mathmetical theory). Therefore, in this case Panic(uint256)
will be raised.
I'll give you an another example. What happens if you pop an item from an empty array?
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0 <0.9.0;
contract C {
uint[] public items;
function test() public {
items.pop();
}
}
Again, this is apparently a bug and it'll raise Panic(uint256)
.
There is a lot more topics to consider to decide between require
and assert
.
But long story short, use require
for normal errors that should be handled, and assert
if that condidion should never happen in production.