EIP-747 深度解析:wallet_watchAsset RPC 方法与钱包资产跟踪标准

原创2026-09-14 12:05:45157 阅读
文章标签:区块链文档Web3

EIP-747 深度解析:wallet_watchAsset RPC 方法与钱包资产跟踪标准

本篇技术指南以 EIPS/eip-747.md 为核心骨架,结合本仓库中的 EIP-1193(Provider API)、EIP-1474(JSON-RPC 规范)等关联标准,系统讲解 wallet_watchAsset 的规范定义、参数格式、返回语义与安全考量。读完本文,你将掌握如何在 DApp 中通过标准 RPC 请求钱包为用户添加代币跟踪,理解 ERC-1046 与 ERC-20 两种资产类型的差异,并了解钱包实现方在 SSRF、校验与指纹防护上的安全边界。

概述:为什么需要 wallet_watchAsset

跟踪用户资产是 Ethereum 钱包最核心的用途之一。在 EIP-747 出现之前,钱包面临两种尴尬处境:

  • 钱包预加载资产列表:钱包需要自行维护一份"受信任资产清单",既要承担这份清单的维护与安全责任,又要为已知资产进行大规模轮询(mass polling),消耗带宽;
  • 用户手动添加资产:用户必须手动输入合约地址、符号、小数位等信息,体验极差。

EIP-747 给出的答案是:定义一个新的 wallet 作用域的 RPC 方法 wallet_watchAsset,允许 DApp(客户端)向用户的钱包"建议"一个需要跟踪的代币资产,由钱包决定是否向用户展示添加提示。它把"添加资产"这一动作从钱包端(集中式清单)与用户端(手动输入)迁移到双方利益天然对齐的时刻——用户正在浏览某个代币的网站。

EIP-747 的元数据如下:

字段 值
EIP 编号 747
标题 wallet_watchAsset RPC Method
状态 Final(最终定稿)
类型 Standards Track(标准跟踪)
类别 Interface(接口)
创建时间 2018-08-13
依赖 EIP-20、EIP-1046、EIP-1193
作者 Dan Finlay、Esteban Mino、Gavin John

该方法依赖 EIP-1193(Ethereum Provider JavaScript API) 作为 Provider 层调用载体,并通过 EIP-1046(ERC-1046 资产元数据) 与 EIP-20(ERC-20 代币标准) 定义资产类型。下图展示了实际开发中通过浏览器控制台调用 watchAsset 发起代币添加请求的流程(代码中通过 web3.currentProvider.sendAsync 携带 type: "ERC20" 与代币元数据):

EIP-747 watchAsset 调用示例

说明:仓库中的 EIP-1046 与 EIP-20 文件已标记为 "Moved"(迁移至 ERC 仓库),EIP-747 中引用的 tokenURI、interop 等概念源自 ERC-1046 规范。

核心规范:方法语义与调用约束

规范正文明确要求:wallet_watchAsset 请求将指定资产"列入用户的钱包"。关键语义如下:

  • 必须立即返回:在提示用户之前,如果请求合法,必须立即返回 true;如果请求不合法,必须返回错误(error);
  • "列入钱包"的含义由钱包实现决定:不同钱包可以有不同的落地方式(加入资产列表、展示在资产页等);
  • 成功 ≠ 用户已同意:一次成功的 wallet_watchAsset 调用只表示钱包识别了该请求、请求本身没有格式问题,并不表示用户被提示了,也不表示资产真的被添加进钱包。真正的授权仍然完全由用户交互控制。

参数:WatchAssetParameters

wallet_watchAsset 接收一个参数——WatchAssetParameters 对象:

interface WatchAssetParameters {
  type: string; // 资产的接口类型,例如 'ERC1046'
  options: any;
}
  • type 字符串应当是资产合约所实现接口的通用公认名称,例如 ERC1046。定义不同资产类型的全局标识符超出了本 EIP 的范围;
  • 该接口应当根据资产的 type 进行扩展或修改,这些改动必须在单独的 EIP 中定义。

返回:true 或错误

