# Exploring Solidity 0.8’s Arithmetic and Error Handling

Author: Markus Waas

Published: 2020-12-18T20:22:35.000Z

Updated: 2026-09-13T14:25:30.000Z

Source: [https://soliditydeveloper.com/solidity-0.8](<https://soliditydeveloper.com/solidity-0.8>)

## Compatibility and review

Before you start

A release-day article about Solidity 0.8.0. Its beta-era tool-support checklist is historical. Checked arithmetic remains the default outside unchecked blocks; later 0.8 releases also support custom errors, so not every revert uses Error(string).

[Official reference](<https://docs.soliditylang.org/en/latest/080-breaking-changes.html>)

We are getting closer to that Solidity 1.0 release (unless of course after 0.9 comes 0.10). Now Solidity [0.8 has been released](<https://blog.soliditylang.org/2020/12/16/solidity-v0.8.0-release-announcement/>) only 5 months after the [0.7 release](<https://blog.soliditylang.org/2020/07/28/solidity-v0.7.0-release-announcement/>)!

Let's explore how you can migrate your contracts today...

![Baby Yoda Release](<https://cdn0.scrvt.com/b095ee27d37b3d7b6b150adba9ac6ec8/355d4464dce55095/b32327a28db3/v/418778b03c08/baby-yoda-release.jpg>)

## New features & how to use them

Let's look at the two big new features which are the integrated SafeMath and the new error handling.

### 1. Integrated SafeMath

![SafeMath Meme](<https://cdn0.scrvt.com/b095ee27d37b3d7b6b150adba9ac6ec8/7a7eff08f474db0b/669a21d51df0/v/a96c2bf8e22b/safemath-meme.jpeg>)

That's right, you don't need to import the Openzeppelin [SafeMath](<https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol>) anymore. Best of all, you don't need to do anything to activate the Solidity integrated SafeMath. Just write `a + b` and it will automatically revert on overflows.

You might see errors in tools like Remix as 0.8 is not fully supported yet. For example overflows don't give you the exact reason yet:

```bash
 transact to Solidity08.test errored: VM error: revert. revert 
```

But this should change in the future.

What if you actually want the code to be able to overflow? Or you are just way too concerned about gas costs?

You can deactivate it by wrapping it with an `unchecked` form like this:

```solidity
contract Solidity08 {
    function test() external pure returns(uint256) {
        // Solidity 0.8 built-in checked arithmetic
        // will revert

        uint256 x = 0;
        x--;

        return x;
    }
}
```

```solidity
contract Solidity08 {
    function test() external pure returns(uint256) {
        // Solidity 0.8 unchecked arithmetic
        // will return type(uint256).max

        uint256 x = 0;
        unchecked { x--; }

        return x;
    }
}
```

### 2. Invalid Opcode replaced by Reverting

Up until now certain operations caused the execution of the `INVALID` opcode. The issue with this opcode is that it's consuming all remaining gas. This is obviously bad and just not necessary. Why would you waste the gas and donate it to the miners?

For more details, check out the difference between `revert` and `assert` [here](<https://medium.com/blockchannel/the-use-of-revert-assert-and-require-in-solidity-and-the-new-revert-opcode-in-the-evm-1a3a7990e06e>).

Now Solidity is using the `revert` opcode. To distinguish between regular reverts and these system reverts, Solidity prefixes the return data with an identifier:

- **Regular Revert Errors** start with the first four bytes of `keccak256(Error(string))` which equals `0x08c379a0`
- **System Internal Errors** start with the first four bytes of `keccak256(Panic(uint256))` which equals `0x4e487b71`

The `Error(string)` selector describes reverts with a reason string. Empty reverts have no such payload, and later Solidity 0.8 releases add custom errors with their own selectors. The `Panic(uint256)` distinction here describes compiler-generated runtime checks.

Panics come with an additional error identifier. Currently available panics are

- **0x01**: A failing `assert` condition.
- **0x11**: SafeMath over-/under-flows.
- **0x12**: Divide by 0.
- **0x21**: Conversion into non-existent enum type.
- **0x22**: Incorrectly encoded storage byte array.
- **0x31**: `pop()` on an empty array.
- **0x32**: Index out of bounds exception.
- **0x41**: Allocating too much memory or creating a too large array.
- **0x51**: Calling a zero-initialized variable of internal function type.

For further details see the new Error handling section in the documentation [here](<https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require>).

![Revert with panic](<https://cdn0.scrvt.com/b095ee27d37b3d7b6b150adba9ac6ec8/3f212024d4646684/1ce7e322fc14/v/607f5fe342b1/revert-with-panic.jpeg>)

## Should you migrate already?

Before we see *how* to migrate, let's first discuss *should* you migrate?

Depending on the time you read this, the answer may differ. Right now it was only just released and proper support from tools doesn't really exist yet. On top it's not heavily tested and used yet. Expect potential bugs!

What does this mean for you?

Let's go through our checklist.

- Has Solidity 0.8 been out for several months now, all tools support it and even Openzeppelin Contracts are migrated to 0.8?

## How to migrate to Solidity 0.8

Alright you said yes to the migration after going through the checklist? Let's see how this can be done...

The migration should in most case be pretty straight-forward. Only some cases where you do strange type conversions could become more difficult.

The changes you have to make for the migration include:

- `ABIEncoderV2` is now the default and automatically activated. The encoder wasn't experimental anymore since 0.6 but the 'pragma experimental' name was just kept for legacy reasons. Now you won't need to add the line anymore.
- Remove any Openzeppelin SafeMath, you won't need it anymore.
- Some type conversions might be required.
- Combine
- Change `x**y**z` to `(x**y)**z `as the default order of execution changed.
- Change type `byte` to bytes1

I've left a few details out, for the full changelog and break down of all changes in detail, check out the documentation [here](<https://docs.soliditylang.org/en/latest/080-breaking-changes.html>).
