返回章节列表
第 07 章高级

账户抽象 SDK 集成

使用 Alchemy AA SDK 或 ZeroDev 实现无 Gas 交易体验

6 课时3-4 小时

概述

账户抽象(Account Abstraction)是 Web3 用户体验革命的核心技术。通过 ERC-4337 标准,我们可以实现无 Gas 交易、社交恢复、批量操作等功能,大幅降低用户进入 Web3 的门槛。本章将介绍如何使用 Alchemy AA SDK 和 ZeroDev 快速集成账户抽象功能。

为什么需要账户抽象?

传统钱包(EOA)存在诸多痛点: 1. Gas 费用门槛:用户必须持有 ETH 才能执行交易 2. 助记词安全:丢失助记词 = 丢失资产 3. 单一签名:无法实现多签、社交恢复等高级功能 4. 交互体验差:每次操作都需要签名确认 ERC-4337 账户抽象解决方案通过智能合约钱包替代传统 EOA: - 可编程验证逻辑(支持多签、生物识别) - Paymaster 代付 Gas(用户无需持有 ETH) - 批量原子操作(多笔交易一次签名) - 可升级(账户逻辑可以迭代)

核心概念

ERC-4337 引入了几个关键组件: • UserOperation:替代传统 transaction 的用户意图结构,包含 sender、nonce、callData、签名等字段 • Bundler:打包多个 UserOp 并提交到链上的服务 • EntryPoint:验证和执行 UserOp 的入口合约(单例部署) • Paymaster:代付 Gas 费用的合约,可以实现 ERC-20 支付、赞助等策略 • Account:智能合约钱包,实现自定义验证逻辑

Alchemy AA SDK 配置

Alchemy AA SDK 提供了完整的账户抽象基础设施: - 智能账户管理 - Gas 估算与优化 - Paymaster 集成 - Bundler 服务 安装依赖: pnpm add @alchemy/aa-core @alchemy/aa-alchemy viem@2.x

ZeroDev SDK 配置

ZeroDev 是另一个流行的 AA SDK,提供: - Kernel:模块化智能账户 - Session Keys:临时授权密钥 - 多种签名方式:Passkey、社交登录 - 灵活的 Paymaster 策略 安装: pnpm add @zerodev/sdk @zerodev/passkey-sdk permissionless viem@2.x

React Hooks 封装

为了提供更好的开发体验,我们可以将账户抽象操作封装为 React Hooks: - useAAAccount: 管理智能账户状态和操作 - useBatchUserOp: 批量执行多笔交易 - usePaymaster: 管理 Gas 赞助策略

Session Keys 实现

Session Keys 是 AA 的高级功能,适用于: - 游戏:玩家在游戏中无需每次操作都签名 - 自动化:定期执行某些操作 - 限制授权:只允许调用特定函数 Session Key 可以设置权限范围、有效期、调用次数等限制,在不牺牲安全性的前提下提供流畅体验。

代码示例

Alchemy AA 客户端配置

使用 Alchemy AA SDK 创建智能账户客户端并发送 UserOperation

typescript
1import { createModularAccountAlchemyClient } from "@alchemy/aa-alchemy";
2import { LocalAccountSigner } from "@alchemy/aa-core";
3import { sepolia } from "@alchemy/aa-core";
4
5// 创建签名者(可以是 MetaMask、Passkey 等)
6const signer = LocalAccountSigner.mnemonicToAccountSigner(
7 process.env.MNEMONIC!
8);
9
10// 创建 AA 客户端
11const client = await createModularAccountAlchemyClient({
12 apiKey: process.env.ALCHEMY_API_KEY!,
13 chain: sepolia,
14 signer,
15 // Gas 策略(可选:使用 Paymaster)
16 gasManagerConfig: {
17 policyId: process.env.ALCHEMY_GAS_POLICY_ID!,
18 },
19});
20
21// 获取智能账户地址
22const smartAccountAddress = client.getAddress();
23console.log("Smart Account:", smartAccountAddress);
24
25// 发送 UserOp
26const { hash } = await client.sendUserOperation({
27 uo: {
28 target: "0x...", // 目标合约
29 data: "0x...", // calldata
30 value: 0n, // ETH 数量
31 },
32});
33
34// 等待交易完成
35const receipt = await client.waitForUserOperationTransaction({ hash });

ZeroDev Kernel 账户

使用 ZeroDev SDK 创建 Kernel 智能账户

