TONY'S LAB · 技术文件
关于 EIP-7702 账户委托机制的说明
—— 一份你可能已经签过字的全权委托书
一、摘要
EIP-7702 由 Vitalik Buterin 于 2024 年提出,2025 年 5 月随 Pectra 升级在以太坊主网启用。它允许一个普通钱包地址(EOA)把执行逻辑委托给一个智能合约,同时保留原地址、原私钥、原资产。
对外,它被描述为「让存量钱包零成本升级为智能合约钱包」;对内,它引入了一种此前不存在的签名类型——一次签名,即可让某个合约地址长期代你执行任意操作。
本文说明三件事:它怎么工作,它能拿到多大权限,以及这个权限的边界应该划在哪里。
二、机制:它是怎么运作的
(一)一种新的交易类型
Pectra 引入了 0x04 类型的交易。和普通转账不同,它多了一个字段:authorization_list(授权列表)。列表中的每一项,都是一张授权书。
(二)授权书里写了什么
每一项包含六个字段:chain_id、address(受托合约)、nonce、y_parity、r、s。前三个是条款,后三个是签名。签名对象是 keccak256(0x05 ‖ rlp([chain_id, address, nonce]))。
请注意这个签名里不包含任何金额、收款人或调用数据。它只声明一件事:我把这个地址的执行权,交给 address。
(三)链上留下的痕迹
交易上链后,这个 EOA 的 code 字段会变成 23 字节的委托指示符:
ef 01 00 ‖ a1 b2 c3 … 9f (0x)
0xef 开头不是可执行代码,而是一个标记。EVM 看到它就知道:这个地址的代码在别处。此后所有发往这个 EOA 的调用都会转发到受托合约执行,但使用的是 EOA 自己的存储和余额——受托合约的代码运行在委托方的上下文里。
(四)它不会自己消失
委托持久生效,直到你主动改委托,或者签一张 address 为全零地址的授权把它清空。没有过期时间,没有额度上限,没有单笔限额。
(五)三个容易被忽略的细节
- 授权中的
nonce必须等于账户当前 nonce,每生效一条加一,所以一笔交易里可以塞进多张授权书。 - 受托合约没有构造函数——部署时写的初始化逻辑不会执行,合约必须自己处理「未被初始化」的状态。
chain_id填0表示「所有链都认」。这是为跨链同地址场景设计的,代价是同一个签名在每条支持 7702 的链上都有效。
三、权限:签下去等于交出去什么
(一)设计初衷
- 批量交易:approve + swap 一笔签完,不用再签两次。
- Gas 代付:由第三方付 gas,或用 ERC-20 付 gas。
- Passkey / 生物识别:手机指纹签名,不碰助记词。
- 社交恢复与会话密钥:给 dApp 一个限时限额的临时权限。
- 零迁移:老地址、老资产、老 ENS 全部保留。
(二)与 ERC-4337 的分工
| ERC-4337 | EIP-7702 | |
|---|---|---|
| 地址 | 另开一个智能账户 | 原地址不变 |
| 入口 | EntryPoint + Bundler | 原生交易类型 |
| 迁移成本 | 需要搬资产 | 零 |
| 权限来源 | 合约代码内部定义 | 受托合约决定 |
4337 是「另建一个智能账户」,7702 是「给老账户装一个可替换的大脑」。前者权限由合约代码约束,后者权限完全由受托合约决定——而受托合约可以是任何人部署的任何东西。
四、风险条款
(一)一次签名,全部资产
传统 approve 钓鱼,骗到的是一种代币的额度,损失以那一种资产为上限。7702 钓鱼骗到的是整个账户的执行权:受托合约可以把这个地址上的所有资产、所有既有授权、所有 NFT 一次转走。爆炸半径从「部分」变成「全部」。
(二)chain_id = 0 的跨链重放
一张 chain_id 为 0 的授权,在以太坊、BNB Chain、Polygon 以及所有支持 7702 的链上同时有效。用户以为自己只在一个网站上签了一次。
(三)存储冲突
EOA 此前没有存储。受托合约若按普通合约的布局写 storage,会和这个地址上的状态产生冲突。写 7702 兼容的合约,必须把 storage 布局当成对外接口来设计。
(四)受托合约可以被换掉
委托指向的是一个地址,不是一段代码。如果那个合约可升级、有 owner、有 delegatecall 后门,用户等于长期租了一间房东随时能进出的房子。
(五)没有构造函数
初始化逻辑跑不了,缺一步就可能出现「任何人都能抢先初始化」的经典漏洞。
(六)工具链跟不上
区块浏览器、撤销工具、硬件钱包的签名界面,大多还没准备好展示「你正在委托执行权」这件事。用户看到的是一串哈希,签下去的是整个账户。
7702 真正改变的不是钱包的能力,是签名的语义。
以前签名是「我同意这一笔交易」;现在签名可以是「我同意你以后说的每一句话」。
五、处理意见
(一)反对的意见
7702 不是必需品。批量交易、gas 代付,ERC-4337 都能做,代价只是迁移地址。用「迁移成本」换「全账户风险」,这笔交易不划算。推文作者 0xAA 的判断是弊大于利,不该被继续支持。
(二)支持的意见
迁移地址的成本被系统性低估了。要求几千万存量用户为了批量交易去换地址,等于让账户抽象永远停在少数派。7702 是唯一能在不迁移的前提下把账户抽象铺开的路径,风险可以在钱包层约束。
(三)本文意见
不禁用,但要设边界:
- 热钱包、托管钱包、交易所钱包:直接禁用 7702,或强制拒绝
chain_id = 0的授权。 - 钱包签名界面:把「这是委托执行权」和「这是一笔转账」做成完全不同的确认流程——不同配色、不同文案、不同层级的二次确认。
- 默认收紧:授权默认只对当前链生效,默认不接受可升级合约作为受托方。
- 一键撤销:把「查我有没有被委托」和「撤销委托」做成显眼入口,而不是藏在高级设置里。
最后一点:如果根因是签名基础设施被突破——私钥泄露、HSM 或 MPC 策略引擎被绕过——那么没有 7702 也一样丢钱,黑客直接转账即可。7702 不是根因,它只是把「拿到签名之后能造成的破坏」放大到了上限。真正需要修的是两端:谁能拿到签名,以及拿到之后能做什么。
六、自查:怎么查自己有没有被委托
判断标准只有一条:这个地址的 code 是不是以 0xef0100 开头。是,就被委托了;返回 0x,就是干净的。
(一)最可靠:直接问节点
eth_getCode 是所有方法里最不容易骗人的一个——它不经过任何第三方界面,直接读链上状态。
# Foundry 的 cast
cast code 0x你的地址 --rpc-url https://eth.llamarpc.com
# 或者裸 curl
curl -s -X POST https://eth.llamarpc.com \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,
"method":"eth_getCode",
"params":["0x你的地址","latest"]}'
如果返回一串以 0xef0100 开头的内容,后面 40 位十六进制就是受托合约地址。把它贴进区块浏览器看一眼是谁——认得,是你在用的智能钱包;不认得,就是出事了。
(二)用区块浏览器
地址页的 Contract / Code 标签里,被委托的账户会直接显示出 0xef0100…;部分浏览器还会在地址旁加一个 Delegated 标记,并能跳转到受托合约。这个方法适合肉眼确认,但注意两点:确认自己看的是哪条链,以及别在缓存过的页面上做判断。
(三)四条容易漏的地方
- 一条链一条链查。chain_id 为 0 的授权在所有支持 7702 的链上都有效,只查主网会漏掉其它链上的委托。
- 查 EOA,不查合约。合约地址本来就有 code,这个方法对合约地址没有意义。
- 受托地址是空合约时,协议层视同没有委托——但别指望这一点,攻击者不会给你留一个空地址。
- 查到不认识的受托地址,先停手。不要在同一个页面里继续签任何东西,换一台设备或硬件钱包重新确认,再谈撤销。
(四)撤销
撤销的方式是签一张 address 为全零地址的授权去覆盖原来那条。它本身是一笔链上交易:要付 gas,授权里的 nonce 必须等于账户当前 nonce。部分钱包和授权管理工具已经提供了「撤销委托」按钮,但请你记住——撤销也是一次签名。钓鱼页面完全可以把「撤销」做成一条新的授权,签之前把受托地址逐字节看清楚。
自查这件事,与其等出事再查,不如记进季度清单:换钱包、换设备、签过大额授权之后,各查一次。
七、委托书(示例)
二〇二六年十月三十日