This EIP defines a standard set of custom errors for commonly-used tokens, which are defined as ERC-20, ERC-721, and ERC-1155 tokens.
Ethereum applications and wallets have historically relied on revert reason strings to display the cause of transaction errors to users. Recent Solidity versions offer rich revert reasons with error-specific decoding (sometimes called “custom errors”). This EIP defines a standard set of errors designed to give at least the same relevant information as revert reason strings, but in a structured and expected way that clients can implement decoding for.
Motivation
Since the introduction of Solidity custom errors in v0.8.4, these have provided a way to show failures in a more expressive and gas efficient manner with dynamic arguments, while reducing deployment costs.
However, ERC-20, ERC-721, ERC-1155 were already finalized when custom errors were released, so no errors are included in their specification.
Standardized errors allow users to expect more consistent error messages across applications or testing environments, while exposing pertinent arguments and overall reducing the need of writing expensive revert strings in the deployment bytecode.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
The following errors were designed according to the criteria described in Rationale.
This EIP defines standard errors that may be used by implementations in certain scenarios but it does not specify whether implementations should revert in those scenarios, which remains up to the implementers unless a revert is mandated by the corresponding EIPs.
The names of the error arguments are defined in the Parameter Glossary and MUST be used according to those definitions.
Indicates an error related to the ownership over a particular token.
Used in transfers.
Usage guidelines:
sender MUST NOT be owner.
MUST NOT be used for approval operations.
ERC721InvalidSender(address sender)
Indicates a failure with the token sender.
Used in transfers.
Usage guidelines:
RECOMMENDED for disallowed transfers from the zero address.
MUST NOT be used for approval operations.
MUST NOT be used for ownership or approval requirements.
Use ERC721IncorrectOwner or ERC721InsufficientApproval instead.
ERC721InvalidReceiver(address receiver)
Indicates a failure with the token receiver.
Used in transfers.
Usage guidelines:
RECOMMENDED for disallowed transfers to the zero address.
RECOMMENDED for disallowed transfers to non-ERC721TokenReceiver contracts or those that reject a transfer. (eg. returning an invalid response in onERC721Received).
Indicates an error related to the current balance of a sender.
Used in transfers.
Usage guidelines:
balance MUST be less than needed for a tokenId.
ERC1155InvalidSender(address sender)
Indicates a failure with the token sender.
Used in transfers.
Usage guidelines:
RECOMMENDED for disallowed transfers from the zero address.
MUST NOT be used for approval operations.
MUST NOT be used for balance or allowance requirements.
Use ERC1155InsufficientBalance or ERC1155MissingApprovalForAll instead.
ERC1155InvalidReceiver(address receiver)
Indicates a failure with the token receiver.
Used in transfers.
Usage guidelines:
RECOMMENDED for disallowed transfers to the zero address.
RECOMMENDED for disallowed transfers to non-ERC1155TokenReceiver contracts or those that reject a transfer. (eg. returning an invalid response in onERC1155Received).
Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
Used in batch transfers.
Usage guidelines:
idsLength MUST NOT be valuesLength.
Parameter Glossary
Name
Description
sender
Address whose tokens are being transferred.
balance
Current balance for the interacting account.
needed
Minimum amount required to perform an action.
receiver
Address to which tokens are being transferred.
spender
Address that may be allowed to operate on tokens without being their owner.
allowance
Amount of tokens a spender is allowed to operate with.
approver
Address initiating an approval operation.
tokenId
Identifier number of a token.
owner
Address of the current owner of a token.
operator
Same as spender.
*Length
Array length for the prefixed parameter.
Error additions
Any addition to this EIP or implementation-specific errors (such as extensions) SHOULD follow the guidelines presented in the rationale section to keep consistency.
Rationale
The chosen objectives for a standard for token errors are to provide context about the error, and to make moderate use of meaningful arguments (to maintain the code size benefits with respect to strings).
Considering this, the error names are designed following a basic grammatical structure based on the standard actions that can be performed on each token and the subjects involved.
Actions and subjects
An error is defined based on the following actions that can be performed on a token and its involved subjects:
Transfer: An operation in which a sender moves to a receiver any number of tokens (fungible balance and/or non-fungible token ids).
Approval: An operation in which an approver grants any form of approval to an operator.
These attempt to exhaustively represent what can go wrong in a token operation. Therefore, the errors can be constructed by specifying which subject failed during an action execution, and prefixing with an error prefix.
Note that the action is never seen as the subject of an error.
If a subject is called different on a particular token standard, the error should be consistent with the standard’s naming convention.
Error prefixes
An error prefix is added to a subject to derive a concrete error condition.
Developers can think about an error prefix as the why an error happened.
A prefix can be Invalid for general incorrectness, or more specific like Insufficient for amounts.
Domain
Each error’s arguments may vary depending on the token domain. If there are errors with the same name and different arguments, the Solidity compiler currently fails with a DeclarationError.
For that reason, a domain prefix is proposed to avoid declaration clashing, which is the name of the ERC and its corresponding number appended at the beginning.
The selection of arguments depends on the subject involved, and it should follow the order presented below:
Who is involved with the error (eg. address sender)
What failed (eg. uint256 allowance)
Why it failed, expressed in additional arguments (eg. uint256 needed)
A particular argument may fall into overlapping categories (eg. Who may also be What), so not all of these will be present but the order shouldn’t be broken.
Some tokens may need a tokenId. This is suggested to include at the end as additional information instead of as a subject.
Error grammar rules
Given the above, we can summarize the construction of error names with a grammar that errors will follow:
<Domain><ErrorPrefix><Subject>(<Arguments>);
Where:
Domain: ERC20, ERC721 or ERC1155. Although other token standards may be suggested if not considered in this EIP.
ErrorPrefix: Invalid, Insufficient, or another if it’s more appropriate.
Subject: Sender, Receiver, Balance, Approver, Operator, Approval or another if it’s more appropriate, and must make adjustments based on the domain’s naming convention.
Tokens already deployed rely mostly on revert strings and make use of require instead of custom errors. Even most of the newly deployed tokens since Solidity’s v0.8.4 release inherit from implementations using revert strings.
This EIP can not be enforced on non-upgradeable already deployed tokens, however, these tokens generally use similar conventions with small variations such as:
Upgradeable contracts MAY be upgraded to implement this EIP.
Implementers and DApp developers that implement special support for tokens that are compliant with this EIP, SHOULD tolerate different errors emitted by non-compliant contracts, as well as classic revert strings.
Reference Implementation
Solidity
pragmasolidity^0.8.4;/// @title Standard ERC20 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-20
/// https://eips.ethereum.org/EIPS/eip-6093
interfaceERC20Errors{errorERC20InsufficientBalance(addresssender,uint256balance,uint256needed);errorERC20InvalidSender(addresssender);errorERC20InvalidReceiver(addressreceiver);errorERC20InsufficientAllowance(addressspender,uint256allowance,uint256needed);errorERC20InvalidApprover(addressapprover);errorERC20InvalidSpender(addressspender);}/// @title Standard ERC721 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// https://eips.ethereum.org/EIPS/eip-6093
interfaceERC721Errors{errorERC721InvalidOwner(addressowner);errorERC721NonexistentToken(uint256tokenId);errorERC721IncorrectOwner(addresssender,uint256tokenId,addressowner);errorERC721InvalidSender(addresssender);errorERC721InvalidReceiver(addressreceiver);errorERC721InsufficientApproval(addressoperator,uint256tokenId);errorERC721InvalidApprover(addressapprover);errorERC721InvalidOperator(addressoperator);}/// @title Standard ERC1155 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// https://eips.ethereum.org/EIPS/eip-6093
interfaceERC1155Errors{errorERC1155InsufficientBalance(addresssender,uint256balance,uint256needed,uint256tokenId);errorERC1155InvalidSender(addresssender);errorERC1155InvalidReceiver(addressreceiver);errorERC1155MissingApprovalForAll(addressoperator,addressowner)errorERC1155InvalidApprover(addressapprover);errorERC1155InvalidOperator(addressoperator);errorERC1155InvalidArrayLength(uint256idsLength,uint256valuesLength);}
Security Considerations
There are no known signature hash collisions for the specified errors.
Tokens upgraded to implement this EIP may break assumptions in other systems relying on revert strings.
Offchain applications should be cautious when dealing with untrusted contracts that may revert using these custom errors. For instance, if a user interface prompts actions based on error decoding, malicious contracts could exploit this to encourage untrusted and potentially harmful operations.