7

For Example:

/** Custom Errors **/
    ///`cid` is an invalid Ipfs-Cid
    /// @param cid Ipfs-Cid entered.
    error InvalidCid(string cid);
    
    ///Sender's address isnt valid
    error InvalidSenderAddress(address sender);



function _addCid(string memory _cid) public {
            
       
        /// @dev Check for valid Cid
        
        //check using require
        require(bytes(_cid).length > 0, "Cannot accept empty Cid");
        
        //check using custom error
        if(bytes(_cid).length < 0) 
        revert InvalidCid(_cid);
    
    
    
        /// @dev Check for valid sender's address 
        
        //require function
        require(msg.sender != address(0), "Cannot be called from 0x0 address.");
    
        //revert function 
        if(msg.sender == address(0))
        revert InvalidSenderAddress(msg.sender);

function proceed();

}
    

In the above code, I've used both revert and require for each of the validations-

  • Valid Ipfs-Cid
  • Valid sender's address

My question is which one should I use and why?

1
  • Note that there is no case in the world where msg.sender could be 0x0, so you can remove this check. Jun 12, 2021 at 19:25

3 Answers 3

10

The benefit of custom errors is that they can significantly reduce the cost to deploy and call a contract, while still providing the same amount of information (or more). Let's look at the following example:

pragma solidity ^0.8.4;

contract Example {
  error InvalidSenderAddress(address _address);

  function foo() external {
    revert InvalidSenderAddress(msg.sender);
  }
}

This costs 83,249 gas to deploy in Remix, and calling foo results in a gas cost of 21,245. Now let's compare that to the following contract:

pragma solidity ^0.8.4;

contract Example {
  function foo() external {
    revert("Invalid sender address");
  }
}

This costs 91,463 gas to deploy, and calling foo results in a gas cost of 21,288, simply because we are using a string instead of a custom error. It also does not provide any info, like which address is invalid for example.

Custom errors are ABI encoded, and can be decoded using existing ABI decoders. This makes it a lot more efficient to store and use compared to strings.

For a more in-depth explanation of custom errors, I recommend this article: https://blog.soliditylang.org/2021/04/21/custom-errors/

3

To further explain since the question covers both requirements and the answer provided only deals with revert and using custom errors.

error Unauthorized();
address payable owner = payable(msg.sender);

    function withdrawal() public {
        if (msg.sender != owner)
            revert Unauthorized();

        owner.transfer(address(this).balance);
    }

Call withdrawal results in a gas cost of 23,388, simply because we are using a short statement for the custom error.

error UnauthorizedUnsydhjhejdjjsmsksksdjdjmdnssslssj();
address payable owner = payable(msg.sender);
    function withdrawWIthLongString() public {
        if (msg.sender != owner)
            revert UnauthorizedUnsydhjhejdjjsmsksksdjdjmdnssslssj();

        owner.transfer(address(this).balance);
    }   

Call withdrawWIthLongString results in a gas cost of 23,454, which costs more gas simply because we are using a long statement for the custom error.

Then proceeding to require statement, let's see how much gas it consumes.

address payable owner = payable(msg.sender);
    function witRequireShot() public {
            require(msg.sender == owner, "Unau");

        owner.transfer(address(this).balance);
    }

Call witRequireShot results in a gas cost of 23,830, simply because we are using a short string on the required statement which costs more than both custom error with a short string and with a long string.

address payable owner = payable(msg.sender);
    function withRequireLong() public {
        require(msg.sender == owner, "Unauhfjssdjasdjff agdjdjhhrjhr ahdjjfwfmfj ahdndjhddj");

        owner.transfer(address(this).balance);
    }

Call withRequireLong results in more gas at a high cost of 23,736 simply because it has a long string error;

1
  • I guess the gas cost of 23,736 is wrong, since in your example the withRequireLong would be cheaper than witRequireShot
    – Andy
    May 9, 2023 at 11:04
-1

revert with custom error is better because it's not added to the blockchain, doesn't take any gas fee, and is more visible to the caller of the functions.

1
  • It is not correct that they have different behavior, both use the same low level opcode REVERT.
    – Ismael
    May 21, 2022 at 17:38

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.