跳转到主要内容

使用 ERC-7730 为你的协议添加明文签名

ERC-7730
安全
签名
智能合约
钱包
中级
海斯特·布鲁克曼
2026年5月11日
11 分钟阅读

大多数重大的以太坊漏洞利用都有相同的最后一步:用户授权了一笔他们无法真正理解的交易。硬件钱包显示原始的十六进制调用数据,更糟糕的是,它们迫使你开启盲签。软件钱包会显示解码后的字段,但前提是它们能识别该合约。当它们无法识别时(无论是因为协议是新的、应用程序被攻破,还是设备离线),用户只能盲签。

ERC-7730 (opens in a new tab) 定义了一种标准的 JSON 格式,用于描述你的合约函数调用的含义

支持 ERC-7730 的钱包会读取你的描述符并显示:

兑换
发送:1,000 USDC
最低接收:0.42 WETH
协议:尤尼斯瓦普 V3 (Uniswap V3)

或者是一句人类和代理都能读懂的完整句子:

将 1,000 USDC 兑换为至少 0.42 WETH

而不是一个函数选择器和一堆原始整数值。

这就是明文签名 (opens in a new tab)——“所见即所签”。本教程将引导你为自己的合约编写描述符,使用官方 CLI 工具进行验证,并将其提交到开放注册表。

前提条件

  • 熟悉 Solidity 和智能合约 ABI
  • 一个已部署且具有已验证 ABI 的智能合约(在描述符被注册表接受之前,需要进行 Sourcify (opens in a new tab) 验证)
  • 用于验证 CLI 的 Python 3.12+
  • 基本的 JSON 知识

什么是 ERC-7730 描述符?

描述符是一个包含三个部分的单一 JSON 文件:

部分目的
context通过链 ID 和地址将描述符绑定到特定的合约部署
metadata命名项目并定义可重用的常量
display将每个函数签名映射到人类可读的标签和字段格式

由于描述符与合约本身是分离的,你可以为任何现有协议添加明文签名支持,而无需重新部署。钱包从注册表中检索描述符,并在签名时使用它们。

第 1 步:创建文件骨架

创建一个名为 calldata-<contractname>-<descriptorversion>.json 的文件。calldata- 前缀告诉注册表此描述符涵盖合约函数调用,而不是用于类型化数据消息的 eip712-descriptorversion 告诉注册表描述符文件的版本,如果未提供版本,则默认为 0。

{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json",
  "context": {},
  "metadata": {},
  "display": {
    "formats": {}
  }
}

第 2 步:编写上下文部分

context 部分将描述符绑定到一个或多个合约部署。钱包使用它来将传入的交易与正确的描述符进行匹配。

上下文字段

  • context.$id — 此描述符文档或部署配置的唯一标识符。
  • contract.deployments — 此描述符适用的部署集合。
  • deployments[].chainId — 部署的 EVM 链 ID。包括你的合约部署的每条链。
  • deployments[].address — 钱包应与此描述符关联的合约地址。使用包含执行逻辑的实现地址。

第 3 步:编写元数据部分

元数据部分提供有关此文件描述的项目和合约的人类可读信息。钱包可能会在签名期间使用此信息来显示协议名称、链接和其他上下文详细信息。

"metadata": {
  "owner": "Example Swap Protocol",
  "info": { "url": "https://example.xyz" },
  "contractName": "SwapRouter"
}

元数据字段

  • owner — 负责此描述符的项目、协议、组织或维护者。
  • info.url — 钱包可能向用户显示的规范项目或文档 URL,以提供额外的上下文。
  • contractName — 此文件描述的合约或实现名称,通常与已验证的源代码或 ABI 匹配。

如果你的 ERC-7730 文件描述的是一个 ERC-20 合约,你也应该添加一个代币对象。

第 4 步:编写显示格式部分

display.formats 对象将函数签名映射到人类可读的签名指令。这就是钱包在用户授权交易之前向用户显示你的函数的方式!

每个键都是一个人类可读的 ABI 片段——包含参数名称和参数类型的函数签名,与它们在你的 ABI 中出现的方式完全一致。

示例:描述代币兑换

显示字段

  • intent(必填) 操作的简短、用户友好的描述,例如“兑换”。
  • interpolatedIntent(推荐) 嵌入格式化字段值的更丰富的句子模板,例如 "Swap {amountIn} for at least {amountOutMin}"。将其与 intent 一起包含,以提供更用户友好的描述符,钱包可以根据任何显示限制选择显示。
  • fields(必填) 钱包应向用户显示的交易字段的有序列表。
    • path(必填) 对交易数据的引用。#.fieldName 指向按 ABI 中名称解码的调用数据参数。@.value 指随交易发送的 ETH 值。

    • label(必填) 显示在值旁边的人类可读标签。

    • format(推荐) 控制应如何渲染该值。常见格式包括:

      • tokenAmount
      • addressName
      • date

      当不需要额外的格式化时,使用 raw。某些格式接受额外的 params 配置。例如:

      • tokenAmount 可以使用 tokenPath 来识别哪个代币地址提供小数位数和代码元数据。
      • date 可以使用 encoding 来描述时间戳的编码方式。

      如果所选格式不需要额外信息,请省略 params

完整的描述符

第 5 步:提交到注册表

ERC-7730 注册表 (opens in a new tab)是一个由以太坊基金会作为中立管理者托管的开放存储库。任何人都可以自由克隆并自行托管它——钱包独立决定它们信任哪些注册表实例。

  1. 在 GitHub 上复刻 (Fork) 该存储库
  2. registry/<your-project-name>/ 处创建一个文件夹
  3. 将你的文件放入其中:registry/myproject/calldata-mycontract-0_0.json
  4. $schema 字段更新为存储库中使用的相对路径:"../../specs/erc7730-v2.schema.json"
  5. 开启一个拉取请求 (Pull request)

当你开启 PR 时,CI 会自动运行模式验证,检查函数签名是否生成有效的选择器,确认合约地址已在 Sourcify 上验证,并标记 ABI 不一致之处。检查结果会内联显示在 PR 上。注册表维护者会筛选提交的内容,以查找格式错误或潜在恶意的描述符。包含在注册表中并不意味着经过审计或认可。

注意: 你的合约必须在 Sourcify 上验证后,你的 PR 才能被接受。如果尚未验证,请先提交验证

合并后会发生什么?

注册表中的所有描述符都对审计员开放。在你的 PR 合并后,任何审计员都可以审查你的描述符并发布加密证明(根据 ERC-8176 (opens in a new tab))以确认其准确性。

这些证明信号让钱包能够应用自己的信任策略——具有多个独立证明的描述符比没有证明的描述符更有分量。你可以通过 clearsigning.org (opens in a new tab) 联系审计员社区。

钱包选择它们将支持的注册表。一旦你的描述符进入注册表,支持 ERC-7730 的钱包如果其注册表中包含该描述符,就会开始获取它,并在用户与你的合约交互时显示人类可读的数据。

延伸阅读

页面最后更新: 2026年5月12日

这篇教程对您有帮助吗?