wallet_watchAsset 在不等待用户交互的情况下立即返回布尔值 true(表示请求被识别,无论用户是否被提示),或对无效请求返回错误。可能触发错误的场景(非穷尽列举):

  • 资产类型无法识别/不受支持;
  • 资产因 allowlist(白名单)或 denylist(黑名单)被拦截——这会使请求"无效",因为根本原因需要开发者处理;
  • 下载图片失败;
  • 钱包出于防范潜在 SSRF 攻击的考虑,没有加载展示资产所需的部分元数据。

从错误机制上看,wallet_watchAsset 走的是标准 RPC 错误通道。根据 EIP-1474 的 JSON-RPC 错误码表,错误响应包含 code 与 message 字段,例如标准错误 -32602 Invalid params(参数无效)。而在 EIP-1193 的 ProviderRpcError 规范 中,错误对象还携带整数 code,其中 4200 Unsupported Method 正是用于表示 Provider 不支持所请求的方法——当钱包未实现 wallet_watchAsset 时,Provider 应以此类错误拒绝调用。

ERC1046 类型:支持图片与自定义元数据的推荐方案

当 type 为 ERC1046 时,options 字段的格式如下:

interface ERC1046WatchAssetOptions {
  {
    address: string; // 代币合约的十六进制地址
    chainId?: number; // 资产的链 ID。留空则默认使用当前链 ID。
  };
}

字段约束:

  • address 必填,必须是 0x 前缀的、符合 EIP-55 校验和(checksum)规则的十六进制代币合约地址;
  • chainId 可选,必须是资产所属链的链 ID;
  • 校验和失败即请求无效:如果 checksum 校验失败,请求必须被视为无效;
  • 链 ID 无法识别即调用失败:如果钱包无法识别 chainId,或者 chainId 为空且钱包没有"当前活跃链"的概念,调用必须失败。

通过 tokenURI 与 interop 字段判定代币类型

wallet_watchAsset 必须获取 ERC-1046 的 tokenURI 并检查其中的 interop 字段,以确定代币的类型。如果解析失败或类型未知,RPC 调用必须报错。

与知名代币列表的交叉校验

wallet_watchAsset 应当将 name、symbol 字段以及合约 address、chainId 与一份知名代币列表进行比对。如果 name/symbol 与列表中的某个代币相似,但 chainId/address 不匹配,应当向用户展示警告(防止钓鱼仿冒)。

SSRF 防护

钱包应当对特定端口和 scheme(协议)设置白名单和/或黑名单,以避免 SSRF 攻击(详见下文安全章节)。

Legacy ERC20 类型:兼容旧生态的过渡方案

当 type 为 ERC20(即传统 ERC-20 代币)时,options 字段格式为:

interface ERC20WatchAssetOptions {
  {
    address: string; // 代币合约的十六进制地址
    chainId?: number; // 资产的链 ID。留空则默认使用当前链 ID。
  };
}

字段约束与 ERC1046 类型完全一致:

  • address 必填,必须是 0x 前缀的校验和十六进制地址;
  • 校验和失败 ⇒ 请求无效;
  • chainId 无法识别,或为空且钱包无"活跃链"概念 ⇒ 调用失败;
  • 应当执行与知名代币列表的 name/symbol/address/chainId 交叉校验,相似名称但地址不匹配时应当向用户展示警告。

规范同时给出明确建议:如果可能,推荐优先使用 ERC1046 类型,因为它支持图片与自定义元数据,能提供更丰富的展示信息。ERC20 类型被定位为兼容旧生态的"遗留"(Legacy)方案。

设计动机(Rationale):为什么必须由钱包介入

EIP-747 的 Rationale 部分详细阐述了设计背后的权衡:

  1. 展示用户资产是 DApp 用户的基础预期。但大多数钱包要么自行维护客户端资产列表,要么查询中心化 API 获取余额——后者降低了去中心化程度,还可能将账户持有人与 IP 地址关联(隐私问题)。此外,从网络刷新/轮询资产列表成本高昂,尤其对带宽受限的设备不友好。而且,维护一份资产列表本身就成了一种"政治行为",会招致骚扰并诱导钱包方被迫上线各种冷门资产。

  2. 自动列出资产会把资产变成"垃圾邮件"。用户会在钱包里突然看到自己并不关心的新资产,这可能被用于发送未经请求的信息,甚至实施钓鱼诈骗。这种现象在空投代币中已经非常普遍,而空投代币也正是网络拥堵的一大原因——因为向人们撒新代币在当下被"奖励"以更多用户关注。

  3. 用户手动添加资产的时刻,恰好是双方利益天然对齐的时刻。用户通常是从某个网站上了解到某个代币的,此刻网站与用户都希望用户能跟踪这个代币。这正是引入 API 让双方自然协作的最佳切入点。

