ERC-6093: 常用 Token 的自定义错误
列出常用 token 实现的自定义错误
Authors | Ernesto García (@ernestognw), Francisco Giordano (@frangio), Hadrien Croubois (@Amxx) |
---|---|
Created | 2022-12-06 |
Requires | EIP-20, EIP-721, EIP-1155 |
Table of Contents
摘要
本 EIP 定义了一组用于常用 token 的标准自定义错误,这些 token 被定义为 ERC-20、ERC-721 和 ERC-1155 token。
以太坊应用程序和钱包历来依赖于 revert 原因字符串,向用户显示交易错误的原因。最近的 Solidity 版本提供了带有错误特定解码的丰富 revert 原因(有时称为“自定义错误”)。本 EIP 定义了一组标准错误,旨在提供至少与 revert 原因字符串相关的相同信息,但以一种结构化和预期的方式,客户端可以实现解码。
动机
自从 Solidity 在 v0.8.4 中引入自定义错误以来,这些错误提供了一种以更具表现力和 gas 效率的方式显示失败的方法,并带有动态参数,同时降低了部署成本。
但是,ERC-20、ERC-721、ERC-1155 在自定义错误发布时已经最终确定,因此它们的规范中未包含任何错误。
标准化的错误允许用户期望在应用程序或测试环境中获得更一致的错误消息,同时公开相关的参数并总体上减少在部署字节码中编写昂贵的 revert 字符串的需求。
规范
本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、“MAY”和“OPTIONAL”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。
以下错误是根据 原理 中描述的标准设计的。
本 EIP 定义了实现可以在某些情况下使用的标准错误,但未指定实现是否应在这些情况下 revert,除非相应的 EIP 强制 revert,否则这仍然由实现者决定。
错误参数的名称在 参数术语表 中定义,并且必须按照这些定义使用。
ERC-20
ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)
表示与 sender
的当前 balance
相关的错误。
用于转账。
使用指南:
balance
必须小于needed
。
ERC20InvalidSender(address sender)
表示 token sender
出现故障。
用于转账。
使用指南:
- 推荐用于禁止从零地址转账。
- 不得用于批准操作。
- 不得用于余额或额度要求。
- 请改用
ERC20InsufficientBalance
或ERC20InsufficientAllowance
。
- 请改用
ERC20InvalidReceiver(address receiver)
表示 token receiver
出现故障。
用于转账。
使用指南:
- 推荐用于禁止转账到零地址。
- 推荐用于禁止转账到不兼容的地址(例如合约地址)。
- 不得用于批准操作。
ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)
表示 spender
的 allowance
出现故障。
用于转账。
使用指南:
allowance
必须小于needed
。
ERC20InvalidApprover(address approver)
表示要批准的 token 的 approver
出现故障。
用于批准。
使用指南:
- 推荐用于禁止从零地址进行批准。
- 不得用于转账操作。
ERC20InvalidSpender(address spender)
表示要批准的 spender
出现故障。
用于批准。
使用指南:
- 推荐用于禁止批准到零地址。
- 推荐用于禁止批准给自己。
- 不得用于转账操作。
- 请改用
ERC20InsufficientAllowance
。
- 请改用
ERC-721
ERC721InvalidOwner(address owner)
表示地址不能是所有者。 用于余额查询。
使用指南:
- 推荐用于禁止拥有所有权的地址(例如,ERC-721 明确禁止
address(0)
成为所有者)。 - 不得用于转账。
- 请改用
ERC721IncorrectOwner
。
- 请改用
ERC721NonexistentToken(uint256 tokenId)
表示 owner
为零地址的 tokenId
。
使用指南:
tokenId
必须是未铸造或已销毁的 token。
ERC721IncorrectOwner(address sender, uint256 tokenId, address owner)
表示与特定 token 的所有权相关的错误。 用于转账。
使用指南:
sender
不得为owner
。- 不得用于批准操作。
ERC721InvalidSender(address sender)
表示 token sender
出现故障。
用于转账。
使用指南:
- 推荐用于禁止从零地址转账。
- 不得用于批准操作。
- 不得用于所有权或批准要求。
- 请改用
ERC721IncorrectOwner
或ERC721InsufficientApproval
。
- 请改用
ERC721InvalidReceiver(address receiver)
表示 token receiver
出现故障。
用于转账。
使用指南:
- 推荐用于禁止转账到零地址。
- 推荐用于禁止转账到非
ERC721TokenReceiver
合约或拒绝转账的合约。(例如,在onERC721Received
中返回无效响应)。 - 不得用于批准操作。
ERC721InsufficientApproval(address operator, uint256 tokenId)
表示 operator
的批准出现故障。
用于转账。
使用指南:
- 对于
tokenId
的所有者和operator
,isApprovedForAll(owner, operator)
必须为 false。 getApproved(tokenId)
不得为operator
。
ERC721InvalidApprover(address approver)
表示要批准的 token 的 owner
出现故障。
用于批准。
使用指南:
- 推荐用于禁止从零地址进行批准。
- 不得用于转账操作。
ERC721InvalidOperator(address operator)
表示要批准的 operator
出现故障。
用于批准。
使用指南:
- 推荐用于禁止批准到零地址。
operator
不得为已批准 token 的所有者。- 不得用于转账操作。
- 请改用
ERC721InsufficientApproval
。
- 请改用
ERC-1155
ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId)
表示与 sender
的当前 balance
相关的错误。
用于转账。
使用指南:
- 对于
tokenId
,balance
必须小于needed
。
ERC1155InvalidSender(address sender)
表示 token sender
出现故障。
用于转账。
使用指南:
- 推荐用于禁止从零地址转账。
- 不得用于批准操作。
- 不得用于余额或额度要求。
- 请改用
ERC1155InsufficientBalance
或ERC1155MissingApprovalForAll
。
- 请改用
ERC1155InvalidReceiver(address receiver)
表示 token receiver
出现故障。
用于转账。
使用指南:
- 推荐用于禁止转账到零地址。
- 推荐用于禁止转账到非
ERC1155TokenReceiver
合约或拒绝转账的合约。(例如,在onERC1155Received
中返回无效响应)。 - 不得用于批准操作。
ERC1155MissingApprovalForAll(address operator, address owner)
表示转账中 operator
的批准出现故障。
用于转账。
使用指南:
- 对于
tokenId
的所有者和operator
,isApprovedForAll(owner, operator)
必须为 false。
ERC1155InvalidApprover(address approver)
表示要批准的 token 的 approver
出现故障。
用于批准。
使用指南:
- 推荐用于禁止从零地址进行批准。
- 不得用于转账操作。
ERC1155InvalidOperator(address operator)
表示要批准的 operator
出现故障。
用于批准。
使用指南:
- 推荐用于禁止批准到零地址。
- 必须用于禁止批准给自己。
- 不得用于转账操作。
- 请改用
ERC1155InsufficientApproval
。
- 请改用
ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength)
表示 safeBatchTransferFrom
操作中 ids
和 values
之间的数组长度不匹配。
用于批量转账。
使用指南:
idsLength
不得为valuesLength
。
参数术语表
名称 | 描述 |
---|---|
sender |
其 token 正在被转移的地址。 |
balance |
交互账户的当前余额。 |
needed |
执行操作所需的最小数量。 |
receiver |
token 正在被转移到的地址。 |
spender |
可能被允许在没有所有者的情况下操作 token 的地址。 |
allowance |
spender 被允许操作的 token 数量。 |
approver |
启动批准操作的地址。 |
tokenId |
token 的标识符编号。 |
owner |
token 当前所有者的地址。 |
operator |
与 spender 相同。 |
*Length |
带前缀参数的数组长度。 |
错误添加
对本 EIP 的任何添加或特定于实现的错误(例如扩展)都应遵循 原理 部分中介绍的指南,以保持一致性。
原理
token 错误标准的选择目标是提供有关错误的上下文,并适度使用有意义的参数(以保持代码大小方面的优势,相对于字符串而言)。
考虑到这一点,错误名称的设计遵循基于可以在每个 token 上执行的标准操作和所涉及的 主题 的基本语法结构。
操作和主题
错误是基于可以在 token 及其相关 主题 上执行的以下 操作 定义的:
- 转账:sender 将任何数量的 token(可替代的 balance 和/或不可替代的 token id)移动到 receiver 的操作。
- 批准:approver 授予 operator 任何形式的 批准 的操作。
这些尝试详尽地表示 token 操作中可能出错的情况。因此,可以通过指定在 操作 执行期间哪个 主题 失败,并以 错误前缀 为前缀来构造错误。
请注意,该操作永远不会被视为错误的主题。
如果在特定 token 标准上以不同的方式调用主题,则错误应与该标准的命名约定保持一致。
错误前缀
错误前缀被添加到主题以派生具体的错误条件。 开发人员可以将错误前缀视为发生错误的 原因。
前缀可以是 Invalid
表示一般的错误,或者更具体,例如 Insufficient
表示金额。
域
每个错误的参数可能会因 token 域而异。如果存在具有相同名称和不同参数的错误,则 Solidity 编译器当前会因 DeclarationError
而失败。
一个例子是:
InsufficientApproval(address spender, uint256 allowance, uint256 needed);
InsufficientApproval(address operator, uint256 tokenId);
因此,建议使用域前缀来避免声明冲突,即 ERC 的名称及其附加在开头的相应数字。
例子:
ERC20InsufficientApproval(address spender, uint256 allowance, uint256 needed);
ERC721InsufficientApproval(address operator, uint256 tokenId);
参数
参数的选择取决于所涉及的主题,它应遵循下面介绍的顺序:
- 谁 与该错误有关(例如
address sender
) - 什么 失败了(例如
uint256 allowance
) - 为什么 失败了,以其他参数表示(例如
uint256 needed
)
特定参数可能属于重叠的类别(例如,谁 也可能是 什么),因此并非所有参数都会出现,但顺序不应被破坏。
某些 token 可能需要 tokenId
。建议将其包含在最后作为附加信息,而不是作为主题。
错误语法规则
鉴于以上所述,我们可以使用错误将遵循的语法来总结错误名称的构造:
<Domain><ErrorPrefix><Subject>(<Arguments>);
其中:
- Domain:
ERC20
、ERC721
或ERC1155
。尽管如果本 EIP 中未考虑其他 token 标准,则可以提出其他标准。 - ErrorPrefix:
Invalid
、Insufficient
或其他更合适的名称。 - Subject:
Sender
、Receiver
、Balance
、Approver
、Operator
、Approval
或其他更合适的名称,并且必须根据域的命名约定进行调整。 - Arguments:遵循 who、what 和 why 顺序。
向后兼容性
已经部署的 token 主要依靠 revert 字符串,并使用 require
而不是自定义错误。即使自 Solidity v0.8.4 版本发布以来,大多数新部署的 token 也继承自使用 revert 字符串的实现。
此 EIP 无法在不可升级的已部署 token 上强制执行,但是,这些 token 通常使用相似的约定,但略有变化,例如:
可升级的合约可以升级以实现此 EIP。
对于实现对此 EIP 兼容的 token 的特殊支持的实现者和 DApp 开发人员,应容忍非兼容合约发出的不同错误以及经典的 revert 字符串。
参考实现
Solidity
pragma solidity ^0.8.4;
/// @title 标准 ERC20 错误
/// @dev 请参阅 https://eips.ethereum.org/EIPS/eip-20
/// https://eips.ethereum.org/EIPS/eip-6093
interface ERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
/// @title 标准 ERC721 错误
/// @dev 请参阅 https://eips.ethereum.org/EIPS/eip-721
/// https://eips.ethereum.org/EIPS/eip-6093
interface ERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
/// @title 标准 ERC1155 错误
/// @dev 请参阅 https://eips.ethereum.org/EIPS/eip-1155
/// https://eips.ethereum.org/EIPS/eip-6093
interface ERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner)
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
安全考虑
对于指定错误,没有已知的签名哈希冲突。
升级为实现此 EIP 的 token 可能会破坏其他依赖于 revert 字符串的系统中的假设。
在处理可能使用这些自定义错误进行 revert 的不受信任的合约时,链下应用程序应谨慎。例如,如果用户界面根据错误解码提示操作,则恶意合约可能会利用此漏洞来鼓励不受信任且可能有害的操作。
版权
版权和相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Ernesto García (@ernestognw), Francisco Giordano (@frangio), Hadrien Croubois (@Amxx), "ERC-6093: 常用 Token 的自定义错误," Ethereum Improvement Proposals, no. 6093, December 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6093.