4
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 overfow revert message anymore. If I remove require and just leave z = z + x as the compiler suggests, I have no idea with what message it will get reverted with. What I want to achieve is to use 0.8 and still get overflow revert message.

NOTE I don't want to use unchecked.

3
+100

Bit of Explanation

First you should familiarise 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 behaviour.

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.

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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