Skip to main content

zerodev recovery

ZeroDev 账户恢复脚本

import "dotenv/config"
import {
createKernelAccount,
createZeroDevPaymasterClient,
createKernelAccountClient,
} from "@zerodev/sdk"
import { UserOperation, bundlerActions } from "permissionless"
import { http, createPublicClient, Hex, toFunctionSelector, parseAbi, encodeFunctionData, zeroAddress } from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { polygonMumbai } from "viem/chains"
import { createWeightedECDSAValidator } from "@zerodev/weighted-ecdsa-validator"
import { ECDSA_VALIDATOR_ADDRESS, signerToEcdsaValidator } from "@zerodev/ecdsa-validator"

if (!process.env.BUNDLER_RPC || !process.env.PAYMASTER_RPC || !process.env.PRIVATE_KEY) {
throw new Error("BUNDLER_RPC or PAYMASTER_RPC or PRIVATE_KEY is not set")
}

const publicClient = createPublicClient({
transport: http(process.env.BUNDLER_RPC),
})

const oldSigner = privateKeyToAccount(generatePrivateKey())
const newSigner = privateKeyToAccount(process.env.PRIVATE_KEY as Hex)
const guardian = privateKeyToAccount(generatePrivateKey())

const recoveryExecutorAddress = '0x2f65dB8039fe5CAEE0a8680D2879deB800F31Ae1'
const recoveryExecutorFunction = 'function doRecovery(address _validator, bytes calldata _data)'
const recoveryExecutorSelector = toFunctionSelector(recoveryExecutorFunction)

const main = async () => {

const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
signer: oldSigner,
})

const guardianValidator = await createWeightedECDSAValidator(publicClient, {
config: {
threshold: 100,
signers: [
{ address: guardian.address, weight: 100 },
],
},
signers: [guardian]
})

const account = await createKernelAccount(publicClient, {
plugins: {
sudo: ecdsaValidator,
regular: guardianValidator,
executorData: {
executor: recoveryExecutorAddress,
selector: recoveryExecutorSelector,
},
}
})

console.log('recovery selector:', recoveryExecutorSelector)

const kernelClient = createKernelAccountClient({
account,
chain: polygonMumbai,
transport: http(process.env.BUNDLER_RPC),
sponsorUserOperation: async ({ userOperation }): Promise<UserOperation> => {
const paymasterClient = createZeroDevPaymasterClient({
chain: polygonMumbai,
transport: http(process.env.PAYMASTER_RPC),
})
return paymasterClient.sponsorUserOperation({
userOperation,
})
},
})

console.log('performing recovery...')
const userOpHash = await kernelClient.sendUserOperation({
userOperation: {
callData: encodeFunctionData({
abi: parseAbi([recoveryExecutorFunction]),
functionName: 'doRecovery',
args: [ECDSA_VALIDATOR_ADDRESS, newSigner.address],
})
},
})

console.log('recovery userOp hash:', userOpHash)

const bundlerClient = kernelClient.extend(bundlerActions)
await bundlerClient.waitForUserOperationReceipt({
hash: userOpHash,
})

console.log('recovery completed!')

const newEcdsaValidator = await signerToEcdsaValidator(publicClient, {
signer: newSigner,
})

const newAccount = await createKernelAccount(publicClient, {
deployedAccountAddress: account.address,
plugins: {
sudo: newEcdsaValidator,
}
})

const newKernelClient = createKernelAccountClient({
account: newAccount,
chain: polygonMumbai,
transport: http(process.env.BUNDLER_RPC),
sponsorUserOperation: async ({ userOperation }): Promise<UserOperation> => {
const paymasterClient = createZeroDevPaymasterClient({
chain: polygonMumbai,
transport: http(process.env.PAYMASTER_RPC),
})
return paymasterClient.sponsorUserOperation({
userOperation,
})
},
})

console.log('sending userOp with new signer')
const userOpHash2 = await newKernelClient.sendUserOperation({
userOperation: {
callData: await newAccount.encodeCallData({
to: zeroAddress,
value: BigInt(0),
data: "0x",
}),
},
})
console.log('userOp hash:', userOpHash2)

await bundlerClient.waitForUserOperationReceipt({
hash: userOpHash2,
})
console.log('userOp completed!')
}

main()

代码解释

这段代码是一个 Node.js 脚本,使用了多个与区块链交互的库,特别是与以太坊兼容的区块链(如 Polygon Mumbai 测试网)。这段脚本的主要目的是通过使用智能合约和密钥管理操作来执行账户恢复过程。下面是代码的逐行解释:

