Search code examples
ethereumsolidity

ethereum solidity what's the difference between require and revert + error


I'm wondering what's the difference from

contract TestToken {
    mapping(address => uint) balance;
    error InsufficientBalance(uint256 available, uint256 required);
    function transfer(address to, uint256 amount) public {
        if (amount > balance[msg.sender])
            // Error call using named parameters. Equivalent to
            // revert InsufficientBalance(balance[msg.sender], amount);
            revert InsufficientBalance({
                available: balance[msg.sender],
                required: amount
            });
        balance[msg.sender] -= amount;
        balance[to] += amount;
    }
    // ...
}

and

contract TestToken {
        mapping(address => uint) balance;
        error InsufficientBalance(uint256 available, uint256 required);
        function transfer(address to, uint256 amount) public {
            require(balance[msg.sender]<amount, "Insufficient Balance");
            balance[msg.sender] -= amount;
            balance[to] += amount;
        }
        // ...
    }

to handle error in solidity


Solution

  • From the low-level standpoint, both approaches are the same. Both throw an exception with an array of bytes as the exception data.

    You can catch both errors in the low-level catch (bytes memory) block

    function foo() public {
        try this.transfer(address(0x123), 2) {
            // ok
        } catch (bytes memory data) {
            // returns either the encoded object or the encoded string
        }
    }
    

    But you can only catch the string-encoded error with the "regular" catch Error(string memory) block

    function foo() public {
        try this.transfer(address(0x123), 2) {
            // ok
        } catch Error (string memory reason) {
            // returns the string message
            // fails to catch if an object is returned
        }
    }
    

    Docs: https://docs.soliditylang.org/en/v0.8.13/control-structures.html#try-catch


    Note that there is a logical error in the second snippet.

    // `balance` needs to be lower than `amount`
    // otherwise fail
    require(balance[msg.sender]<amount, "Insufficient Balance");
    

    should be

    // `balance` needs to be larger or equal than `amount`
    // otherwise fail
    require(balance[msg.sender] => amount, "Insufficient Balance");