mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Documentation for custom errors.
This commit is contained in:
+55
-24
@@ -17,7 +17,7 @@ the usual semantics known from C or JavaScript.
|
||||
|
||||
Solidity also supports exception handling in the form of ``try``/``catch``-statements,
|
||||
but only for :ref:`external function calls <external-function-calls>` and
|
||||
contract creation calls.
|
||||
contract creation calls. Errors can be created using the :ref:`revert statement <revert-statement>`.
|
||||
|
||||
Parentheses can *not* be omitted for conditionals, but curly braces can be omitted
|
||||
around single-statement bodies.
|
||||
@@ -551,7 +551,8 @@ state in the current call (and all its sub-calls) and
|
||||
flags an error to the caller.
|
||||
|
||||
When exceptions happen in a sub-call, they "bubble up" (i.e.,
|
||||
exceptions are rethrown) automatically. Exceptions to this rule are ``send``
|
||||
exceptions are rethrown) automatically unless they are caught in
|
||||
a ``try/catch`` statement. Exceptions to this rule are ``send``
|
||||
and the low-level functions ``call``, ``delegatecall`` and
|
||||
``staticcall``: they return ``false`` as their first return value in case
|
||||
of an exception instead of "bubbling up".
|
||||
@@ -562,17 +563,11 @@ of an exception instead of "bubbling up".
|
||||
if the account called is non-existent, as part of the design
|
||||
of the EVM. Account existence must be checked prior to calling if needed.
|
||||
|
||||
Exceptions in external calls can be caught with the ``try``/``catch`` statement.
|
||||
|
||||
Exceptions can contain data that is passed back to the caller.
|
||||
This data consists of a 4-byte selector and subsequent :ref:`ABI-encoded<abi>` data.
|
||||
The selector is computed in the same way as a function selector, i.e.,
|
||||
the first four bytes of the keccak256-hash of a function
|
||||
signature - in this case an error signature.
|
||||
|
||||
Currently, Solidity supports two error signatures: ``Error(string)``
|
||||
and ``Panic(uint256)``. The first ("error") is used for "regular" error conditions
|
||||
while the second ("panic") is used for errors that should not be present in bug-free code.
|
||||
Exceptions can contain error data that is passed back to the caller
|
||||
in the form of :ref:`error instances <errors>`.
|
||||
The built-in errors ``Error(string)`` and ``Panic(uint256)`` are
|
||||
used by special functions, as explained below. ``Error`` is used for "regular" error conditions
|
||||
while ``Panic`` is used for errors that should not be present in bug-free code.
|
||||
|
||||
Panic via ``assert`` and Error via ``require``
|
||||
----------------------------------------------
|
||||
@@ -604,17 +599,24 @@ The error code supplied with the error data indicates the kind of panic.
|
||||
#. 0x41: If you allocate too much memory or create an array that is too large.
|
||||
#. 0x51: If you call a zero-initialized variable of internal function type.
|
||||
|
||||
The ``require`` function either creates an error of type ``Error(string)``
|
||||
or an error without any error data and it
|
||||
The ``require`` function either creates an error without any data or
|
||||
an error of type ``Error(string)``. It
|
||||
should be used to ensure valid conditions
|
||||
that cannot be detected until execution time.
|
||||
This includes conditions on inputs
|
||||
or return values from calls to external contracts.
|
||||
|
||||
A ``Error(string)`` exception (or an exception without data) is generated
|
||||
.. note::
|
||||
|
||||
It is currently not possible to use custom errors in combination
|
||||
with ``require``. Please use ``if (!condition) revert CustomError();`` instead.
|
||||
|
||||
An ``Error(string)`` exception (or an exception without data) is generated
|
||||
by the compiler
|
||||
in the following situations:
|
||||
|
||||
#. Calling ``require`` with an argument that evaluates to ``false``.
|
||||
#. Calling ``require(x)`` where ``x`` evaluates to ``false``.
|
||||
#. If you use ``revert()`` or ``revert("description")``.
|
||||
#. If you perform an external function call targeting a contract that contains no code.
|
||||
#. If your contract receives Ether via a public function without
|
||||
``payable`` modifier (including the constructor and the fallback function).
|
||||
@@ -679,22 +681,43 @@ the changes in the caller will always be reverted.
|
||||
which consumed all gas available to the call.
|
||||
Exceptions that use ``require`` used to consume all gas until before the Metropolis release.
|
||||
|
||||
.. _revert-statement:
|
||||
|
||||
``revert``
|
||||
----------
|
||||
|
||||
The ``revert`` function is another way to trigger exceptions from within other code blocks to flag an error and
|
||||
revert the current call. The function takes an optional string
|
||||
message containing details about the error that is passed back to the caller
|
||||
and it will create an ``Error(string)`` exception.
|
||||
A direct revert can be triggered using the ``revert`` statement and the ``revert`` function.
|
||||
|
||||
The following example shows how to use an error string together with ``revert`` and the equivalent ``require``:
|
||||
The ``revert`` statement takes a custom error as direct argument without parentheses:
|
||||
|
||||
revert CustomError(arg1, arg2);
|
||||
|
||||
For backards-compatibility reasons, there is also the ``revert()`` function, which uses parentheses
|
||||
and accepts a string:
|
||||
|
||||
revert();
|
||||
revert("description");
|
||||
|
||||
The error data will be passed back to the caller and can be caught there.
|
||||
Using ``revert()`` causes a revert without any error data while ``revert("description")``
|
||||
will create an ``Error(string)`` error.
|
||||
|
||||
Using a custom error instance will usually be much cheaper than a string description,
|
||||
because you can use the name of the error to describe it, which is encoded in only
|
||||
four bytes. A longer description can be supplied via NatSpec which does not incur
|
||||
any costs.
|
||||
|
||||
The following example shows how to use an error string and a custom error instance
|
||||
together with ``revert`` and the equivalent ``require``:
|
||||
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.9.0;
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
contract VendingMachine {
|
||||
address owner;
|
||||
error Unauthorized();
|
||||
function buy(uint amount) public payable {
|
||||
if (amount > msg.value / 2 ether)
|
||||
revert("Not enough Ether provided.");
|
||||
@@ -705,9 +728,17 @@ The following example shows how to use an error string together with ``revert``
|
||||
);
|
||||
// Perform the purchase.
|
||||
}
|
||||
function withdraw() public {
|
||||
if (msg.sender != owner)
|
||||
revert Unauthorized();
|
||||
|
||||
payable(msg.sender).transfer(address(this).balance);
|
||||
}
|
||||
}
|
||||
|
||||
If you provide the reason string directly, then the two syntax options are equivalent, it is the developer's preference which one to use.
|
||||
The two ways ``if (!condition) revert(...);`` and ``require(condition, ...);`` are
|
||||
equivalent as long as the arguments to ``revert`` and ``require`` do not have side-effects,
|
||||
for example if they are just strings.
|
||||
|
||||
.. note::
|
||||
The ``require`` function is evaluated just as any other function.
|
||||
|
||||
Reference in New Issue
Block a user