import type { GetKernelVersion, KernelValidator } from "@zerodev/sdk/types" import type { TypedData } from "abitype" import { type UserOperation, getUserOperationHash } from "permissionless" import { SignTransactionNotSupportedBySmartAccount, type SmartAccountSigner } from "permissionless/accounts" import type { EntryPoint, GetEntryPointVersion } from "permissionless/types/entrypoint" import type { Address, Chain, Client, Hex, LocalAccount, Transport, TypedDataDefinition } from "viem" import { toAccount } from "viem/accounts" import { signMessage, signTypedData } from "viem/actions" import { getChainId } from "viem/actions" import { MULTI_CHAIN_ECDSA_VALIDATOR_ADDRESS } from "../constants.js" export async function toMultiChainECDSAValidator< entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", TAddress extends Address = Address >( client: Client, { signer, entryPoint: entryPointAddress, kernelVersion: _, validatorAddress }: { signer: SmartAccountSigner entryPoint: entryPoint kernelVersion: GetKernelVersion validatorAddress?: Address } ): Promise> { validatorAddress = validatorAddress ?? MULTI_CHAIN_ECDSA_VALIDATOR_ADDRESS // Get the private key related account const viemSigner: LocalAccount = { ...signer, signTransaction: (_, __) => { throw new SignTransactionNotSupportedBySmartAccount() } } as LocalAccount // Fetch chain id const chainId = await getChainId(client) // Build the EOA Signer const account = toAccount({ address: viemSigner.address, async signMessage({ message }) { return signMessage(client, { account: viemSigner, message }) }, async signTransaction(_, __) { throw new SignTransactionNotSupportedBySmartAccount() }, async signTypedData< const TTypedData extends TypedData | Record, TPrimaryType extends | keyof TTypedData | "EIP712Domain" = keyof TTypedData >(typedData: TypedDataDefinition) { return signTypedData( client, { account: viemSigner, ...typedData } ) } }) return { ...account, supportedKernelVersions: ">=0.3.0", validatorType: "SECONDARY", address: validatorAddress, source: "MultiChainECDSAValidator", getIdentifier() { return validatorAddress ?? MULTI_CHAIN_ECDSA_VALIDATOR_ADDRESS }, async getEnableData() { return viemSigner.address }, async getNonceKey(_accountAddress?: Address, customNonceKey?: bigint) { if (customNonceKey) { return customNonceKey } return 0n }, async signUserOperation( userOperation: UserOperation> ) { const hash = getUserOperationHash({ userOperation: { ...userOperation, signature: "0x" }, entryPoint: entryPointAddress, chainId: chainId }) const signature = await signMessage(client, { account: viemSigner, message: { raw: hash } }) return signature }, async getDummySignature(_userOperation) { return "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" }, async isEnabled( _kernelAccountAddress: Address, _selector: Hex ): Promise { return false } } }