安全考量(Security Considerations)

服务端请求伪造(SSRF)

钱包在向 URL 发起任意请求时必须格外小心。规范建议钱包通过白名单 scheme 和端口来净化 URI。一个存在漏洞的钱包可能被诱导,例如去修改本地托管的 redis 数据库中的数据(攻击者可构造指向 http://localhost:6379/ 之类的 URI)。因此,对 tokenURI 的拉取必须限制协议(如仅 https)与端口范围。

校验(Validation)

钱包应当在 symbol 或 name 与某个知名代币相同或相似时警告用户,以避免钓鱼诈骗。这正是前述"知名代币列表交叉校验"在安全层面的意义:攻击者可能注册一个符号叫 "USDT"、地址却是恶意的代币,若不加警告,用户极易上当。

指纹识别防护(Fingerprinting)

为避免基于钱包行为和/或已列资产对用户进行指纹识别,RPC 调用必须在用户被提示或发生错误的那一刻立即返回,不能等待用户接受或拒绝提示。换言之,钱包的响应时间不应泄露"用户是否在意这个代币"、"用户是否安装了某钱包"等信息——所有用户无论选择与否,调用都几乎同时返回,抹平可被观察的差异。

实战:在 DApp 中调用 wallet_watchAsset

基于 EIP-1193 的 request API,wallet_watchAsset 在浏览器中的典型调用如下(window.ethereum 是社区惯例上的 Provider 挂载点,并非规范强制要求):

// 基于 EIP-1193 Provider.request 调用 wallet_watchAsset
const ethereum = window.ethereum;

try {
  const wasAdded = await ethereum.request({
    method: 'wallet_watchAsset',
    params: {
      type: 'ERC20', // 或 'ERC1046'
      options: {
        address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // 校验和格式的合约地址
        chainId: 1, // 可选,默认当前链
        // ERC1046 类型下还可补充 name/symbol 等元数据字段
      },
    },
  });

  if (wasAdded) {
    console.log('请求已被钱包识别,用户可能已看到添加提示');
  }
} catch (error) {
  console.error(`watchAsset 失败: ${error.code} - ${error.message}`);
  // 例如 -32602 (Invalid params) 表示参数非法,
  // 4200 (Unsupported Method) 表示钱包不支持该方法
}

要点回顾:

  • 返回 true 只代表请求合法且被钱包识别,不代表用户已同意添加;
  • 参数校验(checksum、chainId 可识别性)失败时,Promise 会 reject,错误对象遵循 EIP-1193 的 ProviderRpcError 约定;
  • 该调用不等待用户交互,因此也不存在"等待用户点击"造成的长时间挂起。

总结

EIP-747 通过一个轻量的 wallet 作用域 RPC 方法,把"资产跟踪"从钱包的中心化清单与用户的手动输入中解放出来,让 DApp 与钱包在利益对齐的瞬间自然协作。其核心设计可以概括为:

  • 标准化:统一的 WatchAssetParameters 结构与 true/错误返回语义;
  • 分层资产类型:推荐 ERC1046(支持图片与自定义元数据,通过 tokenURI 的 interop 字段判定类型),保留 ERC20 作为遗留兼容方案;
  • 安全第一:SSRF 防护(scheme/端口白名单)、知名代币交叉校验防钓鱼、立即返回防指纹识别;
  • 用户主权:钱包始终保留提示与拒绝的权力,RPC 只负责"建议"。

对于 DApp 开发者,这意味着只需一次标准 RPC 调用即可引导用户添加代币;对于钱包实现者,EIPS/eip-747.md 给出了必须遵循的校验规则与推荐的安全边界。结合 EIP-1193 的 Provider 错误码约定与 EIP-1474 的 JSON-RPC 错误体系,wallet_watchAsset 已成为现代钱包生态中资产跟踪的事实标准接口。

本文章内容版权遵循 EIP 仓库的 CC0 许可声明。

登录后查看全文
EIPs