import type { ModularSigner } from "@zerodev/permissions" import { decodeParamsFromInitCode, toPermissionValidator } from "@zerodev/permissions" import { CallPolicyVersion, ParamCondition, toCallPolicy } from "@zerodev/permissions/policies" import { type KernelSmartAccount, type KernelValidator, createKernelAccount } from "@zerodev/sdk" import type { EntryPoint } from "permissionless/types" import type { Address, Chain, Transport } from "viem" import { erc20Abi } from "viem" import { invoiceManagerAbi } from "../../abis/invoiceManagerAbi" import { vaultManagerAbi } from "../../abis/vaultManagerAbi" import { getInvoiceManagerAddress, getVaultManagerAddress } from "../../utils/constants" import { getPublicClient } from "../../utils/getPublicClient" type GetPermissionAccountParams< TEntryPoint extends EntryPoint, TTransport extends Transport, TChain extends Chain | undefined = Chain | undefined, TSmartAccount extends KernelSmartAccount< TEntryPoint, TTransport, TChain > = KernelSmartAccount > = { account: TSmartAccount entryPoint: TEntryPoint sessionSigner: ModularSigner chainId: number vaults: { token: Address vault: Address }[] cabPaymasterAddress: Address } export const getPermissionAccount = async < TEntryPoint extends EntryPoint, TTransport extends Transport, TChain extends Chain | undefined = Chain | undefined, TSmartAccount extends KernelSmartAccount< TEntryPoint, TTransport, TChain > = KernelSmartAccount >( params: GetPermissionAccountParams< TEntryPoint, TTransport, TChain, TSmartAccount > ): Promise> => { const { account, entryPoint, sessionSigner, chainId, vaults, cabPaymasterAddress } = params const kernelVersion = account.kernelVersion // as GetKernelVersion const invoiceManagerAddress = getInvoiceManagerAddress({ cabPaymasterAddress }) const vaultManagerAddress = getVaultManagerAddress({ cabPaymasterAddress }) const publicClient = getPublicClient(chainId) // @ts-ignore const permissinos = vaults .flatMap(({ token }) => [ // deposit into vault { abi: erc20Abi, target: token, functionName: "approve", args: [ { condition: ParamCondition.EQUAL, value: vaultManagerAddress }, null ] } ]) // @ts-ignore .concat([ // register paymaster { // @ts-ignore abi: invoiceManagerAbi, target: invoiceManagerAddress, functionName: "registerPaymaster", args: [ { condition: ParamCondition.EQUAL, value: cabPaymasterAddress }, { condition: ParamCondition.EQUAL, value: cabPaymasterAddress }, null ] }, // complete withdrawal { // @ts-ignore abi: vaultManagerAbi, target: vaultManagerAddress, functionName: "completeWithdrawals", args: [null] }, // deposit to vaultManager { // @ts-ignore abi: vaultManagerAbi, target: vaultManagerAddress, functionName: "deposit", args: [ // { // condition: ParamCondition.EQUAL, // value: token // }, // { // condition: ParamCondition.EQUAL, // value: vault // }, null, null, null, null // { // condition: ParamCondition.EQUAL, // value: false // } ] } ]) const policies = toCallPolicy({ // @ts-ignore Ignore type error for different abi types permissions: permissinos, policyVersion: CallPolicyVersion.V0_0_4 }) const permissionPlugin = await toPermissionValidator(publicClient, { entryPoint, signer: sessionSigner, policies: [policies], kernelVersion }) const initCode = await account.generateInitCode() const { index, useMetaFactory } = decodeParamsFromInitCode( initCode, kernelVersion ) const { initConfig } = await account.kernelPluginManager.getValidatorInitData() const sessionAccount = await createKernelAccount(publicClient, { entryPoint, plugins: { sudo: account.kernelPluginManager.sudoValidator as KernelValidator< TEntryPoint, string >, regular: permissionPlugin }, kernelVersion: kernelVersion, index: index, // @ts-ignore initConfig: initConfig, useMetaFactory: useMetaFactory }) return sessionAccount as KernelSmartAccount }