首先,导入所需的库和函数:

  • dotenv/config:加载环境变量文件 .env
  • @zerodev/sdk:ZeroDev SDK,用于与区块链交互。
  • permissionless:可能是一个库,用于处理无需权限的区块链交互。
  • viem:一个区块链交互库,含有多个工具函数。
  • @zerodev/weighted-ecdsa-validator@zerodev/ecdsa-validator:用于处理 ECDSA 验证器的库。

接着,检查环境变量是否已设置,如果没有设置,则抛出错误:

  • BUNDLER_RPC:处理用户操作的 Bundler RPC 地址。
  • PAYMASTER_RPC:处理支付操作的 Paymaster RPC 地址。
  • PRIVATE_KEY:用户的私钥。

创建 publicClient 用于与区块链公开节点进行通信。

定义了一些账户和相关地址:

  • oldSignernewSigner 代表旧的和新的签名者账户。
  • guardian 是一个守护者账户,可能用于恢复机制或额外的安全措施。
  • recoveryExecutorAddress 是恢复操作执行者的智能合约地址。
  • recoveryExecutorFunction 是恢复执行者合约中的函数签名。
  • recoveryExecutorSelector 是该函数的选择器(函数标识符)。

main 函数是脚本的主要执行函数:

  1. 创建 ECDSA 验证器实例。
  2. 创建守护者验证器实例。
  3. 创建一个内核账户,配置其插件,如 sudo 和 regular 插件,以及恢复执行者数据。
  4. 使用内核账户客户端发起恢复操作。
  5. 等待恢复操作的收据。
  6. 创建新的 ECDSA 验证器实例。
  7. 更新内核账户,设置新的 ECDSA 验证器。
  8. 使用新的内核账户客户端发送用户操作。
  9. 等待用户操作的收据。

main 函数最后,调用 main() 来执行脚本。

整个脚本的流程是:

  • 配置和初始化所需的客户端和验证器。
  • 通过内核账户执行账户恢复操作。
  • 更新内核账户的验证器。
  • 发送新的用户操作以验证更新是否成功。

这个脚本可能是用于一个账户恢复场景,在这个场景中,如果某个用户丢失了私钥,可以通过一系列预设的恢复机制(如守护者账户或多重签名验证器)来更换账户的控制权。这种机制在去中心化身份和钱包解决方案中非常常见。

publicClient account kernelClient bundlerClient 关系?

在这段代码中,publicClientaccountkernelClientbundlerClient 是与区块链交互的不同实体,它们之间的关系如下:

  1. publicClient: publicClient 是一个客户端实例,它使用提供的 RPC (远程过程调用) 地址来与区块链网络进行通信。这个客户端不需要特定的用户身份验证或私钥就能与公共区块链节点进行交互。它可以用来读取区块链数据或者发送不需要特定用户权限的请求,比如创建新的 ECDSA 验证器或者内核账户。

  2. account: account 代表一个在区块链上的账户,它是通过 createKernelAccount 函数创建的。这个账户拥有一系列插件配置,它决定了账户可以执行哪些类型的操作以及如何执行这些操作。在这段代码中,account 被配置了两个验证器(sudo 和 regular)和一个恢复执行者数据。

  3. kernelClient: kernelClient 是一个客户端实例,它与 account 相关联,用于发送和管理与该内核账户相关的用户操作。它使用 account 的配置和权限来构建和发送交易。kernelClient 通过 createKernelAccountClient 函数创建,并且配置了如何通过 Paymaster 客户端赞助用户操作,这是一种支付交易费用的机制。

  4. bundlerClient: bundlerClientkernelClient 的一个扩展,它继承了 kernelClient 的所有功能,并且添加了 bundlerActions 的特定功能。bundlerActions 可能包含了一些特定的方法,用于处理与 Bundler 相关的操作,Bundler 是一种服务,它帮助用户将他们的操作打包并发送到区块链上。

总结关系:

  • publicClient 是用来与区块链网络进行通信的基础客户端。
  • account 是一个具体的区块链账户,拥有特定的配置和权限。
  • kernelClient 是为了与 account 相关的操作而创建的客户端,用于执行和赞助用户交易。
  • bundlerClient 基于 kernelClient,添加了与 Bundler 交互的功能。

这些组件共同工作,以便在区块链上执行复杂的操作,如账户恢复和更新验证器,同时处理交易费用和与区块链网络的交互。