10
function nice(uint8 x) public returns(uint8 z) {
    uint8 z = 0;
    z = z + 240;
    require(z = z + x, "overflow");
}

I have been using this code with Solidity prior to the 0.8 update. If there was an overflow, the transaction would get reverted with the message overflow.

Now, I am moving to 0.8. If I use the same code, my test cases fail, because they don't get overflow revert message anymore. If I remove require and just leave z = z + x as the compiler suggests, I have no idea what message it will get reverted with. What I want to achieve is to use 0.8 and still get the overflow revert message.

NOTE I don't want to use unchecked.

3 Answers 3

15
+100

Bit of Explanation

First you should familiarize yourself with the concept of "unchecked arithmetic", which is part of the v0.8 breaking changes list:

Arithmetic operations revert on underflow and overflow. You can use unchecked { ... } to use the previous wrapping behavior.

Importantly, overflows and underflows use the REVERT opcode instead of the INVALID opcode:

Failing assertions and other internal checks like division by zero or arithmetic overflow do not use the invalid opcode but instead the revert opcode.

If you're a user of Hardhat, you will get the following JavaScript/ TypeScript error in the terminal while testing your contract:

Error: VM Exception while processing transaction: reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)

It looks like Solidity chose the hexadecimal number 0x11 to be the panic code associated with arithmetic overflows and underflows.

Code Updated

Unfortunately there is no way to achieve what you want without wrapping your code in an unchecked block.

First you do that, and then you do what SafeMath does: check that the sum is greater than x; if it isn't, the operation has overflown max uint8.

function nice(uint8 x) public  returns(uint8 z){
    uint8 z = 0;
    z = z + 240;
    unchecked {
        z = z + x;
        require(z >= x, "Your custom message here");
    }
}

Suggestion

Why use revert reasons when you can now define custom errors?

error Overflow(uint8 z, uint8 x);

function nice(uint8 x) public  returns(uint8 z){
    uint8 z = 0;
    z = z + 240;
    unchecked {
        z = z + x;
        if (z < x) {
            revert Overflow(x, z);
        }
    }
}

Imo this is a godsend for Solidity development. Compared to revert reason strings, custom errors are easier to work with, more gas efficient, and more elegant.

2
  • I really like the idea of custom errors, but I struggled with using them in the IDE (VS Code) - that was a few months ago, hopefully things get ironed out soon.
    – flcoder
    Commented Dec 21, 2021 at 2:37
  • @flcoder What do you mean by "struggled"? I am using VSCode too and custom errors are highlighted correctly using Juan Blanco's Solidity extension. Commented Dec 21, 2021 at 8:39
1

Solidity 0.8 includes the following change regarding arithmatic overflows/underflows:

Arithmetic operations revert on underflow and overflow. You can use unchecked { ... } to use the previous wrapping behaviour.

The Solidity 0.8 arithmetic exception gets triggered before that require statement is fully assessed. I believe there is not way you could maintain the previous Solidity behavior without using unchecked. But the good news is that you don't even need that require statement anymore with Solidity 0.8, but you would need to adapt your tests to catch that thrown arithmetic Solidity exception instead of your "overflow" error.

0

I incurred a similar problem like this:

uint256 a;
uint256 b;
uint256 c;
a = b - c;  // if b=0, c=1, a=-1

It is possible to panic because the b is large than the c, and the a is an unsigned number.

So I do like this:

if (b > c) {
  a = b - c;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.