什么是 EIP-7702
EIP-7701
是以太坊 Pectra
升级的内容之一。是一种新的交易类型( 0x4
)。提高了以太坊的账号抽象的能力,支持直接使用 EOA
账号去执行临时智能合约。可以实现批量交易、gas
代付 等能力,这将会在钱包开发中起到很大作用。
EIP-7702 的能力
-
批量交易:可以在一次
EOA
账号发起交易时,发送多次交易。(非EIP-7702
类型的EOA
账号一次只能发送一笔交易) -
gas 代付:允许第三方(例如接收方或代理机构)为你支付本次交易的
gas
费用。(原始EOA
交易没有gas
代付能力) -
安全访问:授予临时的对合约的访问,用完后
EOA
账号恢复成为普通账号。调用时无须暴露私钥。 -
合约共享:逻辑合约可以共享,只需部署一次,便可提供给多个
EOA
账号使用。逻辑合约可永久存在链上(临时合约用完即毁)。
EIP-7702 在钱包场景下的作用
可以用在交易所钱包的 归集
操作上。传统的以太坊 EOA
账号进行归集操作,从用户地址发送到归集地址,只能一笔一笔进行归集,并且需要交易所下发一笔小额资金作为归集 gas
费用。效率十分低下且存在粉尘资金增多、额外消耗 gas
的问题。而采用 EIP-7702
的新交易类型,可以在共用 EOA
账号的同时,平滑升级到支持批量归集、gas
代付的能力。
EIP-7702 实现的核心原理
-
签名授权
EOA
账号在签名时候,签订一个授权信息,内容包括链 ID
、nonce
、委托地址
、EIP-712 的签名
。这个授权信息供验证者节点打包交易时,从委托地址中查出运行代码,然后附加到EOA
账号中。- 临时代码注入 节点收到
EOA
账号发送的交易后,验证EOA
账号的签名,从链上读取委托合约的bytecode
然后临时注入到EOA
账号的地址上。 -
自动代码卸载 在交易执行完后,该地址又会变回普通
EOA
地址,EXTCODEHASH(address) == 0x0
。代码区会变回0
。且状态不会存储到链上,确保不存在污染。
EIP-7702 实操及流程解析
git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/ethereum/eip-7702
- 安装依赖
安装
forge
库和OZ
代码库
forge install foundry-rs/forge-std
forge install OpenZeppelin/openzeppelin-contracts
- 启动 anvil
注意,在未完全升级之前,必须携带
--hardfork prague
参数,否则无法执行。
anvil --hardfork prague
- 使用 script 部署合约
❯ forge script script/BatchCallAndSponsor.s.sol \
--rpc-url http://127.0.0.1:8545 \
--broadcast \
--tc BatchCallAndSponsorScript -vvvv
观察到以下结果,代码部署成功。
6. 观察日志
- performDirectExecution() 批量转账日志观察
- performSponsoredExecution() gas 代付日志观察
6. 部署流程解析
- 原始 EOA 转账
首先来分析一下没有
EIP-7702
的原始转账情况,用户 A
通过离线签名,将交易发送到以太坊 RPC
节点,在通过对用户 A
的签名认证之后,可以将交易广播到以太坊网络。此时,交易只能一笔一笔的发送,且无 gas
代付能力。
- performDirectExecution() 批量转账
而在使用了
EIP-7702
后,交易流程发生了变化。首先,我们来看一个总的执行图。后面再回去根据代码分析。
1. 在这个执行图中(
A
代指 Alice
,B
代指 Bob
),EOA
账户 Alice
离线发起委托签名,签名时,将委托的逻辑合约包含在其中,发送给以太坊 RPC 节点。

-
然后,
RPC
节点经过验证签名有效后,读取这个逻辑合约的字节码,注入给EOA
用户Alice
。此时,用户Alice
从一个EOA
账户升级成为一个临时合约账户(合约的地址和用户Alice
的地址一致),可以执行合约的逻辑(批量转账等) -
在此处
Alice
的临时合约中,因为合约的调用者是Alice
,无须对Alice
进行验签处理,使用require(msg.sender == address(this))
即可完成签名的验证。 -
此外,由于发送给
RPC
节点时from
地址为Alice
,to
地址也为Alice
。在此过程中,Alice
为合约账户,属于合约内部交易,所以这条记录不会被记录在以太坊的交易记录中。 -
最后,这个账户就拥有了合约的调用能力,其中的交易给
Bob
的两笔交易(ETH
和ERC20
代币)都通过B.call()
的方式进行发送到以太坊网络中。(from
地址为Alice
,to
地址为Bob
,from
地址属于合约地址,to
地址属于EOA
地址,属合约内部交易,故也不存在交易记录中)
- performSponsoredExecution() gas 代付

`gas` 代付的情况相对于普通批量转账的场景而言,稍微复杂与一点。可以分为以下几步:
1. **Alice 构造委托合约,并签名**:

2. **Bob 持有 Alice 的数据,并签名**:

3. **Bob 发送交易到 RPC 节点**:

4. `RPC` 节点对 `Bob` 进行验签,通过后读取 `Alice` 委托的逻辑合约代码,注入到 `Alice` 的地址中。然后广播交易。此时,用户 `Alice` 从一个 `EOA` 账户升级成为一个临时合约账户(合约的地址和用户 `Alice` 的地址一致),可以执行合约的逻辑(批量转账等)
5. 并且,由于在这种 `gas` 代付的方案中,交易的发起者是 `Bob`,所以 `RPC` 节点在进行验签的时候,只会验证 `Bob` 的签名,`Alice` 的签名并不会去处理。在合约中,没办法像上面批量交易那样使用 `require(msg.sender == address(this))` 故我们临时合约中还需要去验证 `Alice` 的签名,以防止伪造交易的情况出现。

6. 此外,由于发送给 `RPC` 节点时,发送者 `from` 为 `Bob`,接受者 `to` 地址为 `Alice`,`Bob` 是一个 `EOA` 账户,`Alice` 为一个合约账户,故这笔交易记录会被记录上。

7. 但是,由于在 `Alice` 合约内部,发生了从 `Alice` 转账给 `Tom`(也可以是 `Bob`) 的情况,`Alice` 属于合约地址,`Tom`(`Bob`) 属EOA 地址,属合约内部交易,故这笔记录也不会存在以太坊的交易记录中。