ERC-165如何判断合约接口? 图 1
ERC-165如何判断合约接口? · 图 1

调用一个未知合约前,前端希望知道它是不是ERC-721、ERC-1155接收器或其他标准实现。ERC-165提供的是“接口声明探测”:给合约一个4字节interfaceId,询问supportsInterface是否返回true。它能减少盲调,却不是代码质量证明。

interfaceId从哪里来

每个外部函数先按“函数名(参数类型)”计算keccak256并取前4字节选择器,再把接口内全部函数选择器逐个异或。返回值类型不参与选择器,继承接口还要按标准定义确认是否包含父接口。不要从ABI文字顺序或合约地址猜接口ID。

探测步骤输入期望结果失败含义
ERC-165自检0x01ffc9a7true不应按ERC-165继续判断
无效接口自检0xfffffffffalse实现不符合标准探测规则
目标接口查询目标interfaceIdtrue/false仅表示声明结果

接口探测的证据链

  1. 接口ID是接口中函数选择器的异或值,函数选择器取规范函数签名keccak256的前4字节。
  2. 标准探测先确认supportsInterface自身可用且对0xffffffff返回false,再查询目标接口ID。
  3. supportsInterface调用应在30000 Gas内完成;返回true只表示合约声明支持该接口,不替代业务行为和安全审计。

为什么要做两步自检

直接查询目标ID可能把fallback恒定返回true的恶意合约误判为支持。EIP-165建议先确认0x01ffc9a7被支持,再确认0xffffffff被拒绝,最后才问目标接口。每次调用应受30000 Gas上限约束,避免探测成为拒绝服务入口。

调用未知合约前怎么探测

  1. 从权威标准或编译器产物取得interfaceId
  2. 先测ERC-165自身与0xffffffff
  3. 为staticcall设置Gas上限和失败回退
  4. 代理合约同时读取implementation与升级权限
  5. 把接口结果与实际函数调用分开记录

声明和行为是两层证据

合约可以声明支持ERC-721,却在transferFrom中加入额外限制;代理升级后实现也可能变化。supportsInterface只回答当前调用返回什么,不证明所有函数存在、符合经济语义或永不改变。高价值集成仍要核对源码、代码哈希、代理实现和真实小额调用。

返回true不是安全证明

看到false也不能立刻断言合约没有相关功能:早期标准或非ERC-165实现可能具备同名函数却不声明接口。看到true更不能把资产直接发送过去。探测结果是兼容性线索,资产安全还取决于接收钩子、回滚处理和权限逻辑。

事件和函数数据的ABI结构可结合以太坊日志topics和data理解;合约地址来源先按代币合约地址核验确认,代理或工厂部署再参考CREATE2确定性地址