EIP-7702 实施指南:构建和测试智能账户

  • QuickNode
  • 发布于 2024-06-19 10:20
  • 阅读 64

EIP-7702引入了一种新的交易类型0x4,使外部账户(EOA)能够执行临时的智能合约功能,支持批量交易、赞助Gas支付等功能。文章详细介绍了EIP-7702的技术细节、使用场景,并通过Foundry工具展示了如何测试和部署该功能。


概述

EIP-7702以太坊的 Pectra 升级 中引入了一种新的交易类型 0x4,使外部拥有账户(EOAs)能够执行临时的智能合约功能。这一账户抽象的进步弥合了 EOAs 和智能合约之间的差距,实现了批量交易、赞助 gas 支付和受控访问委托等关键功能。

注意

虽然 EIP-7702 尚未在主网或测试网上线,但可以通过本地 Foundry 环境和 Odyssey 测试网 在 Pectra 升级发布前进行测试

本指南将带你了解 EIP-7702 的技术细节、用例以及如何使用 Foundry 和 Foundry 的 cheatcodes 进行测试。通过本指南,你将清楚地了解如何在项目中利用 EIP-7702,通过部署一个实现合约来查看 EIP-7702 的实际应用,并测试 EIP-7702 的功能。

你将完成的任务

  • 学习如何使用 EOA 实现 0x4 交易
  • 通过 EIP‑7702 开发智能账户
  • 在本地网络上测试和部署 0x4 交易,查看 EIP‑7702 的实际应用

你需要准备的内容

EIP-7702 交易

虽然典型的以太坊交易要么是转账,要么是与智能合约交互,但新的 0x4 交易类型允许 EOA 直接执行代码。这为外部拥有账户(EOAs)解锁了新的可能性,使它们能够更像智能合约一样运作。

通过这一新标准,EOAs 可以直接从自己的地址执行智能合约逻辑,从而实现以下功能:

  • 批量交易:将多个操作合并为一个原子交易(代币批准、交换、转账)。
  • 有限访问委托:授予临时的、有范围的权限,而无需暴露密钥。
  • Gas 赞助:允许第三方(例如支付方)为你的交易支付 gas 费用。
  • 钱包恢复:为私钥丢失实现恢复机制。

以太坊账户类型

  • 外部拥有账户(EOAs):仅由私钥控制;它们持有资金但无法运行代码。(例如,用户钱包如 MetaMask)
  • 智能合约账户:持有代码并可以执行复杂操作。(例如,Uniswap Factory、Uniswap Router)

通过 本指南 了解更多关于以太坊账户类型的信息。

签名授权

用户(EOA)签署一个授权消息,该消息包括链 ID、nonce、委托地址和签名部分(y_parityrs)。这生成了一个签名授权,确保只有批准的实现合约可以执行交易,并防止重放攻击。

对于每个授权的委托地址,用户(EOA)存储一个委托指示器,指向 EOA 将委托给的实现合约。当用户(或赞助者)执行 EIP-7702 交易时,它会从该指示器指示的地址加载并运行代码。

交易构建

在典型的以太坊交易中,如果你想调用智能合约上的函数,你将 to 字段设置为该合约的地址,并包含适当的 data 以调用其函数。在 EIP-7702 中,你将 to 字段设置为 EOA 的地址,并包含 data 以调用实现合约的函数,同时附带签名授权消息

EIP-7702 交易的结构

以下代码片段展示了如何使用 Viem 的钱包客户端为 EIP‑7702 智能账户构建批量交易。

  1. 它为特定合约生成授权签名。
  2. 然后,它构建一个交易,其中 to 字段设置为智能账户自己的地址。
  3. data 字段通过编码对 execute 函数的调用创建,该函数包含两个调用对象的数组。execute 函数应在实现合约中定义,并处理批量交易逻辑。
  4. 最后,交易在 authorizationList 中包含签名授权,允许智能账户将执行委托给实现合约。

如果另一个钱包(赞助者)想要执行此交易(赞助交易),它可以使用相同的授权签名将执行委托给实现合约。

注意: 实现合约应设计为处理由 EIP-7702 启用的批量交易和其他功能。此外,它们应包括 nonce 和重放保护机制,以防止未经授权的交易。

使用 Viem 发送 EIP-7702 交易

import { createWalletClient, http, parseEther } from 'viem'
import { anvil } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { eip7702Actions } from 'viem/experimental'
import { abi, contractAddress } from './contract' // 假设你已经部署了合约并在单独的文件中导出了 ABI 和合约地址

const account = privateKeyToAccount('0x...')

const walletClient = createWalletClient({
  account,
  chain: anvil,
  transport: http(),
}).extend(eip7702Actions())

