Alert Source Discuss
Standards Track: ERC

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

摘要

本 EIP 定义了一组用于常用 token 的标准自定义错误,这些 token 被定义为 ERC-20ERC-721ERC-1155 token。

以太坊应用程序和钱包历来依赖于 revert 原因字符串,向用户显示交易错误的原因。最近的 Solidity 版本提供了带有错误特定解码的丰富 revert 原因(有时称为“自定义错误”)。本 EIP 定义了一组标准错误,旨在提供至少与 revert 原因字符串相关的相同信息,但以一种结构化和预期的方式,客户端可以实现解码。

动机

自从 Solidity 在 v0.8.4 中引入自定义错误以来,这些错误提供了一种以更具表现力和 gas 效率的方式显示失败的方法,并带有动态参数,同时降低了部署成本。

但是,ERC-20ERC-721ERC-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 出现故障。 用于转账。

使用指南:

  • 推荐用于禁止从零地址转账。
  • 不得用于批准操作。
  • 不得用于余额或额度要求。
    • 请改用 ERC20InsufficientBalanceERC20InsufficientAllowance

ERC20InvalidReceiver(address receiver)

表示 token receiver 出现故障。 用于转账。

使用指南:

  • 推荐用于禁止转账到零地址。
  • 推荐用于禁止转账到不兼容的地址(例如合约地址)。
  • 不得用于批准操作。

ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)

表示 spenderallowance 出现故障。 用于转账。

使用指南:

  • 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 出现故障。 用于转账。

使用指南:

  • 推荐用于禁止从零地址转账。
  • 不得用于批准操作。
  • 不得用于所有权或批准要求。
    • 请改用 ERC721IncorrectOwnerERC721InsufficientApproval

ERC721InvalidReceiver(address receiver)

表示 token receiver 出现故障。 用于转账。

使用指南:

  • 推荐用于禁止转账到零地址。
  • 推荐用于禁止转账到非 ERC721TokenReceiver 合约或拒绝转账的合约。(例如,在 onERC721Received 中返回无效响应)。
  • 不得用于批准操作。

ERC721InsufficientApproval(address operator, uint256 tokenId)

表示 operator 的批准出现故障。 用于转账。

使用指南:

  • 对于 tokenId 的所有者和 operatorisApprovedForAll(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 相关的错误。 用于转账。

使用指南:

  • 对于 tokenIdbalance 必须小于 needed

ERC1155InvalidSender(address sender)

表示 token sender 出现故障。 用于转账。

使用指南:

  • 推荐用于禁止从零地址转账。
  • 不得用于批准操作。
  • 不得用于余额或额度要求。
    • 请改用 ERC1155InsufficientBalanceERC1155MissingApprovalForAll

ERC1155InvalidReceiver(address receiver)

表示 token receiver 出现故障。 用于转账。

使用指南:

  • 推荐用于禁止转账到零地址。
  • 推荐用于禁止转账到非 ERC1155TokenReceiver 合约或拒绝转账的合约。(例如,在 onERC1155Received 中返回无效响应)。
  • 不得用于批准操作。

ERC1155MissingApprovalForAll(address operator, address owner)

表示转账中 operator 的批准出现故障。 用于转账。

使用指南:

  • 对于 tokenId 的所有者和 operatorisApprovedForAll(owner, operator) 必须为 false。

ERC1155InvalidApprover(address approver)

表示要批准的 token 的 approver 出现故障。 用于批准。

使用指南:

  • 推荐用于禁止从零地址进行批准。
  • 不得用于转账操作。

ERC1155InvalidOperator(address operator)

表示要批准的 operator 出现故障。 用于批准。

使用指南:

  • 推荐用于禁止批准到零地址。
  • 必须用于禁止批准给自己。
  • 不得用于转账操作。
    • 请改用 ERC1155InsufficientApproval

ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength)

表示 safeBatchTransferFrom 操作中 idsvalues 之间的数组长度不匹配。 用于批量转账。

使用指南:

  • 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);

参数

参数的选择取决于所涉及的主题,它应遵循下面介绍的顺序:

  1. 与该错误有关(例如 address sender
  2. 什么 失败了(例如 uint256 allowance
  3. 为什么 失败了,以其他参数表示(例如 uint256 needed

特定参数可能属于重叠的类别(例如, 也可能是 什么),因此并非所有参数都会出现,但顺序不应被破坏。

某些 token 可能需要 tokenId。建议将其包含在最后作为附加信息,而不是作为主题。

错误语法规则

鉴于以上所述,我们可以使用错误将遵循的语法来总结错误名称的构造:

<Domain><ErrorPrefix><Subject>(<Arguments>);

其中:

  • DomainERC20ERC721ERC1155。尽管如果本 EIP 中未考虑其他 token 标准,则可以提出其他标准。
  • ErrorPrefixInvalidInsufficient 或其他更合适的名称。
  • SubjectSenderReceiverBalanceApproverOperatorApproval 或其他更合适的名称,并且必须根据域的命名约定进行调整。
  • Arguments:遵循 whowhatwhy 顺序

向后兼容性

已经部署的 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.