typescript
1import { createKernelAccount, createKernelAccountClient } from "@zerodev/sdk";
2import { KERNEL_V3_1 } from "@zerodev/sdk/constants";
3import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator";
4import { http } from "viem";
5import { sepolia } from "viem/chains";
6import { privateKeyToAccount } from "viem/accounts";
7
8// 创建 ECDSA 验证器
9const signer = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
10const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
11 signer,
12 entryPoint: ENTRYPOINT_ADDRESS_V07,
13 kernelVersion: KERNEL_V3_1,
14});
15
16// 创建 Kernel 账户
17const account = await createKernelAccount(publicClient, {
18 plugins: {
19 sudo: ecdsaValidator,
20 },
21 entryPoint: ENTRYPOINT_ADDRESS_V07,
22 kernelVersion: KERNEL_V3_1,
23});
24
25console.log("Kernel Account:", account.address);
26
27// 创建客户端
28const kernelClient = createKernelAccountClient({
29 account,
30 chain: sepolia,
31 bundlerTransport: http(process.env.BUNDLER_URL!),
32 entryPoint: ENTRYPOINT_ADDRESS_V07,
33});
34
35// 发送交易
36const txHash = await kernelClient.sendTransaction({
37 to: "0x...",
38 data: "0x...",
39 value: 0n,
40});

React useAAAccount Hook

封装 AA 客户端为 React Hook,提供更好的开发体验

typescript
1'use client';
2
3import { useState, useCallback, useEffect } from 'react';
4import { createModularAccountAlchemyClient } from "@alchemy/aa-alchemy";
5import type { Address } from 'viem';
6
7interface UseAAAccountResult {
8 address: Address | null;
9 isLoading: boolean;
10 error: Error | null;
11 sendUserOp: (target: Address, data: `0x${string}`, value?: bigint) => Promise<string>;
12}
13
14export function useAAAccount(): UseAAAccountResult {
15 const [client, setClient] = useState<any>(null);
16 const [address, setAddress] = useState<Address | null>(null);
17 const [isLoading, setIsLoading] = useState(true);
18 const [error, setError] = useState<Error | null>(null);
19
20 useEffect(() => {
21 async function initClient() {
22 try {
23 const aaClient = await createModularAccountAlchemyClient({
24 // ... config
25 });
26 setClient(aaClient);
27 setAddress(aaClient.getAddress());
28 } catch (err) {
29 setError(err as Error);
30 } finally {
31 setIsLoading(false);
32 }
33 }
34 initClient();
35 }, []);
36
37 const sendUserOp = useCallback(
38 async (target: Address, data: `0x${string}`, value: bigint = 0n) => {
39 if (!client) throw new Error("Client not initialized");
40
41 const { hash } = await client.sendUserOperation({
42 uo: { target, data, value },
43 });
44
45 await client.waitForUserOperationTransaction({ hash });
46 return hash;
47 },
48 [client]
49 );
50
51 return { address, isLoading, error, sendUserOp };
52}

无 Gas 交易组件

实现一个用户无需持有 ETH 即可执行的 NFT Mint 操作

tsx
1'use client';
2
3import { useState } from 'react';
4import { useAAAccount } from '@/hooks/useAAAccount';
5import { encodeFunctionData } from 'viem';
6
7const NFT_CONTRACT = '0x...' as const;
8const NFT_ABI = [
9 {
10 name: 'mint',
11 type: 'function',
12 inputs: [{ name: 'to', type: 'address' }],
13 outputs: [],
14 },
15] as const;
16
17export function GaslessMint() {
18 const { address, sendUserOp, isLoading } = useAAAccount();
19 const [status, setStatus] = useState<'idle' | 'pending' | 'success' | 'error'>('idle');
20 const [txHash, setTxHash] = useState<string>();
21
22 const handleMint = async () => {
23 if (!address) return;
24 setStatus('pending');
25
26 try {
27 const callData = encodeFunctionData({
28 abi: NFT_ABI,
29 functionName: 'mint',
30 args: [address],
31 });
32
33 // 发送 UserOp(Gas 由 Paymaster 代付)
34 const hash = await sendUserOp(NFT_CONTRACT, callData);
35 setTxHash(hash);
36 setStatus('success');
37 } catch (err) {
38 console.error(err);
39 setStatus('error');
40 }
41 };
42
43 return (
44 <div className="p-6 bg-card border border-border rounded-xl">
45 <h2 className="text-xl font-bold mb-4">🎨 免 Gas Mint NFT</h2>
46 {isLoading ? (
47 <p>初始化智能账户...</p>
48 ) : (
49 <>
50 <p className="text-sm text-muted-foreground mb-4">
51 智能账户: {address}
52 </p>
53 <button
54 onClick={handleMint}
55 disabled={status === 'pending'}
56 className="px-6 py-3 bg-primary text-primary-foreground rounded-lg"
57 >
58 {status === 'pending' ? 'Minting...' : 'Mint NFT(免 Gas)'}
59 </button>
60 {status === 'success' && <p className="mt-4 text-green-400">✅ 成功!</p>}
61 </>
62 )}
63 </div>
64 );
65}

相关资源

ERC-4337 官方文档Alchemy Account KitZeroDev DocumentationAccount Abstraction SDK (GitHub)
上一章: 签名与身份验证