Integer Overflow and Underflow
What are Overflows or Underflows?
In previous versions of Solidity (prior Solidity 0.8.x) an integer would automatically roll-over to a lower or higher number. If you would decrement 0 by 1 (0-1) on an unsigned integer, the result would not be -1, or an error, the result would simple be: MAX(uint).
For this example I want to use uint8. We havenāt used different types of uint yet. In our previous example worked with uint256, but bear with me for a moment. Uint8 is going from 0 to 2^8 - 1. In other words: uint8 ranges from 0 to 255. If you increment 255 it will automatically be 0, if you decrement 0, it will become 255. No warnings, no errors. For example, this can become problematic, if you store a token-balance in a variable and decrement it without checking.
Letās do an actual example!
Sample Smart Contract
Create a new Smart Contract with the name āRolloverExample.solā. Weāre going to use Solidity 0.7 for this example, as in Solidity 0.8 this behavior is different.
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.7.0;
contract RolloverExample {
uint8 public myUint8;
function decrement() public {
myUint8--;
}
function increment() public {
myUint8++;
}
}
Letās deploy the Smart Contract and see what happens if we call decrement.
Initially, myUint8 is 0:
If you press the ādecrementā button, then the myUint8 is decremented by one. Letās see what happens, and also observe the Remix console:
The transaction works perfectly. No errors occur. If you retrieve the value for myUint8 then you see itās 255:
Try yourself what happens when you increment again. Does it roll over again without a warning?
Now you see one of the quirks with Solidity. Itās not completely unique to Solidity, but definitely something to be aware of. This is where Libraries like SafeMathā were invented, which you will see later.
But what happened in Solidity 0.8?
Solidity 0.8 Difference
In Solidity 0.8, the compiler will automatically take care of checking for overflows and underflows. Letās run the same example with Solidity 0.8. Create a new file and fill in the following Smart Contract:
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.0;
contract RolloverExample2 {
uint8 public myUint8;
function decrement() public {
myUint8--;
}
function increment() public {
myUint8++;
}
}
Deploy the new version and try to hit ādecrementā. Now you will get an error in the Remix console:
Your variable āmyUint8ā will remain 0, because it cannot roll over anymore:
But what if you actually want to roll over? Then there is a new āuncheckedā block you can wrap your variables around:
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.0;
contract RolloverExample2 {
uint8 public myUint8;
function decrement() public {
unchecked {
myUint8--;
}
}
function increment() public {
unchecked {
myUint8++;
}
}
}
Then everything works again as you know it from previous Solidity versions. This is such an important quirks of Solidity that I wanted to bring it up early. Now, letās go back to some lighter topics.