题目
普通钱包能登录,但智能账户提示签名无效。其中一些地址尚无代码,另一些已经部署。服务端仅恢复 EOA 地址,或者先发一个 eth_call 部署、再发另一个 eth_call 验签。请指出这两种方案的问题,给出支持反事实账户的验证流程。
考察目标
- 识别包装签名优先于地址代码检查。
- 区分模拟部署、真实交易与调用内部副作用。
- 建立消息、链和会话的服务端信任边界。
用 ERC-6492 识别反事实签名,在一次模拟执行里完成部署和 ERC-1271 校验。
普通钱包能登录,但智能账户提示签名无效。其中一些地址尚无代码,另一些已经部署。服务端仅恢复 EOA 地址,或者先发一个 eth_call 部署、再发另一个 eth_call 验签。请指出这两种方案的问题,给出支持反事实账户的验证流程。
先识别 ERC-6492 后缀并解包,按规范在同一次模拟执行中处理必要的 factory 调用,再以 ERC-1271 校验合约签名;普通 EOA 使用对应消息格式恢复地址。不能要求反事实用户先发部署交易,也不能把模拟部署拆成两个 eth_call。验签结果之外,登录服务还要校验自己的 challenge、域、链、nonce 和有效期。
ERC-6492 的固定后缀是 32 字节,即十六进制 6492 重复 16 次。包装中包含 factory、factoryCalldata 与原始签名,检测到包装后不能把它直接交给 ecrecover。账户已部署时也需要正确解包;是否执行 factory 或准备动作按规范分支决定,不能无条件重复部署。
ERC-1271 接受消息哈希与任意长度签名,有效时返回 0x1626ba7e。哈希方式与协议对应:普通消息和 typed data 不可混用。不要写死规范没有承诺的低 gas 上限;同时服务需要总请求超时和资源控制,防止不可信验证耗尽服务容量。
eth_call 不把部署状态持久化,第二次独立调用看不到第一次模拟产生的代码。应使用成熟的 universal validator,让 factory 与验签处于同一次执行。参考实现提供带副作用及回滚封装的不同入口;内部 revert 策略与重入安全有关,不是 eth_call 获得“不写链”性质的前提。真正发送部署交易是另一个用户授权操作,登录校验不应偷偷执行它。
链从服务端允许的 challenge/消息上下文确定,不信任客户端自报“我是合约账户”。有代码也不代表实现 ERC-1271,EIP-7702 等账户形态需要所选验证工具明确支持。把无效签名、验证合约回滚、部署模拟失败与 RPC 不可用分开;基础设施失败不能静默降级为接受客户端恢复结果。
合约验签可能依赖链上状态,长期缓存通过结论会遗漏 owner 或授权变化。会话按地址与链绑定,必要时因权限变化失效;nonce 一次性消费,消息原文与签名重新核验,不能只校验一个客户端提交的哈希。
下面使用 viem 公共客户端的消息验证入口处理相应账户签名。它只负责签名有效性;SIWE 字段解析、服务端 nonce 消费和会话建立由登录服务另行执行。RPC URL 和允许链由服务端配置。
import { createPublicClient, http, type Address, type Hex } from "viem";
import { mainnet } from "viem/chains";
export async function verifyLoginSignature(
rpcUrl: string,
address: Address,
message: string,
signature: Hex,
) {
const client = createPublicClient({
chain: mainnet,
transport: http(rpcUrl),
});
return client.verifyMessage({ address, message, signature });
}
发现这道题有问题? 反馈此题