const authorization = await walletClient.signAuthorization({
  contractAddress,
})

const hash = await walletClient.sendTransaction({
  authorizationList: [authorization],
  data: encodeFunctionData({
    abi,
    functionName: 'execute',
    args: [\
      [\
        {\
          data: '0x',\
          to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',\
          value: parseEther('0.001'),\
        },\
        {\
          data: '0x',\
          to: '0xd2135CfB216b74109775236E36d4b433F1DF507B',\
          value: parseEther('0.002'),\
        },\
      ],\
    ]
  }),
  to: walletClient.account.address,
})

EIP-7702 交易的流程

如果 EIP-7702 感觉抽象或复杂,不用担心!我们将通过一个动手演示来分解它——部署一个实现合约并测试其功能。

如何使用 Foundry 测试 EIP-7702 功能

在本节中,你将学习如何使用 Foundry 实现 EIP-7702 功能,Foundry 是一个强大的智能合约开发工具。

Foundry Cheatcodes

在撰写本文时,EIP‑7702 尚未在以太坊主网或公共测试网上得到支持。但是,你可以使用 Foundry 在本地网络上实验其功能。Foundry 提供了一组 cheatcodes——特殊的命令,用于修改以太坊虚拟机(EVM)的行为以简化测试。在本指南中,我们将使用 signDelegationattachDelegationsignAndAttachDelegation cheatcodes 来测试 EIP‑7702 功能。有关更多信息,请查看 Foundry Cheatcodes 文档

项目概述

在本项目中,我们部署了一个名为 BatchCallAndSponsor 的实现合约,该合约支持以下功能:

  • 批量交易:在单个交易中执行多个调用。
  • 赞助交易:允许赞助者支付 gas 费用。
  • 重放保护:使用 nonce 防止交易重放。

项目包括以下文件:

  • BatchCallAndSponsor.sol – 包含批量交易和赞助交易的核心逻辑。
  • BatchCallAndSponsor.t.sol – 包括直接执行和赞助执行的单元测试。
  • BatchCallAndSponsor.s.sol – 用于部署合约并执行网络交易的脚本。
  • MockERC20.sol – 用于测试代币转账的模拟 ERC-20 代币合约。

警告

本项目中的所有材料和代码仅用于教育目的。它们不适用于生产环境。

环境设置

步骤 1:安装 Foundry

如果尚未安装 Foundry,请使用以下命令进行安装:

curl -L https://foundry.paradigm.xyz | bash

然后,重新启动终端并运行:

foundryup

这将确保你安装了最新版本。

步骤 2:初始化 Foundry 项目

如果你想从头开始设置项目,请初始化一个新的 Foundry 项目:

forge init eip-7702-project
cd eip-7702-project

或者,你可以克隆 QuickNode 示例项目:

git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/ethereum/eip-7702

步骤 3:安装所需的依赖项

安装所需的库:

forge install foundry-rs/forge-std
forge install OpenZeppelin/openzeppelin-contracts
  • forge-std:提供测试的实用函数。
  • openzeppelin-contracts:包括 ERC-20 实现和加密实用工具。

步骤 4:配置重映射

为了简化导入路径,请运行以下命令。它将在项目根目录中创建一个 remappings.txt 文件,包括所需的重映射。

forge remappings > remappings.txt

这将确保像以下这样的合约导入能够正确工作,而无需长相对路径:

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

步骤 5:更新 Foundry 配置以支持 EIP‑7702

修改 foundry.toml 以确保与 EIP‑7702 兼容,设置 Prague 硬分叉。在 [profile.default] 部分添加以下行:

evm_version = "prague"

这是必要的,因为 EIP‑7702 仅在 Prague 升级之后可用。

如果你使用示例项目,可以跳过此部分及以下步骤。

步骤 6:实现智能合约

src 文件夹中,创建一个名为 BatchCallAndSponsor.sol 的新文件,并从 EIP-7702 示例项目 中添加合约逻辑。这是一个支持批量交易和赞助 gas 的基本实现合约。

不要忘记从 src 文件夹中删除任何未使用的文件(例如 Counter.sol)。

实现合约的详细信息在 实现合约详解 部分提供。

步骤 7:编写测试用例

test 文件夹中,创建一个名为 BatchCallAndSponsor.t.sol 的文件来测试合约。从 EIP-7702 示例项目 中添加测试用例。

不要忘记从 test 文件夹中删除任何未使用的文件(例如 Counter.t.sol)。

测试用例的详细信息在 测试用例详解 部分提供。

步骤 8:创建部署脚本

script 文件夹中创建一个名为 BatchCallAndSponsor.s.sol 的文件,用于部署合约并执行交易。从 EIP-7702 示例项目 中添加部署脚本。

不要忘记从 script 文件夹中删除任何未使用的文件(例如 Counter.s.sol)。

部署脚本的详细信息在 部署脚本详解 部分提供。

项目结构如下:

├── README.md
├── foundry.toml                    # Foundry 配置文件
├── lib                             # 已安装的包
│   ├── forge-std
│   └── openzeppelin-contracts
├── remappings.txt                  # 重映射文件
├── script
│   └── BatchCallAndSponsor.s.sol   # 部署脚本
├── src
│   └── BatchCallAndSponsor.sol     # 实现合约
└── test
    └── BatchCallAndSponsor.t.sol   # 测试用例

如果你想跳过详解并直接进入操作,请转到 运行和测试 EIP-7702 项目 部分。

实现合约详解

BatchCallAndSponsor 合约是一个支持批量交易和赞助 gas 的简单实现合约。

请查看项目中的 BatchCallAndSponsor.sol 文件以获取完整实现。以下部分提供了合约功能的简要概述;但请注意,未包含完整的实现代码。

批量执行逻辑

合约中的 execute 函数接受一个 Call 结构体数组,每个结构体代表一个不同的调用,并指定目标地址、值(以 Ether 为单位)和调用数据。

struct Call {
    address to;
    uint256 value;
    bytes data;
}

function execute(Call[] calldata calls) external payable {
    require(msg.sender == address(this), "Invalid authority");
    _executeBatch(calls);
}

function _executeBatch(Call[] calldata calls) internal {
    uint256 currentNonce = nonce;
    nonce++;

    for (uint256 i = 0; i < calls.length; i++) {
        _executeCall(calls[i]);
    }

    emit BatchExecuted(currentNonce, calls);
}

function _executeCall(Call calldata callItem) internal {
    (bool success,) = callItem.to.call{value: callItem.value}(callItem.data);
    require(success, "Call reverted");
    emit CallExecuted(msg.sender, callItem.to, callItem.value, callItem.data);
}

签名验证逻辑

合约使用 OpenZeppelin 的 ECDSA 库和 MessageHashUtils 验证签名。签名消息包括调用者地址、目标合约、调用和 nonce。

bytes32 digest = keccak256(abi.encodePacked(nonce, encodedCalls));
require(ECDSA.recover(digest, signature) == msg.sender, "Invalid signature");

处理直接和赞助执行

合约支持直接执行或赞助执行。

  • 直接执行:调用者自己执行调用。
  • 赞助执行:赞助者在验证签名是由 EOA 签署后,代表调用者执行调用。
function execute(Call[] calldata calls) external payable {
    // 调用者直接执行调用
}
function execute(Call[] calldata calls, bytes calldata signature) external payable {
    // 赞助者代表调用者执行调用
}

使用 Nonce 进行重放保护

合约使用 nonce 防止重放攻击。每次成功执行后,nonce 都会递增。如果不实现 nonce,攻击者可以多次重放相同的交易。

function _executeBatch(Call[] calldata calls) internal {
    uint256 currentNonce = nonce;
    nonce++; // 递增 nonce 以防止重放攻击

    for (uint256 i = 0; i < calls.length; i++) {
        _executeCall(calls[i]);
    }

    emit BatchExecuted(currentNonce, calls);
}

测试用例详解

BatchCallAndSponsor.t.sol 文件包含 BatchCallAndSponsor 合约的测试用例。测试用例涵盖了直接执行和赞助执行场景、重放保护和错误处理。

以下部分提供了一些测试代码的见解,但并未包含所有代码。完整的测试文件请参考 BatchCallAndSponsor.t.sol 文件。

直接执行测试

testDirectExecution 函数测试调用者(即 Alice)直接执行调用。它验证 Alice 在单个交易中向 Bob 发送 1 ETH 和 100 个代币。

在此测试中,Alice 授权实现合约代表她执行交易。我们使用 signAndAttachDelegation cheatcode 签署授权消息并将其附加到交易中。

然后,Alice 自己在Alice 的 EOA 上调用 execute 函数,并传递调用数组,这在没有 EIP-7702 的情况下是不可能的。

testDirectExecution 函数的部分代码


function testDirectExecution() public {
    console2.log("Sending 1 ETH from Alice to Bob and transferring 100 tokens to Bob in a single transaction");
    BatchCallAndSponsor.Call[] memory calls = new BatchCallAndSponsor.Call[](2);

    // ETH 转账
    calls[0] = BatchCallAndSponsor.Call({to: BOB_ADDRESS, value: 1 ether, data: ""});

    // 代币转账

>- 原文链接: [quicknode.com/guides/eth...](https://www.quicknode.com/guides/ethereum-development/smart-contracts/eip-7702-smart-accounts)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。