From 4bf5489d521d550d3df1c082744d349fa96547fe Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Mon, 12 Feb 2024 17:44:02 +0530 Subject: [PATCH 01/35] EntryPoint 0.7 support --- bun.lockb | Bin 525464 -> 525848 bytes packages/permissionless-test/utils.ts | 16 +- .../privateKeyToBiconomySmartAccount.ts | 23 +- .../biconomy/signerToBiconomySmartAccount.ts | 70 ++-- .../kernel/signerToEcdsaKernelSmartAccount.ts | 108 +++-- .../safe/privateKeyToSafeSmartAccount.ts | 5 +- .../accounts/safe/signerToSafeSmartAccount.ts | 62 ++- .../simple/privateKeyToSimpleSmartAccount.ts | 32 +- .../simple/signerToSimpleSmartAccount.ts | 148 ++++--- packages/permissionless/accounts/types.ts | 16 +- .../permissionless/actions/bundler/chainId.ts | 4 +- .../bundler/estimateUserOperationGas.ts | 40 +- .../actions/bundler/getUserOperationByHash.ts | 61 ++- .../bundler/getUserOperationReceipt.ts | 4 +- .../actions/bundler/sendUserOperation.ts | 34 +- .../actions/bundler/supportedEntryPoints.ts | 8 +- .../actions/pimlico/sponsorUserOperation.ts | 90 +++-- .../pimlico/validateSponsorshipPolicies.ts | 29 +- .../actions/public/getAccountNonce.ts | 3 +- .../actions/public/getSenderAddress.ts | 36 +- .../actions/smartAccount/deployContract.ts | 18 +- .../prepareUserOperationRequest.ts | 260 ++++++++++-- .../actions/smartAccount/sendTransaction.ts | 25 +- .../actions/smartAccount/sendTransactions.ts | 22 +- .../actions/smartAccount/sendUserOperation.ts | 77 +++- .../actions/smartAccount/signMessage.ts | 4 +- .../actions/smartAccount/signTypedData.ts | 4 +- .../actions/smartAccount/writeContract.ts | 15 +- .../actions/stackup/sponsorUserOperation.ts | 81 ++-- .../clients/createBundlerClient.ts | 7 +- .../clients/createSmartAccountClient.ts | 37 +- .../clients/decorators/bundler.ts | 379 +++++++++--------- .../clients/decorators/pimlico.ts | 34 +- .../clients/decorators/smartAccount.ts | 149 +++++-- .../clients/decorators/stackup.ts | 24 +- packages/permissionless/clients/pimlico.ts | 14 +- packages/permissionless/clients/stackup.ts | 16 +- .../errors/estimateUserOperationGas.ts | 16 +- .../errors/sendUserOperation.ts | 7 +- packages/permissionless/types/bundler.ts | 50 +-- packages/permissionless/types/entrypoint.ts | 13 + packages/permissionless/types/index.ts | 21 +- packages/permissionless/types/pimlico.ts | 60 ++- packages/permissionless/types/stackup.ts | 54 ++- .../permissionless/types/userOperation.ts | 115 ++++-- .../getEstimateUserOperationGasError.ts | 21 +- .../utils/errors/getSendUserOperationError.ts | 8 +- .../utils/getEntryPointVersion.ts | 15 + .../utils/getUserOperationHash.ts | 149 +++++-- packages/permissionless/utils/index.ts | 10 +- .../utils/signUserOperationHashWithECDSA.ts | 21 +- packages/wagmi-demo/package.json | 2 +- packages/wagmi/package.json | 14 +- 53 files changed, 1779 insertions(+), 752 deletions(-) create mode 100644 packages/permissionless/types/entrypoint.ts create mode 100644 packages/permissionless/utils/getEntryPointVersion.ts diff --git a/bun.lockb b/bun.lockb index 47a10ab8d657be737d9858251bb4ec21979c4183..54f90dcddda0b4b8b976322877feedb5319a89a2 100755 GIT binary patch delta 7706 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 delta 7431 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 => { + sponsorUserOperation: async ({ userOperation, entryPoint }) => { const gasPrice = await pimlicoBundlerClient.getUserOperationGasPrice() @@ -242,7 +240,7 @@ export const getEoaWalletClient = () => { export const getEntryPoint = () => { if (!process.env.ENTRYPOINT_ADDRESS) throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - return process.env.ENTRYPOINT_ADDRESS as Address + return ENTRYPOINT_ADDRESS_0_6 } export const getPublicClient = async () => { diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts index c6097821..6d766f1c 100644 --- a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts @@ -1,16 +1,18 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { Prettify } from "../../types" +import type { DefaultEntryPoint, EntryPoint, Prettify } from "../../types" import { type BiconomySmartAccount, type SignerToBiconomySmartAccountParameters, signerToBiconomySmartAccount } from "./signerToBiconomySmartAccount" -export type PrivateKeyToBiconomySmartAccountParameters = Prettify< +export type PrivateKeyToBiconomySmartAccountParameters< + entryPoint extends EntryPoint = DefaultEntryPoint +> = Prettify< { privateKey: Hex - } & Omit + } & Omit, "signer"> > /** @@ -19,14 +21,23 @@ export type PrivateKeyToBiconomySmartAccountParameters = Prettify< * @returns A Private Key Biconomy Smart Account using ECDSA as default validation module. */ export async function privateKeyToBiconomySmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( client: Client, - { privateKey, ...rest }: PrivateKeyToBiconomySmartAccountParameters -): Promise> { + { + privateKey, + ...rest + }: PrivateKeyToBiconomySmartAccountParameters +): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) - return signerToBiconomySmartAccount(client, { + return signerToBiconomySmartAccount< + entryPoint, + TTransport, + TChain, + "privateKey" + >(client, { signer: privateKeyAccount, ...rest }) diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 8f063958..509bb67a 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -7,19 +7,19 @@ import { type LocalAccount, type Transport, type TypedDataDefinition, - concatHex, encodeAbiParameters, encodeFunctionData, encodePacked, getContractAddress, hexToBigInt, keccak256, - parseAbiParameters + parseAbiParameters, + concatHex } from "viem" import { toAccount } from "viem/accounts" import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { Prettify } from "../../types" +import type { DefaultEntryPoint, Prettify } from "../../types" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { @@ -31,12 +31,13 @@ import { BiconomyExecuteAbi, BiconomyInitAbi } from "./abi/BiconomySmartAccountAbi" -// import Abis +import type { EntryPoint } from "../../types/entrypoint" export type BiconomySmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined -> = SmartAccount<"biconomySmartAccount", transport, chain> +> = SmartAccount /** * The account creation ABI for Biconomy Smart Account (from the biconomy SmartAccountFactory) @@ -104,12 +105,10 @@ const BICONOMY_PROXY_CREATION_CODE = const getAccountInitCode = async ({ owner, index, - factoryAddress, ecdsaModuleAddress }: { owner: Address index: bigint - factoryAddress: Address ecdsaModuleAddress: Address }): Promise => { if (!owner) throw new Error("Owner account not found") @@ -122,14 +121,11 @@ const getAccountInitCode = async ({ }) // Build the account init code - return concatHex([ - factoryAddress, - encodeFunctionData({ - abi: createAccountAbi, - functionName: "deployCounterFactualAccount", - args: [ecdsaModuleAddress, ecdsaOwnershipInitData, index] - }) as Hex - ]) + return encodeFunctionData({ + abi: createAccountAbi, + functionName: "deployCounterFactualAccount", + args: [ecdsaModuleAddress, ecdsaOwnershipInitData, index] + }) } const getAccountAddress = async ({ @@ -186,11 +182,12 @@ const getAccountAddress = async ({ } export type SignerToBiconomySmartAccountParameters< + entryPoint extends EntryPoint = DefaultEntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ signer: SmartAccountSigner - entryPoint: Address + entryPoint: entryPoint address?: Address index?: bigint factoryAddress?: Address @@ -210,6 +207,7 @@ export type SignerToBiconomySmartAccountParameters< * @param ecdsaModuleAddress */ export async function signerToBiconomySmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -219,14 +217,14 @@ export async function signerToBiconomySmartAccount< { signer, address, - entryPoint, + entryPoint: entryPointAddress, index = 0n, factoryAddress = BICONOMY_ADDRESSES.FACTORY_ADDRESS, accountLogicAddress = BICONOMY_ADDRESSES.ACCOUNT_V2_0_LOGIC, fallbackHandlerAddress = BICONOMY_ADDRESSES.DEFAULT_FALLBACK_HANDLER_ADDRESS, ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE - }: SignerToBiconomySmartAccountParameters -): Promise> { + }: SignerToBiconomySmartAccountParameters +): Promise> { // Get the private key related account const viemSigner: LocalAccount = { ...signer, @@ -240,7 +238,6 @@ export async function signerToBiconomySmartAccount< getAccountInitCode({ owner: viemSigner.address, index, - factoryAddress, ecdsaModuleAddress }) @@ -294,14 +291,14 @@ export async function signerToBiconomySmartAccount< ...account, client: client, publicKey: accountAddress, - entryPoint: entryPoint, + entryPoint: entryPointAddress, source: "biconomySmartAccount", // Get the nonce of the smart account async getNonce() { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPoint + entryPoint: entryPointAddress }) }, @@ -312,7 +309,7 @@ export async function signerToBiconomySmartAccount< ...userOperation, signature: "0x" }, - entryPoint: entryPoint, + entryPoint: entryPointAddress, chainId: chainId }) const signature = await signMessage(client, { @@ -327,6 +324,31 @@ export async function signerToBiconomySmartAccount< return signatureWithModuleAddress }, + async getFactory() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + + return factoryAddress + }, + + async getFactoryData() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + return generateInitCode() + }, + // Encode the init code async getInitCode() { if (smartAccountDeployed) return "0x" @@ -338,7 +360,7 @@ export async function signerToBiconomySmartAccount< if (smartAccountDeployed) return "0x" - return generateInitCode() + return concatHex([factoryAddress, await generateInitCode()]) }, // Encode the deploy call data diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index c300106e..5bbc3077 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -7,9 +7,9 @@ import { type LocalAccount, type Transport, type TypedDataDefinition, - concatHex, encodeFunctionData, - isAddressEqual + isAddressEqual, + concatHex } from "viem" import { toAccount } from "viem/accounts" import { @@ -20,7 +20,12 @@ import { } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" -import type { Prettify } from "../../types" +import type { + DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_0_7, + Prettify +} from "../../types" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import type { SmartAccount } from "../types" @@ -29,11 +34,14 @@ import { type SmartAccountSigner } from "../types" import { KernelExecuteAbi, KernelInitAbi } from "./abi/KernelAccountAbi" +import type { EntryPoint } from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" export type KernelEcdsaSmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined -> = SmartAccount<"kernelEcdsaSmartAccount", transport, chain> +> = SmartAccount /** * The account creation ABI for a kernel smart account (from the KernelFactory) @@ -94,13 +102,11 @@ const KERNEL_ADDRESSES: { const getAccountInitCode = async ({ owner, index, - factoryAddress, accountLogicAddress, ecdsaValidatorAddress }: { owner: Address index: bigint - factoryAddress: Address accountLogicAddress: Address ecdsaValidatorAddress: Address }): Promise => { @@ -114,14 +120,11 @@ const getAccountInitCode = async ({ }) // Build the account init code - return concatHex([ - factoryAddress, - encodeFunctionData({ - abi: createAccountAbi, - functionName: "createAccount", - args: [accountLogicAddress, initialisationData, index] - }) as Hex - ]) + return encodeFunctionData({ + abi: createAccountAbi, + functionName: "createAccount", + args: [accountLogicAddress, initialisationData, index] + }) } /** @@ -134,20 +137,23 @@ const getAccountInitCode = async ({ * @param deployedAccountAddress */ const getAccountAddress = async < + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >({ client, owner, - entryPoint, + entryPoint: entryPointAddress, initCodeProvider, ecdsaValidatorAddress, - deployedAccountAddress + deployedAccountAddress, + factoryAddress }: { client: Client owner: Address initCodeProvider: () => Promise - entryPoint: Address + factoryAddress: Address + entryPoint: entryPoint ecdsaValidatorAddress: Address deployedAccountAddress?: Address }): Promise
=> { @@ -191,21 +197,32 @@ const getAccountAddress = async < } // Find the init code for this account - const initCode = await initCodeProvider() + const factoryData = await initCodeProvider() + + const entryPointVersion = getEntryPointVersion(entryPointAddress) + + if (entryPointVersion === "0.6") { + return getSenderAddress(client, { + initCode: concatHex([factoryAddress, factoryData]), + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6 + }) + } // Get the sender address based on the init code - return getSenderAddress(client, { - initCode, - entryPoint + return getSenderAddress(client, { + factory: factoryAddress, + factoryData, + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7 }) } export type SignerToEcdsaKernelSmartAccountParameters< + entryPoint extends EntryPoint = DefaultEntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ signer: SmartAccountSigner - entryPoint: Address + entryPoint: entryPoint address?: Address index?: bigint factoryAddress?: Address @@ -225,6 +242,7 @@ export type SignerToEcdsaKernelSmartAccountParameters< * @param deployedAccountAddress */ export async function signerToEcdsaKernelSmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -234,14 +252,14 @@ export async function signerToEcdsaKernelSmartAccount< { signer, address, - entryPoint, + entryPoint: entryPointAddress, index = 0n, factoryAddress = KERNEL_ADDRESSES.FACTORY_ADDRESS, accountLogicAddress = KERNEL_ADDRESSES.ACCOUNT_V2_2_LOGIC, ecdsaValidatorAddress = KERNEL_ADDRESSES.ECDSA_VALIDATOR, deployedAccountAddress - }: SignerToEcdsaKernelSmartAccountParameters -): Promise> { + }: SignerToEcdsaKernelSmartAccountParameters +): Promise> { // Get the private key related account const viemSigner: LocalAccount = { ...signer, @@ -255,7 +273,6 @@ export async function signerToEcdsaKernelSmartAccount< getAccountInitCode({ owner: viemSigner.address, index, - factoryAddress, accountLogicAddress, ecdsaValidatorAddress }) @@ -263,13 +280,14 @@ export async function signerToEcdsaKernelSmartAccount< // Fetch account address and chain id const [accountAddress, chainId] = await Promise.all([ address ?? - getAccountAddress({ + getAccountAddress({ client, - entryPoint, + entryPoint: entryPointAddress, owner: viemSigner.address, ecdsaValidatorAddress, initCodeProvider: generateInitCode, - deployedAccountAddress + deployedAccountAddress, + factoryAddress }), getChainId(client) ]) @@ -310,14 +328,14 @@ export async function signerToEcdsaKernelSmartAccount< ...account, client: client, publicKey: accountAddress, - entryPoint: entryPoint, + entryPoint: entryPointAddress, source: "kernelEcdsaSmartAccount", // Get the nonce of the smart account async getNonce() { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPoint + entryPoint: entryPointAddress }) }, @@ -328,7 +346,7 @@ export async function signerToEcdsaKernelSmartAccount< ...userOperation, signature: "0x" }, - entryPoint: entryPoint, + entryPoint: entryPointAddress, chainId: chainId }) const signature = await signMessage(client, { @@ -350,6 +368,32 @@ export async function signerToEcdsaKernelSmartAccount< if (smartAccountDeployed) return "0x" + return concatHex([factoryAddress, await generateInitCode()]) + }, + + async getFactory() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + + return factoryAddress + }, + + async getFactoryData() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + return generateInitCode() }, diff --git a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts index 088e01c4..1a55589f 100644 --- a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts @@ -1,6 +1,6 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { Prettify } from "../../types" +import type { DefaultEntryPoint, EntryPoint, Prettify } from "../../types" import { type SafeSmartAccount, type SignerToSafeSmartAccountParameters, @@ -19,12 +19,13 @@ export type PrivateKeyToSafeSmartAccountParameters = Prettify< * @returns A Private Key Simple Account. */ export async function privateKeyToSafeSmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( client: Client, { privateKey, ...rest }: PrivateKeyToSafeSmartAccountParameters -): Promise> { +): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) return signerToSafeSmartAccount(client, { diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 9b45ce6f..245bcc58 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -28,13 +28,15 @@ import { signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { Prettify } from "../../types" +import type { ENTRYPOINT_ADDRESS_0_6, Prettify } from "../../types" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { SignTransactionNotSupportedBySmartAccount, type SmartAccount, type SmartAccountSigner } from "../types" +import type { EntryPoint } from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" export type SafeVersion = "1.4.1" @@ -172,9 +174,10 @@ const encodeMultiSend = ( } export type SafeSmartAccount< + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined -> = SmartAccount<"SafeSmartAccount", transport, chain> +> = SmartAccount const getInitializerCode = async ({ owner, @@ -292,7 +295,6 @@ const getAccountInitCode = async ({ owner, addModuleLibAddress, safe4337ModuleAddress, - safeProxyFactoryAddress, safeSingletonAddress, multiSendAddress, saltNonce = 0n, @@ -302,7 +304,6 @@ const getAccountInitCode = async ({ owner: Address addModuleLibAddress: Address safe4337ModuleAddress: Address - safeProxyFactoryAddress: Address safeSingletonAddress: Address multiSendAddress: Address saltNonce?: bigint @@ -359,7 +360,7 @@ const getAccountInitCode = async ({ args: [safeSingletonAddress, initializer, saltNonce] }) - return concatHex([safeProxyFactoryAddress, initCodeCallData]) + return initCodeCallData } const getAccountAddress = async < @@ -495,7 +496,7 @@ export type SignerToSafeSmartAccountParameters< > = Prettify<{ signer: SmartAccountSigner safeVersion: SafeVersion - entryPoint: Address + entryPoint: EntryPoint address?: Address addModuleLibAddress?: Address safe4337ModuleAddress?: Address @@ -520,6 +521,7 @@ export type SignerToSafeSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function signerToSafeSmartAccount< + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -530,7 +532,7 @@ export async function signerToSafeSmartAccount< signer, address, safeVersion, - entryPoint, + entryPoint: entryPointAddress, addModuleLibAddress: _addModuleLibAddress, safe4337ModuleAddress: _safe4337ModuleAddress, safeProxyFactoryAddress: _safeProxyFactoryAddress, @@ -543,7 +545,13 @@ export async function signerToSafeSmartAccount< safeModules = [], setupTransactions = [] }: SignerToSafeSmartAccountParameters -): Promise> { +): Promise> { + const entryPointVersion = getEntryPointVersion(entryPointAddress) + + if (entryPointVersion !== "0.6") { + throw new Error("Only EntryPoint 0.6 is supported") + } + const chainId = await getChainId(client) const viemSigner: LocalAccount = { @@ -651,12 +659,12 @@ export async function signerToSafeSmartAccount< ...account, client: client, publicKey: accountAddress, - entryPoint: entryPoint, + entryPoint: entryPointAddress, source: "SafeSmartAccount", async getNonce() { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPoint + entryPoint: entryPointAddress }) }, async signUserOperation(userOperation) { @@ -674,7 +682,7 @@ export async function signerToSafeSmartAccount< message: { safe: accountAddress, callData: userOperation.callData, - entryPoint: entryPoint, + entryPoint: entryPointAddress, nonce: userOperation.nonce, initCode: userOperation.initCode, maxFeePerGas: userOperation.maxFeePerGas, @@ -713,11 +721,39 @@ export async function signerToSafeSmartAccount< if (safeDeployed) return "0x" - return getAccountInitCode({ + const initCodeCallData = await getAccountInitCode({ + owner: viemSigner.address, + addModuleLibAddress, + safe4337ModuleAddress, + safeSingletonAddress, + multiSendAddress, + saltNonce, + setupTransactions, + safeModules + }) + + return concatHex([safeProxyFactoryAddress, initCodeCallData]) + }, + async getFactory() { + if (safeDeployed) return null + + safeDeployed = await isSmartAccountDeployed(client, accountAddress) + + if (safeDeployed) return null + + return safeProxyFactoryAddress + }, + async getFactoryData() { + if (safeDeployed) return null + + safeDeployed = await isSmartAccountDeployed(client, accountAddress) + + if (safeDeployed) return null + + return await getAccountInitCode({ owner: viemSigner.address, addModuleLibAddress, safe4337ModuleAddress, - safeProxyFactoryAddress, safeSingletonAddress, multiSendAddress, saltNonce, diff --git a/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts index e0eb683e..886c4f77 100644 --- a/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts @@ -1,16 +1,24 @@ -import { type Chain, type Client, type Hex, type Transport } from "viem" +import { + type Address, + type Chain, + type Client, + type Hex, + type Transport +} from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { Prettify } from "../../types" +import type { DefaultEntryPoint, EntryPoint, Prettify } from "../../types" import { type SignerToSimpleSmartAccountParameters, type SimpleSmartAccount, signerToSimpleSmartAccount } from "./signerToSimpleSmartAccount" -export type PrivateKeyToSimpleSmartAccountParameters = Prettify< +export type PrivateKeyToSimpleSmartAccountParameters< + entryPoint extends EntryPoint = DefaultEntryPoint +> = Prettify< { privateKey: Hex - } & Omit + } & Omit, "signer"> > /** @@ -19,15 +27,25 @@ export type PrivateKeyToSimpleSmartAccountParameters = Prettify< * @returns A Private Key Simple Account. */ export async function privateKeyToSimpleSmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( client: Client, - { privateKey, ...rest }: PrivateKeyToSimpleSmartAccountParameters -): Promise> { + { + privateKey, + ...rest + }: PrivateKeyToSimpleSmartAccountParameters +): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) - return signerToSimpleSmartAccount(client, { + return signerToSimpleSmartAccount< + entryPoint, + TTransport, + TChain, + "privateKey", + Address + >(client, { signer: privateKeyAccount, ...rest }) diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 44331f9c..2d585f23 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -14,7 +14,12 @@ import { toAccount } from "viem/accounts" import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" -import type { Prettify } from "../../types" +import type { + DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_0_7, + Prettify +} from "../../types" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { @@ -22,85 +27,94 @@ import { type SmartAccount, type SmartAccountSigner } from "../types" +import type { EntryPoint } from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" export type SimpleSmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined -> = SmartAccount<"SimpleSmartAccount", transport, chain> +> = SmartAccount -const getAccountInitCode = async ( - factoryAddress: Address, - owner: Address, - index = 0n -): Promise => { +const getAccountInitCode = async (owner: Address, index = 0n): Promise => { if (!owner) throw new Error("Owner account not found") - return concatHex([ - factoryAddress, - encodeFunctionData({ - abi: [ - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address" - }, - { - internalType: "uint256", - name: "salt", - type: "uint256" - } - ], - name: "createAccount", - outputs: [ - { - internalType: "contract SimpleAccount", - name: "ret", - type: "address" - } - ], - stateMutability: "nonpayable", - type: "function" - } - ], - functionName: "createAccount", - args: [owner, index] - }) as Hex - ]) + return encodeFunctionData({ + abi: [ + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address" + }, + { + internalType: "uint256", + name: "salt", + type: "uint256" + } + ], + name: "createAccount", + outputs: [ + { + internalType: "contract SimpleAccount", + name: "ret", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + } + ], + functionName: "createAccount", + args: [owner, index] + }) } const getAccountAddress = async < + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >({ client, factoryAddress, - entryPoint, + entryPoint: entryPointAddress, owner, index = 0n }: { client: Client factoryAddress: Address owner: Address - entryPoint: Address + entryPoint: entryPoint index?: bigint }): Promise
=> { - const initCode = await getAccountInitCode(factoryAddress, owner, index) + const entryPointVersion = getEntryPointVersion(entryPointAddress) - return getSenderAddress(client, { - initCode, - entryPoint + const factoryData = await getAccountInitCode(owner, index) + + if (entryPointVersion === "0.6") { + return getSenderAddress(client, { + initCode: concatHex([factoryAddress, factoryData]), + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6 + }) + } + + // Get the sender address based on the init code + return getSenderAddress(client, { + factory: factoryAddress, + factoryData, + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7 }) } export type SignerToSimpleSmartAccountParameters< + entryPoint extends EntryPoint = DefaultEntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ signer: SmartAccountSigner factoryAddress: Address - entryPoint: Address + entryPoint: entryPoint index?: bigint address?: Address }> @@ -111,6 +125,7 @@ export type SignerToSimpleSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function signerToSimpleSmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -120,11 +135,11 @@ export async function signerToSimpleSmartAccount< { signer, factoryAddress, - entryPoint, + entryPoint: entryPointAddress, index = 0n, address - }: SignerToSimpleSmartAccountParameters -): Promise> { + }: SignerToSimpleSmartAccountParameters +): Promise> { const viemSigner: LocalAccount = { ...signer, signTransaction: (_, __) => { @@ -134,10 +149,10 @@ export async function signerToSimpleSmartAccount< const [accountAddress, chainId] = await Promise.all([ address ?? - getAccountAddress({ + getAccountAddress({ client, factoryAddress, - entryPoint, + entryPoint: entryPointAddress, owner: viemSigner.address, index }), @@ -179,12 +194,12 @@ export async function signerToSimpleSmartAccount< ...account, client: client, publicKey: accountAddress, - entryPoint: entryPoint, + entryPoint: entryPointAddress, source: "SimpleSmartAccount", async getNonce() { return getAccountNonce(client, { sender: accountAddress, - entryPoint: entryPoint + entryPoint: entryPointAddress }) }, async signUserOperation(userOperation) { @@ -192,7 +207,7 @@ export async function signerToSimpleSmartAccount< message: { raw: getUserOperationHash({ userOperation, - entryPoint: entryPoint, + entryPoint: entryPointAddress, chainId: chainId }) } @@ -208,7 +223,28 @@ export async function signerToSimpleSmartAccount< if (smartAccountDeployed) return "0x" - return getAccountInitCode(factoryAddress, viemSigner.address, index) + return concatHex([ + factoryAddress, + await getAccountInitCode(viemSigner.address, index) + ]) + }, + async getFactory() { + if (smartAccountDeployed) return null + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + if (smartAccountDeployed) return null + return factoryAddress + }, + async getFactoryData() { + if (smartAccountDeployed) return null + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + if (smartAccountDeployed) return null + return getAccountInitCode(viemSigner.address, index) }, async encodeDeployCallData(_) { throw new Error("Simple account doesn't support account deployment") diff --git a/packages/permissionless/accounts/types.ts b/packages/permissionless/accounts/types.ts index 28c32734..1d6102fa 100644 --- a/packages/permissionless/accounts/types.ts +++ b/packages/permissionless/accounts/types.ts @@ -7,7 +7,8 @@ import { type LocalAccount } from "viem" import type { Chain, EncodeDeployDataParameters, Transport } from "viem" -import { type UserOperation } from "../types" +import type { DefaultEntryPoint, UserOperation } from "../types" +import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" export class SignTransactionNotSupportedBySmartAccount extends BaseError { override name = "SignTransactionNotSupportedBySmartAccount" @@ -26,15 +27,18 @@ export class SignTransactionNotSupportedBySmartAccount extends BaseError { } export type SmartAccount< + entryPoint extends EntryPoint = DefaultEntryPoint, Name extends string = string, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, TAbi extends Abi | readonly unknown[] = Abi > = LocalAccount & { client: Client - entryPoint: Address + entryPoint: EntryPoint getNonce: () => Promise getInitCode: () => Promise + getFactory: () => Promise
+ getFactoryData: () => Promise encodeCallData: ( args: | { @@ -48,13 +52,17 @@ export type SmartAccount< data: Hex }[] ) => Promise - getDummySignature(userOperation: UserOperation): Promise + getDummySignature( + userOperation: UserOperation> + ): Promise encodeDeployCallData: ({ abi, args, bytecode }: EncodeDeployDataParameters) => Promise - signUserOperation: (userOperation: UserOperation) => Promise + signUserOperation: ( + userOperation: UserOperation> + ) => Promise } export type SmartAccountSigner< diff --git a/packages/permissionless/actions/bundler/chainId.ts b/packages/permissionless/actions/bundler/chainId.ts index b5aeb045..bc23607f 100644 --- a/packages/permissionless/actions/bundler/chainId.ts +++ b/packages/permissionless/actions/bundler/chainId.ts @@ -1,6 +1,7 @@ import type { Account, Chain, Client, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { BundlerRpcSchema } from "../../types/bundler" +import type { DefaultEntryPoint, EntryPoint } from "../../types" /** * Returns the supported chain id by the bundler service @@ -25,11 +26,12 @@ import type { BundlerRpcSchema } from "../../types/bundler" * */ export const chainId = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client + client: Client> ) => { return Number( await client.request({ diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index cb937aab..5b1043d6 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -1,6 +1,5 @@ import { type Account, - type Address, BaseError, type Chain, type Client, @@ -16,14 +15,29 @@ import { type GetEstimateUserOperationGasErrorReturnType, getEstimateUserOperationGasError } from "../../utils/errors/getEstimateUserOperationGasError" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" -export type EstimateUserOperationGasParameters = { - userOperation: PartialBy< - UserOperation, - "callGasLimit" | "preVerificationGas" | "verificationGasLimit" - > - entryPoint: Address -} +export type EstimateUserOperationGasParameters = + { + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperation<"0.6">, + "callGasLimit" | "preVerificationGas" | "verificationGasLimit" + > + : PartialBy< + UserOperation<"0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + > + entryPoint: entryPoint + } export type EstimateUserOperationGasReturnType = { preVerificationGas: bigint @@ -31,8 +45,9 @@ export type EstimateUserOperationGasReturnType = { callGasLimit: bigint } -export type EstimateUserOperationErrorType = - GetEstimateUserOperationGasErrorReturnType +export type EstimateUserOperationErrorType< + entryPoint extends EntryPoint = DefaultEntryPoint +> = GetEstimateUserOperationGasErrorReturnType /** * Estimates preVerificationGas, verificationGasLimit and callGasLimit for user operation @@ -62,12 +77,13 @@ export type EstimateUserOperationErrorType = * */ export const estimateUserOperationGas = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client, - args: Prettify, + client: Client>, + args: Prettify>, stateOverrides?: StateOverrides ): Promise> => { const { userOperation, entryPoint } = args diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.ts index 4ca6c6cc..7c7bbcf1 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.ts @@ -3,13 +3,19 @@ import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" import type { UserOperation } from "../../types/userOperation" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type GetUserOperationByHashParameters = { hash: Hash } -export type GetUserOperationByHashReturnType = { - userOperation: UserOperation +export type GetUserOperationByHashReturnType = { + userOperation: UserOperation> entryPoint: Address transactionHash: Hash blockHash: Hash @@ -39,13 +45,14 @@ export type GetUserOperationByHashReturnType = { * */ export const getUserOperationByHash = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client, + client: Client>, { hash }: Prettify -): Promise | null> => { +): Promise> | null> => { const params: [Hash] = [hash] const response = await client.request({ @@ -63,16 +70,44 @@ export const getUserOperationByHash = async < blockNumber } = response + const entryPointVersion = getEntryPointVersion(entryPoint) + return { - userOperation: { - ...userOperation, - nonce: BigInt(userOperation.nonce), - callGasLimit: BigInt(userOperation.callGasLimit), - verificationGasLimit: BigInt(userOperation.verificationGasLimit), - preVerificationGas: BigInt(userOperation.preVerificationGas), - maxFeePerGas: BigInt(userOperation.maxFeePerGas), - maxPriorityFeePerGas: BigInt(userOperation.maxPriorityFeePerGas) - } as UserOperation, + userOperation: (entryPointVersion === "0.6" + ? { + ...userOperation, + nonce: BigInt(userOperation.nonce), + callGasLimit: BigInt(userOperation.callGasLimit), + verificationGasLimit: BigInt( + userOperation.verificationGasLimit + ), + preVerificationGas: BigInt(userOperation.preVerificationGas), + maxFeePerGas: BigInt(userOperation.maxFeePerGas), + maxPriorityFeePerGas: BigInt( + userOperation.maxPriorityFeePerGas + ) + } + : { + ...userOperation, + nonce: BigInt(userOperation.nonce), + callGasLimit: BigInt(userOperation.callGasLimit), + verificationGasLimit: BigInt( + userOperation.verificationGasLimit + ), + preVerificationGas: BigInt(userOperation.preVerificationGas), + maxFeePerGas: BigInt(userOperation.maxFeePerGas), + maxPriorityFeePerGas: BigInt( + userOperation.maxPriorityFeePerGas + ), + paymasterVerificationGasLimit: + userOperation.paymasterVerificationGasLimit + ? BigInt(userOperation.paymasterVerificationGasLimit) + : undefined, + paymasterPostOpGasLimit: + userOperation.paymasterVerificationGasLimit + ? BigInt(userOperation.paymasterPostOpGasLimit) + : undefined + }) as UserOperation>, entryPoint: entryPoint, transactionHash: transactionHash, blockHash: blockHash, diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.ts index a1d41475..51f24147 100644 --- a/packages/permissionless/actions/bundler/getUserOperationReceipt.ts +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.ts @@ -12,6 +12,7 @@ import type { Prettify } from "../../types" import type { BundlerRpcSchema } from "../../types/bundler" import type { TStatus } from "../../types/userOperation" import { transactionReceiptStatus } from "../../utils/deepHexlify" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type GetUserOperationReceiptParameters = { hash: Hash @@ -73,11 +74,12 @@ export type GetUserOperationReceiptReturnType = { * */ export const getUserOperationReceipt = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client, + client: Client>, { hash }: Prettify ): Promise | null> => { const params: [Hash] = [hash] diff --git a/packages/permissionless/actions/bundler/sendUserOperation.ts b/packages/permissionless/actions/bundler/sendUserOperation.ts index 74e1c563..b893a5bf 100644 --- a/packages/permissionless/actions/bundler/sendUserOperation.ts +++ b/packages/permissionless/actions/bundler/sendUserOperation.ts @@ -1,12 +1,4 @@ -import type { - Account, - Address, - BaseError, - Chain, - Client, - Hash, - Transport -} from "viem" +import type { Account, BaseError, Chain, Client, Hash, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" @@ -16,10 +8,15 @@ import type { } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" import { getSendUserOperationError } from "../../utils/errors/getSendUserOperationError" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" -export type SendUserOperationParameters = { - userOperation: UserOperation - entryPoint: Address +export type SendUserOperationParameters = { + userOperation: UserOperation> + entryPoint: entryPoint } /** @@ -48,12 +45,13 @@ export type SendUserOperationParameters = { * // Return '0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34' */ export const sendUserOperation = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client, - args: Prettify + client: Client>, + args: Prettify> ): Promise => { const { userOperation, entryPoint } = args @@ -61,8 +59,10 @@ export const sendUserOperation = async < const userOperationHash = await client.request({ method: "eth_sendUserOperation", params: [ - deepHexlify(userOperation) as UserOperationWithBigIntAsHex, - entryPoint as Address + deepHexlify(userOperation) as UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, + entryPoint ] }) @@ -70,7 +70,7 @@ export const sendUserOperation = async < } catch (err) { throw getSendUserOperationError( err as BaseError, - args as SendUserOperationParameters + args as SendUserOperationParameters ) } } diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.ts index 384e7542..fc7cc9f5 100644 --- a/packages/permissionless/actions/bundler/supportedEntryPoints.ts +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.ts @@ -1,6 +1,7 @@ -import type { Account, Address, Chain, Client, Transport } from "viem" +import type { Account, Chain, Client, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { BundlerRpcSchema } from "../../types/bundler" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" /** * Returns the supported entrypoints by the bundler service @@ -25,12 +26,13 @@ import type { BundlerRpcSchema } from "../../types/bundler" * */ export const supportedEntryPoints = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client -): Promise => { + client: Client> +): Promise => { return client.request({ method: "eth_supportedEntryPoints", params: [] diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts index 44ac73f1..66c093c9 100644 --- a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts @@ -1,4 +1,4 @@ -import type { Account, Address, Chain, Client, Transport } from "viem" +import type { Account, Chain, Client, Transport } from "viem" import type { PartialBy } from "viem/types/utils" import type { Prettify } from "../../types/" import type { PimlicoPaymasterRpcSchema } from "../../types/pimlico" @@ -7,20 +7,35 @@ import type { UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils/getEntryPointVersion" -export type PimlicoSponsorUserOperationParameters = { - userOperation: PartialBy< - UserOperation, - | "callGasLimit" - | "preVerificationGas" - | "verificationGasLimit" - | "paymasterAndData" - > - entryPoint: Address +export type PimlicoSponsorUserOperationParameters< + entryPoint extends EntryPoint +> = { + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperation<"0.6">, + "callGasLimit" | "preVerificationGas" | "verificationGasLimit" + > + : PartialBy< + UserOperation<"0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + > + entryPoint: entryPoint sponsorshipPolicyId?: string } -export type SponsorUserOperationReturnType = UserOperation +export type SponsorUserOperationReturnType = + UserOperation> /** * Returns paymasterAndData & updated gas parameters required to sponsor a userOperation. @@ -48,20 +63,28 @@ export type SponsorUserOperationReturnType = UserOperation * */ export const sponsorUserOperation = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client, - args: Prettify -): Promise> => { + client: Client< + TTransport, + TChain, + TAccount, + PimlicoPaymasterRpcSchema + >, + args: Prettify> +): Promise>> => { const response = await client.request({ method: "pm_sponsorUserOperation", params: args.sponsorshipPolicyId ? [ deepHexlify( args.userOperation - ) as UserOperationWithBigIntAsHex, + ) as UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, args.entryPoint, { sponsorshipPolicyId: args.sponsorshipPolicyId @@ -70,18 +93,39 @@ export const sponsorUserOperation = async < : [ deepHexlify( args.userOperation - ) as UserOperationWithBigIntAsHex, + ) as UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, args.entryPoint ] }) - const userOperation: UserOperation = { - ...args.userOperation, - paymasterAndData: response.paymasterAndData, - preVerificationGas: BigInt(response.preVerificationGas), - verificationGasLimit: BigInt(response.verificationGasLimit), - callGasLimit: BigInt(response.callGasLimit) - } + const entryPointVersion = getEntryPointVersion(args.entryPoint) + + const userOperation: SponsorUserOperationReturnType = ( + entryPointVersion === "0.6" + ? { + ...args.userOperation, + paymasterAndData: response.paymasterAndData, + preVerificationGas: BigInt(response.preVerificationGas), + verificationGasLimit: BigInt(response.verificationGasLimit), + callGasLimit: BigInt(response.callGasLimit) + } + : { + ...args.userOperation, + paymasterAndData: response.paymasterAndData, + preVerificationGas: BigInt(response.preVerificationGas), + verificationGasLimit: BigInt(response.verificationGasLimit), + callGasLimit: BigInt(response.callGasLimit), + paymasterVerificationGasLimit: + response.paymasterVerificationGasLimit + ? BigInt(response.paymasterVerificationGasLimit) + : undefined, + paymasterPostOpGasLimit: response.paymasterPostOpGasLimit + ? BigInt(response.paymasterPostOpGasLimit) + : undefined + } + ) as SponsorUserOperationReturnType return userOperation } diff --git a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts index a5b70060..2f0d97af 100644 --- a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts +++ b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts @@ -1,4 +1,4 @@ -import type { Account, Address, Chain, Client, Transport } from "viem" +import type { Account, Chain, Client, Transport } from "viem" import type { Prettify } from "../../types/" import type { PimlicoPaymasterRpcSchema } from "../../types/pimlico" import type { @@ -6,10 +6,17 @@ import type { UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" -export type ValidateSponsorshipPoliciesParameters = { - userOperation: UserOperation - entryPoint: Address +export type ValidateSponsorshipPoliciesParameters< + entryPoint extends EntryPoint +> = { + userOperation: UserOperation> + entryPoint: entryPoint sponsorshipPolicyIds: string[] } @@ -59,17 +66,25 @@ export type ValidateSponsorshipPolicies = { * ] */ export const validateSponsorshipPolicies = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined >( - client: Client, - args: Prettify + client: Client< + TTransport, + TChain, + TAccount, + PimlicoPaymasterRpcSchema + >, + args: Prettify> ): Promise[]> => { return await client.request({ method: "pm_validateSponsorshipPolicies", params: [ - deepHexlify(args.userOperation) as UserOperationWithBigIntAsHex, + deepHexlify(args.userOperation) as UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, args.entryPoint, args.sponsorshipPolicyIds ] diff --git a/packages/permissionless/actions/public/getAccountNonce.ts b/packages/permissionless/actions/public/getAccountNonce.ts index ce3dff49..1018ea0d 100644 --- a/packages/permissionless/actions/public/getAccountNonce.ts +++ b/packages/permissionless/actions/public/getAccountNonce.ts @@ -2,10 +2,11 @@ import type { Address, Chain, Client, Transport } from "viem" import { readContract } from "viem/actions" import type { Prettify } from "../../types/" import { getAction } from "../../utils/getAction" +import type { EntryPoint } from "../../types/entrypoint" export type GetAccountNonceParams = { sender: Address - entryPoint: Address + entryPoint: EntryPoint key?: bigint } diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index cb0228e9..37ae05b9 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -6,14 +6,33 @@ import { type ContractFunctionExecutionErrorType, type ContractFunctionRevertedErrorType, type Hex, - type Transport + type Transport, + concat } from "viem" import { simulateContract } from "viem/actions" import type { Prettify } from "../../types/" import { getAction } from "../../utils/getAction" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" -export type GetSenderAddressParams = { initCode: Hex; entryPoint: Address } +export type GetSenderAddressParams = + GetEntryPointVersion extends "0.6" + ? { + initCode: Hex + entryPoint: entryPoint + factory?: never + factoryData?: never + } + : { + entryPoint: entryPoint + factory: Address + factoryData: Hex + initCode?: never + } export class InvalidEntryPointError extends BaseError { override name = "InvalidEntryPointError" @@ -59,13 +78,20 @@ export class InvalidEntryPointError extends BaseError { * // Return '0x7a88a206ba40b37a8c07a2b5688cf8b287318b63' */ export const getSenderAddress = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( client: Client, - args: Prettify + args: Prettify> ): Promise
=> { - const { initCode, entryPoint } = args + const { initCode, entryPoint, factory, factoryData } = args + + if (!initCode && (!factory || !factoryData)) { + throw new Error( + "Either `initCode` or `factory` and `factoryData` must be provided" + ) + } try { await getAction( @@ -100,7 +126,7 @@ export const getSenderAddress = async < } ], functionName: "getSenderAddress", - args: [initCode] + args: [initCode || concat([factory as Hex, factoryData as Hex])] }) } catch (e) { const err = e as ContractFunctionExecutionErrorType diff --git a/packages/permissionless/actions/smartAccount/deployContract.ts b/packages/permissionless/actions/smartAccount/deployContract.ts index 3d32f016..e29e97f5 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.ts @@ -15,14 +15,18 @@ import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashW import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { sendUserOperation } from "./sendUserOperation" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type DeployContractParametersWithPaymaster< + entryPoint extends EntryPoint, TAbi extends Abi | readonly unknown[] = Abi | readonly unknown[], TChain extends Chain | undefined = Chain | undefined, - TAccount extends SmartAccount | undefined = SmartAccount | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined, TChainOverride extends Chain | undefined = Chain | undefined > = DeployContractParameters & - SponsorUserOperationMiddleware + SponsorUserOperationMiddleware /** * Deploys a contract to the network, given bytecode and constructor arguments. @@ -54,10 +58,11 @@ export type DeployContractParametersWithPaymaster< */ export async function deployContract< TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined + TAccount extends SmartAccount | undefined, + entryPoint extends EntryPoint = DefaultEntryPoint >( client: Client, - args: Prettify + args: Prettify> ): Promise { const { abi, @@ -75,15 +80,14 @@ export async function deployContract< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const userOpHash = await getAction( client, - sendUserOperation + sendUserOperation )({ userOperation: { sender: account.address, - paymasterAndData: "0x", maxFeePerGas: request.maxFeePerGas || 0n, maxPriorityFeePerGas: request.maxPriorityFeePerGas || 0n, callData: await account.encodeDeployCallData({ diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index 321c2da2..2087f7bb 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -1,4 +1,4 @@ -import type { Address, Chain, Client, Transport } from "viem" +import type { Chain, Client, Transport } from "viem" import { estimateFeesPerGas } from "viem/actions" import type { SmartAccount } from "../../accounts/types" import type { @@ -11,44 +11,80 @@ import type { StateOverrides } from "../../types/bundler" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { estimateUserOperationGas } from "../bundler/estimateUserOperationGas" +import type { + DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_0_7, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils/getEntryPointVersion" -export type SponsorUserOperationMiddleware = { +export type SponsorUserOperationMiddleware< + entryPoint extends EntryPoint = DefaultEntryPoint +> = { sponsorUserOperation?: (args: { - userOperation: UserOperation - entryPoint: Address - }) => Promise + userOperation: UserOperation> + entryPoint: entryPoint + }) => Promise>> } export type PrepareUserOperationRequestParameters< - TAccount extends SmartAccount | undefined = SmartAccount | undefined + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined > = { - userOperation: PartialBy< - UserOperation, - | "nonce" - | "sender" - | "initCode" - | "callGasLimit" - | "verificationGasLimit" - | "preVerificationGas" - | "maxFeePerGas" - | "maxPriorityFeePerGas" - | "paymasterAndData" - | "signature" - > -} & GetAccountParameter & - SponsorUserOperationMiddleware - -export type PrepareUserOperationRequestReturnType = UserOperation + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperation<"0.6">, + | "sender" + | "nonce" + | "initCode" + | "callGasLimit" + | "verificationGasLimit" + | "preVerificationGas" + | "maxFeePerGas" + | "maxPriorityFeePerGas" + | "paymasterAndData" + | "signature" + > + : PartialBy< + UserOperation<"0.7">, + | "sender" + | "nonce" + | "factory" + | "factoryData" + | "callGasLimit" + | "verificationGasLimit" + | "preVerificationGas" + | "maxFeePerGas" + | "maxPriorityFeePerGas" + | "paymaster" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + | "paymasterData" + | "signature" + > +} & GetAccountParameter & + SponsorUserOperationMiddleware -export async function prepareUserOperationRequest< +export type PrepareUserOperationRequestReturnType< + entryPoint extends EntryPoint +> = UserOperation> + +async function prepareUserOperationRequestEntryPointVersion0_6< + entryPoint extends ENTRYPOINT_ADDRESS_0_6, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, - TAccount extends SmartAccount | undefined = SmartAccount | undefined + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined >( client: Client, - args: Prettify>, + args: Prettify>, stateOverrides?: StateOverrides -): Promise> { +): Promise>> { const { account: account_ = client.account, userOperation: partialUserOperation, @@ -56,7 +92,9 @@ export async function prepareUserOperationRequest< } = args if (!account_) throw new AccountOrClientNotFoundError() - const account = parseAccount(account_) as SmartAccount + const account = parseAccount( + account_ + ) as SmartAccount const [sender, nonce, initCode, callData, gasEstimation] = await Promise.all([ @@ -70,7 +108,7 @@ export async function prepareUserOperationRequest< : undefined ]) - let userOperation: UserOperation = { + let userOperation: UserOperation<"0.6"> = { sender, nonce, initCode, @@ -95,10 +133,13 @@ export async function prepareUserOperationRequest< } if (sponsorUserOperation) { - userOperation = await sponsorUserOperation({ + userOperation = (await sponsorUserOperation({ userOperation, entryPoint: account.entryPoint - }) + } as { + userOperation: UserOperation> + entryPoint: entryPoint + })) as UserOperation<"0.6"> } else if ( !userOperation.callGasLimit || !userOperation.verificationGasLimit || @@ -106,10 +147,11 @@ export async function prepareUserOperationRequest< ) { const gasParameters = await getAction(client, estimateUserOperationGas)( { - userOperation: { - ...userOperation - }, + userOperation, entryPoint: account.entryPoint + } as { + userOperation: UserOperation> + entryPoint: entryPoint }, stateOverrides ) @@ -123,5 +165,153 @@ export async function prepareUserOperationRequest< userOperation.preVerificationGas || gasParameters.preVerificationGas } - return userOperation + return userOperation as PrepareUserOperationRequestReturnType +} + +async function prepareUserOperationRequestEntryPointVersion0_7< + entryPoint extends ENTRYPOINT_ADDRESS_0_7, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + args: Prettify>, + stateOverrides?: StateOverrides +): Promise>> { + const { + account: account_ = client.account, + userOperation: partialUserOperation, + sponsorUserOperation + } = args + if (!account_) throw new AccountOrClientNotFoundError() + + const account = parseAccount( + account_ + ) as SmartAccount + + const [sender, nonce, factory, factoryData, callData, gasEstimation] = + await Promise.all([ + partialUserOperation.sender || account.address, + partialUserOperation.nonce || account.getNonce(), + partialUserOperation.factory || account.getFactory(), + partialUserOperation.factoryData || account.getFactoryData(), + partialUserOperation.callData, + !partialUserOperation.maxFeePerGas || + !partialUserOperation.maxPriorityFeePerGas + ? estimateFeesPerGas(account.client) + : undefined + ]) + + let userOperation: UserOperation<"0.7"> = { + sender, + nonce, + factory: factory || undefined, + factoryData: factoryData || undefined, + callData, + callGasLimit: partialUserOperation.callGasLimit || 0n, + verificationGasLimit: partialUserOperation.verificationGasLimit || 0n, + preVerificationGas: partialUserOperation.preVerificationGas || 0n, + maxFeePerGas: + partialUserOperation.maxFeePerGas || + gasEstimation?.maxFeePerGas || + 0n, + maxPriorityFeePerGas: + partialUserOperation.maxPriorityFeePerGas || + gasEstimation?.maxPriorityFeePerGas || + 0n, + paymaster: undefined, + paymasterVerificationGasLimit: undefined, + paymasterPostOpGasLimit: undefined, + paymasterData: "0x", + signature: partialUserOperation.signature || "0x" + } + + if (userOperation.signature === "0x") { + userOperation.signature = await account.getDummySignature(userOperation) + } + + if (sponsorUserOperation) { + userOperation = (await sponsorUserOperation({ + userOperation, + entryPoint: account.entryPoint + } as { + userOperation: UserOperation> + entryPoint: entryPoint + })) as UserOperation<"0.7"> + } else if ( + !userOperation.callGasLimit || + !userOperation.verificationGasLimit || + !userOperation.preVerificationGas + ) { + const gasParameters = await getAction(client, estimateUserOperationGas)( + { + userOperation, + entryPoint: account.entryPoint + } as { + userOperation: UserOperation> + entryPoint: entryPoint + }, + stateOverrides + ) + + userOperation.callGasLimit = + userOperation.callGasLimit || gasParameters.callGasLimit + userOperation.verificationGasLimit = + userOperation.verificationGasLimit || + gasParameters.verificationGasLimit + userOperation.preVerificationGas = + userOperation.preVerificationGas || gasParameters.preVerificationGas + } + + return userOperation as PrepareUserOperationRequestReturnType +} + +export async function prepareUserOperationRequest< + entryPoint extends EntryPoint = DefaultEntryPoint, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined +>( + client: Client, + args: Prettify>, + stateOverrides?: StateOverrides +): Promise>> { + const { account: account_ = client.account } = args + if (!account_) throw new AccountOrClientNotFoundError() + + const account = parseAccount(account_) as SmartAccount + + const entryPointVersion = getEntryPointVersion(account.entryPoint) + + if (entryPointVersion === "0.6") { + return prepareUserOperationRequestEntryPointVersion0_6( + client as Client< + TTransport, + TChain, + SmartAccount | undefined + >, + args as PrepareUserOperationRequestParameters< + ENTRYPOINT_ADDRESS_0_6, + SmartAccount | undefined + >, + stateOverrides + ) as Promise> + } + + return prepareUserOperationRequestEntryPointVersion0_7( + client as Client< + TTransport, + TChain, + SmartAccount | undefined + >, + args as PrepareUserOperationRequestParameters< + ENTRYPOINT_ADDRESS_0_7, + SmartAccount | undefined + >, + stateOverrides + ) as Promise> } diff --git a/packages/permissionless/actions/smartAccount/sendTransaction.ts b/packages/permissionless/actions/smartAccount/sendTransaction.ts index d7c0f1e7..53999169 100644 --- a/packages/permissionless/actions/smartAccount/sendTransaction.ts +++ b/packages/permissionless/actions/smartAccount/sendTransaction.ts @@ -12,13 +12,17 @@ import { getAction } from "../../utils/getAction" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { sendUserOperation } from "./sendUserOperation" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type SendTransactionWithPaymasterParameters< + entryPoint extends EntryPoint, TChain extends Chain | undefined = Chain | undefined, - TAccount extends SmartAccount | undefined = SmartAccount | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined, TChainOverride extends Chain | undefined = Chain | undefined > = SendTransactionParameters & - SponsorUserOperationMiddleware + SponsorUserOperationMiddleware /** * Creates, signs, and sends a new transaction to the network. @@ -68,12 +72,18 @@ export type SendTransactionWithPaymasterParameters< */ export async function sendTransaction< TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined, - TChainOverride extends Chain | undefined + TAccount extends SmartAccount | undefined, + entryPoint extends EntryPoint = DefaultEntryPoint, + TChainOverride extends Chain | undefined = Chain | undefined >( client: Client, args: Prettify< - SendTransactionWithPaymasterParameters + SendTransactionWithPaymasterParameters< + entryPoint, + TChain, + TAccount, + TChainOverride + > > ): Promise { const { @@ -93,7 +103,7 @@ export async function sendTransaction< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount if (!to) throw new Error("Missing to address") @@ -109,11 +119,10 @@ export async function sendTransaction< const userOpHash = await getAction( client, - sendUserOperation + sendUserOperation )({ userOperation: { sender: account.address, - paymasterAndData: "0x", maxFeePerGas: maxFeePerGas || 0n, maxPriorityFeePerGas: maxPriorityFeePerGas || 0n, callData: callData, diff --git a/packages/permissionless/actions/smartAccount/sendTransactions.ts b/packages/permissionless/actions/smartAccount/sendTransactions.ts index 17f69a65..2b81d684 100644 --- a/packages/permissionless/actions/smartAccount/sendTransactions.ts +++ b/packages/permissionless/actions/smartAccount/sendTransactions.ts @@ -14,13 +14,17 @@ import { getAction } from "../../utils/getAction" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { sendUserOperation } from "./sendUserOperation" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type SendTransactionsWithPaymasterParameters< - TAccount extends SmartAccount | undefined = SmartAccount | undefined + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined > = { transactions: { to: Address; value: bigint; data: Hex }[] -} & GetAccountParameter & - SponsorUserOperationMiddleware & { +} & GetAccountParameter & + SponsorUserOperationMiddleware & { maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint nonce?: bigint @@ -74,10 +78,13 @@ export type SendTransactionsWithPaymasterParameters< */ export async function sendTransactions< TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined + TAccount extends SmartAccount | undefined, + entryPoint extends EntryPoint = DefaultEntryPoint >( client: Client, - args: Prettify> + args: Prettify< + SendTransactionsWithPaymasterParameters + > ): Promise { const { account: account_ = client.account, @@ -94,7 +101,7 @@ export async function sendTransactions< }) } - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount if (account.type !== "local") { throw new Error("RPC account type not supported") @@ -113,11 +120,10 @@ export async function sendTransactions< const userOpHash = await getAction( client, - sendUserOperation + sendUserOperation )({ userOperation: { sender: account.address, - paymasterAndData: "0x", maxFeePerGas: maxFeePerGas || 0n, maxPriorityFeePerGas: maxPriorityFeePerGas || 0n, callData: callData, diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.ts index d800a5ea..ac1a7240 100644 --- a/packages/permissionless/actions/smartAccount/sendUserOperation.ts +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.ts @@ -13,48 +13,81 @@ import { type SponsorUserOperationMiddleware, prepareUserOperationRequest } from "./prepareUserOperationRequest" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" export type SendUserOperationParameters< - TAccount extends SmartAccount | undefined = SmartAccount | undefined + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined > = { - userOperation: PartialBy< - UserOperation, - | "nonce" - | "sender" - | "initCode" - | "signature" - | "callGasLimit" - | "maxFeePerGas" - | "maxPriorityFeePerGas" - | "preVerificationGas" - | "verificationGasLimit" - | "paymasterAndData" - > -} & GetAccountParameter & - SponsorUserOperationMiddleware + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperation<"0.6">, + | "sender" + | "nonce" + | "initCode" + | "callGasLimit" + | "verificationGasLimit" + | "preVerificationGas" + | "maxFeePerGas" + | "maxPriorityFeePerGas" + | "paymasterAndData" + | "signature" + > + : PartialBy< + UserOperation<"0.7">, + | "sender" + | "nonce" + | "factory" + | "factoryData" + | "callGasLimit" + | "verificationGasLimit" + | "preVerificationGas" + | "maxFeePerGas" + | "maxPriorityFeePerGas" + | "paymaster" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + | "paymasterData" + | "signature" + > +} & GetAccountParameter & + SponsorUserOperationMiddleware export async function sendUserOperation< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, - TAccount extends SmartAccount | undefined = SmartAccount | undefined + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined >( client: Client, - args: Prettify> + args: Prettify> ): Promise { const { account: account_ = client.account } = args if (!account_) throw new AccountOrClientNotFoundError() - const account = parseAccount(account_) as SmartAccount + const account = parseAccount(account_) as SmartAccount const userOperation = await getAction( client, - prepareUserOperationRequest + prepareUserOperationRequest )(args) - userOperation.signature = await account.signUserOperation(userOperation) + userOperation.signature = await account.signUserOperation( + userOperation as UserOperation> + ) return sendUserOperationBundler(client, { - userOperation: userOperation, + userOperation: userOperation as UserOperation< + GetEntryPointVersion + >, entryPoint: account.entryPoint }) } diff --git a/packages/permissionless/actions/smartAccount/signMessage.ts b/packages/permissionless/actions/smartAccount/signMessage.ts index 72930694..fcb9c7a6 100644 --- a/packages/permissionless/actions/smartAccount/signMessage.ts +++ b/packages/permissionless/actions/smartAccount/signMessage.ts @@ -7,6 +7,7 @@ import type { } from "viem" import { type SmartAccount } from "../../accounts/types" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" /** * Calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`. @@ -56,7 +57,8 @@ import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" */ export async function signMessage< TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined + TAccount extends SmartAccount | undefined, + entryPoint extends EntryPoint = DefaultEntryPoint >( client: Client, { diff --git a/packages/permissionless/actions/smartAccount/signTypedData.ts b/packages/permissionless/actions/smartAccount/signTypedData.ts index 637e6a2c..ac9fac8d 100644 --- a/packages/permissionless/actions/smartAccount/signTypedData.ts +++ b/packages/permissionless/actions/smartAccount/signTypedData.ts @@ -11,6 +11,7 @@ import { } from "viem" import { type SmartAccount } from "../../accounts/types" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" /** * Signs typed data and calculates an Ethereum-specific signature in [https://eips.ethereum.org/EIPS/eip-712](https://eips.ethereum.org/EIPS/eip-712): `sign(keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message)))` @@ -114,7 +115,8 @@ export async function signTypedData< const TTypedData extends TypedData | { [key: string]: unknown }, TPrimaryType extends string, TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined + TAccount extends SmartAccount | undefined, + entryPoint extends EntryPoint = DefaultEntryPoint >( client: Client, { diff --git a/packages/permissionless/actions/smartAccount/writeContract.ts b/packages/permissionless/actions/smartAccount/writeContract.ts index 40d31eb5..7f2adaca 100644 --- a/packages/permissionless/actions/smartAccount/writeContract.ts +++ b/packages/permissionless/actions/smartAccount/writeContract.ts @@ -17,6 +17,7 @@ import { type SendTransactionWithPaymasterParameters, sendTransaction } from "./sendTransaction" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" /** * Executes a write function on a contract. @@ -70,8 +71,11 @@ import { * const hash = await writeContract(client, request) */ export type WriteContractWithPaymasterParameters< + entryPoint extends EntryPoint = DefaultEntryPoint, TChain extends Chain | undefined = Chain | undefined, - TAccount extends SmartAccount | undefined = SmartAccount | undefined, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined, TAbi extends Abi | readonly unknown[] = Abi | readonly unknown[], TFunctionName extends ContractFunctionName< TAbi, @@ -91,12 +95,13 @@ export type WriteContractWithPaymasterParameters< TAccount, TChainOverride > & - SponsorUserOperationMiddleware + SponsorUserOperationMiddleware export async function writeContract< TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined, + TAccount extends SmartAccount | undefined, const TAbi extends Abi | readonly unknown[], + entryPoint extends EntryPoint = DefaultEntryPoint, TFunctionName extends ContractFunctionName< TAbi, "nonpayable" | "payable" @@ -117,6 +122,7 @@ export async function writeContract< functionName, ...request }: WriteContractWithPaymasterParameters< + entryPoint, TChain, TAccount, TAbi, @@ -132,12 +138,13 @@ export async function writeContract< } as EncodeFunctionDataParameters) const hash = await getAction( client, - sendTransaction + sendTransaction )({ data: `${data}${dataSuffix ? dataSuffix.replace("0x", "") : ""}`, to: address, ...request } as unknown as SendTransactionWithPaymasterParameters< + entryPoint, TChain, TAccount, TChainOverride diff --git a/packages/permissionless/actions/stackup/sponsorUserOperation.ts b/packages/permissionless/actions/stackup/sponsorUserOperation.ts index a97c9003..1d8bd46a 100644 --- a/packages/permissionless/actions/stackup/sponsorUserOperation.ts +++ b/packages/permissionless/actions/stackup/sponsorUserOperation.ts @@ -1,4 +1,3 @@ -import type { Address } from "viem" import type { PartialBy } from "viem/types/utils" import { type StackupPaymasterClient } from "../../clients/stackup" import type { StackupPaymasterContext } from "../../types/stackup" @@ -7,20 +6,33 @@ import type { UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils/getEntryPointVersion" -export type SponsorUserOperationParameters = { - userOperation: PartialBy< - UserOperation, - | "callGasLimit" - | "preVerificationGas" - | "verificationGasLimit" - | "paymasterAndData" - > - entryPoint: Address +export type SponsorUserOperationParameters = { + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperation<"0.6">, + "callGasLimit" | "preVerificationGas" | "verificationGasLimit" + > + : PartialBy< + UserOperation<"0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + > + entryPoint: entryPoint context: StackupPaymasterContext } -export type SponsorUserOperationReturnType = UserOperation +export type SponsorUserOperationReturnType = + UserOperation> /** * Returns paymasterAndData & updated gas parameters required to sponsor a userOperation. @@ -47,26 +59,49 @@ export type SponsorUserOperationReturnType = UserOperation * }}) * */ -export const sponsorUserOperation = async ( - client: StackupPaymasterClient, - args: SponsorUserOperationParameters -): Promise => { +export const sponsorUserOperation = async < + entryPoint extends EntryPoint = DefaultEntryPoint +>( + client: StackupPaymasterClient, + args: SponsorUserOperationParameters +): Promise> => { const response = await client.request({ method: "pm_sponsorUserOperation", params: [ - deepHexlify(args.userOperation) as UserOperationWithBigIntAsHex, + deepHexlify(args.userOperation) as UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, args.entryPoint, args.context ] }) - const userOperation: UserOperation = { - ...args.userOperation, - paymasterAndData: response.paymasterAndData, - preVerificationGas: BigInt(response.preVerificationGas), - verificationGasLimit: BigInt(response.verificationGasLimit), - callGasLimit: BigInt(response.callGasLimit) - } + const entryPointVersion = getEntryPointVersion(args.entryPoint) + + const userOperation: SponsorUserOperationReturnType = ( + entryPointVersion === "0.6" + ? { + ...args.userOperation, + paymasterAndData: response.paymasterAndData, + preVerificationGas: BigInt(response.preVerificationGas), + verificationGasLimit: BigInt(response.verificationGasLimit), + callGasLimit: BigInt(response.callGasLimit) + } + : { + ...args.userOperation, + paymasterAndData: response.paymasterAndData, + preVerificationGas: BigInt(response.preVerificationGas), + verificationGasLimit: BigInt(response.verificationGasLimit), + callGasLimit: BigInt(response.callGasLimit), + paymasterVerificationGasLimit: + response.paymasterVerificationGasLimit + ? BigInt(response.paymasterVerificationGasLimit) + : undefined, + paymasterPostOpGasLimit: response.paymasterPostOpGasLimit + ? BigInt(response.paymasterPostOpGasLimit) + : undefined + } + ) as SponsorUserOperationReturnType return userOperation } diff --git a/packages/permissionless/clients/createBundlerClient.ts b/packages/permissionless/clients/createBundlerClient.ts index 698cdaa8..ede22458 100644 --- a/packages/permissionless/clients/createBundlerClient.ts +++ b/packages/permissionless/clients/createBundlerClient.ts @@ -8,14 +8,16 @@ import type { import { createClient } from "viem" import type { BundlerRpcSchema } from "../types/bundler" import { type BundlerActions, bundlerActions } from "./decorators/bundler" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" export type BundlerClient< + entryPoint extends EntryPoint = DefaultEntryPoint, TChain extends Chain | undefined = Chain | undefined > = Client< Transport, TChain, Account | undefined, - BundlerRpcSchema, + BundlerRpcSchema, BundlerActions > /** @@ -39,10 +41,11 @@ export type BundlerClient< */ export const createBundlerClient = < transport extends Transport, + entryPoint extends EntryPoint = DefaultEntryPoint, chain extends Chain | undefined = undefined >( parameters: PublicClientConfig -): BundlerClient => { +): BundlerClient => { const { key = "public", name = "Bundler Client" } = parameters const client = createClient({ ...parameters, diff --git a/packages/permissionless/clients/createSmartAccountClient.ts b/packages/permissionless/clients/createSmartAccountClient.ts index 9270bf5f..6463ae82 100644 --- a/packages/permissionless/clients/createSmartAccountClient.ts +++ b/packages/permissionless/clients/createSmartAccountClient.ts @@ -14,6 +14,7 @@ import { type SmartAccountActions, smartAccountActions } from "./decorators/smartAccount" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" /** * TODO: @@ -21,30 +22,36 @@ import { * - Fix typing, 'accounts' is required to signMessage, signTypedData, signTransaction, but not needed here, since account is embedded in the client */ export type SmartAccountClient< + entryPoint extends EntryPoint = DefaultEntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, - account extends SmartAccount | undefined = SmartAccount | undefined + account extends SmartAccount | undefined = + | SmartAccount + | undefined > = Prettify< Client< transport, chain, account, - BundlerRpcSchema, - SmartAccountActions + BundlerRpcSchema, + SmartAccountActions > > export type SmartAccountClientConfig< + entryPoint extends EntryPoint = DefaultEntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, - account extends SmartAccount | undefined = SmartAccount | undefined + account extends SmartAccount | undefined = + | SmartAccount + | undefined > = Prettify< Pick< ClientConfig, "cacheTime" | "chain" | "key" | "name" | "pollingInterval" | "transport" > & { account?: account - } & SponsorUserOperationMiddleware + } & SponsorUserOperationMiddleware > /** @@ -69,15 +76,17 @@ export type SmartAccountClientConfig< export function createSmartAccountClient< TTransport extends Transport, + entryPoint extends EntryPoint = DefaultEntryPoint, TChain extends Chain | undefined = undefined, - TSmartAccount extends SmartAccount | undefined = undefined + TSmartAccount extends SmartAccount | undefined = undefined >( - parameters: SmartAccountClientConfig -): SmartAccountClient - -export function createSmartAccountClient( - parameters: SmartAccountClientConfig -): SmartAccountClient { + parameters: SmartAccountClientConfig< + entryPoint, + TTransport, + TChain, + TSmartAccount + > +): SmartAccountClient { const { key = "Account", name = "Smart Account Client", @@ -92,8 +101,8 @@ export function createSmartAccountClient( }) return client.extend( - smartAccountActions({ + smartAccountActions({ sponsorUserOperation: parameters.sponsorUserOperation }) - ) + ) as SmartAccountClient } diff --git a/packages/permissionless/clients/decorators/bundler.ts b/packages/permissionless/clients/decorators/bundler.ts index 5ae8de84..515c36e0 100644 --- a/packages/permissionless/clients/decorators/bundler.ts +++ b/packages/permissionless/clients/decorators/bundler.ts @@ -28,197 +28,212 @@ import { import type { Prettify } from "../../types/" import type { StateOverrides } from "../../types/bundler" import type { BundlerClient } from "../createBundlerClient" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" -export type BundlerActions = { - /** - * - * Sends user operation to the bundler - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/sendUserOperation - * - * @param args {@link SendUserOperationParameters}. - * @returns UserOpHash that you can use to track user operation as {@link Hash}. - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http("https://api.pimlico.io/v2/goerli/rpc?apikey=YOUR_API_KEY_HERE") - * }).extend(bundlerActions) - * - * const userOpHash = await bundlerClient.sendUserOperation({ - * userOperation: signedUserOperation, - * entryPoint: entryPoint - * }) - * - * // Return '0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34' - */ - sendUserOperation: ( - args: Prettify - ) => Promise - /** - * - * Estimates preVerificationGas, verificationGasLimit and callGasLimit for user operation - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/estimateUserOperationGas - * - * @param args {@link EstimateUserOperationGasParameters} - * @returns preVerificationGas, verificationGasLimit and callGasLimit as {@link EstimateUserOperationGasReturnType} - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * const gasParameters = await bundlerClient.estimateUserOperationGas({ - * userOperation: signedUserOperation, - * entryPoint: entryPoint - * }) - * - * // Return {preVerificationGas: 43492n, verificationGasLimit: 59436n, callGasLimit: 9000n} - */ - estimateUserOperationGas: ( - args: Prettify, - stateOverrides?: StateOverrides - ) => Promise> - /** - * - * Returns the supported entrypoints by the bundler service - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/supportedEntryPoints - * - * @returns Supported entryPoints - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * const supportedEntryPoints = await bundlerClient.supportedEntryPoints() - * - * // Return ['0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'] - */ - supportedEntryPoints: () => Promise - /** - * - * Returns the supported chain id by the bundler service - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/chainId - * - * @returns Supported chain id - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * const chainId = await bundlerClient.chainId() - * // Return 5n for Goerli - */ - chainId: () => Promise - /** - * - * Returns the user operation from userOpHash - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationByHash - * - * @param args {@link GetUserOperationByHash} UserOpHash that was returned by {@link sendUserOperation} - * @returns userOperation along with entryPoint, transactionHash, blockHash, blockNumber if found or null - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * await bundlerClient.getUserOperationByHash(userOpHash) - * - */ - getUserOperationByHash: ( - args: Prettify - ) => Promise | null> - /** - * - * Returns the user operation receipt from userOpHash - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt - * - * @param args {@link GetUserOperationReceiptParameters} UserOpHash that was returned by {@link sendUserOperation} - * @returns user operation receipt {@link GetUserOperationReceiptReturnType} if found or null - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * await bundlerClient.getUserOperationReceipt({hash: userOpHash}) - * - */ - getUserOperationReceipt: ( - args: Prettify - ) => Promise | null> +export type BundlerActions = + { + /** + * + * Sends user operation to the bundler + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/sendUserOperation + * + * @param args {@link SendUserOperationParameters}. + * @returns UserOpHash that you can use to track user operation as {@link Hash}. + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http("https://api.pimlico.io/v2/goerli/rpc?apikey=YOUR_API_KEY_HERE") + * }).extend(bundlerActions) + * + * const userOpHash = await bundlerClient.sendUserOperation({ + * userOperation: signedUserOperation, + * entryPoint: entryPoint + * }) + * + * // Return '0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34' + */ + sendUserOperation: ( + args: Prettify> + ) => Promise + /** + * + * Estimates preVerificationGas, verificationGasLimit and callGasLimit for user operation + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/estimateUserOperationGas + * + * @param args {@link EstimateUserOperationGasParameters} + * @returns preVerificationGas, verificationGasLimit and callGasLimit as {@link EstimateUserOperationGasReturnType} + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * const gasParameters = await bundlerClient.estimateUserOperationGas({ + * userOperation: signedUserOperation, + * entryPoint: entryPoint + * }) + * + * // Return {preVerificationGas: 43492n, verificationGasLimit: 59436n, callGasLimit: 9000n} + */ + estimateUserOperationGas: < + entryPoint extends EntryPoint = DefaultEntryPoint + >( + args: Prettify>, + stateOverrides?: StateOverrides + ) => Promise> + /** + * + * Returns the supported entrypoints by the bundler service + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/supportedEntryPoints + * + * @returns Supported entryPoints + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * const supportedEntryPoints = await bundlerClient.supportedEntryPoints() + * + * // Return ['0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'] + */ + supportedEntryPoints: () => Promise + /** + * + * Returns the supported chain id by the bundler service + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/chainId + * + * @returns Supported chain id + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * const chainId = await bundlerClient.chainId() + * // Return 5n for Goerli + */ + chainId: () => Promise + /** + * + * Returns the user operation from userOpHash + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationByHash + * + * @param args {@link GetUserOperationByHash} UserOpHash that was returned by {@link sendUserOperation} + * @returns userOperation along with entryPoint, transactionHash, blockHash, blockNumber if found or null + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * await bundlerClient.getUserOperationByHash(userOpHash) + * + */ + getUserOperationByHash: ( + args: Prettify + ) => Promise + > | null> + /** + * + * Returns the user operation receipt from userOpHash + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt + * + * @param args {@link GetUserOperationReceiptParameters} UserOpHash that was returned by {@link sendUserOperation} + * @returns user operation receipt {@link GetUserOperationReceiptReturnType} if found or null + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * await bundlerClient.getUserOperationReceipt({hash: userOpHash}) + * + */ + getUserOperationReceipt: ( + args: Prettify + ) => Promise | null> - /** - * Waits for the User Operation to be included on a [Block](https://viem.sh/docs/glossary/terms.html#block) (one confirmation), and then returns the [User Operation Receipt](https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt). - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/waitForUserOperationReceipt - * - * @param client - Bundler Client to use - * @param parameters - {@link WaitForUserOperationReceiptParameters} - * @returns The transaction receipt. {@link GetUserOperationReceiptReturnType} - * - * @example - * import { createBundlerClient, waitForUserOperationReceipt, http } from 'viem' - * import { mainnet } from 'viem/chains' - * - * const bundlerClient = createBundlerClient({ - * chain: mainnet, - * transport: http(), - * }) - * const userOperationReceipt = await bundlerClient.waitForUserOperationReceipt({ - * hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d', - * }) - */ - waitForUserOperationReceipt: ( - args: Prettify - ) => Promise> -} + /** + * Waits for the User Operation to be included on a [Block](https://viem.sh/docs/glossary/terms.html#block) (one confirmation), and then returns the [User Operation Receipt](https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt). + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/waitForUserOperationReceipt + * + * @param client - Bundler Client to use + * @param parameters - {@link WaitForUserOperationReceiptParameters} + * @returns The transaction receipt. {@link GetUserOperationReceiptReturnType} + * + * @example + * import { createBundlerClient, waitForUserOperationReceipt, http } from 'viem' + * import { mainnet } from 'viem/chains' + * + * const bundlerClient = createBundlerClient({ + * chain: mainnet, + * transport: http(), + * }) + * const userOperationReceipt = await bundlerClient.waitForUserOperationReceipt({ + * hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d', + * }) + */ + waitForUserOperationReceipt: ( + args: Prettify + ) => Promise> + } -const bundlerActions = (client: Client): BundlerActions => ({ +const bundlerActions = ( + client: Client +): BundlerActions => ({ sendUserOperation: async ( - args: SendUserOperationParameters - ): Promise => sendUserOperation(client as BundlerClient, args), - estimateUserOperationGas: ( - args: EstimateUserOperationGasParameters, - stateOverrides + args: SendUserOperationParameters + ): Promise => + sendUserOperation(client as BundlerClient, args), + estimateUserOperationGas: < + entryPoint extends EntryPoint = DefaultEntryPoint + >( + args: EstimateUserOperationGasParameters, + stateOverrides?: StateOverrides ) => - estimateUserOperationGas(client as BundlerClient, args, stateOverrides), + estimateUserOperationGas( + client as BundlerClient, + args, + stateOverrides + ), supportedEntryPoints: (): Promise => supportedEntryPoints(client as BundlerClient), chainId: () => chainId(client as BundlerClient), getUserOperationByHash: (args: GetUserOperationByHashParameters) => - getUserOperationByHash(client as BundlerClient, args), + getUserOperationByHash(client as BundlerClient, args), getUserOperationReceipt: (args: GetUserOperationReceiptParameters) => getUserOperationReceipt(client as BundlerClient, args), waitForUserOperationReceipt: ( diff --git a/packages/permissionless/clients/decorators/pimlico.ts b/packages/permissionless/clients/decorators/pimlico.ts index ffd93930..64261d8b 100644 --- a/packages/permissionless/clients/decorators/pimlico.ts +++ b/packages/permissionless/clients/decorators/pimlico.ts @@ -22,6 +22,7 @@ import { } from "../../actions/pimlico/sponsorUserOperation" import type { Prettify } from "../../types/" import type { PimlicoBundlerClient, PimlicoPaymasterClient } from "../pimlico" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type PimlicoBundlerActions = { /** @@ -109,7 +110,9 @@ export const pimlicoBundlerActions = ( ) => sendCompressedUserOperation(client as PimlicoBundlerClient, args) }) -export type PimlicoPaymasterClientActions = { +export type PimlicoPaymasterClientActions< + entryPoint extends EntryPoint = DefaultEntryPoint +> = { /** * Returns paymasterAndData & updated gas parameters required to sponsor a userOperation. * @@ -134,11 +137,11 @@ export type PimlicoPaymasterClientActions = { * */ sponsorUserOperation: ( - args: Prettify - ) => Promise> + args: Prettify> + ) => Promise>> validateSponsorshipPolicies: ( - args: Prettify + args: Prettify> ) => Promise[]> } @@ -177,14 +180,25 @@ export type PimlicoPaymasterClientActions = { * } * ] */ -export const pimlicoPaymasterActions = ( +export const pimlicoPaymasterActions = < + entryPoint extends EntryPoint = DefaultEntryPoint +>( client: Client -): PimlicoPaymasterClientActions => ({ - sponsorUserOperation: async (args: PimlicoSponsorUserOperationParameters) => - sponsorUserOperation(client as PimlicoPaymasterClient, args), +): PimlicoPaymasterClientActions => ({ + sponsorUserOperation: async ( + args: PimlicoSponsorUserOperationParameters + ) => + sponsorUserOperation( + client as PimlicoPaymasterClient, + args + ), validateSponsorshipPolicies: async ( - args: ValidateSponsorshipPoliciesParameters - ) => validateSponsorshipPolicies(client as PimlicoPaymasterClient, args) + args: ValidateSponsorshipPoliciesParameters + ) => + validateSponsorshipPolicies( + client as PimlicoPaymasterClient, + args + ) }) /** diff --git a/packages/permissionless/clients/decorators/smartAccount.ts b/packages/permissionless/clients/decorators/smartAccount.ts index 7b07f476..40cd5256 100644 --- a/packages/permissionless/clients/decorators/smartAccount.ts +++ b/packages/permissionless/clients/decorators/smartAccount.ts @@ -41,10 +41,14 @@ import { } from "../../actions/smartAccount/writeContract" import type { Prettify } from "../../types/" import type { StateOverrides } from "../../types/bundler" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type SmartAccountActions< + entryPoint extends EntryPoint = DefaultEntryPoint, TChain extends Chain | undefined = Chain | undefined, - TSmartAccount extends SmartAccount | undefined = SmartAccount | undefined + TSmartAccount extends SmartAccount | undefined = + | SmartAccount + | undefined > = { /** * Creates, signs, and sends a new transaction to the network. @@ -91,9 +95,7 @@ export type SmartAccountActions< */ sendTransaction: ( args: SendTransactionParameters - ) => ReturnType< - typeof sendTransaction - > + ) => Promise /** * Calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`. * @@ -138,8 +140,10 @@ export type SmartAccountActions< * }) */ signMessage: ( - args: Parameters>[1] - ) => ReturnType> + args: Parameters< + typeof signMessage + >[1] + ) => ReturnType> /** * Signs typed data and calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`. * @@ -245,11 +249,18 @@ export type SmartAccountActions< TTypedData, TPrimaryType, TChain, - TSmartAccount + TSmartAccount, + entryPoint > >[1] ) => ReturnType< - typeof signTypedData + typeof signTypedData< + TTypedData, + TPrimaryType, + TChain, + TSmartAccount, + entryPoint + > > /** * Deploys a contract to the network, given bytecode and constructor arguments. @@ -289,7 +300,7 @@ export type SmartAccountActions< TChainOverride > > - ) => ReturnType> + ) => ReturnType> /** * Executes a write function on a contract. * This function also allows you to sponsor this transaction if sender is a smartAccount @@ -364,6 +375,7 @@ export type SmartAccountActions< TChain, TSmartAccount, TAbi, + entryPoint, TFunctionName, TArgs, TChainOverride @@ -373,6 +385,7 @@ export type SmartAccountActions< args: Prettify< Parameters< typeof prepareUserOperationRequest< + entryPoint, TTransport, TChain, TSmartAccount @@ -380,11 +393,16 @@ export type SmartAccountActions< >[1] >, stateOverrides?: StateOverrides - ) => Promise> + ) => Promise>> sendUserOperation: ( args: Prettify< Parameters< - typeof sendUserOperation + typeof sendUserOperation< + entryPoint, + TTransport, + TChain, + TSmartAccount + > >[1] > ) => Promise @@ -438,22 +456,24 @@ export type SmartAccountActions< * }]) */ sendTransactions: ( - args: Prettify> - ) => ReturnType> + args: Prettify< + SendTransactionsWithPaymasterParameters + > + ) => ReturnType> } -export function smartAccountActions({ - sponsorUserOperation -}: SponsorUserOperationMiddleware) { +export function smartAccountActions< + entryPoint extends EntryPoint = DefaultEntryPoint +>({ sponsorUserOperation }: SponsorUserOperationMiddleware) { return < TTransport extends Transport, TChain extends Chain | undefined = Chain | undefined, - TSmartAccount extends SmartAccount | undefined = - | SmartAccount + TSmartAccount extends SmartAccount | undefined = + | SmartAccount | undefined >( client: Client - ): SmartAccountActions => ({ + ): SmartAccountActions => ({ prepareUserOperationRequest: (args, stateOverrides) => prepareUserOperationRequest( client, @@ -464,31 +484,92 @@ export function smartAccountActions({ stateOverrides ), deployContract: (args) => - deployContract(client, { + deployContract(client, { ...args, sponsorUserOperation - } as DeployContractParametersWithPaymaster), + } as DeployContractParametersWithPaymaster), sendTransaction: (args) => - sendTransaction(client, { + sendTransaction(client, { ...args, sponsorUserOperation - } as SendTransactionWithPaymasterParameters), + } as SendTransactionWithPaymasterParameters< + entryPoint, + TChain, + TSmartAccount + >), sendTransactions: (args) => - sendTransactions(client, { + sendTransactions(client, { ...args, sponsorUserOperation - } as SendTransactionsWithPaymasterParameters), + } as SendTransactionsWithPaymasterParameters< + entryPoint, + TSmartAccount + >), sendUserOperation: (args) => - sendUserOperation(client, { - ...args, - sponsorUserOperation - } as SendUserOperationParameters), - signMessage: (args) => signMessage(client, args), - signTypedData: (args) => signTypedData(client, args), - writeContract: (args) => - writeContract(client, { + sendUserOperation( + client, + { + ...args, + sponsorUserOperation + } as SendUserOperationParameters + ), + signMessage: (args) => + signMessage(client, args), + signTypedData: < + const TTypedData extends TypedData | { [key: string]: unknown }, + TPrimaryType extends string + >( + args: Parameters< + typeof signTypedData< + TTypedData, + TPrimaryType, + TChain, + TSmartAccount, + entryPoint + > + >[1] + ) => + signTypedData< + TTypedData, + TPrimaryType, + TChain, + TSmartAccount, + entryPoint + >(client, args), + writeContract: < + const TAbi extends Abi | readonly unknown[], + TFunctionName extends ContractFunctionName< + TAbi, + "nonpayable" | "payable" + > = ContractFunctionName, + TArgs extends ContractFunctionArgs< + TAbi, + "nonpayable" | "payable", + TFunctionName + > = ContractFunctionArgs< + TAbi, + "nonpayable" | "payable", + TFunctionName + >, + TChainOverride extends Chain | undefined = undefined + >( + args: WriteContractParameters< + TAbi, + TFunctionName, + TArgs, + TChain, + TSmartAccount, + TChainOverride + > + ) => + writeContract(client, { ...args, sponsorUserOperation - } as WriteContractWithPaymasterParameters) + } as WriteContractWithPaymasterParameters< + entryPoint, + TChain, + TSmartAccount, + TAbi + >) }) } diff --git a/packages/permissionless/clients/decorators/stackup.ts b/packages/permissionless/clients/decorators/stackup.ts index 82f5fbaf..39aaa766 100644 --- a/packages/permissionless/clients/decorators/stackup.ts +++ b/packages/permissionless/clients/decorators/stackup.ts @@ -9,8 +9,11 @@ import { sponsorUserOperation } from "../../actions/stackup/sponsorUserOperation" import { type StackupPaymasterClient } from "../stackup" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" -export type StackupPaymasterClientActions = { +export type StackupPaymasterClientActions< + entryPoint extends EntryPoint = DefaultEntryPoint +> = { /** * Returns paymasterAndData & updated gas parameters required to sponsor a userOperation. * @@ -35,8 +38,8 @@ export type StackupPaymasterClientActions = { * */ sponsorUserOperation: ( - args: SponsorUserOperationParameters - ) => Promise + args: SponsorUserOperationParameters + ) => Promise> /** * Returns all the Paymaster addresses associated with an EntryPoint that’s owned by this service. @@ -63,11 +66,18 @@ export type StackupPaymasterClientActions = { accounts: (args: AccountsParameters) => Promise } -export const stackupPaymasterActions = ( +export const stackupPaymasterActions = < + entryPoint extends EntryPoint = DefaultEntryPoint +>( client: Client -): StackupPaymasterClientActions => ({ - sponsorUserOperation: async (args: SponsorUserOperationParameters) => - sponsorUserOperation(client as StackupPaymasterClient, args), +): StackupPaymasterClientActions => ({ + sponsorUserOperation: async ( + args: SponsorUserOperationParameters + ) => + sponsorUserOperation( + client as StackupPaymasterClient, + args + ), accounts: async (args: AccountsParameters) => accounts(client as StackupPaymasterClient, args) }) diff --git a/packages/permissionless/clients/pimlico.ts b/packages/permissionless/clients/pimlico.ts index 2a912866..cf61730e 100644 --- a/packages/permissionless/clients/pimlico.ts +++ b/packages/permissionless/clients/pimlico.ts @@ -17,6 +17,7 @@ import { pimlicoBundlerActions, pimlicoPaymasterActions } from "./decorators/pimlico" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" export type PimlicoBundlerClient = Client< Transport, @@ -26,12 +27,14 @@ export type PimlicoBundlerClient = Client< PimlicoBundlerActions & BundlerActions > -export type PimlicoPaymasterClient = Client< +export type PimlicoPaymasterClient< + entryPoint extends EntryPoint = DefaultEntryPoint +> = Client< Transport, Chain | undefined, Account | undefined, - PimlicoPaymasterRpcSchema, - PimlicoPaymasterClientActions + PimlicoPaymasterRpcSchema, + PimlicoPaymasterClientActions > /** @@ -90,10 +93,11 @@ export const createPimlicoBundlerClient = < */ export const createPimlicoPaymasterClient = < transport extends Transport, + entryPoint extends EntryPoint = DefaultEntryPoint, chain extends Chain | undefined = undefined >( parameters: PublicClientConfig -): PimlicoPaymasterClient => { +): PimlicoPaymasterClient => { const { key = "public", name = "Pimlico Paymaster Client" } = parameters const client = createClient({ ...parameters, @@ -101,5 +105,5 @@ export const createPimlicoPaymasterClient = < name, type: "pimlicoPaymasterClient" }) - return client.extend(pimlicoPaymasterActions) + return client.extend(pimlicoPaymasterActions) } diff --git a/packages/permissionless/clients/stackup.ts b/packages/permissionless/clients/stackup.ts index 972f6164..c080fc2f 100644 --- a/packages/permissionless/clients/stackup.ts +++ b/packages/permissionless/clients/stackup.ts @@ -12,13 +12,16 @@ import { type StackupPaymasterClientActions, stackupPaymasterActions } from "./decorators/stackup" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" -export type StackupPaymasterClient = Client< +export type StackupPaymasterClient< + entryPoint extends EntryPoint = DefaultEntryPoint +> = Client< Transport, Chain | undefined, Account | undefined, - StackupPaymasterRpcSchema, - StackupPaymasterClientActions & BundlerActions + StackupPaymasterRpcSchema, + StackupPaymasterClientActions & BundlerActions > /** @@ -42,10 +45,11 @@ export type StackupPaymasterClient = Client< */ export const createStackupPaymasterClient = < transport extends Transport, + entryPoint extends EntryPoint = DefaultEntryPoint, chain extends Chain | undefined = undefined >( parameters: PublicClientConfig -): StackupPaymasterClient => { +): StackupPaymasterClient => { const { key = "public", name = "Stackup Paymaster Client" } = parameters const client = createClient({ ...parameters, @@ -53,5 +57,7 @@ export const createStackupPaymasterClient = < name, type: "stackupPaymasterClient" }) - return client.extend(bundlerActions).extend(stackupPaymasterActions) + return client + .extend(bundlerActions) + .extend(stackupPaymasterActions) } diff --git a/packages/permissionless/errors/estimateUserOperationGas.ts b/packages/permissionless/errors/estimateUserOperationGas.ts index 280cf499..3599714a 100644 --- a/packages/permissionless/errors/estimateUserOperationGas.ts +++ b/packages/permissionless/errors/estimateUserOperationGas.ts @@ -1,12 +1,16 @@ import { BaseError } from "viem" import type { EstimateUserOperationGasParameters } from "../actions/bundler/estimateUserOperationGas" import { prettyPrint } from "./utils" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" -export type EstimateUserOperationGasErrorType = - EstimateUserOperationGasError & { - name: "EstimateUserOperationGasError" - } -export class EstimateUserOperationGasError extends BaseError { +export type EstimateUserOperationGasErrorType< + entryPoint extends EntryPoint = DefaultEntryPoint +> = EstimateUserOperationGasError & { + name: "EstimateUserOperationGasError" +} +export class EstimateUserOperationGasError< + entryPoint extends EntryPoint = DefaultEntryPoint +> extends BaseError { override cause: BaseError override name = "EstimateUserOperationGasError" @@ -17,7 +21,7 @@ export class EstimateUserOperationGasError extends BaseError { userOperation, entryPoint, docsPath - }: EstimateUserOperationGasParameters & { + }: EstimateUserOperationGasParameters & { docsPath?: string } ) { diff --git a/packages/permissionless/errors/sendUserOperation.ts b/packages/permissionless/errors/sendUserOperation.ts index e866017c..930af741 100644 --- a/packages/permissionless/errors/sendUserOperation.ts +++ b/packages/permissionless/errors/sendUserOperation.ts @@ -1,11 +1,14 @@ import { BaseError } from "viem" import { type SendUserOperationParameters } from "../actions/bundler/sendUserOperation" import { prettyPrint } from "./utils" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" export type SendUserOperationErrorType = SendUserOperationError & { name: "SendUserOperationError" } -export class SendUserOperationError extends BaseError { +export class SendUserOperationError< + entryPoint extends EntryPoint = DefaultEntryPoint +> extends BaseError { override cause: BaseError override name = "SendUserOperationError" @@ -16,7 +19,7 @@ export class SendUserOperationError extends BaseError { userOperation, entryPoint, docsPath - }: SendUserOperationParameters & { + }: SendUserOperationParameters & { docsPath?: string } ) { diff --git a/packages/permissionless/types/bundler.ts b/packages/permissionless/types/bundler.ts index d35db7ad..7ff61ca2 100644 --- a/packages/permissionless/types/bundler.ts +++ b/packages/permissionless/types/bundler.ts @@ -1,37 +1,39 @@ import type { Address, Hash, Hex } from "viem" import type { PartialBy } from "viem/types/utils" import type { UserOperationWithBigIntAsHex } from "./userOperation" +import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" -export type BundlerRpcSchema = [ +export type BundlerRpcSchema = [ { Method: "eth_sendUserOperation" Parameters: [ - userOperation: UserOperationWithBigIntAsHex, - entryPoint: Address + userOperation: UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, + entryPoint: entryPoint ] ReturnType: Hash }, { Method: "eth_estimateUserOperationGas" Parameters: [ - userOperation: PartialBy< - UserOperationWithBigIntAsHex, - "callGasLimit" | "preVerificationGas" | "verificationGasLimit" - >, - entryPoint: Address, - stateOverrides?: { - [x: string]: { - balance?: Hex - nonce?: Hex - code?: Hex - state?: { - [x: Hex]: Hex - } - stateDiff?: { - [x: Hex]: Hex - } - } - } + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperationWithBigIntAsHex<"0.6">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + > + : PartialBy< + UserOperationWithBigIntAsHex<"0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + >, + entryPoint: entryPoint, + stateOverrides?: StateOverrides ] ReturnType: { preVerificationGas: Hex @@ -53,8 +55,10 @@ export type BundlerRpcSchema = [ Method: "eth_getUserOperationByHash" Parameters: [hash: Hash] ReturnType: { - userOperation: UserOperationWithBigIntAsHex - entryPoint: Address + userOperation: UserOperationWithBigIntAsHex< + GetEntryPointVersion + > + entryPoint: entryPoint transactionHash: Hash blockHash: Hash blockNumber: Hex diff --git a/packages/permissionless/types/entrypoint.ts b/packages/permissionless/types/entrypoint.ts new file mode 100644 index 00000000..010718b0 --- /dev/null +++ b/packages/permissionless/types/entrypoint.ts @@ -0,0 +1,13 @@ +export type EntryPointVersion = "0.6" | "0.7" + +export type DefaultEntryPoint = ENTRYPOINT_ADDRESS_0_6 + +export type ENTRYPOINT_ADDRESS_0_6 = + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" +export type ENTRYPOINT_ADDRESS_0_7 = + "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" + +export type GetEntryPointVersion = + entryPoint extends ENTRYPOINT_ADDRESS_0_6 ? "0.6" : "0.7" + +export type EntryPoint = ENTRYPOINT_ADDRESS_0_6 | ENTRYPOINT_ADDRESS_0_7 diff --git a/packages/permissionless/types/index.ts b/packages/permissionless/types/index.ts index 2352b791..43ebed35 100644 --- a/packages/permissionless/types/index.ts +++ b/packages/permissionless/types/index.ts @@ -1,9 +1,17 @@ import type { Account, Chain, Client, Transport } from "viem" import type { SmartAccount } from "../accounts/types" import type { UserOperation } from "./userOperation" +import type { IsUndefined } from "viem/types/utils" +import type { EntryPoint } from "./entrypoint" export type { UserOperation } - -export type IsUndefined = [undefined] extends [T] ? true : false +export type { + EntryPointVersion, + DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_0_7, + GetEntryPointVersion, + EntryPoint +} from "./entrypoint" export type GetAccountParameterWithClient< TTransport extends Transport = Transport, @@ -14,10 +22,13 @@ export type GetAccountParameterWithClient< : { client: Client; account?: Account } export type GetAccountParameter< - TAccount extends SmartAccount | undefined = SmartAccount | undefined + entryPoint extends EntryPoint, + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined > = IsUndefined extends true - ? { account: SmartAccount } - : { account?: SmartAccount } + ? { account: SmartAccount } + : { account?: SmartAccount } export type Prettify = { [K in keyof T]: T[K] diff --git a/packages/permissionless/types/pimlico.ts b/packages/permissionless/types/pimlico.ts index 238f04fb..8d2ff971 100644 --- a/packages/permissionless/types/pimlico.ts +++ b/packages/permissionless/types/pimlico.ts @@ -1,6 +1,7 @@ import type { Address, Hash, Hex } from "viem" import type { PartialBy } from "viem/types/utils" import type { UserOperationWithBigIntAsHex } from "./userOperation" +import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" type PimlicoUserOperationGasPriceWithBigIntAsHex = { slow: { @@ -51,34 +52,59 @@ export type PimlicoBundlerRpcSchema = [ } ] -export type PimlicoPaymasterRpcSchema = [ +export type PimlicoPaymasterRpcSchema = [ { Method: "pm_sponsorUserOperation" Parameters: [ - userOperation: PartialBy< - UserOperationWithBigIntAsHex, - | "callGasLimit" - | "preVerificationGas" - | "verificationGasLimit" - | "paymasterAndData" - >, - entryPoint: Address, + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperationWithBigIntAsHex<"0.6">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + > + : PartialBy< + UserOperationWithBigIntAsHex<"0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + >, + entryPoint: entryPoint, metadata?: { sponsorshipPolicyId?: string } ] - ReturnType: { - paymasterAndData: Hex - preVerificationGas: Hex - verificationGasLimit: Hex - callGasLimit: Hex - } + ReturnType: GetEntryPointVersion extends "0.6" + ? { + paymasterAndData: Hex + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + paymaster?: never + paymasterVerificationGasLimit?: never + paymasterPostOpGasLimit?: never + paymasterData?: never + } + : { + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + paymaster: Address + paymasterVerificationGasLimit: Hex + paymasterPostOpGasLimit: Hex + paymasterData: Hex + paymasterAndData?: never + } }, { Method: "pm_validateSponsorshipPolicies" Parameters: [ - userOperation: UserOperationWithBigIntAsHex, - entryPoint: Address, + userOperation: UserOperationWithBigIntAsHex< + GetEntryPointVersion + >, + entryPoint: entryPoint, sponsorshipPolicyIds: string[] ] ReturnType: { diff --git a/packages/permissionless/types/stackup.ts b/packages/permissionless/types/stackup.ts index ca803b6b..ca37d467 100644 --- a/packages/permissionless/types/stackup.ts +++ b/packages/permissionless/types/stackup.ts @@ -1,6 +1,7 @@ import type { Address, Hex } from "viem" import type { PartialBy } from "viem/types/utils" import type { UserOperationWithBigIntAsHex } from "./userOperation" +import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" interface StackupPaymasterContextType { type: "erc20token" | "payg" @@ -10,26 +11,49 @@ export type StackupPaymasterContext = | (StackupPaymasterContextType & { type: "erc20token"; token: string }) | (StackupPaymasterContextType & { type: "payg" }) -export type StackupPaymasterRpcSchema = [ +export type StackupPaymasterRpcSchema = [ { Method: "pm_sponsorUserOperation" Parameters: [ - userOperation: PartialBy< - UserOperationWithBigIntAsHex, - | "callGasLimit" - | "preVerificationGas" - | "verificationGasLimit" - | "paymasterAndData" - >, - entryPoint: Address, + userOperation: GetEntryPointVersion extends "0.6" + ? PartialBy< + UserOperationWithBigIntAsHex<"0.6">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + > + : PartialBy< + UserOperationWithBigIntAsHex<"0.7">, + | "callGasLimit" + | "preVerificationGas" + | "verificationGasLimit" + | "paymasterVerificationGasLimit" + | "paymasterPostOpGasLimit" + >, + entryPoint: entryPoint, context: StackupPaymasterContext ] - ReturnType: { - paymasterAndData: Hex - preVerificationGas: Hex - verificationGasLimit: Hex - callGasLimit: Hex - } + ReturnType: GetEntryPointVersion extends "0.6" + ? { + paymasterAndData: Hex + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + paymaster?: never + paymasterVerificationGasLimit?: never + paymasterPostOpGasLimit?: never + paymasterData?: never + } + : { + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + paymaster: Address + paymasterVerificationGasLimit: Hex + paymasterPostOpGasLimit: Hex + paymasterData: Hex + paymasterAndData?: never + } }, { Method: "pm_accounts" diff --git a/packages/permissionless/types/userOperation.ts b/packages/permissionless/types/userOperation.ts index 0f4c80d1..21aaec07 100644 --- a/packages/permissionless/types/userOperation.ts +++ b/packages/permissionless/types/userOperation.ts @@ -1,32 +1,95 @@ import type { Address } from "viem" import type { Hex } from "viem" +import type { + DefaultEntryPoint, + EntryPointVersion, + GetEntryPointVersion +} from "./entrypoint" export type TStatus = "success" | "reverted" -export type UserOperationWithBigIntAsHex = { - sender: Address - nonce: Hex - initCode: Hex - callData: Hex - callGasLimit: Hex - verificationGasLimit: Hex - preVerificationGas: Hex - maxFeePerGas: Hex - maxPriorityFeePerGas: Hex - paymasterAndData: Hex - signature: Hex -} +export type UserOperationWithBigIntAsHex< + entryPointVersion extends + EntryPointVersion = GetEntryPointVersion +> = entryPointVersion extends "0.6" + ? { + sender: Address + nonce: Hex + initCode: Hex + callData: Hex + callGasLimit: Hex + verificationGasLimit: Hex + preVerificationGas: Hex + maxFeePerGas: Hex + maxPriorityFeePerGas: Hex + paymasterAndData: Hex + signature: Hex + factory?: never + factoryData?: never + paymaster?: never + paymasterVerificationGasLimit?: never + paymasterPostOpGasLimit?: never + paymasterData?: never + } + : { + sender: Address + nonce: Hex + factory: Address + factoryData: Hex + callData: Hex + callGasLimit: Hex + verificationGasLimit: Hex + preVerificationGas: Hex + maxFeePerGas: Hex + maxPriorityFeePerGas: Hex + paymaster: Address + paymasterVerificationGasLimit: Hex + paymasterPostOpGasLimit: Hex + paymasterData: Hex + signature: Hex + initCode?: never + paymasterAndData?: never + } -export type UserOperation = { - sender: Address - nonce: bigint - initCode: Hex - callData: Hex - callGasLimit: bigint - verificationGasLimit: bigint - preVerificationGas: bigint - maxFeePerGas: bigint - maxPriorityFeePerGas: bigint - paymasterAndData: Hex - signature: Hex -} +export type UserOperation< + entryPointVersion extends + EntryPointVersion = GetEntryPointVersion +> = entryPointVersion extends "0.6" + ? { + sender: Address + nonce: bigint + initCode: Hex + callData: Hex + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + maxFeePerGas: bigint + maxPriorityFeePerGas: bigint + paymasterAndData: Hex + signature: Hex + factory?: never + factoryData?: never + paymaster?: never + paymasterVerificationGasLimit?: never + paymasterPostOpGasLimit?: never + paymasterData?: never + } + : { + sender: Address + nonce: bigint + factory?: Address + factoryData?: Hex + callData: Hex + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + maxFeePerGas: bigint + maxPriorityFeePerGas: bigint + paymaster?: Address + paymasterVerificationGasLimit?: bigint + paymasterPostOpGasLimit?: bigint + paymasterData?: Hex + signature: Hex + initCode?: never + paymasterAndData?: never + } diff --git a/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts b/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts index 0dfaa18c..b61f6ee3 100644 --- a/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts +++ b/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts @@ -10,16 +10,19 @@ import { type GetBundlerErrorReturnType, getBundlerError } from "./getBundlerError" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" -export type GetEstimateUserOperationGasErrorReturnType = - Omit & { - cause: cause | GetBundlerErrorReturnType - } +export type GetEstimateUserOperationGasErrorReturnType< + entryPoint extends EntryPoint = DefaultEntryPoint, + cause = ErrorType +> = Omit, "cause"> & { + cause: cause | GetBundlerErrorReturnType +} -export function getEstimateUserOperationGasError>( - error: err, - args: EstimateUserOperationGasParameters -) { +export function getEstimateUserOperationGasError< + err extends ErrorType, + entryPoint extends EntryPoint = DefaultEntryPoint +>(error: err, args: EstimateUserOperationGasParameters) { const cause = (() => { const cause = getBundlerError( // biome-ignore lint/complexity/noBannedTypes: @@ -33,5 +36,5 @@ export function getEstimateUserOperationGasError>( throw new EstimateUserOperationGasError(cause, { ...args - }) as GetEstimateUserOperationGasErrorReturnType + }) as GetEstimateUserOperationGasErrorReturnType } diff --git a/packages/permissionless/utils/errors/getSendUserOperationError.ts b/packages/permissionless/utils/errors/getSendUserOperationError.ts index d475566b..970e9cb0 100644 --- a/packages/permissionless/utils/errors/getSendUserOperationError.ts +++ b/packages/permissionless/utils/errors/getSendUserOperationError.ts @@ -5,11 +5,11 @@ import { type GetBundlerErrorParameters, getBundlerError } from "./getBundlerError" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" -export function getSendUserOperationError( - err: BaseError, - args: SendUserOperationParameters -) { +export function getSendUserOperationError< + entryPoint extends EntryPoint = DefaultEntryPoint +>(err: BaseError, args: SendUserOperationParameters) { const cause = (() => { const cause = getBundlerError( err as BaseError, diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts new file mode 100644 index 00000000..342a5b35 --- /dev/null +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -0,0 +1,15 @@ +import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" +import type { + ENTRYPOINT_ADDRESS_0_6 as ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_0_7 as ENTRYPOINT_ADDRESS_0_7_TYPE +} from "../types" + +export const ENTRYPOINT_ADDRESS_0_6: ENTRYPOINT_ADDRESS_0_6_TYPE = + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" +export const ENTRYPOINT_ADDRESS_0_7: ENTRYPOINT_ADDRESS_0_7_TYPE = + "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" + +export const getEntryPointVersion = ( + entryPoint: EntryPoint +): GetEntryPointVersion => + entryPoint === ENTRYPOINT_ADDRESS_0_6 ? "0.6" : "0.7" diff --git a/packages/permissionless/utils/getUserOperationHash.ts b/packages/permissionless/utils/getUserOperationHash.ts index 71e88212..bf1b56b3 100644 --- a/packages/permissionless/utils/getUserOperationHash.ts +++ b/packages/permissionless/utils/getUserOperationHash.ts @@ -1,11 +1,97 @@ import type { Address, Hash, Hex } from "viem" -import { encodeAbiParameters, keccak256 } from "viem" +import { concat, encodeAbiParameters, keccak256, pad, toHex } from "viem" import type { UserOperation } from "../types/userOperation" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../types" +import { getEntryPointVersion } from "./getEntryPointVersion" -function packUserOp({ userOperation }: { userOperation: UserOperation }): Hex { - const hashedInitCode = keccak256(userOperation.initCode) - const hashedCallData = keccak256(userOperation.callData) - const hashedPaymasterAndData = keccak256(userOperation.paymasterAndData) +function packUserOp({ + userOperation, + entryPoint: entryPointAddress +}: { + userOperation: UserOperation> + entryPoint: entryPoint +}): Hex { + const entryPointVersion = getEntryPointVersion(entryPointAddress) + + if (entryPointVersion === "0.6") { + const userOperationVersion0_6 = userOperation as UserOperation<"0.6"> + const hashedInitCode = keccak256(userOperationVersion0_6.initCode) + const hashedCallData = keccak256(userOperationVersion0_6.callData) + const hashedPaymasterAndData = keccak256( + userOperationVersion0_6.paymasterAndData + ) + + return encodeAbiParameters( + [ + { type: "address" }, + { type: "uint256" }, + { type: "bytes32" }, + { type: "bytes32" }, + { type: "uint256" }, + { type: "uint256" }, + { type: "uint256" }, + { type: "uint256" }, + { type: "uint256" }, + { type: "bytes32" } + ], + [ + userOperationVersion0_6.sender as Address, + userOperationVersion0_6.nonce, + hashedInitCode, + hashedCallData, + userOperationVersion0_6.callGasLimit, + userOperationVersion0_6.verificationGasLimit, + userOperationVersion0_6.preVerificationGas, + userOperationVersion0_6.maxFeePerGas, + userOperationVersion0_6.maxPriorityFeePerGas, + hashedPaymasterAndData + ] + ) + } + + const userOperationVersion0_7 = userOperation as UserOperation<"0.7"> + const hashedInitCode = + userOperationVersion0_7.factory && userOperationVersion0_7.factoryData + ? keccak256( + concat([ + userOperationVersion0_7.factory, + userOperationVersion0_7.factoryData + ]) + ) + : "0x" + const hashedCallData = keccak256(userOperationVersion0_7.callData) + const hashedPaymasterAndData = + userOperationVersion0_7.paymaster && + userOperationVersion0_7.paymasterVerificationGasLimit && + userOperationVersion0_7.paymasterPostOpGasLimit && + userOperationVersion0_7.paymasterData + ? keccak256( + concat([ + userOperationVersion0_7.paymaster, + pad( + toHex( + userOperationVersion0_7.paymasterVerificationGasLimit + ), + { + size: 16 + } + ), + pad( + toHex( + userOperationVersion0_7.paymasterPostOpGasLimit + ), + { + size: 16 + } + ), + userOperationVersion0_7.paymasterData + ]) + ) + : "0x" return encodeAbiParameters( [ @@ -13,31 +99,37 @@ function packUserOp({ userOperation }: { userOperation: UserOperation }): Hex { { type: "uint256" }, { type: "bytes32" }, { type: "bytes32" }, + { type: "bytes32" }, { type: "uint256" }, - { type: "uint256" }, - { type: "uint256" }, - { type: "uint256" }, - { type: "uint256" }, + { type: "bytes32" }, { type: "bytes32" } ], [ - userOperation.sender as Address, - userOperation.nonce, + userOperationVersion0_7.sender as Address, + userOperationVersion0_7.nonce, hashedInitCode, hashedCallData, - userOperation.callGasLimit, - userOperation.verificationGasLimit, - userOperation.preVerificationGas, - userOperation.maxFeePerGas, - userOperation.maxPriorityFeePerGas, + concat([ + pad(toHex(userOperationVersion0_7.verificationGasLimit), { + size: 16 + }), + pad(toHex(userOperationVersion0_7.callGasLimit), { size: 16 }) + ]), + userOperationVersion0_7.preVerificationGas, + concat([ + pad(toHex(userOperationVersion0_7.maxPriorityFeePerGas), { + size: 16 + }), + pad(toHex(userOperationVersion0_7.maxFeePerGas), { size: 16 }) + ]), hashedPaymasterAndData ] ) } -export type GetUserOperationHashParams = { - userOperation: UserOperation - entryPoint: Address +export type GetUserOperationHashParams = { + userOperation: UserOperation> + entryPoint: entryPoint chainId: number } @@ -62,14 +154,25 @@ export type GetUserOperationHashParams = { * // Returns "0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34" * */ -export const getUserOperationHash = ({ +export const getUserOperationHash = < + entryPoint extends EntryPoint = DefaultEntryPoint +>({ userOperation, - entryPoint, + entryPoint: entryPointAddress, chainId -}: GetUserOperationHashParams): Hash => { +}: GetUserOperationHashParams): Hash => { const encoded = encodeAbiParameters( [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }], - [keccak256(packUserOp({ userOperation })), entryPoint, BigInt(chainId)] + [ + keccak256( + packUserOp({ + userOperation, + entryPoint: entryPointAddress + }) + ), + entryPointAddress, + BigInt(chainId) + ] ) as `0x${string}` return keccak256(encoded) diff --git a/packages/permissionless/utils/index.ts b/packages/permissionless/utils/index.ts index d3b15f8e..1e930d40 100644 --- a/packages/permissionless/utils/index.ts +++ b/packages/permissionless/utils/index.ts @@ -24,6 +24,11 @@ export function parseAccount(account: Address | Account): Account { return { address: account, type: "json-rpc" } return account } +import { + getEntryPointVersion, + ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_0_7 +} from "./getEntryPointVersion" export { transactionReceiptStatus, @@ -39,5 +44,8 @@ export { AccountOrClientNotFoundError, isSmartAccountDeployed, providerToSmartAccountSigner, - getAddressFromInitCodeOrPaymasterAndData + getAddressFromInitCodeOrPaymasterAndData, + getEntryPointVersion, + ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_0_7 } diff --git a/packages/permissionless/utils/signUserOperationHashWithECDSA.ts b/packages/permissionless/utils/signUserOperationHashWithECDSA.ts index 55c18f01..d2aec7d7 100644 --- a/packages/permissionless/utils/signUserOperationHashWithECDSA.ts +++ b/packages/permissionless/utils/signUserOperationHashWithECDSA.ts @@ -1,6 +1,5 @@ import { type Account, - type Address, BaseError, type Chain, type Client, @@ -8,12 +7,18 @@ import { type Hex, type Transport } from "viem" -import { type GetAccountParameterWithClient } from "../types/" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion, + GetAccountParameterWithClient +} from "../types/" import type { UserOperation } from "../types/userOperation" import { parseAccount } from "./" import { getUserOperationHash } from "./getUserOperationHash" export type SignUserOperationHashWithECDSAParams< + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined @@ -27,8 +32,8 @@ export type SignUserOperationHashWithECDSAParams< } | { hash?: undefined - userOperation: UserOperation - entryPoint: Address + userOperation: UserOperation> + entryPoint: entryPoint chainId: number } ) @@ -73,6 +78,7 @@ export class AccountOrClientNotFoundError extends BaseError { * */ export const signUserOperationHashWithECDSA = async < + entryPoint extends EntryPoint = DefaultEntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined @@ -82,8 +88,9 @@ export const signUserOperationHashWithECDSA = async < hash, userOperation, chainId, - entryPoint + entryPoint: entryPointAddress }: SignUserOperationHashWithECDSAParams< + entryPoint, TTransport, TChain, TAccount @@ -99,10 +106,10 @@ export const signUserOperationHashWithECDSA = async < if (hash) { userOperationHash = hash } else { - userOperationHash = getUserOperationHash({ + userOperationHash = getUserOperationHash({ userOperation, chainId, - entryPoint + entryPoint: entryPointAddress }) } diff --git a/packages/wagmi-demo/package.json b/packages/wagmi-demo/package.json index 7895b6b7..a5aff509 100644 --- a/packages/wagmi-demo/package.json +++ b/packages/wagmi-demo/package.json @@ -16,7 +16,7 @@ "viem": "^2.0.0", "@tanstack/react-query": "5.0.5", "react": "^18.2.0", - "permissionless": "workspace:packages/permissionless", + "permissionless": "0.0.35", "vite": "^4.4.9", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", diff --git a/packages/wagmi/package.json b/packages/wagmi/package.json index c04cda00..7e9936ea 100644 --- a/packages/wagmi/package.json +++ b/packages/wagmi/package.json @@ -11,13 +11,7 @@ "type": "module", "sideEffects": false, "description": "A utility library for working with ERC-4337", - "keywords": [ - "ethereum", - "erc-4337", - "eip-4337", - "paymaster", - "bundler" - ], + "keywords": ["ethereum", "erc-4337", "eip-4337", "paymaster", "bundler"], "license": "MIT", "exports": { ".": { @@ -26,9 +20,11 @@ "default": "./_cjs/index.js" } }, + "dependencies": { + "permissionless": "0.0.35" + }, "peerDependencies": { "wagmi": "^2.5.1", - "viem": "^2.0.0", - "permissionless": "^0.0.35" + "viem": "^2.0.0" } } From fd80183f85e86028f9f2f23fc5785d63f867b5f5 Mon Sep 17 00:00:00 2001 From: plusminushalf Date: Mon, 12 Feb 2024 12:14:43 +0000 Subject: [PATCH 02/35] chore: format --- .../accounts/biconomy/signerToBiconomySmartAccount.ts | 6 +++--- .../accounts/kernel/signerToEcdsaKernelSmartAccount.ts | 8 ++++---- .../accounts/safe/signerToSafeSmartAccount.ts | 4 ++-- .../accounts/simple/signerToSimpleSmartAccount.ts | 4 ++-- packages/permissionless/actions/bundler/chainId.ts | 2 +- .../actions/bundler/estimateUserOperationGas.ts | 10 +++++----- .../actions/bundler/getUserOperationByHash.ts | 2 +- .../actions/bundler/getUserOperationReceipt.ts | 2 +- .../actions/bundler/sendUserOperation.ts | 10 +++++----- .../actions/pimlico/sponsorUserOperation.ts | 10 +++++----- .../actions/pimlico/validateSponsorshipPolicies.ts | 10 +++++----- .../permissionless/actions/public/getAccountNonce.ts | 2 +- .../permissionless/actions/public/getSenderAddress.ts | 2 +- .../actions/smartAccount/deployContract.ts | 2 +- .../smartAccount/prepareUserOperationRequest.ts | 6 +++--- .../actions/smartAccount/sendTransaction.ts | 2 +- .../actions/smartAccount/sendTransactions.ts | 2 +- .../actions/smartAccount/sendUserOperation.ts | 10 +++++----- .../permissionless/actions/smartAccount/signMessage.ts | 2 +- .../actions/smartAccount/signTypedData.ts | 2 +- .../actions/smartAccount/writeContract.ts | 2 +- .../actions/stackup/sponsorUserOperation.ts | 10 +++++----- packages/permissionless/clients/createBundlerClient.ts | 2 +- .../permissionless/clients/createSmartAccountClient.ts | 2 +- packages/permissionless/clients/decorators/bundler.ts | 2 +- packages/permissionless/clients/decorators/pimlico.ts | 2 +- packages/permissionless/clients/decorators/stackup.ts | 2 +- packages/permissionless/clients/pimlico.ts | 2 +- packages/permissionless/clients/stackup.ts | 2 +- .../permissionless/errors/estimateUserOperationGas.ts | 2 +- packages/permissionless/errors/sendUserOperation.ts | 2 +- packages/permissionless/types/bundler.ts | 2 +- packages/permissionless/types/index.ts | 4 ++-- packages/permissionless/types/pimlico.ts | 2 +- packages/permissionless/types/stackup.ts | 2 +- .../utils/errors/getEstimateUserOperationGasError.ts | 2 +- .../utils/errors/getSendUserOperationError.ts | 2 +- packages/permissionless/utils/getEntryPointVersion.ts | 2 +- packages/permissionless/utils/getUserOperationHash.ts | 2 +- packages/permissionless/utils/index.ts | 4 ++-- .../utils/signUserOperationHashWithECDSA.ts | 4 ++-- 41 files changed, 77 insertions(+), 77 deletions(-) diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 509bb67a..9b9bf5c4 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -7,19 +7,20 @@ import { type LocalAccount, type Transport, type TypedDataDefinition, + concatHex, encodeAbiParameters, encodeFunctionData, encodePacked, getContractAddress, hexToBigInt, keccak256, - parseAbiParameters, - concatHex + parseAbiParameters } from "viem" import { toAccount } from "viem/accounts" import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import type { DefaultEntryPoint, Prettify } from "../../types" +import type { EntryPoint } from "../../types/entrypoint" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { @@ -31,7 +32,6 @@ import { BiconomyExecuteAbi, BiconomyInitAbi } from "./abi/BiconomySmartAccountAbi" -import type { EntryPoint } from "../../types/entrypoint" export type BiconomySmartAccount< entryPoint extends EntryPoint = DefaultEntryPoint, diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 5bbc3077..3f3499ea 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -7,9 +7,9 @@ import { type LocalAccount, type Transport, type TypedDataDefinition, + concatHex, encodeFunctionData, - isAddressEqual, - concatHex + isAddressEqual } from "viem" import { toAccount } from "viem/accounts" import { @@ -26,6 +26,8 @@ import type { ENTRYPOINT_ADDRESS_0_7, Prettify } from "../../types" +import type { EntryPoint } from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import type { SmartAccount } from "../types" @@ -34,8 +36,6 @@ import { type SmartAccountSigner } from "../types" import { KernelExecuteAbi, KernelInitAbi } from "./abi/KernelAccountAbi" -import type { EntryPoint } from "../../types/entrypoint" -import { getEntryPointVersion } from "../../utils" export type KernelEcdsaSmartAccount< entryPoint extends EntryPoint = DefaultEntryPoint, diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 245bcc58..6f565145 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -29,14 +29,14 @@ import { } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import type { ENTRYPOINT_ADDRESS_0_6, Prettify } from "../../types" +import type { EntryPoint } from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { SignTransactionNotSupportedBySmartAccount, type SmartAccount, type SmartAccountSigner } from "../types" -import type { EntryPoint } from "../../types/entrypoint" -import { getEntryPointVersion } from "../../utils" export type SafeVersion = "1.4.1" diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 2d585f23..61532c27 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -20,6 +20,8 @@ import type { ENTRYPOINT_ADDRESS_0_7, Prettify } from "../../types" +import type { EntryPoint } from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { @@ -27,8 +29,6 @@ import { type SmartAccount, type SmartAccountSigner } from "../types" -import type { EntryPoint } from "../../types/entrypoint" -import { getEntryPointVersion } from "../../utils" export type SimpleSmartAccount< entryPoint extends EntryPoint = DefaultEntryPoint, diff --git a/packages/permissionless/actions/bundler/chainId.ts b/packages/permissionless/actions/bundler/chainId.ts index bc23607f..607e79a5 100644 --- a/packages/permissionless/actions/bundler/chainId.ts +++ b/packages/permissionless/actions/bundler/chainId.ts @@ -1,7 +1,7 @@ import type { Account, Chain, Client, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" -import type { BundlerRpcSchema } from "../../types/bundler" import type { DefaultEntryPoint, EntryPoint } from "../../types" +import type { BundlerRpcSchema } from "../../types/bundler" /** * Returns the supported chain id by the bundler service diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index 5b1043d6..97568be1 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -9,17 +9,17 @@ import type { PartialBy } from "viem/types/utils" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema, StateOverrides } from "../../types/bundler" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" import type { UserOperation } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" import { type GetEstimateUserOperationGasErrorReturnType, getEstimateUserOperationGasError } from "../../utils/errors/getEstimateUserOperationGasError" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" export type EstimateUserOperationGasParameters = { diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.ts index 7c7bbcf1..5ff314a8 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.ts @@ -2,12 +2,12 @@ import type { Account, Address, Chain, Client, Hash, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" -import type { UserOperation } from "../../types/userOperation" import type { DefaultEntryPoint, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" +import type { UserOperation } from "../../types/userOperation" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type GetUserOperationByHashParameters = { diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.ts index 51f24147..e78c3172 100644 --- a/packages/permissionless/actions/bundler/getUserOperationReceipt.ts +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.ts @@ -10,9 +10,9 @@ import type { import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types" import type { BundlerRpcSchema } from "../../types/bundler" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import type { TStatus } from "../../types/userOperation" import { transactionReceiptStatus } from "../../utils/deepHexlify" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type GetUserOperationReceiptParameters = { hash: Hash diff --git a/packages/permissionless/actions/bundler/sendUserOperation.ts b/packages/permissionless/actions/bundler/sendUserOperation.ts index b893a5bf..859ae118 100644 --- a/packages/permissionless/actions/bundler/sendUserOperation.ts +++ b/packages/permissionless/actions/bundler/sendUserOperation.ts @@ -2,17 +2,17 @@ import type { Account, BaseError, Chain, Client, Hash, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" import type { UserOperation, UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" import { getSendUserOperationError } from "../../utils/errors/getSendUserOperationError" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" export type SendUserOperationParameters = { userOperation: UserOperation> diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts index 66c093c9..00897b36 100644 --- a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts @@ -1,17 +1,17 @@ import type { Account, Chain, Client, Transport } from "viem" import type { PartialBy } from "viem/types/utils" import type { Prettify } from "../../types/" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" import type { PimlicoPaymasterRpcSchema } from "../../types/pimlico" import type { UserOperation, UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type PimlicoSponsorUserOperationParameters< diff --git a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts index 2f0d97af..31fcc60a 100644 --- a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts +++ b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts @@ -1,16 +1,16 @@ import type { Account, Chain, Client, Transport } from "viem" import type { Prettify } from "../../types/" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" import type { PimlicoPaymasterRpcSchema } from "../../types/pimlico" import type { UserOperation, UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" export type ValidateSponsorshipPoliciesParameters< entryPoint extends EntryPoint diff --git a/packages/permissionless/actions/public/getAccountNonce.ts b/packages/permissionless/actions/public/getAccountNonce.ts index 1018ea0d..5b0ecd8d 100644 --- a/packages/permissionless/actions/public/getAccountNonce.ts +++ b/packages/permissionless/actions/public/getAccountNonce.ts @@ -1,8 +1,8 @@ import type { Address, Chain, Client, Transport } from "viem" import { readContract } from "viem/actions" import type { Prettify } from "../../types/" -import { getAction } from "../../utils/getAction" import type { EntryPoint } from "../../types/entrypoint" +import { getAction } from "../../utils/getAction" export type GetAccountNonceParams = { sender: Address diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 37ae05b9..66d91488 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -12,12 +12,12 @@ import { import { simulateContract } from "viem/actions" import type { Prettify } from "../../types/" -import { getAction } from "../../utils/getAction" import type { DefaultEntryPoint, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" +import { getAction } from "../../utils/getAction" export type GetSenderAddressParams = GetEntryPointVersion extends "0.6" diff --git a/packages/permissionless/actions/smartAccount/deployContract.ts b/packages/permissionless/actions/smartAccount/deployContract.ts index e29e97f5..4ce408a5 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.ts @@ -9,13 +9,13 @@ import type { } from "viem" import type { SmartAccount } from "../../accounts/types" import type { Prettify } from "../../types/" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { sendUserOperation } from "./sendUserOperation" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type DeployContractParametersWithPaymaster< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index 2087f7bb..50de3024 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -8,9 +8,6 @@ import type { UserOperation } from "../../types/" import type { StateOverrides } from "../../types/bundler" -import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" -import { getAction } from "../../utils/getAction" -import { estimateUserOperationGas } from "../bundler/estimateUserOperationGas" import type { DefaultEntryPoint, ENTRYPOINT_ADDRESS_0_6, @@ -18,7 +15,10 @@ import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" +import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" +import { getAction } from "../../utils/getAction" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" +import { estimateUserOperationGas } from "../bundler/estimateUserOperationGas" export type SponsorUserOperationMiddleware< entryPoint extends EntryPoint = DefaultEntryPoint diff --git a/packages/permissionless/actions/smartAccount/sendTransaction.ts b/packages/permissionless/actions/smartAccount/sendTransaction.ts index 53999169..998a2b48 100644 --- a/packages/permissionless/actions/smartAccount/sendTransaction.ts +++ b/packages/permissionless/actions/smartAccount/sendTransaction.ts @@ -7,12 +7,12 @@ import type { } from "viem" import { type SmartAccount } from "../../accounts/types" import type { Prettify } from "../../types/" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { sendUserOperation } from "./sendUserOperation" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type SendTransactionWithPaymasterParameters< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/smartAccount/sendTransactions.ts b/packages/permissionless/actions/smartAccount/sendTransactions.ts index 2b81d684..3be584cf 100644 --- a/packages/permissionless/actions/smartAccount/sendTransactions.ts +++ b/packages/permissionless/actions/smartAccount/sendTransactions.ts @@ -9,12 +9,12 @@ import type { } from "viem" import { type SmartAccount } from "../../accounts/types" import type { GetAccountParameter, Prettify } from "../../types/" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { sendUserOperation } from "./sendUserOperation" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type SendTransactionsWithPaymasterParameters< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.ts index ac1a7240..58a5918a 100644 --- a/packages/permissionless/actions/smartAccount/sendUserOperation.ts +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.ts @@ -6,6 +6,11 @@ import type { Prettify, UserOperation } from "../../types/" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { sendUserOperation as sendUserOperationBundler } from "../bundler/sendUserOperation" @@ -13,11 +18,6 @@ import { type SponsorUserOperationMiddleware, prepareUserOperationRequest } from "./prepareUserOperationRequest" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" export type SendUserOperationParameters< entryPoint extends EntryPoint, diff --git a/packages/permissionless/actions/smartAccount/signMessage.ts b/packages/permissionless/actions/smartAccount/signMessage.ts index fcb9c7a6..01c22ade 100644 --- a/packages/permissionless/actions/smartAccount/signMessage.ts +++ b/packages/permissionless/actions/smartAccount/signMessage.ts @@ -6,8 +6,8 @@ import type { Transport } from "viem" import { type SmartAccount } from "../../accounts/types" -import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" /** * Calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`. diff --git a/packages/permissionless/actions/smartAccount/signTypedData.ts b/packages/permissionless/actions/smartAccount/signTypedData.ts index ac9fac8d..1c83a98b 100644 --- a/packages/permissionless/actions/smartAccount/signTypedData.ts +++ b/packages/permissionless/actions/smartAccount/signTypedData.ts @@ -10,8 +10,8 @@ import { validateTypedData } from "viem" import { type SmartAccount } from "../../accounts/types" -import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" /** * Signs typed data and calculates an Ethereum-specific signature in [https://eips.ethereum.org/EIPS/eip-712](https://eips.ethereum.org/EIPS/eip-712): `sign(keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message)))` diff --git a/packages/permissionless/actions/smartAccount/writeContract.ts b/packages/permissionless/actions/smartAccount/writeContract.ts index 7f2adaca..08260dd2 100644 --- a/packages/permissionless/actions/smartAccount/writeContract.ts +++ b/packages/permissionless/actions/smartAccount/writeContract.ts @@ -11,13 +11,13 @@ import { encodeFunctionData } from "viem" import { type SmartAccount } from "../../accounts/types" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import { getAction } from "../../utils/getAction" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { type SendTransactionWithPaymasterParameters, sendTransaction } from "./sendTransaction" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" /** * Executes a write function on a contract. diff --git a/packages/permissionless/actions/stackup/sponsorUserOperation.ts b/packages/permissionless/actions/stackup/sponsorUserOperation.ts index 1d8bd46a..38704152 100644 --- a/packages/permissionless/actions/stackup/sponsorUserOperation.ts +++ b/packages/permissionless/actions/stackup/sponsorUserOperation.ts @@ -1,16 +1,16 @@ import type { PartialBy } from "viem/types/utils" import { type StackupPaymasterClient } from "../../clients/stackup" +import type { + DefaultEntryPoint, + EntryPoint, + GetEntryPointVersion +} from "../../types/entrypoint" import type { StackupPaymasterContext } from "../../types/stackup" import type { UserOperation, UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type SponsorUserOperationParameters = { diff --git a/packages/permissionless/clients/createBundlerClient.ts b/packages/permissionless/clients/createBundlerClient.ts index ede22458..06b457fb 100644 --- a/packages/permissionless/clients/createBundlerClient.ts +++ b/packages/permissionless/clients/createBundlerClient.ts @@ -7,8 +7,8 @@ import type { } from "viem" import { createClient } from "viem" import type { BundlerRpcSchema } from "../types/bundler" -import { type BundlerActions, bundlerActions } from "./decorators/bundler" import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import { type BundlerActions, bundlerActions } from "./decorators/bundler" export type BundlerClient< entryPoint extends EntryPoint = DefaultEntryPoint, diff --git a/packages/permissionless/clients/createSmartAccountClient.ts b/packages/permissionless/clients/createSmartAccountClient.ts index 6463ae82..df7ae708 100644 --- a/packages/permissionless/clients/createSmartAccountClient.ts +++ b/packages/permissionless/clients/createSmartAccountClient.ts @@ -10,11 +10,11 @@ import { type SmartAccount } from "../accounts/types" import { type SponsorUserOperationMiddleware } from "../actions/smartAccount/prepareUserOperationRequest" import type { Prettify } from "../types/" import { type BundlerRpcSchema } from "../types/bundler" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" import { type SmartAccountActions, smartAccountActions } from "./decorators/smartAccount" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" /** * TODO: diff --git a/packages/permissionless/clients/decorators/bundler.ts b/packages/permissionless/clients/decorators/bundler.ts index 515c36e0..87e0b2a7 100644 --- a/packages/permissionless/clients/decorators/bundler.ts +++ b/packages/permissionless/clients/decorators/bundler.ts @@ -27,8 +27,8 @@ import { } from "../../actions/bundler/waitForUserOperationReceipt" import type { Prettify } from "../../types/" import type { StateOverrides } from "../../types/bundler" -import type { BundlerClient } from "../createBundlerClient" import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { BundlerClient } from "../createBundlerClient" export type BundlerActions = { diff --git a/packages/permissionless/clients/decorators/pimlico.ts b/packages/permissionless/clients/decorators/pimlico.ts index 64261d8b..ecde5fa6 100644 --- a/packages/permissionless/clients/decorators/pimlico.ts +++ b/packages/permissionless/clients/decorators/pimlico.ts @@ -21,8 +21,8 @@ import { sponsorUserOperation } from "../../actions/pimlico/sponsorUserOperation" import type { Prettify } from "../../types/" -import type { PimlicoBundlerClient, PimlicoPaymasterClient } from "../pimlico" import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { PimlicoBundlerClient, PimlicoPaymasterClient } from "../pimlico" export type PimlicoBundlerActions = { /** diff --git a/packages/permissionless/clients/decorators/stackup.ts b/packages/permissionless/clients/decorators/stackup.ts index 39aaa766..641d8a26 100644 --- a/packages/permissionless/clients/decorators/stackup.ts +++ b/packages/permissionless/clients/decorators/stackup.ts @@ -8,8 +8,8 @@ import { type SponsorUserOperationReturnType, sponsorUserOperation } from "../../actions/stackup/sponsorUserOperation" -import { type StackupPaymasterClient } from "../stackup" import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import { type StackupPaymasterClient } from "../stackup" export type StackupPaymasterClientActions< entryPoint extends EntryPoint = DefaultEntryPoint diff --git a/packages/permissionless/clients/pimlico.ts b/packages/permissionless/clients/pimlico.ts index cf61730e..be7fde64 100644 --- a/packages/permissionless/clients/pimlico.ts +++ b/packages/permissionless/clients/pimlico.ts @@ -6,6 +6,7 @@ import type { Transport } from "viem" import { createClient } from "viem" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" import type { PimlicoBundlerRpcSchema, PimlicoPaymasterRpcSchema @@ -17,7 +18,6 @@ import { pimlicoBundlerActions, pimlicoPaymasterActions } from "./decorators/pimlico" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" export type PimlicoBundlerClient = Client< Transport, diff --git a/packages/permissionless/clients/stackup.ts b/packages/permissionless/clients/stackup.ts index c080fc2f..32aef7bc 100644 --- a/packages/permissionless/clients/stackup.ts +++ b/packages/permissionless/clients/stackup.ts @@ -6,13 +6,13 @@ import { type Transport, createClient } from "viem" +import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" import type { StackupPaymasterRpcSchema } from "../types/stackup" import { type BundlerActions, bundlerActions } from "./decorators/bundler" import { type StackupPaymasterClientActions, stackupPaymasterActions } from "./decorators/stackup" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" export type StackupPaymasterClient< entryPoint extends EntryPoint = DefaultEntryPoint diff --git a/packages/permissionless/errors/estimateUserOperationGas.ts b/packages/permissionless/errors/estimateUserOperationGas.ts index 3599714a..39c3258e 100644 --- a/packages/permissionless/errors/estimateUserOperationGas.ts +++ b/packages/permissionless/errors/estimateUserOperationGas.ts @@ -1,7 +1,7 @@ import { BaseError } from "viem" import type { EstimateUserOperationGasParameters } from "../actions/bundler/estimateUserOperationGas" -import { prettyPrint } from "./utils" import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import { prettyPrint } from "./utils" export type EstimateUserOperationGasErrorType< entryPoint extends EntryPoint = DefaultEntryPoint diff --git a/packages/permissionless/errors/sendUserOperation.ts b/packages/permissionless/errors/sendUserOperation.ts index 930af741..f539cf84 100644 --- a/packages/permissionless/errors/sendUserOperation.ts +++ b/packages/permissionless/errors/sendUserOperation.ts @@ -1,7 +1,7 @@ import { BaseError } from "viem" import { type SendUserOperationParameters } from "../actions/bundler/sendUserOperation" -import { prettyPrint } from "./utils" import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import { prettyPrint } from "./utils" export type SendUserOperationErrorType = SendUserOperationError & { name: "SendUserOperationError" diff --git a/packages/permissionless/types/bundler.ts b/packages/permissionless/types/bundler.ts index 7ff61ca2..fce3be8d 100644 --- a/packages/permissionless/types/bundler.ts +++ b/packages/permissionless/types/bundler.ts @@ -1,7 +1,7 @@ import type { Address, Hash, Hex } from "viem" import type { PartialBy } from "viem/types/utils" -import type { UserOperationWithBigIntAsHex } from "./userOperation" import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" +import type { UserOperationWithBigIntAsHex } from "./userOperation" export type BundlerRpcSchema = [ { diff --git a/packages/permissionless/types/index.ts b/packages/permissionless/types/index.ts index 43ebed35..d03f06cf 100644 --- a/packages/permissionless/types/index.ts +++ b/packages/permissionless/types/index.ts @@ -1,8 +1,8 @@ import type { Account, Chain, Client, Transport } from "viem" -import type { SmartAccount } from "../accounts/types" -import type { UserOperation } from "./userOperation" import type { IsUndefined } from "viem/types/utils" +import type { SmartAccount } from "../accounts/types" import type { EntryPoint } from "./entrypoint" +import type { UserOperation } from "./userOperation" export type { UserOperation } export type { EntryPointVersion, diff --git a/packages/permissionless/types/pimlico.ts b/packages/permissionless/types/pimlico.ts index 8d2ff971..341b05d6 100644 --- a/packages/permissionless/types/pimlico.ts +++ b/packages/permissionless/types/pimlico.ts @@ -1,7 +1,7 @@ import type { Address, Hash, Hex } from "viem" import type { PartialBy } from "viem/types/utils" -import type { UserOperationWithBigIntAsHex } from "./userOperation" import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" +import type { UserOperationWithBigIntAsHex } from "./userOperation" type PimlicoUserOperationGasPriceWithBigIntAsHex = { slow: { diff --git a/packages/permissionless/types/stackup.ts b/packages/permissionless/types/stackup.ts index ca37d467..0a779612 100644 --- a/packages/permissionless/types/stackup.ts +++ b/packages/permissionless/types/stackup.ts @@ -1,7 +1,7 @@ import type { Address, Hex } from "viem" import type { PartialBy } from "viem/types/utils" -import type { UserOperationWithBigIntAsHex } from "./userOperation" import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" +import type { UserOperationWithBigIntAsHex } from "./userOperation" interface StackupPaymasterContextType { type: "erc20token" | "payg" diff --git a/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts b/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts index b61f6ee3..0f54ed34 100644 --- a/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts +++ b/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts @@ -5,12 +5,12 @@ import { type EstimateUserOperationGasErrorType } from "../../errors/estimateUserOperationGas" import { type ErrorType } from "../../errors/utils" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import { type GetBundlerErrorParameters, type GetBundlerErrorReturnType, getBundlerError } from "./getBundlerError" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export type GetEstimateUserOperationGasErrorReturnType< entryPoint extends EntryPoint = DefaultEntryPoint, diff --git a/packages/permissionless/utils/errors/getSendUserOperationError.ts b/packages/permissionless/utils/errors/getSendUserOperationError.ts index 970e9cb0..93bc4c3f 100644 --- a/packages/permissionless/utils/errors/getSendUserOperationError.ts +++ b/packages/permissionless/utils/errors/getSendUserOperationError.ts @@ -1,11 +1,11 @@ import { BaseError, UnknownNodeError } from "viem" import type { SendUserOperationParameters } from "../../actions/bundler/sendUserOperation" import { SendUserOperationError } from "../../errors" +import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" import { type GetBundlerErrorParameters, getBundlerError } from "./getBundlerError" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" export function getSendUserOperationError< entryPoint extends EntryPoint = DefaultEntryPoint diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts index 342a5b35..070a09af 100644 --- a/packages/permissionless/utils/getEntryPointVersion.ts +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -1,8 +1,8 @@ -import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" import type { ENTRYPOINT_ADDRESS_0_6 as ENTRYPOINT_ADDRESS_0_6_TYPE, ENTRYPOINT_ADDRESS_0_7 as ENTRYPOINT_ADDRESS_0_7_TYPE } from "../types" +import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" export const ENTRYPOINT_ADDRESS_0_6: ENTRYPOINT_ADDRESS_0_6_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" diff --git a/packages/permissionless/utils/getUserOperationHash.ts b/packages/permissionless/utils/getUserOperationHash.ts index bf1b56b3..106bc90d 100644 --- a/packages/permissionless/utils/getUserOperationHash.ts +++ b/packages/permissionless/utils/getUserOperationHash.ts @@ -1,11 +1,11 @@ import type { Address, Hash, Hex } from "viem" import { concat, encodeAbiParameters, keccak256, pad, toHex } from "viem" -import type { UserOperation } from "../types/userOperation" import type { DefaultEntryPoint, EntryPoint, GetEntryPointVersion } from "../types" +import type { UserOperation } from "../types/userOperation" import { getEntryPointVersion } from "./getEntryPointVersion" function packUserOp({ diff --git a/packages/permissionless/utils/index.ts b/packages/permissionless/utils/index.ts index 1e930d40..2fd84e49 100644 --- a/packages/permissionless/utils/index.ts +++ b/packages/permissionless/utils/index.ts @@ -25,9 +25,9 @@ export function parseAccount(account: Address | Account): Account { return account } import { - getEntryPointVersion, ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7 + ENTRYPOINT_ADDRESS_0_7, + getEntryPointVersion } from "./getEntryPointVersion" export { diff --git a/packages/permissionless/utils/signUserOperationHashWithECDSA.ts b/packages/permissionless/utils/signUserOperationHashWithECDSA.ts index d2aec7d7..dfccde5c 100644 --- a/packages/permissionless/utils/signUserOperationHashWithECDSA.ts +++ b/packages/permissionless/utils/signUserOperationHashWithECDSA.ts @@ -10,8 +10,8 @@ import { import type { DefaultEntryPoint, EntryPoint, - GetEntryPointVersion, - GetAccountParameterWithClient + GetAccountParameterWithClient, + GetEntryPointVersion } from "../types/" import type { UserOperation } from "../types/userOperation" import { parseAccount } from "./" From f6539021e109c3b1a11313d50b0b661f34b2f8b2 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 13 Feb 2024 12:40:14 +0530 Subject: [PATCH 03/35] Infer types from entryPoint --- .../bundlerActions.test.ts | 81 ++-- .../privateKeyToBiconomySmartAccount.ts | 6 +- .../biconomy/signerToBiconomySmartAccount.ts | 8 +- .../kernel/signerToEcdsaKernelSmartAccount.ts | 25 +- .../safe/privateKeyToSafeSmartAccount.ts | 12 +- .../accounts/safe/signerToSafeSmartAccount.ts | 15 +- .../simple/privateKeyToSimpleSmartAccount.ts | 6 +- .../simple/signerToSimpleSmartAccount.ts | 19 +- packages/permissionless/accounts/types.ts | 6 +- .../permissionless/actions/bundler/chainId.ts | 4 +- .../bundler/estimateUserOperationGas.ts | 13 +- .../actions/bundler/getUserOperationByHash.ts | 18 +- .../bundler/getUserOperationReceipt.ts | 4 +- .../actions/bundler/sendUserOperation.ts | 8 +- .../actions/bundler/supportedEntryPoints.ts | 4 +- .../actions/pimlico/sponsorUserOperation.ts | 12 +- .../pimlico/validateSponsorshipPolicies.ts | 8 +- .../actions/public/getSenderAddress.ts | 9 +- .../actions/smartAccount/deployContract.ts | 6 +- .../prepareUserOperationRequest.ts | 43 +- .../actions/smartAccount/sendTransaction.ts | 4 +- .../actions/smartAccount/sendTransactions.ts | 4 +- .../actions/smartAccount/sendUserOperation.ts | 6 +- .../actions/smartAccount/signMessage.ts | 6 +- .../actions/smartAccount/signTypedData.ts | 6 +- .../actions/smartAccount/writeContract.ts | 6 +- .../actions/stackup/accounts.ts | 13 +- .../actions/stackup/sponsorUserOperation.ts | 21 +- .../clients/createBundlerClient.ts | 16 +- .../clients/createSmartAccountClient.ts | 22 +- .../clients/decorators/bundler.ts | 429 +++++++++--------- .../clients/decorators/pimlico.ts | 68 +-- .../clients/decorators/smartAccount.ts | 45 +- .../clients/decorators/stackup.ts | 20 +- packages/permissionless/clients/pimlico.ts | 33 +- packages/permissionless/clients/stackup.ts | 16 +- .../errors/estimateUserOperationGas.ts | 13 +- .../errors/sendUserOperation.ts | 11 +- packages/permissionless/types/entrypoint.ts | 12 +- packages/permissionless/types/index.ts | 5 +- packages/permissionless/types/stackup.ts | 6 +- .../permissionless/types/userOperation.ts | 91 ++-- .../utils/errors/getBundlerError.ts | 16 +- .../getEstimateUserOperationGasError.ts | 8 +- .../utils/errors/getSendUserOperationError.ts | 11 +- .../utils/getEntryPointVersion.ts | 4 +- .../utils/getRequiredPrefund.ts | 46 +- .../utils/getUserOperationHash.ts | 10 +- .../utils/signUserOperationHashWithECDSA.ts | 5 +- 49 files changed, 629 insertions(+), 631 deletions(-) diff --git a/packages/permissionless-test/bundlerActions.test.ts b/packages/permissionless-test/bundlerActions.test.ts index 2b7e865f..b7db166c 100644 --- a/packages/permissionless-test/bundlerActions.test.ts +++ b/packages/permissionless-test/bundlerActions.test.ts @@ -1,12 +1,19 @@ import dotenv from "dotenv" import { BundlerClient, + ENTRYPOINT_ADDRESS_0_7, UserOperation, WaitForUserOperationReceiptTimeoutError, - getAccountNonce + createBundlerClient, + createSmartAccountClient, + getAccountNonce, + walletClientToSmartAccountSigner } from "permissionless" +import { signerToSimpleSmartAccount } from "permissionless/accounts" +import { ENTRYPOINT_ADDRESS_0_7_TYPE } from "permissionless/types" import { getUserOperationHash } from "permissionless/utils" -import { Address, type Hash, parseEther } from "viem" +import { http, Address, type Hash, parseEther } from "viem" +import { privateKeyToAccount } from "viem/accounts" import { beforeAll, beforeEach, @@ -21,6 +28,7 @@ import { getEntryPoint, getEoaWalletClient, getPublicClient, + getSignerToSimpleSmartAccount, getTestingChain, waitForNonceUpdate } from "./utils" @@ -45,7 +53,7 @@ describe("BUNDLER ACTIONS", () => { bundlerClient = getBundlerClient() }) - test("Supported entry points request", async () => { + test.skip("Supported entry points request", async () => { const supportedEntryPoints = await bundlerClient.supportedEntryPoints() expectTypeOf(supportedEntryPoints).toBeArray() @@ -53,7 +61,7 @@ describe("BUNDLER ACTIONS", () => { expect(supportedEntryPoints.includes(getEntryPoint())).toBe(true) }) - test("Chain id call", async () => { + test.skip("Chain id call", async () => { const chainId = await bundlerClient.chainId() const chain = getTestingChain() @@ -62,7 +70,7 @@ describe("BUNDLER ACTIONS", () => { expect(chainId === chain.id).toBe(true) }) - test("Estimate user operation gas", async () => { + test.skip("Estimate user operation gas", async () => { const eoaWalletClient = getEoaWalletClient() const userOperation = await buildUserOp(eoaWalletClient) @@ -78,43 +86,40 @@ describe("BUNDLER ACTIONS", () => { }) test("Sending user operation", async () => { - const eoaWalletClient = getEoaWalletClient() const publicClient = await getPublicClient() - const userOperation = await buildUserOp(eoaWalletClient) - - const entryPoint = getEntryPoint() - const chain = getTestingChain() + const eoaWalletClient = getEoaWalletClient() - const gasParameters = await bundlerClient.estimateUserOperationGas( - { - userOperation, - entryPoint: getEntryPoint() - }, - { - [userOperation.sender]: { - balance: 1000n - } - } - ) + const bundlerClient = createBundlerClient({ + chain: getTestingChain(), + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + entryPoint: ENTRYPOINT_ADDRESS_0_7 + }) - userOperation.callGasLimit = gasParameters.callGasLimit - userOperation.verificationGasLimit = gasParameters.verificationGasLimit - userOperation.preVerificationGas = gasParameters.preVerificationGas + const simpleAccount = await signerToSimpleSmartAccount(publicClient, { + signer: walletClientToSmartAccountSigner(eoaWalletClient), + entryPoint: ENTRYPOINT_ADDRESS_0_7, + factoryAddress: process.env.FACTORY_ADDRESS as Address + }) - userOperation.signature = await eoaWalletClient.signMessage({ - account: eoaWalletClient.account, - message: { - raw: getUserOperationHash({ - userOperation, - entryPoint, - chainId: chain.id - }) - } + const smartAccountClient = createSmartAccountClient({ + account: simpleAccount, + chain: getTestingChain(), + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + sponsorUserOperation: async (args) => { + return args.userOperation + }, + entryPoint: ENTRYPOINT_ADDRESS_0_7 }) + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: "0x" + } + }) + const userOpHash = await bundlerClient.sendUserOperation({ - userOperation: userOperation, - entryPoint: entryPoint as Address + userOperation: userOperation }) expectTypeOf(userOpHash).toBeString() @@ -143,7 +148,9 @@ describe("BUNDLER ACTIONS", () => { await bundlerClient.getUserOperationByHash({ hash: userOpHash }) expect(userOperationFromUserOpHash).not.toBeNull() - expect(userOperationFromUserOpHash?.entryPoint).toBe(entryPoint) + expect(userOperationFromUserOpHash?.entryPoint).toBe( + ENTRYPOINT_ADDRESS_0_7 + ) expect(userOperationFromUserOpHash?.transactionHash).toBe( userOperationReceipt?.receipt.transactionHash ) @@ -163,7 +170,7 @@ describe("BUNDLER ACTIONS", () => { // expect(newNonce).toBe(userOperation.nonce + BigInt(1)) }, 100000) - test("wait for user operation receipt fail", async () => { + test.skip("wait for user operation receipt fail", async () => { const eoaWalletClient = getEoaWalletClient() const userOperation = await buildUserOp(eoaWalletClient) diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts index 6d766f1c..802116c4 100644 --- a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts @@ -1,6 +1,6 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { DefaultEntryPoint, EntryPoint, Prettify } from "../../types" +import type { EntryPoint, Prettify } from "../../types" import { type BiconomySmartAccount, type SignerToBiconomySmartAccountParameters, @@ -8,7 +8,7 @@ import { } from "./signerToBiconomySmartAccount" export type PrivateKeyToBiconomySmartAccountParameters< - entryPoint extends EntryPoint = DefaultEntryPoint + entryPoint extends EntryPoint > = Prettify< { privateKey: Hex @@ -21,7 +21,7 @@ export type PrivateKeyToBiconomySmartAccountParameters< * @returns A Private Key Biconomy Smart Account using ECDSA as default validation module. */ export async function privateKeyToBiconomySmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 9b9bf5c4..33df0a1a 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -19,7 +19,7 @@ import { import { toAccount } from "viem/accounts" import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { DefaultEntryPoint, Prettify } from "../../types" +import type { Prettify } from "../../types" import type { EntryPoint } from "../../types/entrypoint" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" @@ -34,7 +34,7 @@ import { } from "./abi/BiconomySmartAccountAbi" export type BiconomySmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -182,7 +182,7 @@ const getAccountAddress = async ({ } export type SignerToBiconomySmartAccountParameters< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ @@ -207,7 +207,7 @@ export type SignerToBiconomySmartAccountParameters< * @param ecdsaModuleAddress */ export async function signerToBiconomySmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 3f3499ea..bbdd9a7d 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -20,13 +20,12 @@ import { } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" +import type { Prettify } from "../../types" import type { - DefaultEntryPoint, - ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7, - Prettify -} from "../../types" -import type { EntryPoint } from "../../types/entrypoint" + ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_0_7_TYPE, + EntryPoint +} from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" @@ -38,7 +37,7 @@ import { import { KernelExecuteAbi, KernelInitAbi } from "./abi/KernelAccountAbi" export type KernelEcdsaSmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -202,22 +201,22 @@ const getAccountAddress = async < const entryPointVersion = getEntryPointVersion(entryPointAddress) if (entryPointVersion === "0.6") { - return getSenderAddress(client, { + return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6 + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6_TYPE }) } // Get the sender address based on the init code - return getSenderAddress(client, { + return getSenderAddress(client, { factory: factoryAddress, factoryData, - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7 + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7_TYPE }) } export type SignerToEcdsaKernelSmartAccountParameters< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ @@ -242,7 +241,7 @@ export type SignerToEcdsaKernelSmartAccountParameters< * @param deployedAccountAddress */ export async function signerToEcdsaKernelSmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", diff --git a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts index 1a55589f..7b99fceb 100644 --- a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts @@ -1,16 +1,18 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { DefaultEntryPoint, EntryPoint, Prettify } from "../../types" +import type { EntryPoint, Prettify } from "../../types" import { type SafeSmartAccount, type SignerToSafeSmartAccountParameters, signerToSafeSmartAccount } from "./signerToSafeSmartAccount" -export type PrivateKeyToSafeSmartAccountParameters = Prettify< +export type PrivateKeyToSafeSmartAccountParameters< + entryPoint extends EntryPoint +> = Prettify< { privateKey: Hex - } & Omit + } & Omit, "signer"> > /** @@ -19,12 +21,12 @@ export type PrivateKeyToSafeSmartAccountParameters = Prettify< * @returns A Private Key Simple Account. */ export async function privateKeyToSafeSmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( client: Client, - { privateKey, ...rest }: PrivateKeyToSafeSmartAccountParameters + { privateKey, ...rest }: PrivateKeyToSafeSmartAccountParameters ): Promise> { const privateKeyAccount = privateKeyToAccount(privateKey) diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 6f565145..ed1bc5fb 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -28,7 +28,7 @@ import { signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { ENTRYPOINT_ADDRESS_0_6, Prettify } from "../../types" +import type { ENTRYPOINT_ADDRESS_0_6_TYPE, Prettify } from "../../types" import type { EntryPoint } from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" @@ -174,7 +174,7 @@ const encodeMultiSend = ( } export type SafeSmartAccount< - entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6, + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6_TYPE, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -491,12 +491,13 @@ const getDefaultAddresses = ( } export type SignerToSafeSmartAccountParameters< + entryPoint extends EntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ signer: SmartAccountSigner safeVersion: SafeVersion - entryPoint: EntryPoint + entryPoint: entryPoint address?: Address addModuleLibAddress?: Address safe4337ModuleAddress?: Address @@ -521,7 +522,7 @@ export type SignerToSafeSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function signerToSafeSmartAccount< - entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -544,7 +545,7 @@ export async function signerToSafeSmartAccount< validAfter = 0, safeModules = [], setupTransactions = [] - }: SignerToSafeSmartAccountParameters + }: SignerToSafeSmartAccountParameters ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) @@ -655,7 +656,7 @@ export async function signerToSafeSmartAccount< } }) - return { + const safeSmartAccount: SafeSmartAccount = { ...account, client: client, publicKey: accountAddress, @@ -834,4 +835,6 @@ export async function signerToSafeSmartAccount< return "0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } } + + return safeSmartAccount } diff --git a/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts index 886c4f77..dfbc2f3c 100644 --- a/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/privateKeyToSimpleSmartAccount.ts @@ -6,7 +6,7 @@ import { type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { DefaultEntryPoint, EntryPoint, Prettify } from "../../types" +import type { EntryPoint, Prettify } from "../../types" import { type SignerToSimpleSmartAccountParameters, type SimpleSmartAccount, @@ -14,7 +14,7 @@ import { } from "./signerToSimpleSmartAccount" export type PrivateKeyToSimpleSmartAccountParameters< - entryPoint extends EntryPoint = DefaultEntryPoint + entryPoint extends EntryPoint > = Prettify< { privateKey: Hex @@ -27,7 +27,7 @@ export type PrivateKeyToSimpleSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function privateKeyToSimpleSmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 61532c27..a1b4adaf 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -15,9 +15,8 @@ import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" import type { - DefaultEntryPoint, - ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7, + ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_0_7_TYPE, Prettify } from "../../types" import type { EntryPoint } from "../../types/entrypoint" @@ -31,7 +30,7 @@ import { } from "../types" export type SimpleSmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -93,22 +92,22 @@ const getAccountAddress = async < const factoryData = await getAccountInitCode(owner, index) if (entryPointVersion === "0.6") { - return getSenderAddress(client, { + return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6 + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6_TYPE }) } // Get the sender address based on the init code - return getSenderAddress(client, { + return getSenderAddress(client, { factory: factoryAddress, factoryData, - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7 + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7_TYPE }) } export type SignerToSimpleSmartAccountParameters< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ @@ -125,7 +124,7 @@ export type SignerToSimpleSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function signerToSimpleSmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", diff --git a/packages/permissionless/accounts/types.ts b/packages/permissionless/accounts/types.ts index 1d6102fa..f1c34fac 100644 --- a/packages/permissionless/accounts/types.ts +++ b/packages/permissionless/accounts/types.ts @@ -7,7 +7,7 @@ import { type LocalAccount } from "viem" import type { Chain, EncodeDeployDataParameters, Transport } from "viem" -import type { DefaultEntryPoint, UserOperation } from "../types" +import type { UserOperation } from "../types" import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" export class SignTransactionNotSupportedBySmartAccount extends BaseError { @@ -27,14 +27,14 @@ export class SignTransactionNotSupportedBySmartAccount extends BaseError { } export type SmartAccount< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, Name extends string = string, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, TAbi extends Abi | readonly unknown[] = Abi > = LocalAccount & { client: Client - entryPoint: EntryPoint + entryPoint: entryPoint getNonce: () => Promise getInitCode: () => Promise getFactory: () => Promise
diff --git a/packages/permissionless/actions/bundler/chainId.ts b/packages/permissionless/actions/bundler/chainId.ts index 607e79a5..c17c0b28 100644 --- a/packages/permissionless/actions/bundler/chainId.ts +++ b/packages/permissionless/actions/bundler/chainId.ts @@ -1,6 +1,6 @@ import type { Account, Chain, Client, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" -import type { DefaultEntryPoint, EntryPoint } from "../../types" +import type { EntryPoint } from "../../types" import type { BundlerRpcSchema } from "../../types/bundler" /** @@ -26,7 +26,7 @@ import type { BundlerRpcSchema } from "../../types/bundler" * */ export const chainId = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index 97568be1..3f474972 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -9,11 +9,7 @@ import type { PartialBy } from "viem/types/utils" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema, StateOverrides } from "../../types/bundler" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" +import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { UserOperation } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" import { @@ -45,9 +41,8 @@ export type EstimateUserOperationGasReturnType = { callGasLimit: bigint } -export type EstimateUserOperationErrorType< - entryPoint extends EntryPoint = DefaultEntryPoint -> = GetEstimateUserOperationGasErrorReturnType +export type EstimateUserOperationErrorType = + GetEstimateUserOperationGasErrorReturnType /** * Estimates preVerificationGas, verificationGasLimit and callGasLimit for user operation @@ -77,7 +72,7 @@ export type EstimateUserOperationErrorType< * */ export const estimateUserOperationGas = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.ts index 5ff314a8..a29b7b45 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.ts @@ -2,13 +2,9 @@ import type { Account, Address, Chain, Client, Hash, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" +import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { UserOperation } from "../../types/userOperation" -import { getEntryPointVersion } from "../../utils/getEntryPointVersion" +import { ENTRYPOINT_ADDRESS_0_6 } from "../../utils/getEntryPointVersion" export type GetUserOperationByHashParameters = { hash: Hash @@ -45,7 +41,7 @@ export type GetUserOperationByHashReturnType = { * */ export const getUserOperationByHash = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined @@ -64,16 +60,14 @@ export const getUserOperationByHash = async < const { userOperation, - entryPoint, + entryPoint: entryPointAddress, transactionHash, blockHash, blockNumber } = response - const entryPointVersion = getEntryPointVersion(entryPoint) - return { - userOperation: (entryPointVersion === "0.6" + userOperation: (entryPointAddress === ENTRYPOINT_ADDRESS_0_6 ? { ...userOperation, nonce: BigInt(userOperation.nonce), @@ -108,7 +102,7 @@ export const getUserOperationByHash = async < ? BigInt(userOperation.paymasterPostOpGasLimit) : undefined }) as UserOperation>, - entryPoint: entryPoint, + entryPoint: entryPointAddress, transactionHash: transactionHash, blockHash: blockHash, blockNumber: BigInt(blockNumber) diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.ts index e78c3172..70be0bdb 100644 --- a/packages/permissionless/actions/bundler/getUserOperationReceipt.ts +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.ts @@ -10,7 +10,7 @@ import type { import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types" import type { BundlerRpcSchema } from "../../types/bundler" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import type { TStatus } from "../../types/userOperation" import { transactionReceiptStatus } from "../../utils/deepHexlify" @@ -74,7 +74,7 @@ export type GetUserOperationReceiptReturnType = { * */ export const getUserOperationReceipt = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined diff --git a/packages/permissionless/actions/bundler/sendUserOperation.ts b/packages/permissionless/actions/bundler/sendUserOperation.ts index 859ae118..04b60ffe 100644 --- a/packages/permissionless/actions/bundler/sendUserOperation.ts +++ b/packages/permissionless/actions/bundler/sendUserOperation.ts @@ -2,11 +2,7 @@ import type { Account, BaseError, Chain, Client, Hash, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" +import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { UserOperation, UserOperationWithBigIntAsHex @@ -45,7 +41,7 @@ export type SendUserOperationParameters = { * // Return '0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34' */ export const sendUserOperation = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.ts index fc7cc9f5..208ade1f 100644 --- a/packages/permissionless/actions/bundler/supportedEntryPoints.ts +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.ts @@ -1,7 +1,7 @@ import type { Account, Chain, Client, Transport } from "viem" import type { BundlerClient } from "../../clients/createBundlerClient" import type { BundlerRpcSchema } from "../../types/bundler" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" /** * Returns the supported entrypoints by the bundler service @@ -26,7 +26,7 @@ import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" * */ export const supportedEntryPoints = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts index 00897b36..61660e90 100644 --- a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts @@ -2,7 +2,7 @@ import type { Account, Chain, Client, Transport } from "viem" import type { PartialBy } from "viem/types/utils" import type { Prettify } from "../../types/" import type { - DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -12,12 +12,12 @@ import type { UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" -import { getEntryPointVersion } from "../../utils/getEntryPointVersion" +import { ENTRYPOINT_ADDRESS_0_6 } from "../../utils/getEntryPointVersion" export type PimlicoSponsorUserOperationParameters< entryPoint extends EntryPoint > = { - userOperation: GetEntryPointVersion extends "0.6" + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? PartialBy< UserOperation<"0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" @@ -63,7 +63,7 @@ export type SponsorUserOperationReturnType = * */ export const sponsorUserOperation = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined @@ -100,10 +100,8 @@ export const sponsorUserOperation = async < ] }) - const entryPointVersion = getEntryPointVersion(args.entryPoint) - const userOperation: SponsorUserOperationReturnType = ( - entryPointVersion === "0.6" + args.entryPoint === ENTRYPOINT_ADDRESS_0_6 ? { ...args.userOperation, paymasterAndData: response.paymasterAndData, diff --git a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts index 31fcc60a..2eb511c0 100644 --- a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts +++ b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.ts @@ -1,10 +1,6 @@ import type { Account, Chain, Client, Transport } from "viem" import type { Prettify } from "../../types/" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../../types/entrypoint" +import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { PimlicoPaymasterRpcSchema } from "../../types/pimlico" import type { UserOperation, @@ -66,7 +62,7 @@ export type ValidateSponsorshipPolicies = { * ] */ export const validateSponsorshipPolicies = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 66d91488..568f102f 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -13,14 +13,13 @@ import { import { simulateContract } from "viem/actions" import type { Prettify } from "../../types/" import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion + ENTRYPOINT_ADDRESS_0_6_TYPE, + EntryPoint } from "../../types/entrypoint" import { getAction } from "../../utils/getAction" export type GetSenderAddressParams = - GetEntryPointVersion extends "0.6" + entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? { initCode: Hex entryPoint: entryPoint @@ -78,7 +77,7 @@ export class InvalidEntryPointError extends BaseError { * // Return '0x7a88a206ba40b37a8c07a2b5688cf8b287318b63' */ export const getSenderAddress = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( diff --git a/packages/permissionless/actions/smartAccount/deployContract.ts b/packages/permissionless/actions/smartAccount/deployContract.ts index 4ce408a5..d6a15221 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.ts @@ -9,7 +9,7 @@ import type { } from "viem" import type { SmartAccount } from "../../accounts/types" import type { Prettify } from "../../types/" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { AccountOrClientNotFoundError } from "../../utils/signUserOperationHashWithECDSA" @@ -57,9 +57,9 @@ export type DeployContractParametersWithPaymaster< * }) */ export async function deployContract< + entryPoint extends EntryPoint, TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined, - entryPoint extends EntryPoint = DefaultEntryPoint + TAccount extends SmartAccount | undefined >( client: Client, args: Prettify> diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index 50de3024..c48a3801 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -9,9 +9,8 @@ import type { } from "../../types/" import type { StateOverrides } from "../../types/bundler" import type { - DefaultEntryPoint, - ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7, + ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_0_7_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -20,9 +19,7 @@ import { getAction } from "../../utils/getAction" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" import { estimateUserOperationGas } from "../bundler/estimateUserOperationGas" -export type SponsorUserOperationMiddleware< - entryPoint extends EntryPoint = DefaultEntryPoint -> = { +export type SponsorUserOperationMiddleware = { sponsorUserOperation?: (args: { userOperation: UserOperation> entryPoint: entryPoint @@ -35,7 +32,7 @@ export type PrepareUserOperationRequestParameters< | SmartAccount | undefined > = { - userOperation: GetEntryPointVersion extends "0.6" + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? PartialBy< UserOperation<"0.6">, | "sender" @@ -74,7 +71,7 @@ export type PrepareUserOperationRequestReturnType< > = UserOperation> async function prepareUserOperationRequestEntryPointVersion0_6< - entryPoint extends ENTRYPOINT_ADDRESS_0_6, + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = @@ -94,7 +91,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< const account = parseAccount( account_ - ) as SmartAccount + ) as SmartAccount const [sender, nonce, initCode, callData, gasEstimation] = await Promise.all([ @@ -169,7 +166,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< } async function prepareUserOperationRequestEntryPointVersion0_7< - entryPoint extends ENTRYPOINT_ADDRESS_0_7, + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_7_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = @@ -189,7 +186,7 @@ async function prepareUserOperationRequestEntryPointVersion0_7< const account = parseAccount( account_ - ) as SmartAccount + ) as SmartAccount const [sender, nonce, factory, factoryData, callData, gasEstimation] = await Promise.all([ @@ -269,7 +266,7 @@ async function prepareUserOperationRequestEntryPointVersion0_7< } export async function prepareUserOperationRequest< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = @@ -289,29 +286,15 @@ export async function prepareUserOperationRequest< if (entryPointVersion === "0.6") { return prepareUserOperationRequestEntryPointVersion0_6( - client as Client< - TTransport, - TChain, - SmartAccount | undefined - >, - args as PrepareUserOperationRequestParameters< - ENTRYPOINT_ADDRESS_0_6, - SmartAccount | undefined - >, + client, + args, stateOverrides ) as Promise> } return prepareUserOperationRequestEntryPointVersion0_7( - client as Client< - TTransport, - TChain, - SmartAccount | undefined - >, - args as PrepareUserOperationRequestParameters< - ENTRYPOINT_ADDRESS_0_7, - SmartAccount | undefined - >, + client, + args, stateOverrides ) as Promise> } diff --git a/packages/permissionless/actions/smartAccount/sendTransaction.ts b/packages/permissionless/actions/smartAccount/sendTransaction.ts index 998a2b48..7baf0229 100644 --- a/packages/permissionless/actions/smartAccount/sendTransaction.ts +++ b/packages/permissionless/actions/smartAccount/sendTransaction.ts @@ -7,7 +7,7 @@ import type { } from "viem" import { type SmartAccount } from "../../accounts/types" import type { Prettify } from "../../types/" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" @@ -73,7 +73,7 @@ export type SendTransactionWithPaymasterParameters< export async function sendTransaction< TChain extends Chain | undefined, TAccount extends SmartAccount | undefined, - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TChainOverride extends Chain | undefined = Chain | undefined >( client: Client, diff --git a/packages/permissionless/actions/smartAccount/sendTransactions.ts b/packages/permissionless/actions/smartAccount/sendTransactions.ts index 3be584cf..a12b2dba 100644 --- a/packages/permissionless/actions/smartAccount/sendTransactions.ts +++ b/packages/permissionless/actions/smartAccount/sendTransactions.ts @@ -9,7 +9,7 @@ import type { } from "viem" import { type SmartAccount } from "../../accounts/types" import type { GetAccountParameter, Prettify } from "../../types/" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" import { getAction } from "../../utils/getAction" import { waitForUserOperationReceipt } from "../bundler/waitForUserOperationReceipt" @@ -79,7 +79,7 @@ export type SendTransactionsWithPaymasterParameters< export async function sendTransactions< TChain extends Chain | undefined, TAccount extends SmartAccount | undefined, - entryPoint extends EntryPoint = DefaultEntryPoint + entryPoint extends EntryPoint >( client: Client, args: Prettify< diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.ts index 58a5918a..38d173d0 100644 --- a/packages/permissionless/actions/smartAccount/sendUserOperation.ts +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.ts @@ -7,7 +7,7 @@ import type { UserOperation } from "../../types/" import type { - DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -25,7 +25,7 @@ export type SendUserOperationParameters< | SmartAccount | undefined > = { - userOperation: GetEntryPointVersion extends "0.6" + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? PartialBy< UserOperation<"0.6">, | "sender" @@ -60,7 +60,7 @@ export type SendUserOperationParameters< SponsorUserOperationMiddleware export async function sendUserOperation< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = diff --git a/packages/permissionless/actions/smartAccount/signMessage.ts b/packages/permissionless/actions/smartAccount/signMessage.ts index 01c22ade..a5b48c6f 100644 --- a/packages/permissionless/actions/smartAccount/signMessage.ts +++ b/packages/permissionless/actions/smartAccount/signMessage.ts @@ -6,7 +6,7 @@ import type { Transport } from "viem" import { type SmartAccount } from "../../accounts/types" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" /** @@ -56,9 +56,9 @@ import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" * }) */ export async function signMessage< + entryPoint extends EntryPoint, TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined, - entryPoint extends EntryPoint = DefaultEntryPoint + TAccount extends SmartAccount | undefined >( client: Client, { diff --git a/packages/permissionless/actions/smartAccount/signTypedData.ts b/packages/permissionless/actions/smartAccount/signTypedData.ts index 1c83a98b..76bf6f0b 100644 --- a/packages/permissionless/actions/smartAccount/signTypedData.ts +++ b/packages/permissionless/actions/smartAccount/signTypedData.ts @@ -10,7 +10,7 @@ import { validateTypedData } from "viem" import { type SmartAccount } from "../../accounts/types" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" /** @@ -112,11 +112,11 @@ import { AccountOrClientNotFoundError, parseAccount } from "../../utils/" * }) */ export async function signTypedData< + entryPoint extends EntryPoint, const TTypedData extends TypedData | { [key: string]: unknown }, TPrimaryType extends string, TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined, - entryPoint extends EntryPoint = DefaultEntryPoint + TAccount extends SmartAccount | undefined >( client: Client, { diff --git a/packages/permissionless/actions/smartAccount/writeContract.ts b/packages/permissionless/actions/smartAccount/writeContract.ts index 08260dd2..3896d52c 100644 --- a/packages/permissionless/actions/smartAccount/writeContract.ts +++ b/packages/permissionless/actions/smartAccount/writeContract.ts @@ -11,7 +11,7 @@ import { encodeFunctionData } from "viem" import { type SmartAccount } from "../../accounts/types" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { getAction } from "../../utils/getAction" import { type SponsorUserOperationMiddleware } from "./prepareUserOperationRequest" import { @@ -71,7 +71,7 @@ import { * const hash = await writeContract(client, request) */ export type WriteContractWithPaymasterParameters< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = | SmartAccount @@ -98,10 +98,10 @@ export type WriteContractWithPaymasterParameters< SponsorUserOperationMiddleware export async function writeContract< + entryPoint extends EntryPoint, TChain extends Chain | undefined, TAccount extends SmartAccount | undefined, const TAbi extends Abi | readonly unknown[], - entryPoint extends EntryPoint = DefaultEntryPoint, TFunctionName extends ContractFunctionName< TAbi, "nonpayable" | "payable" diff --git a/packages/permissionless/actions/stackup/accounts.ts b/packages/permissionless/actions/stackup/accounts.ts index 65e3b790..b1d11a61 100644 --- a/packages/permissionless/actions/stackup/accounts.ts +++ b/packages/permissionless/actions/stackup/accounts.ts @@ -1,8 +1,9 @@ import type { Address } from "viem" import type { StackupPaymasterClient } from "../../clients/stackup" +import type { EntryPoint } from "../../types" -export type AccountsParameters = { - entryPoint: Address +export type AccountsParameters = { + entryPoint: entryPoint } /** @@ -27,13 +28,13 @@ export type AccountsParameters = { * }}) * */ -export const accounts = async ( - client: StackupPaymasterClient, - { entryPoint }: AccountsParameters +export const accounts = async ( + client: StackupPaymasterClient, + { entryPoint: entryPointAddress }: AccountsParameters ): Promise => { const response = await client.request({ method: "pm_accounts", - params: [entryPoint] + params: [entryPointAddress] }) return response diff --git a/packages/permissionless/actions/stackup/sponsorUserOperation.ts b/packages/permissionless/actions/stackup/sponsorUserOperation.ts index 38704152..8455bfb3 100644 --- a/packages/permissionless/actions/stackup/sponsorUserOperation.ts +++ b/packages/permissionless/actions/stackup/sponsorUserOperation.ts @@ -1,20 +1,17 @@ import type { PartialBy } from "viem/types/utils" import { type StackupPaymasterClient } from "../../clients/stackup" import type { - DefaultEntryPoint, + ENTRYPOINT_ADDRESS_0_6_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { StackupPaymasterContext } from "../../types/stackup" -import type { - UserOperation, - UserOperationWithBigIntAsHex -} from "../../types/userOperation" +import type { UserOperation } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type SponsorUserOperationParameters = { - userOperation: GetEntryPointVersion extends "0.6" + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? PartialBy< UserOperation<"0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" @@ -59,21 +56,13 @@ export type SponsorUserOperationReturnType = * }}) * */ -export const sponsorUserOperation = async < - entryPoint extends EntryPoint = DefaultEntryPoint ->( +export const sponsorUserOperation = async ( client: StackupPaymasterClient, args: SponsorUserOperationParameters ): Promise> => { const response = await client.request({ method: "pm_sponsorUserOperation", - params: [ - deepHexlify(args.userOperation) as UserOperationWithBigIntAsHex< - GetEntryPointVersion - >, - args.entryPoint, - args.context - ] + params: [deepHexlify(args.userOperation), args.entryPoint, args.context] }) const entryPointVersion = getEntryPointVersion(args.entryPoint) diff --git a/packages/permissionless/clients/createBundlerClient.ts b/packages/permissionless/clients/createBundlerClient.ts index 06b457fb..4ea177dd 100644 --- a/packages/permissionless/clients/createBundlerClient.ts +++ b/packages/permissionless/clients/createBundlerClient.ts @@ -7,18 +7,18 @@ import type { } from "viem" import { createClient } from "viem" import type { BundlerRpcSchema } from "../types/bundler" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import type { EntryPoint } from "../types/entrypoint" import { type BundlerActions, bundlerActions } from "./decorators/bundler" export type BundlerClient< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TChain extends Chain | undefined = Chain | undefined > = Client< Transport, TChain, Account | undefined, BundlerRpcSchema, - BundlerActions + BundlerActions > /** * Creates a EIP-4337 compliant Bundler Client with a given [Transport](https://viem.sh/docs/clients/intro.html) configured for a [Chain](https://viem.sh/docs/clients/chains.html). @@ -40,11 +40,13 @@ export type BundlerClient< * }) */ export const createBundlerClient = < - transport extends Transport, - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, + transport extends Transport = Transport, chain extends Chain | undefined = undefined >( - parameters: PublicClientConfig + parameters: PublicClientConfig & { + entryPoint: entryPoint + } ): BundlerClient => { const { key = "public", name = "Bundler Client" } = parameters const client = createClient({ @@ -53,5 +55,5 @@ export const createBundlerClient = < name, type: "bundlerClient" }) - return client.extend(bundlerActions) + return client.extend(bundlerActions(parameters.entryPoint)) } diff --git a/packages/permissionless/clients/createSmartAccountClient.ts b/packages/permissionless/clients/createSmartAccountClient.ts index df7ae708..69aec940 100644 --- a/packages/permissionless/clients/createSmartAccountClient.ts +++ b/packages/permissionless/clients/createSmartAccountClient.ts @@ -10,7 +10,7 @@ import { type SmartAccount } from "../accounts/types" import { type SponsorUserOperationMiddleware } from "../actions/smartAccount/prepareUserOperationRequest" import type { Prettify } from "../types/" import { type BundlerRpcSchema } from "../types/bundler" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import type { EntryPoint } from "../types/entrypoint" import { type SmartAccountActions, smartAccountActions @@ -22,7 +22,7 @@ import { * - Fix typing, 'accounts' is required to signMessage, signTypedData, signTransaction, but not needed here, since account is embedded in the client */ export type SmartAccountClient< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, account extends SmartAccount | undefined = @@ -39,7 +39,7 @@ export type SmartAccountClient< > export type SmartAccountClientConfig< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, account extends SmartAccount | undefined = @@ -51,7 +51,9 @@ export type SmartAccountClientConfig< "cacheTime" | "chain" | "key" | "name" | "pollingInterval" | "transport" > & { account?: account - } & SponsorUserOperationMiddleware + } & SponsorUserOperationMiddleware & { + entryPoint: entryPoint + } > /** @@ -75,10 +77,12 @@ export type SmartAccountClientConfig< */ export function createSmartAccountClient< - TTransport extends Transport, - entryPoint extends EntryPoint = DefaultEntryPoint, - TChain extends Chain | undefined = undefined, - TSmartAccount extends SmartAccount | undefined = undefined + entryPoint extends EntryPoint, + TSmartAccount extends SmartAccount | undefined = + | SmartAccount + | undefined, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = undefined >( parameters: SmartAccountClientConfig< entryPoint, @@ -101,7 +105,7 @@ export function createSmartAccountClient< }) return client.extend( - smartAccountActions({ + smartAccountActions({ sponsorUserOperation: parameters.sponsorUserOperation }) ) as SmartAccountClient diff --git a/packages/permissionless/clients/decorators/bundler.ts b/packages/permissionless/clients/decorators/bundler.ts index 87e0b2a7..60b00d03 100644 --- a/packages/permissionless/clients/decorators/bundler.ts +++ b/packages/permissionless/clients/decorators/bundler.ts @@ -1,4 +1,3 @@ -import type { Address } from "viem" import type { Client, Hash } from "viem" import { chainId } from "../../actions/bundler/chainId" import { @@ -27,218 +26,228 @@ import { } from "../../actions/bundler/waitForUserOperationReceipt" import type { Prettify } from "../../types/" import type { StateOverrides } from "../../types/bundler" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import type { BundlerClient } from "../createBundlerClient" -export type BundlerActions = - { - /** - * - * Sends user operation to the bundler - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/sendUserOperation - * - * @param args {@link SendUserOperationParameters}. - * @returns UserOpHash that you can use to track user operation as {@link Hash}. - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http("https://api.pimlico.io/v2/goerli/rpc?apikey=YOUR_API_KEY_HERE") - * }).extend(bundlerActions) - * - * const userOpHash = await bundlerClient.sendUserOperation({ - * userOperation: signedUserOperation, - * entryPoint: entryPoint - * }) - * - * // Return '0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34' - */ - sendUserOperation: ( - args: Prettify> - ) => Promise - /** - * - * Estimates preVerificationGas, verificationGasLimit and callGasLimit for user operation - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/estimateUserOperationGas - * - * @param args {@link EstimateUserOperationGasParameters} - * @returns preVerificationGas, verificationGasLimit and callGasLimit as {@link EstimateUserOperationGasReturnType} - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * const gasParameters = await bundlerClient.estimateUserOperationGas({ - * userOperation: signedUserOperation, - * entryPoint: entryPoint - * }) - * - * // Return {preVerificationGas: 43492n, verificationGasLimit: 59436n, callGasLimit: 9000n} - */ - estimateUserOperationGas: < - entryPoint extends EntryPoint = DefaultEntryPoint - >( - args: Prettify>, - stateOverrides?: StateOverrides - ) => Promise> - /** - * - * Returns the supported entrypoints by the bundler service - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/supportedEntryPoints - * - * @returns Supported entryPoints - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * const supportedEntryPoints = await bundlerClient.supportedEntryPoints() - * - * // Return ['0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'] - */ - supportedEntryPoints: () => Promise - /** - * - * Returns the supported chain id by the bundler service - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/chainId - * - * @returns Supported chain id - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * const chainId = await bundlerClient.chainId() - * // Return 5n for Goerli - */ - chainId: () => Promise - /** - * - * Returns the user operation from userOpHash - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationByHash - * - * @param args {@link GetUserOperationByHash} UserOpHash that was returned by {@link sendUserOperation} - * @returns userOperation along with entryPoint, transactionHash, blockHash, blockNumber if found or null - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * await bundlerClient.getUserOperationByHash(userOpHash) - * - */ - getUserOperationByHash: ( - args: Prettify - ) => Promise - > | null> - /** - * - * Returns the user operation receipt from userOpHash - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt - * - * @param args {@link GetUserOperationReceiptParameters} UserOpHash that was returned by {@link sendUserOperation} - * @returns user operation receipt {@link GetUserOperationReceiptReturnType} if found or null - * - * @example - * import { createClient } from "viem" - * import { bundlerActions } from "permissionless" - * - * const bundlerClient = createClient({ - * chain: goerli, - * transport: http(BUNDLER_URL) - * }).extend(bundlerActions) - * - * await bundlerClient.getUserOperationReceipt({hash: userOpHash}) - * - */ - getUserOperationReceipt: ( - args: Prettify - ) => Promise | null> - - /** - * Waits for the User Operation to be included on a [Block](https://viem.sh/docs/glossary/terms.html#block) (one confirmation), and then returns the [User Operation Receipt](https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt). - * - * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/waitForUserOperationReceipt - * - * @param client - Bundler Client to use - * @param parameters - {@link WaitForUserOperationReceiptParameters} - * @returns The transaction receipt. {@link GetUserOperationReceiptReturnType} - * - * @example - * import { createBundlerClient, waitForUserOperationReceipt, http } from 'viem' - * import { mainnet } from 'viem/chains' - * - * const bundlerClient = createBundlerClient({ - * chain: mainnet, - * transport: http(), - * }) - * const userOperationReceipt = await bundlerClient.waitForUserOperationReceipt({ - * hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d', - * }) - */ - waitForUserOperationReceipt: ( - args: Prettify - ) => Promise> - } - -const bundlerActions = ( - client: Client -): BundlerActions => ({ - sendUserOperation: async ( - args: SendUserOperationParameters - ): Promise => - sendUserOperation(client as BundlerClient, args), - estimateUserOperationGas: < - entryPoint extends EntryPoint = DefaultEntryPoint - >( - args: EstimateUserOperationGasParameters, +export type BundlerActions = { + /** + * + * Sends user operation to the bundler + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/sendUserOperation + * + * @param args {@link SendUserOperationParameters}. + * @returns UserOpHash that you can use to track user operation as {@link Hash}. + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http("https://api.pimlico.io/v2/goerli/rpc?apikey=YOUR_API_KEY_HERE") + * }).extend(bundlerActions) + * + * const userOpHash = await bundlerClient.sendUserOperation({ + * userOperation: signedUserOperation, + * entryPoint: entryPoint + * }) + * + * // Return '0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34' + */ + sendUserOperation: ( + args: Prettify< + Omit, "entryPoint"> + > + ) => Promise + /** + * + * Estimates preVerificationGas, verificationGasLimit and callGasLimit for user operation + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/estimateUserOperationGas + * + * @param args {@link EstimateUserOperationGasParameters} + * @returns preVerificationGas, verificationGasLimit and callGasLimit as {@link EstimateUserOperationGasReturnType} + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * const gasParameters = await bundlerClient.estimateUserOperationGas({ + * userOperation: signedUserOperation, + * entryPoint: entryPoint + * }) + * + * // Return {preVerificationGas: 43492n, verificationGasLimit: 59436n, callGasLimit: 9000n} + */ + estimateUserOperationGas: ( + args: Prettify< + Omit, "entryPoint"> + >, stateOverrides?: StateOverrides - ) => - estimateUserOperationGas( - client as BundlerClient, - args, - stateOverrides - ), - supportedEntryPoints: (): Promise => - supportedEntryPoints(client as BundlerClient), - chainId: () => chainId(client as BundlerClient), - getUserOperationByHash: (args: GetUserOperationByHashParameters) => - getUserOperationByHash(client as BundlerClient, args), - getUserOperationReceipt: (args: GetUserOperationReceiptParameters) => - getUserOperationReceipt(client as BundlerClient, args), + ) => Promise> + /** + * + * Returns the supported entrypoints by the bundler service + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/supportedEntryPoints + * + * @returns Supported entryPoints + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * const supportedEntryPoints = await bundlerClient.supportedEntryPoints() + * + * // Return ['0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'] + */ + supportedEntryPoints: () => Promise + /** + * + * Returns the supported chain id by the bundler service + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/chainId + * + * @returns Supported chain id + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * const chainId = await bundlerClient.chainId() + * // Return 5n for Goerli + */ + chainId: () => Promise + /** + * + * Returns the user operation from userOpHash + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationByHash + * + * @param args {@link GetUserOperationByHash} UserOpHash that was returned by {@link sendUserOperation} + * @returns userOperation along with entryPoint, transactionHash, blockHash, blockNumber if found or null + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * await bundlerClient.getUserOperationByHash(userOpHash) + * + */ + getUserOperationByHash: ( + args: Prettify + ) => Promise> | null> + /** + * + * Returns the user operation receipt from userOpHash + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt + * + * @param args {@link GetUserOperationReceiptParameters} UserOpHash that was returned by {@link sendUserOperation} + * @returns user operation receipt {@link GetUserOperationReceiptReturnType} if found or null + * + * @example + * import { createClient } from "viem" + * import { bundlerActions } from "permissionless" + * + * const bundlerClient = createClient({ + * chain: goerli, + * transport: http(BUNDLER_URL) + * }).extend(bundlerActions) + * + * await bundlerClient.getUserOperationReceipt({hash: userOpHash}) + * + */ + getUserOperationReceipt: ( + args: Prettify + ) => Promise | null> + + /** + * Waits for the User Operation to be included on a [Block](https://viem.sh/docs/glossary/terms.html#block) (one confirmation), and then returns the [User Operation Receipt](https://docs.pimlico.io/permissionless/reference/bundler-actions/getUserOperationReceipt). + * + * - Docs: https://docs.pimlico.io/permissionless/reference/bundler-actions/waitForUserOperationReceipt + * + * @param client - Bundler Client to use + * @param parameters - {@link WaitForUserOperationReceiptParameters} + * @returns The transaction receipt. {@link GetUserOperationReceiptReturnType} + * + * @example + * import { createBundlerClient, waitForUserOperationReceipt, http } from 'viem' + * import { mainnet } from 'viem/chains' + * + * const bundlerClient = createBundlerClient({ + * chain: mainnet, + * transport: http(), + * }) + * const userOperationReceipt = await bundlerClient.waitForUserOperationReceipt({ + * hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d', + * }) + */ waitForUserOperationReceipt: ( - args: WaitForUserOperationReceiptParameters - ) => waitForUserOperationReceipt(client as BundlerClient, args) -}) + args: Prettify + ) => Promise> +} + +const bundlerActions = + (entryPointAddress: entryPoint) => + (client: Client): BundlerActions => ({ + sendUserOperation: async ( + args: Omit, "entryPoint"> + ): Promise => + sendUserOperation(client as BundlerClient, { + ...args, + entryPoint: entryPointAddress + }), + estimateUserOperationGas: ( + args: Omit< + EstimateUserOperationGasParameters, + "entryPoint" + >, + stateOverrides?: StateOverrides + ) => + estimateUserOperationGas( + client as BundlerClient, + { ...args, entryPoint: entryPointAddress }, + stateOverrides + ), + supportedEntryPoints: (): Promise => + supportedEntryPoints(client as BundlerClient), + chainId: () => chainId(client as BundlerClient), + getUserOperationByHash: (args: GetUserOperationByHashParameters) => + getUserOperationByHash( + client as BundlerClient, + args + ), + getUserOperationReceipt: (args: GetUserOperationReceiptParameters) => + getUserOperationReceipt(client as BundlerClient, args), + waitForUserOperationReceipt: ( + args: WaitForUserOperationReceiptParameters + ) => + waitForUserOperationReceipt( + client as BundlerClient, + args + ) + }) export { bundlerActions } diff --git a/packages/permissionless/clients/decorators/pimlico.ts b/packages/permissionless/clients/decorators/pimlico.ts index ecde5fa6..06a32178 100644 --- a/packages/permissionless/clients/decorators/pimlico.ts +++ b/packages/permissionless/clients/decorators/pimlico.ts @@ -21,7 +21,7 @@ import { sponsorUserOperation } from "../../actions/pimlico/sponsorUserOperation" import type { Prettify } from "../../types/" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import type { PimlicoBundlerClient, PimlicoPaymasterClient } from "../pimlico" export type PimlicoBundlerActions = { @@ -98,21 +98,26 @@ export type PimlicoBundlerActions = { ) => Promise } -export const pimlicoBundlerActions = ( +export const pimlicoBundlerActions = ( client: Client ): PimlicoBundlerActions => ({ getUserOperationGasPrice: async () => - getUserOperationGasPrice(client as PimlicoBundlerClient), + getUserOperationGasPrice(client as PimlicoBundlerClient), getUserOperationStatus: async (args: GetUserOperationStatusParameters) => - getUserOperationStatus(client as PimlicoBundlerClient, args), + getUserOperationStatus( + client as PimlicoBundlerClient, + args + ), sendCompressedUserOperation: async ( args: SendCompressedUserOperationParameters - ) => sendCompressedUserOperation(client as PimlicoBundlerClient, args) + ) => + sendCompressedUserOperation( + client as PimlicoBundlerClient, + args + ) }) -export type PimlicoPaymasterClientActions< - entryPoint extends EntryPoint = DefaultEntryPoint -> = { +export type PimlicoPaymasterClientActions = { /** * Returns paymasterAndData & updated gas parameters required to sponsor a userOperation. * @@ -180,26 +185,33 @@ export type PimlicoPaymasterClientActions< * } * ] */ -export const pimlicoPaymasterActions = < - entryPoint extends EntryPoint = DefaultEntryPoint ->( - client: Client -): PimlicoPaymasterClientActions => ({ - sponsorUserOperation: async ( - args: PimlicoSponsorUserOperationParameters - ) => - sponsorUserOperation( - client as PimlicoPaymasterClient, - args - ), - validateSponsorshipPolicies: async ( - args: ValidateSponsorshipPoliciesParameters - ) => - validateSponsorshipPolicies( - client as PimlicoPaymasterClient, - args - ) -}) +export const pimlicoPaymasterActions = + (entryPointAddress: entryPoint) => + (client: Client): PimlicoPaymasterClientActions => ({ + sponsorUserOperation: async ( + args: Omit< + PimlicoSponsorUserOperationParameters, + "entryPoint" + > + ) => + sponsorUserOperation( + client as PimlicoPaymasterClient, + { + ...args, + entryPoint: entryPointAddress + } + ), + validateSponsorshipPolicies: async ( + args: Omit< + ValidateSponsorshipPoliciesParameters, + "entryPoint" + > + ) => + validateSponsorshipPolicies( + client as PimlicoPaymasterClient, + { ...args, entryPoint: entryPointAddress } + ) + }) /** * TODO: Add support for pimlicoActions after we support all the actions of v2 of the Pimlico API. diff --git a/packages/permissionless/clients/decorators/smartAccount.ts b/packages/permissionless/clients/decorators/smartAccount.ts index 40cd5256..42add0d5 100644 --- a/packages/permissionless/clients/decorators/smartAccount.ts +++ b/packages/permissionless/clients/decorators/smartAccount.ts @@ -41,10 +41,10 @@ import { } from "../../actions/smartAccount/writeContract" import type { Prettify } from "../../types/" import type { StateOverrides } from "../../types/bundler" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" export type SmartAccountActions< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TChain extends Chain | undefined = Chain | undefined, TSmartAccount extends SmartAccount | undefined = | SmartAccount @@ -141,9 +141,9 @@ export type SmartAccountActions< */ signMessage: ( args: Parameters< - typeof signMessage + typeof signMessage >[1] - ) => ReturnType> + ) => ReturnType> /** * Signs typed data and calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`. * @@ -246,20 +246,20 @@ export type SmartAccountActions< >( args: Parameters< typeof signTypedData< + entryPoint, TTypedData, TPrimaryType, TChain, - TSmartAccount, - entryPoint + TSmartAccount > >[1] ) => ReturnType< typeof signTypedData< + entryPoint, TTypedData, TPrimaryType, TChain, - TSmartAccount, - entryPoint + TSmartAccount > > /** @@ -300,7 +300,7 @@ export type SmartAccountActions< TChainOverride > > - ) => ReturnType> + ) => ReturnType> /** * Executes a write function on a contract. * This function also allows you to sponsor this transaction if sender is a smartAccount @@ -372,10 +372,10 @@ export type SmartAccountActions< > ) => ReturnType< typeof writeContract< + entryPoint, TChain, TSmartAccount, TAbi, - entryPoint, TFunctionName, TArgs, TChainOverride @@ -462,9 +462,9 @@ export type SmartAccountActions< ) => ReturnType> } -export function smartAccountActions< - entryPoint extends EntryPoint = DefaultEntryPoint ->({ sponsorUserOperation }: SponsorUserOperationMiddleware) { +export function smartAccountActions({ + sponsorUserOperation +}: SponsorUserOperationMiddleware) { return < TTransport extends Transport, TChain extends Chain | undefined = Chain | undefined, @@ -484,7 +484,7 @@ export function smartAccountActions< stateOverrides ), deployContract: (args) => - deployContract(client, { + deployContract(client, { ...args, sponsorUserOperation } as DeployContractParametersWithPaymaster), @@ -501,10 +501,7 @@ export function smartAccountActions< sendTransactions(client, { ...args, sponsorUserOperation - } as SendTransactionsWithPaymasterParameters< - entryPoint, - TSmartAccount - >), + }), sendUserOperation: (args) => sendUserOperation( client, @@ -514,27 +511,27 @@ export function smartAccountActions< } as SendUserOperationParameters ), signMessage: (args) => - signMessage(client, args), + signMessage(client, args), signTypedData: < const TTypedData extends TypedData | { [key: string]: unknown }, TPrimaryType extends string >( args: Parameters< typeof signTypedData< + entryPoint, TTypedData, TPrimaryType, TChain, - TSmartAccount, - entryPoint + TSmartAccount > >[1] ) => signTypedData< + entryPoint, TTypedData, TPrimaryType, TChain, - TSmartAccount, - entryPoint + TSmartAccount >(client, args), writeContract: < const TAbi extends Abi | readonly unknown[], @@ -562,7 +559,7 @@ export function smartAccountActions< TChainOverride > ) => - writeContract(client, { + writeContract(client, { ...args, sponsorUserOperation } as WriteContractWithPaymasterParameters< diff --git a/packages/permissionless/clients/decorators/stackup.ts b/packages/permissionless/clients/decorators/stackup.ts index 641d8a26..22c56a32 100644 --- a/packages/permissionless/clients/decorators/stackup.ts +++ b/packages/permissionless/clients/decorators/stackup.ts @@ -8,12 +8,10 @@ import { type SponsorUserOperationReturnType, sponsorUserOperation } from "../../actions/stackup/sponsorUserOperation" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { type StackupPaymasterClient } from "../stackup" -export type StackupPaymasterClientActions< - entryPoint extends EntryPoint = DefaultEntryPoint -> = { +export type StackupPaymasterClientActions = { /** * Returns paymasterAndData & updated gas parameters required to sponsor a userOperation. * @@ -63,21 +61,17 @@ export type StackupPaymasterClientActions< * }}) * */ - accounts: (args: AccountsParameters) => Promise + accounts: (args: AccountsParameters) => Promise } -export const stackupPaymasterActions = < - entryPoint extends EntryPoint = DefaultEntryPoint ->( +export const stackupPaymasterActions = ( client: Client ): StackupPaymasterClientActions => ({ - sponsorUserOperation: async ( - args: SponsorUserOperationParameters - ) => + sponsorUserOperation: async (args) => sponsorUserOperation( client as StackupPaymasterClient, args ), - accounts: async (args: AccountsParameters) => - accounts(client as StackupPaymasterClient, args) + accounts: async (args) => + accounts(client as StackupPaymasterClient, args) }) diff --git a/packages/permissionless/clients/pimlico.ts b/packages/permissionless/clients/pimlico.ts index be7fde64..e35a1e53 100644 --- a/packages/permissionless/clients/pimlico.ts +++ b/packages/permissionless/clients/pimlico.ts @@ -6,7 +6,7 @@ import type { Transport } from "viem" import { createClient } from "viem" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import type { EntryPoint } from "../types/entrypoint" import type { PimlicoBundlerRpcSchema, PimlicoPaymasterRpcSchema @@ -19,17 +19,15 @@ import { pimlicoPaymasterActions } from "./decorators/pimlico" -export type PimlicoBundlerClient = Client< +export type PimlicoBundlerClient = Client< Transport, Chain | undefined, Account | undefined, PimlicoBundlerRpcSchema, - PimlicoBundlerActions & BundlerActions + PimlicoBundlerActions & BundlerActions > -export type PimlicoPaymasterClient< - entryPoint extends EntryPoint = DefaultEntryPoint -> = Client< +export type PimlicoPaymasterClient = Client< Transport, Chain | undefined, Account | undefined, @@ -57,11 +55,14 @@ export type PimlicoPaymasterClient< * }) */ export const createPimlicoBundlerClient = < - transport extends Transport, + entryPoint extends EntryPoint, + transport extends Transport = Transport, chain extends Chain | undefined = undefined >( - parameters: PublicClientConfig -): PimlicoBundlerClient => { + parameters: PublicClientConfig & { + entryPoint: entryPoint + } +): PimlicoBundlerClient => { const { key = "public", name = "Pimlico Bundler Client" } = parameters const client = createClient({ ...parameters, @@ -69,7 +70,9 @@ export const createPimlicoBundlerClient = < name, type: "pimlicoBundlerClient" }) - return client.extend(bundlerActions).extend(pimlicoBundlerActions) + return client + .extend(bundlerActions(parameters.entryPoint)) + .extend(pimlicoBundlerActions) } /** @@ -92,11 +95,13 @@ export const createPimlicoBundlerClient = < * }) */ export const createPimlicoPaymasterClient = < - transport extends Transport, - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, + transport extends Transport = Transport, chain extends Chain | undefined = undefined >( - parameters: PublicClientConfig + parameters: PublicClientConfig & { + entryPoint: entryPoint + } ): PimlicoPaymasterClient => { const { key = "public", name = "Pimlico Paymaster Client" } = parameters const client = createClient({ @@ -105,5 +110,5 @@ export const createPimlicoPaymasterClient = < name, type: "pimlicoPaymasterClient" }) - return client.extend(pimlicoPaymasterActions) + return client.extend(pimlicoPaymasterActions(parameters.entryPoint)) } diff --git a/packages/permissionless/clients/stackup.ts b/packages/permissionless/clients/stackup.ts index 32aef7bc..4e8aa37f 100644 --- a/packages/permissionless/clients/stackup.ts +++ b/packages/permissionless/clients/stackup.ts @@ -6,7 +6,7 @@ import { type Transport, createClient } from "viem" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import type { EntryPoint } from "../types/entrypoint" import type { StackupPaymasterRpcSchema } from "../types/stackup" import { type BundlerActions, bundlerActions } from "./decorators/bundler" import { @@ -14,9 +14,7 @@ import { stackupPaymasterActions } from "./decorators/stackup" -export type StackupPaymasterClient< - entryPoint extends EntryPoint = DefaultEntryPoint -> = Client< +export type StackupPaymasterClient = Client< Transport, Chain | undefined, Account | undefined, @@ -44,11 +42,13 @@ export type StackupPaymasterClient< * }) */ export const createStackupPaymasterClient = < - transport extends Transport, - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, + transport extends Transport = Transport, chain extends Chain | undefined = undefined >( - parameters: PublicClientConfig + parameters: PublicClientConfig & { + entryPoint: entryPoint + } ): StackupPaymasterClient => { const { key = "public", name = "Stackup Paymaster Client" } = parameters const client = createClient({ @@ -58,6 +58,6 @@ export const createStackupPaymasterClient = < type: "stackupPaymasterClient" }) return client - .extend(bundlerActions) + .extend(bundlerActions(parameters.entryPoint)) .extend(stackupPaymasterActions) } diff --git a/packages/permissionless/errors/estimateUserOperationGas.ts b/packages/permissionless/errors/estimateUserOperationGas.ts index 39c3258e..1e3f0691 100644 --- a/packages/permissionless/errors/estimateUserOperationGas.ts +++ b/packages/permissionless/errors/estimateUserOperationGas.ts @@ -1,15 +1,14 @@ import { BaseError } from "viem" import type { EstimateUserOperationGasParameters } from "../actions/bundler/estimateUserOperationGas" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import type { EntryPoint } from "../types/entrypoint" import { prettyPrint } from "./utils" -export type EstimateUserOperationGasErrorType< - entryPoint extends EntryPoint = DefaultEntryPoint -> = EstimateUserOperationGasError & { - name: "EstimateUserOperationGasError" -} +export type EstimateUserOperationGasErrorType = + EstimateUserOperationGasError & { + name: "EstimateUserOperationGasError" + } export class EstimateUserOperationGasError< - entryPoint extends EntryPoint = DefaultEntryPoint + entryPoint extends EntryPoint > extends BaseError { override cause: BaseError diff --git a/packages/permissionless/errors/sendUserOperation.ts b/packages/permissionless/errors/sendUserOperation.ts index f539cf84..170001a5 100644 --- a/packages/permissionless/errors/sendUserOperation.ts +++ b/packages/permissionless/errors/sendUserOperation.ts @@ -1,13 +1,14 @@ import { BaseError } from "viem" import { type SendUserOperationParameters } from "../actions/bundler/sendUserOperation" -import type { DefaultEntryPoint, EntryPoint } from "../types/entrypoint" +import type { EntryPoint } from "../types/entrypoint" import { prettyPrint } from "./utils" -export type SendUserOperationErrorType = SendUserOperationError & { - name: "SendUserOperationError" -} +export type SendUserOperationErrorType = + SendUserOperationError & { + name: "SendUserOperationError" + } export class SendUserOperationError< - entryPoint extends EntryPoint = DefaultEntryPoint + entryPoint extends EntryPoint > extends BaseError { override cause: BaseError diff --git a/packages/permissionless/types/entrypoint.ts b/packages/permissionless/types/entrypoint.ts index 010718b0..9713afe1 100644 --- a/packages/permissionless/types/entrypoint.ts +++ b/packages/permissionless/types/entrypoint.ts @@ -1,13 +1,13 @@ export type EntryPointVersion = "0.6" | "0.7" -export type DefaultEntryPoint = ENTRYPOINT_ADDRESS_0_6 - -export type ENTRYPOINT_ADDRESS_0_6 = +export type ENTRYPOINT_ADDRESS_0_6_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" -export type ENTRYPOINT_ADDRESS_0_7 = +export type ENTRYPOINT_ADDRESS_0_7_TYPE = "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" export type GetEntryPointVersion = - entryPoint extends ENTRYPOINT_ADDRESS_0_6 ? "0.6" : "0.7" + entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? "0.6" : "0.7" -export type EntryPoint = ENTRYPOINT_ADDRESS_0_6 | ENTRYPOINT_ADDRESS_0_7 +export type EntryPoint = + | ENTRYPOINT_ADDRESS_0_6_TYPE + | ENTRYPOINT_ADDRESS_0_7_TYPE diff --git a/packages/permissionless/types/index.ts b/packages/permissionless/types/index.ts index d03f06cf..31628766 100644 --- a/packages/permissionless/types/index.ts +++ b/packages/permissionless/types/index.ts @@ -6,9 +6,8 @@ import type { UserOperation } from "./userOperation" export type { UserOperation } export type { EntryPointVersion, - DefaultEntryPoint, - ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7, + ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_0_7_TYPE, GetEntryPointVersion, EntryPoint } from "./entrypoint" diff --git a/packages/permissionless/types/stackup.ts b/packages/permissionless/types/stackup.ts index 0a779612..f58927b6 100644 --- a/packages/permissionless/types/stackup.ts +++ b/packages/permissionless/types/stackup.ts @@ -1,6 +1,6 @@ import type { Address, Hex } from "viem" import type { PartialBy } from "viem/types/utils" -import type { EntryPoint, GetEntryPointVersion } from "./entrypoint" +import type { ENTRYPOINT_ADDRESS_0_6_TYPE, EntryPoint } from "./entrypoint" import type { UserOperationWithBigIntAsHex } from "./userOperation" interface StackupPaymasterContextType { @@ -15,7 +15,7 @@ export type StackupPaymasterRpcSchema = [ { Method: "pm_sponsorUserOperation" Parameters: [ - userOperation: GetEntryPointVersion extends "0.6" + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? PartialBy< UserOperationWithBigIntAsHex<"0.6">, | "callGasLimit" @@ -33,7 +33,7 @@ export type StackupPaymasterRpcSchema = [ entryPoint: entryPoint, context: StackupPaymasterContext ] - ReturnType: GetEntryPointVersion extends "0.6" + ReturnType: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? { paymasterAndData: Hex preVerificationGas: Hex diff --git a/packages/permissionless/types/userOperation.ts b/packages/permissionless/types/userOperation.ts index 21aaec07..525b6309 100644 --- a/packages/permissionless/types/userOperation.ts +++ b/packages/permissionless/types/userOperation.ts @@ -1,16 +1,11 @@ import type { Address } from "viem" import type { Hex } from "viem" -import type { - DefaultEntryPoint, - EntryPointVersion, - GetEntryPointVersion -} from "./entrypoint" +import type { EntryPointVersion } from "./entrypoint" export type TStatus = "success" | "reverted" export type UserOperationWithBigIntAsHex< - entryPointVersion extends - EntryPointVersion = GetEntryPointVersion + entryPointVersion extends EntryPointVersion > = entryPointVersion extends "0.6" ? { sender: Address @@ -51,45 +46,43 @@ export type UserOperationWithBigIntAsHex< paymasterAndData?: never } -export type UserOperation< - entryPointVersion extends - EntryPointVersion = GetEntryPointVersion -> = entryPointVersion extends "0.6" - ? { - sender: Address - nonce: bigint - initCode: Hex - callData: Hex - callGasLimit: bigint - verificationGasLimit: bigint - preVerificationGas: bigint - maxFeePerGas: bigint - maxPriorityFeePerGas: bigint - paymasterAndData: Hex - signature: Hex - factory?: never - factoryData?: never - paymaster?: never - paymasterVerificationGasLimit?: never - paymasterPostOpGasLimit?: never - paymasterData?: never - } - : { - sender: Address - nonce: bigint - factory?: Address - factoryData?: Hex - callData: Hex - callGasLimit: bigint - verificationGasLimit: bigint - preVerificationGas: bigint - maxFeePerGas: bigint - maxPriorityFeePerGas: bigint - paymaster?: Address - paymasterVerificationGasLimit?: bigint - paymasterPostOpGasLimit?: bigint - paymasterData?: Hex - signature: Hex - initCode?: never - paymasterAndData?: never - } +export type UserOperation = + entryPointVersion extends "0.6" + ? { + sender: Address + nonce: bigint + initCode: Hex + callData: Hex + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + maxFeePerGas: bigint + maxPriorityFeePerGas: bigint + paymasterAndData: Hex + signature: Hex + factory?: never + factoryData?: never + paymaster?: never + paymasterVerificationGasLimit?: never + paymasterPostOpGasLimit?: never + paymasterData?: never + } + : { + sender: Address + nonce: bigint + factory?: Address + factoryData?: Hex + callData: Hex + callGasLimit: bigint + verificationGasLimit: bigint + preVerificationGas: bigint + maxFeePerGas: bigint + maxPriorityFeePerGas: bigint + paymaster?: Address + paymasterVerificationGasLimit?: bigint + paymasterPostOpGasLimit?: bigint + paymasterData?: Hex + signature: Hex + initCode?: never + paymasterAndData?: never + } diff --git a/packages/permissionless/utils/errors/getBundlerError.ts b/packages/permissionless/utils/errors/getBundlerError.ts index 85045899..eeadf0fa 100644 --- a/packages/permissionless/utils/errors/getBundlerError.ts +++ b/packages/permissionless/utils/errors/getBundlerError.ts @@ -38,10 +38,14 @@ import { PaymasterValidityPeriodError, type PaymasterValidityPeriodErrorType } from "../../errors/paymaster" -import type { UserOperation } from "../../types" - -export type GetBundlerErrorParameters = { - userOperation: Partial +import type { + EntryPoint, + GetEntryPointVersion, + UserOperation +} from "../../types" + +export type GetBundlerErrorParameters = { + userOperation: Partial>> entryPoint: Address } @@ -63,9 +67,9 @@ export type GetBundlerErrorReturnType = | PaymasterValidationRevertedErrorType | PaymasterDataRejectedErrorType -export function getBundlerError( +export function getBundlerError( err: BaseError, - args: GetBundlerErrorParameters + args: GetBundlerErrorParameters ) { const message = (err.details || "").toLowerCase() diff --git a/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts b/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts index 0f54ed34..8c162b0c 100644 --- a/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts +++ b/packages/permissionless/utils/errors/getEstimateUserOperationGasError.ts @@ -5,7 +5,7 @@ import { type EstimateUserOperationGasErrorType } from "../../errors/estimateUserOperationGas" import { type ErrorType } from "../../errors/utils" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { type GetBundlerErrorParameters, type GetBundlerErrorReturnType, @@ -13,7 +13,7 @@ import { } from "./getBundlerError" export type GetEstimateUserOperationGasErrorReturnType< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, cause = ErrorType > = Omit, "cause"> & { cause: cause | GetBundlerErrorReturnType @@ -21,13 +21,13 @@ export type GetEstimateUserOperationGasErrorReturnType< export function getEstimateUserOperationGasError< err extends ErrorType, - entryPoint extends EntryPoint = DefaultEntryPoint + entryPoint extends EntryPoint >(error: err, args: EstimateUserOperationGasParameters) { const cause = (() => { const cause = getBundlerError( // biome-ignore lint/complexity/noBannedTypes: error as {} as BaseError, - args as GetBundlerErrorParameters + args as GetBundlerErrorParameters ) // biome-ignore lint/complexity/noBannedTypes: if (cause instanceof UnknownNodeError) return error as {} as BaseError diff --git a/packages/permissionless/utils/errors/getSendUserOperationError.ts b/packages/permissionless/utils/errors/getSendUserOperationError.ts index 93bc4c3f..1efa3797 100644 --- a/packages/permissionless/utils/errors/getSendUserOperationError.ts +++ b/packages/permissionless/utils/errors/getSendUserOperationError.ts @@ -1,19 +1,20 @@ import { BaseError, UnknownNodeError } from "viem" import type { SendUserOperationParameters } from "../../actions/bundler/sendUserOperation" import { SendUserOperationError } from "../../errors" -import type { DefaultEntryPoint, EntryPoint } from "../../types/entrypoint" +import type { EntryPoint } from "../../types/entrypoint" import { type GetBundlerErrorParameters, getBundlerError } from "./getBundlerError" -export function getSendUserOperationError< - entryPoint extends EntryPoint = DefaultEntryPoint ->(err: BaseError, args: SendUserOperationParameters) { +export function getSendUserOperationError( + err: BaseError, + args: SendUserOperationParameters +) { const cause = (() => { const cause = getBundlerError( err as BaseError, - args as GetBundlerErrorParameters + args as GetBundlerErrorParameters ) if (cause instanceof UnknownNodeError) return err as BaseError return cause diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts index 070a09af..2c8f19da 100644 --- a/packages/permissionless/utils/getEntryPointVersion.ts +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -1,6 +1,6 @@ import type { - ENTRYPOINT_ADDRESS_0_6 as ENTRYPOINT_ADDRESS_0_6_TYPE, - ENTRYPOINT_ADDRESS_0_7 as ENTRYPOINT_ADDRESS_0_7_TYPE + ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_0_7_TYPE } from "../types" import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" diff --git a/packages/permissionless/utils/getRequiredPrefund.ts b/packages/permissionless/utils/getRequiredPrefund.ts index f4a32b01..93497d5b 100644 --- a/packages/permissionless/utils/getRequiredPrefund.ts +++ b/packages/permissionless/utils/getRequiredPrefund.ts @@ -1,7 +1,9 @@ -import type { UserOperation } from "../types" +import type { EntryPoint, GetEntryPointVersion, UserOperation } from "../types" +import { ENTRYPOINT_ADDRESS_0_6 } from "./getEntryPointVersion" -export type GetRequiredPrefundReturnType = { - userOperation: UserOperation +export type GetRequiredPrefundReturnType = { + userOperation: UserOperation> + entryPoint: entryPoint } /** @@ -18,14 +20,36 @@ export type GetRequiredPrefundReturnType = { * userOperation * }) */ -export const getRequiredPrefund = ({ - userOperation -}: GetRequiredPrefundReturnType): bigint => { - const multiplier = userOperation.paymasterAndData.length > 2 ? 3n : 1n +export const getRequiredPrefund = ({ + userOperation, + entryPoint: entryPointAddress +}: GetRequiredPrefundReturnType): bigint => { + if (entryPointAddress === ENTRYPOINT_ADDRESS_0_6) { + const userOperationVersion0_6 = userOperation as UserOperation<"0.6"> + const multiplier = + userOperationVersion0_6.paymasterAndData.length > 2 ? 3n : 1n + const requiredGas = + userOperationVersion0_6.callGasLimit + + userOperationVersion0_6.verificationGasLimit * multiplier + + userOperationVersion0_6.preVerificationGas + + return ( + BigInt(requiredGas) * BigInt(userOperationVersion0_6.maxFeePerGas) + ) + } + + const userOperationVersion0_7 = userOperation as UserOperation<"0.7"> + const multiplier = userOperationVersion0_7.paymaster ? 3n : 1n + + const verificationGasLimit = + userOperationVersion0_7.verificationGasLimit + + (userOperationVersion0_7.paymasterPostOpGasLimit || 0n) + + (userOperationVersion0_7.paymasterVerificationGasLimit || 0n) + const requiredGas = - userOperation.callGasLimit + - userOperation.verificationGasLimit * multiplier + - userOperation.preVerificationGas + userOperationVersion0_7.callGasLimit + + verificationGasLimit * multiplier + + userOperationVersion0_7.preVerificationGas - return BigInt(requiredGas) * BigInt(userOperation.maxFeePerGas) + return BigInt(requiredGas) * BigInt(userOperationVersion0_7.maxFeePerGas) } diff --git a/packages/permissionless/utils/getUserOperationHash.ts b/packages/permissionless/utils/getUserOperationHash.ts index 106bc90d..5ef72213 100644 --- a/packages/permissionless/utils/getUserOperationHash.ts +++ b/packages/permissionless/utils/getUserOperationHash.ts @@ -1,10 +1,6 @@ import type { Address, Hash, Hex } from "viem" import { concat, encodeAbiParameters, keccak256, pad, toHex } from "viem" -import type { - DefaultEntryPoint, - EntryPoint, - GetEntryPointVersion -} from "../types" +import type { EntryPoint, GetEntryPointVersion } from "../types" import type { UserOperation } from "../types/userOperation" import { getEntryPointVersion } from "./getEntryPointVersion" @@ -154,9 +150,7 @@ export type GetUserOperationHashParams = { * // Returns "0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34" * */ -export const getUserOperationHash = < - entryPoint extends EntryPoint = DefaultEntryPoint ->({ +export const getUserOperationHash = ({ userOperation, entryPoint: entryPointAddress, chainId diff --git a/packages/permissionless/utils/signUserOperationHashWithECDSA.ts b/packages/permissionless/utils/signUserOperationHashWithECDSA.ts index dfccde5c..e7ab68cb 100644 --- a/packages/permissionless/utils/signUserOperationHashWithECDSA.ts +++ b/packages/permissionless/utils/signUserOperationHashWithECDSA.ts @@ -8,7 +8,6 @@ import { type Transport } from "viem" import type { - DefaultEntryPoint, EntryPoint, GetAccountParameterWithClient, GetEntryPointVersion @@ -18,7 +17,7 @@ import { parseAccount } from "./" import { getUserOperationHash } from "./getUserOperationHash" export type SignUserOperationHashWithECDSAParams< - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined @@ -78,7 +77,7 @@ export class AccountOrClientNotFoundError extends BaseError { * */ export const signUserOperationHashWithECDSA = async < - entryPoint extends EntryPoint = DefaultEntryPoint, + entryPoint extends EntryPoint, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends Account | undefined = Account | undefined From b73996685344095ef6d5924ca51b6ae1170f9563 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 13 Feb 2024 16:34:31 +0530 Subject: [PATCH 04/35] change ENTRYPOINT_ADDRESS_0_7 to ENTRYPOINT_ADDRESS_V07 --- .../permissionless-test/bundlerActions.test.ts | 12 ++++++------ packages/permissionless-test/utils.ts | 4 ++-- .../kernel/signerToEcdsaKernelSmartAccount.ts | 12 ++++++------ .../accounts/safe/signerToSafeSmartAccount.ts | 4 ++-- .../accounts/simple/signerToSimpleSmartAccount.ts | 12 ++++++------ .../actions/bundler/getUserOperationByHash.ts | 4 ++-- .../actions/pimlico/sponsorUserOperation.ts | 8 ++++---- .../actions/public/getSenderAddress.ts | 4 ++-- .../smartAccount/prepareUserOperationRequest.ts | 14 +++++++------- .../actions/smartAccount/sendUserOperation.ts | 4 ++-- .../actions/stackup/sponsorUserOperation.ts | 4 ++-- packages/permissionless/types/entrypoint.ts | 10 +++++----- packages/permissionless/types/index.ts | 4 ++-- packages/permissionless/types/stackup.ts | 6 +++--- .../permissionless/utils/getEntryPointVersion.ts | 10 +++++----- .../permissionless/utils/getRequiredPrefund.ts | 4 ++-- packages/permissionless/utils/index.ts | 8 ++++---- 17 files changed, 62 insertions(+), 62 deletions(-) diff --git a/packages/permissionless-test/bundlerActions.test.ts b/packages/permissionless-test/bundlerActions.test.ts index b7db166c..df6e3f0e 100644 --- a/packages/permissionless-test/bundlerActions.test.ts +++ b/packages/permissionless-test/bundlerActions.test.ts @@ -1,7 +1,7 @@ import dotenv from "dotenv" import { BundlerClient, - ENTRYPOINT_ADDRESS_0_7, + ENTRYPOINT_ADDRESS_V07, UserOperation, WaitForUserOperationReceiptTimeoutError, createBundlerClient, @@ -10,7 +10,7 @@ import { walletClientToSmartAccountSigner } from "permissionless" import { signerToSimpleSmartAccount } from "permissionless/accounts" -import { ENTRYPOINT_ADDRESS_0_7_TYPE } from "permissionless/types" +import { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" import { getUserOperationHash } from "permissionless/utils" import { http, Address, type Hash, parseEther } from "viem" import { privateKeyToAccount } from "viem/accounts" @@ -92,12 +92,12 @@ describe("BUNDLER ACTIONS", () => { const bundlerClient = createBundlerClient({ chain: getTestingChain(), transport: http(`${process.env.BUNDLER_RPC_HOST}`), - entryPoint: ENTRYPOINT_ADDRESS_0_7 + entryPoint: ENTRYPOINT_ADDRESS_V07 }) const simpleAccount = await signerToSimpleSmartAccount(publicClient, { signer: walletClientToSmartAccountSigner(eoaWalletClient), - entryPoint: ENTRYPOINT_ADDRESS_0_7, + entryPoint: ENTRYPOINT_ADDRESS_V07, factoryAddress: process.env.FACTORY_ADDRESS as Address }) @@ -108,7 +108,7 @@ describe("BUNDLER ACTIONS", () => { sponsorUserOperation: async (args) => { return args.userOperation }, - entryPoint: ENTRYPOINT_ADDRESS_0_7 + entryPoint: ENTRYPOINT_ADDRESS_V07 }) const userOperation = @@ -149,7 +149,7 @@ describe("BUNDLER ACTIONS", () => { expect(userOperationFromUserOpHash).not.toBeNull() expect(userOperationFromUserOpHash?.entryPoint).toBe( - ENTRYPOINT_ADDRESS_0_7 + ENTRYPOINT_ADDRESS_V07 ) expect(userOperationFromUserOpHash?.transactionHash).toBe( userOperationReceipt?.receipt.transactionHash diff --git a/packages/permissionless-test/utils.ts b/packages/permissionless-test/utils.ts index 5f1f67c5..05cee0dc 100644 --- a/packages/permissionless-test/utils.ts +++ b/packages/permissionless-test/utils.ts @@ -1,5 +1,5 @@ import { - ENTRYPOINT_ADDRESS_0_6, + ENTRYPOINT_ADDRESS_V06, createBundlerClient, createSmartAccountClient } from "permissionless" @@ -240,7 +240,7 @@ export const getEoaWalletClient = () => { export const getEntryPoint = () => { if (!process.env.ENTRYPOINT_ADDRESS) throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - return ENTRYPOINT_ADDRESS_0_6 + return ENTRYPOINT_ADDRESS_V06 } export const getPublicClient = async () => { diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index bbdd9a7d..40ed04d3 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -22,8 +22,8 @@ import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" import type { Prettify } from "../../types" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, - ENTRYPOINT_ADDRESS_0_7_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, EntryPoint } from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils" @@ -201,17 +201,17 @@ const getAccountAddress = async < const entryPointVersion = getEntryPointVersion(entryPointAddress) if (entryPointVersion === "0.6") { - return getSenderAddress(client, { + return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6_TYPE + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE }) } // Get the sender address based on the init code - return getSenderAddress(client, { + return getSenderAddress(client, { factory: factoryAddress, factoryData, - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7_TYPE + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V07_TYPE }) } diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index ed1bc5fb..811c2526 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -28,7 +28,7 @@ import { signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { ENTRYPOINT_ADDRESS_0_6_TYPE, Prettify } from "../../types" +import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import type { EntryPoint } from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" @@ -174,7 +174,7 @@ const encodeMultiSend = ( } export type SafeSmartAccount< - entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6_TYPE, + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V06_TYPE, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index a1b4adaf..d526dc42 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -15,8 +15,8 @@ import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, - ENTRYPOINT_ADDRESS_0_7_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, Prettify } from "../../types" import type { EntryPoint } from "../../types/entrypoint" @@ -92,17 +92,17 @@ const getAccountAddress = async < const factoryData = await getAccountInitCode(owner, index) if (entryPointVersion === "0.6") { - return getSenderAddress(client, { + return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_6_TYPE + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE }) } // Get the sender address based on the init code - return getSenderAddress(client, { + return getSenderAddress(client, { factory: factoryAddress, factoryData, - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_0_7_TYPE + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V07_TYPE }) } diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.ts index a29b7b45..97c0ee4c 100644 --- a/packages/permissionless/actions/bundler/getUserOperationByHash.ts +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.ts @@ -4,7 +4,7 @@ import type { Prettify } from "../../types/" import type { BundlerRpcSchema } from "../../types/bundler" import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { UserOperation } from "../../types/userOperation" -import { ENTRYPOINT_ADDRESS_0_6 } from "../../utils/getEntryPointVersion" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils/getEntryPointVersion" export type GetUserOperationByHashParameters = { hash: Hash @@ -67,7 +67,7 @@ export const getUserOperationByHash = async < } = response return { - userOperation: (entryPointAddress === ENTRYPOINT_ADDRESS_0_6 + userOperation: (entryPointAddress === ENTRYPOINT_ADDRESS_V06 ? { ...userOperation, nonce: BigInt(userOperation.nonce), diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts index 61660e90..06ca5ff5 100644 --- a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts @@ -2,7 +2,7 @@ import type { Account, Chain, Client, Transport } from "viem" import type { PartialBy } from "viem/types/utils" import type { Prettify } from "../../types/" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -12,12 +12,12 @@ import type { UserOperationWithBigIntAsHex } from "../../types/userOperation" import { deepHexlify } from "../../utils/deepHexlify" -import { ENTRYPOINT_ADDRESS_0_6 } from "../../utils/getEntryPointVersion" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils/getEntryPointVersion" export type PimlicoSponsorUserOperationParameters< entryPoint extends EntryPoint > = { - userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< UserOperation<"0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" @@ -101,7 +101,7 @@ export const sponsorUserOperation = async < }) const userOperation: SponsorUserOperationReturnType = ( - args.entryPoint === ENTRYPOINT_ADDRESS_0_6 + args.entryPoint === ENTRYPOINT_ADDRESS_V06 ? { ...args.userOperation, paymasterAndData: response.paymasterAndData, diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 568f102f..28146138 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -13,13 +13,13 @@ import { import { simulateContract } from "viem/actions" import type { Prettify } from "../../types/" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint } from "../../types/entrypoint" import { getAction } from "../../utils/getAction" export type GetSenderAddressParams = - entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? { initCode: Hex entryPoint: entryPoint diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index c48a3801..d1177b5d 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -9,8 +9,8 @@ import type { } from "../../types/" import type { StateOverrides } from "../../types/bundler" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, - ENTRYPOINT_ADDRESS_0_7_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -32,7 +32,7 @@ export type PrepareUserOperationRequestParameters< | SmartAccount | undefined > = { - userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< UserOperation<"0.6">, | "sender" @@ -71,7 +71,7 @@ export type PrepareUserOperationRequestReturnType< > = UserOperation> async function prepareUserOperationRequestEntryPointVersion0_6< - entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_6_TYPE, + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = @@ -91,7 +91,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< const account = parseAccount( account_ - ) as SmartAccount + ) as SmartAccount const [sender, nonce, initCode, callData, gasEstimation] = await Promise.all([ @@ -166,7 +166,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< } async function prepareUserOperationRequestEntryPointVersion0_7< - entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_0_7_TYPE, + entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V07_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartAccount | undefined = @@ -186,7 +186,7 @@ async function prepareUserOperationRequestEntryPointVersion0_7< const account = parseAccount( account_ - ) as SmartAccount + ) as SmartAccount const [sender, nonce, factory, factoryData, callData, gasEstimation] = await Promise.all([ diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.ts index 38d173d0..6510163b 100644 --- a/packages/permissionless/actions/smartAccount/sendUserOperation.ts +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.ts @@ -7,7 +7,7 @@ import type { UserOperation } from "../../types/" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -25,7 +25,7 @@ export type SendUserOperationParameters< | SmartAccount | undefined > = { - userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< UserOperation<"0.6">, | "sender" diff --git a/packages/permissionless/actions/stackup/sponsorUserOperation.ts b/packages/permissionless/actions/stackup/sponsorUserOperation.ts index 8455bfb3..50363abe 100644 --- a/packages/permissionless/actions/stackup/sponsorUserOperation.ts +++ b/packages/permissionless/actions/stackup/sponsorUserOperation.ts @@ -1,7 +1,7 @@ import type { PartialBy } from "viem/types/utils" import { type StackupPaymasterClient } from "../../clients/stackup" import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" @@ -11,7 +11,7 @@ import { deepHexlify } from "../../utils/deepHexlify" import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type SponsorUserOperationParameters = { - userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< UserOperation<"0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" diff --git a/packages/permissionless/types/entrypoint.ts b/packages/permissionless/types/entrypoint.ts index 9713afe1..829578d2 100644 --- a/packages/permissionless/types/entrypoint.ts +++ b/packages/permissionless/types/entrypoint.ts @@ -1,13 +1,13 @@ export type EntryPointVersion = "0.6" | "0.7" -export type ENTRYPOINT_ADDRESS_0_6_TYPE = +export type ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" -export type ENTRYPOINT_ADDRESS_0_7_TYPE = +export type ENTRYPOINT_ADDRESS_V07_TYPE = "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" export type GetEntryPointVersion = - entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE ? "0.6" : "0.7" + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? "0.6" : "0.7" export type EntryPoint = - | ENTRYPOINT_ADDRESS_0_6_TYPE - | ENTRYPOINT_ADDRESS_0_7_TYPE + | ENTRYPOINT_ADDRESS_V06_TYPE + | ENTRYPOINT_ADDRESS_V07_TYPE diff --git a/packages/permissionless/types/index.ts b/packages/permissionless/types/index.ts index 31628766..34924410 100644 --- a/packages/permissionless/types/index.ts +++ b/packages/permissionless/types/index.ts @@ -6,8 +6,8 @@ import type { UserOperation } from "./userOperation" export type { UserOperation } export type { EntryPointVersion, - ENTRYPOINT_ADDRESS_0_6_TYPE, - ENTRYPOINT_ADDRESS_0_7_TYPE, + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, GetEntryPointVersion, EntryPoint } from "./entrypoint" diff --git a/packages/permissionless/types/stackup.ts b/packages/permissionless/types/stackup.ts index f58927b6..d70ed8fb 100644 --- a/packages/permissionless/types/stackup.ts +++ b/packages/permissionless/types/stackup.ts @@ -1,6 +1,6 @@ import type { Address, Hex } from "viem" import type { PartialBy } from "viem/types/utils" -import type { ENTRYPOINT_ADDRESS_0_6_TYPE, EntryPoint } from "./entrypoint" +import type { ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint } from "./entrypoint" import type { UserOperationWithBigIntAsHex } from "./userOperation" interface StackupPaymasterContextType { @@ -15,7 +15,7 @@ export type StackupPaymasterRpcSchema = [ { Method: "pm_sponsorUserOperation" Parameters: [ - userOperation: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< UserOperationWithBigIntAsHex<"0.6">, | "callGasLimit" @@ -33,7 +33,7 @@ export type StackupPaymasterRpcSchema = [ entryPoint: entryPoint, context: StackupPaymasterContext ] - ReturnType: entryPoint extends ENTRYPOINT_ADDRESS_0_6_TYPE + ReturnType: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? { paymasterAndData: Hex preVerificationGas: Hex diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts index 2c8f19da..726060ae 100644 --- a/packages/permissionless/utils/getEntryPointVersion.ts +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -1,15 +1,15 @@ import type { - ENTRYPOINT_ADDRESS_0_6_TYPE, - ENTRYPOINT_ADDRESS_0_7_TYPE + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE } from "../types" import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" -export const ENTRYPOINT_ADDRESS_0_6: ENTRYPOINT_ADDRESS_0_6_TYPE = +export const ENTRYPOINT_ADDRESS_V06: ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" -export const ENTRYPOINT_ADDRESS_0_7: ENTRYPOINT_ADDRESS_0_7_TYPE = +export const ENTRYPOINT_ADDRESS_V07: ENTRYPOINT_ADDRESS_V07_TYPE = "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" export const getEntryPointVersion = ( entryPoint: EntryPoint ): GetEntryPointVersion => - entryPoint === ENTRYPOINT_ADDRESS_0_6 ? "0.6" : "0.7" + entryPoint === ENTRYPOINT_ADDRESS_V06 ? "0.6" : "0.7" diff --git a/packages/permissionless/utils/getRequiredPrefund.ts b/packages/permissionless/utils/getRequiredPrefund.ts index 93497d5b..f0548434 100644 --- a/packages/permissionless/utils/getRequiredPrefund.ts +++ b/packages/permissionless/utils/getRequiredPrefund.ts @@ -1,5 +1,5 @@ import type { EntryPoint, GetEntryPointVersion, UserOperation } from "../types" -import { ENTRYPOINT_ADDRESS_0_6 } from "./getEntryPointVersion" +import { ENTRYPOINT_ADDRESS_V06 } from "./getEntryPointVersion" export type GetRequiredPrefundReturnType = { userOperation: UserOperation> @@ -24,7 +24,7 @@ export const getRequiredPrefund = ({ userOperation, entryPoint: entryPointAddress }: GetRequiredPrefundReturnType): bigint => { - if (entryPointAddress === ENTRYPOINT_ADDRESS_0_6) { + if (entryPointAddress === ENTRYPOINT_ADDRESS_V06) { const userOperationVersion0_6 = userOperation as UserOperation<"0.6"> const multiplier = userOperationVersion0_6.paymasterAndData.length > 2 ? 3n : 1n diff --git a/packages/permissionless/utils/index.ts b/packages/permissionless/utils/index.ts index 2fd84e49..e38a6e41 100644 --- a/packages/permissionless/utils/index.ts +++ b/packages/permissionless/utils/index.ts @@ -25,8 +25,8 @@ export function parseAccount(account: Address | Account): Account { return account } import { - ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7, + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07, getEntryPointVersion } from "./getEntryPointVersion" @@ -46,6 +46,6 @@ export { providerToSmartAccountSigner, getAddressFromInitCodeOrPaymasterAndData, getEntryPointVersion, - ENTRYPOINT_ADDRESS_0_6, - ENTRYPOINT_ADDRESS_0_7 + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07 } From 01b822b0fd45bc1d52bff3e40108a8feadbb5d56 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 17 Feb 2024 13:10:18 +0530 Subject: [PATCH 05/35] remove skip for test and change 0.6 to v0.6 --- .../bundlerActions.test.ts | 8 +++---- .../kernel/signerToEcdsaKernelSmartAccount.ts | 2 +- .../accounts/safe/signerToSafeSmartAccount.ts | 2 +- .../simple/signerToSimpleSmartAccount.ts | 2 +- .../bundler/estimateUserOperationGas.ts | 6 +++--- .../actions/pimlico/sponsorUserOperation.ts | 4 ++-- .../prepareUserOperationRequest.ts | 21 +++++++++---------- .../actions/smartAccount/sendUserOperation.ts | 4 ++-- .../actions/stackup/sponsorUserOperation.ts | 6 +++--- packages/permissionless/types/bundler.ts | 6 +++--- packages/permissionless/types/entrypoint.ts | 4 ++-- packages/permissionless/types/pimlico.ts | 8 +++---- packages/permissionless/types/stackup.ts | 4 ++-- .../permissionless/types/userOperation.ts | 4 ++-- .../utils/getEntryPointVersion.ts | 2 +- .../utils/getRequiredPrefund.ts | 4 ++-- .../utils/getUserOperationHash.ts | 6 +++--- 17 files changed, 46 insertions(+), 47 deletions(-) diff --git a/packages/permissionless-test/bundlerActions.test.ts b/packages/permissionless-test/bundlerActions.test.ts index df6e3f0e..bf0ef6fc 100644 --- a/packages/permissionless-test/bundlerActions.test.ts +++ b/packages/permissionless-test/bundlerActions.test.ts @@ -53,7 +53,7 @@ describe("BUNDLER ACTIONS", () => { bundlerClient = getBundlerClient() }) - test.skip("Supported entry points request", async () => { + test("Supported entry points request", async () => { const supportedEntryPoints = await bundlerClient.supportedEntryPoints() expectTypeOf(supportedEntryPoints).toBeArray() @@ -61,7 +61,7 @@ describe("BUNDLER ACTIONS", () => { expect(supportedEntryPoints.includes(getEntryPoint())).toBe(true) }) - test.skip("Chain id call", async () => { + test("Chain id call", async () => { const chainId = await bundlerClient.chainId() const chain = getTestingChain() @@ -70,7 +70,7 @@ describe("BUNDLER ACTIONS", () => { expect(chainId === chain.id).toBe(true) }) - test.skip("Estimate user operation gas", async () => { + test("Estimate user operation gas", async () => { const eoaWalletClient = getEoaWalletClient() const userOperation = await buildUserOp(eoaWalletClient) @@ -170,7 +170,7 @@ describe("BUNDLER ACTIONS", () => { // expect(newNonce).toBe(userOperation.nonce + BigInt(1)) }, 100000) - test.skip("wait for user operation receipt fail", async () => { + test("wait for user operation receipt fail", async () => { const eoaWalletClient = getEoaWalletClient() const userOperation = await buildUserOp(eoaWalletClient) diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 40ed04d3..b5dd9e6d 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -200,7 +200,7 @@ const getAccountAddress = async < const entryPointVersion = getEntryPointVersion(entryPointAddress) - if (entryPointVersion === "0.6") { + if (entryPointVersion === "v0.6") { return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index 811c2526..bc97d09b 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -549,7 +549,7 @@ export async function signerToSafeSmartAccount< ): Promise> { const entryPointVersion = getEntryPointVersion(entryPointAddress) - if (entryPointVersion !== "0.6") { + if (entryPointVersion !== "v0.6") { throw new Error("Only EntryPoint 0.6 is supported") } diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index d526dc42..68236ea5 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -91,7 +91,7 @@ const getAccountAddress = async < const factoryData = await getAccountInitCode(owner, index) - if (entryPointVersion === "0.6") { + if (entryPointVersion === "v0.6") { return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index 3f474972..1c8a7185 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -19,13 +19,13 @@ import { export type EstimateUserOperationGasParameters = { - userOperation: GetEntryPointVersion extends "0.6" + userOperation: GetEntryPointVersion extends "v0.6" ? PartialBy< - UserOperation<"0.6">, + UserOperation<"v0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" > : PartialBy< - UserOperation<"0.7">, + UserOperation<"v0.7">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts index 06ca5ff5..5630b896 100644 --- a/packages/permissionless/actions/pimlico/sponsorUserOperation.ts +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.ts @@ -19,11 +19,11 @@ export type PimlicoSponsorUserOperationParameters< > = { userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< - UserOperation<"0.6">, + UserOperation<"v0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" > : PartialBy< - UserOperation<"0.7">, + UserOperation<"v0.7">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index d1177b5d..856be55f 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -34,7 +34,7 @@ export type PrepareUserOperationRequestParameters< > = { userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< - UserOperation<"0.6">, + UserOperation<"v0.6">, | "sender" | "nonce" | "initCode" @@ -47,7 +47,7 @@ export type PrepareUserOperationRequestParameters< | "signature" > : PartialBy< - UserOperation<"0.7">, + UserOperation<"v0.7">, | "sender" | "nonce" | "factory" @@ -70,7 +70,7 @@ export type PrepareUserOperationRequestReturnType< entryPoint extends EntryPoint > = UserOperation> -async function prepareUserOperationRequestEntryPointVersion0_6< +async function prepareUserOperationRequestForEntryPointV0_6< entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, @@ -105,7 +105,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< : undefined ]) - let userOperation: UserOperation<"0.6"> = { + let userOperation: UserOperation<"v0.6"> = { sender, nonce, initCode, @@ -136,7 +136,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< } as { userOperation: UserOperation> entryPoint: entryPoint - })) as UserOperation<"0.6"> + })) as UserOperation<"v0.6"> } else if ( !userOperation.callGasLimit || !userOperation.verificationGasLimit || @@ -153,8 +153,7 @@ async function prepareUserOperationRequestEntryPointVersion0_6< stateOverrides ) - userOperation.callGasLimit = - userOperation.callGasLimit || gasParameters.callGasLimit + userOperation.callGasLimit |= gasParameters.callGasLimit userOperation.verificationGasLimit = userOperation.verificationGasLimit || gasParameters.verificationGasLimit @@ -201,7 +200,7 @@ async function prepareUserOperationRequestEntryPointVersion0_7< : undefined ]) - let userOperation: UserOperation<"0.7"> = { + let userOperation: UserOperation<"v0.7"> = { sender, nonce, factory: factory || undefined, @@ -236,7 +235,7 @@ async function prepareUserOperationRequestEntryPointVersion0_7< } as { userOperation: UserOperation> entryPoint: entryPoint - })) as UserOperation<"0.7"> + })) as UserOperation<"v0.7"> } else if ( !userOperation.callGasLimit || !userOperation.verificationGasLimit || @@ -284,8 +283,8 @@ export async function prepareUserOperationRequest< const entryPointVersion = getEntryPointVersion(account.entryPoint) - if (entryPointVersion === "0.6") { - return prepareUserOperationRequestEntryPointVersion0_6( + if (entryPointVersion === "v0.6") { + return prepareUserOperationRequestForEntryPointV0_6( client, args, stateOverrides diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.ts index 6510163b..9f49cdb5 100644 --- a/packages/permissionless/actions/smartAccount/sendUserOperation.ts +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.ts @@ -27,7 +27,7 @@ export type SendUserOperationParameters< > = { userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< - UserOperation<"0.6">, + UserOperation<"v0.6">, | "sender" | "nonce" | "initCode" @@ -40,7 +40,7 @@ export type SendUserOperationParameters< | "signature" > : PartialBy< - UserOperation<"0.7">, + UserOperation<"v0.7">, | "sender" | "nonce" | "factory" diff --git a/packages/permissionless/actions/stackup/sponsorUserOperation.ts b/packages/permissionless/actions/stackup/sponsorUserOperation.ts index 50363abe..ef485c37 100644 --- a/packages/permissionless/actions/stackup/sponsorUserOperation.ts +++ b/packages/permissionless/actions/stackup/sponsorUserOperation.ts @@ -13,11 +13,11 @@ import { getEntryPointVersion } from "../../utils/getEntryPointVersion" export type SponsorUserOperationParameters = { userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< - UserOperation<"0.6">, + UserOperation<"v0.6">, "callGasLimit" | "preVerificationGas" | "verificationGasLimit" > : PartialBy< - UserOperation<"0.7">, + UserOperation<"v0.7">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" @@ -68,7 +68,7 @@ export const sponsorUserOperation = async ( const entryPointVersion = getEntryPointVersion(args.entryPoint) const userOperation: SponsorUserOperationReturnType = ( - entryPointVersion === "0.6" + entryPointVersion === "v0.6" ? { ...args.userOperation, paymasterAndData: response.paymasterAndData, diff --git a/packages/permissionless/types/bundler.ts b/packages/permissionless/types/bundler.ts index fce3be8d..5596a551 100644 --- a/packages/permissionless/types/bundler.ts +++ b/packages/permissionless/types/bundler.ts @@ -17,15 +17,15 @@ export type BundlerRpcSchema = [ { Method: "eth_estimateUserOperationGas" Parameters: [ - userOperation: GetEntryPointVersion extends "0.6" + userOperation: GetEntryPointVersion extends "v0.6" ? PartialBy< - UserOperationWithBigIntAsHex<"0.6">, + UserOperationWithBigIntAsHex<"v0.6">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" > : PartialBy< - UserOperationWithBigIntAsHex<"0.7">, + UserOperationWithBigIntAsHex<"v0.7">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" diff --git a/packages/permissionless/types/entrypoint.ts b/packages/permissionless/types/entrypoint.ts index 829578d2..22acacd6 100644 --- a/packages/permissionless/types/entrypoint.ts +++ b/packages/permissionless/types/entrypoint.ts @@ -1,4 +1,4 @@ -export type EntryPointVersion = "0.6" | "0.7" +export type EntryPointVersion = "v0.6" | "v0.7" export type ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" @@ -6,7 +6,7 @@ export type ENTRYPOINT_ADDRESS_V07_TYPE = "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" export type GetEntryPointVersion = - entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? "0.6" : "0.7" + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? "v0.6" : "v0.7" export type EntryPoint = | ENTRYPOINT_ADDRESS_V06_TYPE diff --git a/packages/permissionless/types/pimlico.ts b/packages/permissionless/types/pimlico.ts index 341b05d6..839044ed 100644 --- a/packages/permissionless/types/pimlico.ts +++ b/packages/permissionless/types/pimlico.ts @@ -56,15 +56,15 @@ export type PimlicoPaymasterRpcSchema = [ { Method: "pm_sponsorUserOperation" Parameters: [ - userOperation: GetEntryPointVersion extends "0.6" + userOperation: GetEntryPointVersion extends "v0.6" ? PartialBy< - UserOperationWithBigIntAsHex<"0.6">, + UserOperationWithBigIntAsHex<"v0.6">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" > : PartialBy< - UserOperationWithBigIntAsHex<"0.7">, + UserOperationWithBigIntAsHex<"v0.7">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" @@ -76,7 +76,7 @@ export type PimlicoPaymasterRpcSchema = [ sponsorshipPolicyId?: string } ] - ReturnType: GetEntryPointVersion extends "0.6" + ReturnType: GetEntryPointVersion extends "v0.6" ? { paymasterAndData: Hex preVerificationGas: Hex diff --git a/packages/permissionless/types/stackup.ts b/packages/permissionless/types/stackup.ts index d70ed8fb..197a95f6 100644 --- a/packages/permissionless/types/stackup.ts +++ b/packages/permissionless/types/stackup.ts @@ -17,13 +17,13 @@ export type StackupPaymasterRpcSchema = [ Parameters: [ userOperation: entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? PartialBy< - UserOperationWithBigIntAsHex<"0.6">, + UserOperationWithBigIntAsHex<"v0.6">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" > : PartialBy< - UserOperationWithBigIntAsHex<"0.7">, + UserOperationWithBigIntAsHex<"v0.7">, | "callGasLimit" | "preVerificationGas" | "verificationGasLimit" diff --git a/packages/permissionless/types/userOperation.ts b/packages/permissionless/types/userOperation.ts index 525b6309..139879c4 100644 --- a/packages/permissionless/types/userOperation.ts +++ b/packages/permissionless/types/userOperation.ts @@ -6,7 +6,7 @@ export type TStatus = "success" | "reverted" export type UserOperationWithBigIntAsHex< entryPointVersion extends EntryPointVersion -> = entryPointVersion extends "0.6" +> = entryPointVersion extends "v0.6" ? { sender: Address nonce: Hex @@ -47,7 +47,7 @@ export type UserOperationWithBigIntAsHex< } export type UserOperation = - entryPointVersion extends "0.6" + entryPointVersion extends "v0.6" ? { sender: Address nonce: bigint diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts index 726060ae..c64b3570 100644 --- a/packages/permissionless/utils/getEntryPointVersion.ts +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -12,4 +12,4 @@ export const ENTRYPOINT_ADDRESS_V07: ENTRYPOINT_ADDRESS_V07_TYPE = export const getEntryPointVersion = ( entryPoint: EntryPoint ): GetEntryPointVersion => - entryPoint === ENTRYPOINT_ADDRESS_V06 ? "0.6" : "0.7" + entryPoint === ENTRYPOINT_ADDRESS_V06 ? "v0.6" : "v0.7" diff --git a/packages/permissionless/utils/getRequiredPrefund.ts b/packages/permissionless/utils/getRequiredPrefund.ts index f0548434..f8f125ae 100644 --- a/packages/permissionless/utils/getRequiredPrefund.ts +++ b/packages/permissionless/utils/getRequiredPrefund.ts @@ -25,7 +25,7 @@ export const getRequiredPrefund = ({ entryPoint: entryPointAddress }: GetRequiredPrefundReturnType): bigint => { if (entryPointAddress === ENTRYPOINT_ADDRESS_V06) { - const userOperationVersion0_6 = userOperation as UserOperation<"0.6"> + const userOperationVersion0_6 = userOperation as UserOperation<"v0.6"> const multiplier = userOperationVersion0_6.paymasterAndData.length > 2 ? 3n : 1n const requiredGas = @@ -38,7 +38,7 @@ export const getRequiredPrefund = ({ ) } - const userOperationVersion0_7 = userOperation as UserOperation<"0.7"> + const userOperationVersion0_7 = userOperation as UserOperation<"v0.7"> const multiplier = userOperationVersion0_7.paymaster ? 3n : 1n const verificationGasLimit = diff --git a/packages/permissionless/utils/getUserOperationHash.ts b/packages/permissionless/utils/getUserOperationHash.ts index 5ef72213..9cbc6fd3 100644 --- a/packages/permissionless/utils/getUserOperationHash.ts +++ b/packages/permissionless/utils/getUserOperationHash.ts @@ -13,8 +13,8 @@ function packUserOp({ }): Hex { const entryPointVersion = getEntryPointVersion(entryPointAddress) - if (entryPointVersion === "0.6") { - const userOperationVersion0_6 = userOperation as UserOperation<"0.6"> + if (entryPointVersion === "v0.6") { + const userOperationVersion0_6 = userOperation as UserOperation<"v0.6"> const hashedInitCode = keccak256(userOperationVersion0_6.initCode) const hashedCallData = keccak256(userOperationVersion0_6.callData) const hashedPaymasterAndData = keccak256( @@ -49,7 +49,7 @@ function packUserOp({ ) } - const userOperationVersion0_7 = userOperation as UserOperation<"0.7"> + const userOperationVersion0_7 = userOperation as UserOperation<"v0.7"> const hashedInitCode = userOperationVersion0_7.factory && userOperationVersion0_7.factoryData ? keccak256( From 7ea8793c5f8f4fa96dd8457feba29124f0ccc59b Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Tue, 20 Feb 2024 11:54:29 +0530 Subject: [PATCH 06/35] update entryPoint and fix errors --- .../prepareUserOperationRequest.ts | 12 ++-- packages/permissionless/types/entrypoint.ts | 2 +- .../permissionless/types/userOperation.ts | 12 ++-- .../utils/getEntryPointVersion.ts | 2 +- .../utils/getUserOperationHash.ts | 57 ++++++++----------- 5 files changed, 39 insertions(+), 46 deletions(-) diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index 856be55f..b394dd57 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -203,8 +203,8 @@ async function prepareUserOperationRequestEntryPointVersion0_7< let userOperation: UserOperation<"v0.7"> = { sender, nonce, - factory: factory || undefined, - factoryData: factoryData || undefined, + factory: factory || null, + factoryData: factoryData || null, callData, callGasLimit: partialUserOperation.callGasLimit || 0n, verificationGasLimit: partialUserOperation.verificationGasLimit || 0n, @@ -217,10 +217,10 @@ async function prepareUserOperationRequestEntryPointVersion0_7< partialUserOperation.maxPriorityFeePerGas || gasEstimation?.maxPriorityFeePerGas || 0n, - paymaster: undefined, - paymasterVerificationGasLimit: undefined, - paymasterPostOpGasLimit: undefined, - paymasterData: "0x", + paymaster: null, + paymasterVerificationGasLimit: null, + paymasterPostOpGasLimit: null, + paymasterData: null, signature: partialUserOperation.signature || "0x" } diff --git a/packages/permissionless/types/entrypoint.ts b/packages/permissionless/types/entrypoint.ts index 22acacd6..9ca8a3e6 100644 --- a/packages/permissionless/types/entrypoint.ts +++ b/packages/permissionless/types/entrypoint.ts @@ -3,7 +3,7 @@ export type EntryPointVersion = "v0.6" | "v0.7" export type ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" export type ENTRYPOINT_ADDRESS_V07_TYPE = - "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" + "0x7547CAC84A1eF4E6FA8bF83cD89404e7BFB72A4d" export type GetEntryPointVersion = entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? "v0.6" : "v0.7" diff --git a/packages/permissionless/types/userOperation.ts b/packages/permissionless/types/userOperation.ts index 139879c4..282b2a28 100644 --- a/packages/permissionless/types/userOperation.ts +++ b/packages/permissionless/types/userOperation.ts @@ -70,18 +70,18 @@ export type UserOperation = : { sender: Address nonce: bigint - factory?: Address - factoryData?: Hex + factory: Address | null + factoryData: Hex | null callData: Hex callGasLimit: bigint verificationGasLimit: bigint preVerificationGas: bigint maxFeePerGas: bigint maxPriorityFeePerGas: bigint - paymaster?: Address - paymasterVerificationGasLimit?: bigint - paymasterPostOpGasLimit?: bigint - paymasterData?: Hex + paymaster: Address | null + paymasterVerificationGasLimit: bigint | null + paymasterPostOpGasLimit: bigint | null + paymasterData: Hex | null signature: Hex initCode?: never paymasterAndData?: never diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts index c64b3570..ebf5815a 100644 --- a/packages/permissionless/utils/getEntryPointVersion.ts +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -7,7 +7,7 @@ import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" export const ENTRYPOINT_ADDRESS_V06: ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" export const ENTRYPOINT_ADDRESS_V07: ENTRYPOINT_ADDRESS_V07_TYPE = - "0xA959db6F3798192dC21BdFa6C46B6AD8D1b7eDa3" + "0x7547CAC84A1eF4E6FA8bF83cD89404e7BFB72A4d" export const getEntryPointVersion = ( entryPoint: EntryPoint diff --git a/packages/permissionless/utils/getUserOperationHash.ts b/packages/permissionless/utils/getUserOperationHash.ts index 9cbc6fd3..343fe93c 100644 --- a/packages/permissionless/utils/getUserOperationHash.ts +++ b/packages/permissionless/utils/getUserOperationHash.ts @@ -50,44 +50,37 @@ function packUserOp({ } const userOperationVersion0_7 = userOperation as UserOperation<"v0.7"> - const hashedInitCode = + const hashedInitCode = keccak256( userOperationVersion0_7.factory && userOperationVersion0_7.factoryData - ? keccak256( - concat([ - userOperationVersion0_7.factory, - userOperationVersion0_7.factoryData - ]) - ) + ? concat([ + userOperationVersion0_7.factory, + userOperationVersion0_7.factoryData + ]) : "0x" + ) const hashedCallData = keccak256(userOperationVersion0_7.callData) - const hashedPaymasterAndData = + const hashedPaymasterAndData = keccak256( userOperationVersion0_7.paymaster && - userOperationVersion0_7.paymasterVerificationGasLimit && - userOperationVersion0_7.paymasterPostOpGasLimit && - userOperationVersion0_7.paymasterData - ? keccak256( - concat([ - userOperationVersion0_7.paymaster, - pad( - toHex( - userOperationVersion0_7.paymasterVerificationGasLimit - ), - { - size: 16 - } - ), - pad( - toHex( - userOperationVersion0_7.paymasterPostOpGasLimit - ), - { - size: 16 - } + userOperationVersion0_7.paymasterVerificationGasLimit && + userOperationVersion0_7.paymasterPostOpGasLimit && + userOperationVersion0_7.paymasterData + ? concat([ + userOperationVersion0_7.paymaster, + pad( + toHex( + userOperationVersion0_7.paymasterVerificationGasLimit ), - userOperationVersion0_7.paymasterData - ]) - ) + { + size: 16 + } + ), + pad(toHex(userOperationVersion0_7.paymasterPostOpGasLimit), { + size: 16 + }), + userOperationVersion0_7.paymasterData + ]) : "0x" + ) return encodeAbiParameters( [ From bfbce2d959735337eacf2163fc00f37ae36ae7a7 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Thu, 22 Feb 2024 13:26:04 +0530 Subject: [PATCH 07/35] make test 0.6 compliant --- .../biconomySmartaccount.test.ts | 53 ++++++++++++-- .../bundlerActions.test.ts | 71 +++++++++++++++---- .../ecdsaKernelAccount.test.ts | 57 ++++++++++++--- packages/permissionless-test/index.test.ts | 19 ++--- .../pimlicoActions.test.ts | 12 ++-- .../safeSmartAccount.test.ts | 42 ++++++++++- .../permissionless-test/simpleAccount.test.ts | 70 ++++++++++++++---- packages/permissionless-test/userOp.ts | 6 +- packages/permissionless-test/utils.ts | 36 +++++++--- .../walletClientToCustomSigner.test.ts | 55 ++++++++++++-- 10 files changed, 347 insertions(+), 74 deletions(-) diff --git a/packages/permissionless-test/biconomySmartaccount.test.ts b/packages/permissionless-test/biconomySmartaccount.test.ts index b61fdab9..d8fdb7bc 100644 --- a/packages/permissionless-test/biconomySmartaccount.test.ts +++ b/packages/permissionless-test/biconomySmartaccount.test.ts @@ -1,21 +1,42 @@ import dotenv from "dotenv" -import { UserOperation } from "permissionless" import { SignTransactionNotSupportedBySmartAccount, signerToBiconomySmartAccount } from "permissionless/accounts" -import { Address, Hex, decodeEventLog, getContract, zeroAddress } from "viem" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" import { privateKeyToAccount } from "viem/accounts" -import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" import { EntryPointAbi } from "./abis/EntryPoint" import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" import { getBundlerClient, getEntryPoint, getPimlicoPaymasterClient, + getPrivateKeyAccount, getPublicClient, getSignerToBiconomyAccount, getSmartAccountClient, + getTestingChain, + refillSmartAccount, waitForNonceUpdate } from "./utils" @@ -40,6 +61,17 @@ beforeAll(() => { * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) */ describe("Biconomy Modular Smart Account (ECDSA module)", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + test("Account address", async () => { const ecdsaSmartAccount = await getSignerToBiconomyAccount() @@ -118,6 +150,11 @@ describe("Biconomy Modular Smart Account (ECDSA module)", () => { account: await getSignerToBiconomyAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransactions({ transactions: [ { @@ -142,6 +179,10 @@ describe("Biconomy Modular Smart Account (ECDSA module)", () => { const smartAccountClient = await getSmartAccountClient({ account: await getSignerToBiconomyAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const entryPointContract = getContract({ abi: EntryPointAbi, @@ -185,7 +226,7 @@ describe("Biconomy Modular Smart Account (ECDSA module)", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, @@ -248,7 +289,7 @@ describe("Biconomy Modular Smart Account (ECDSA module)", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, @@ -316,7 +357,7 @@ describe("Biconomy Modular Smart Account (ECDSA module)", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, diff --git a/packages/permissionless-test/bundlerActions.test.ts b/packages/permissionless-test/bundlerActions.test.ts index bf0ef6fc..d6685f4d 100644 --- a/packages/permissionless-test/bundlerActions.test.ts +++ b/packages/permissionless-test/bundlerActions.test.ts @@ -10,9 +10,20 @@ import { walletClientToSmartAccountSigner } from "permissionless" import { signerToSimpleSmartAccount } from "permissionless/accounts" -import { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" +import { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { getUserOperationHash } from "permissionless/utils" -import { http, Address, type Hash, parseEther } from "viem" +import { + http, + Account, + Address, + Chain, + type Hash, + Transport, + WalletClient, + createWalletClient, + parseEther, + zeroAddress +} from "viem" import { privateKeyToAccount } from "viem/accounts" import { beforeAll, @@ -27,9 +38,11 @@ import { getBundlerClient, getEntryPoint, getEoaWalletClient, + getPrivateKeyAccount, getPublicClient, getSignerToSimpleSmartAccount, getTestingChain, + refillSmartAccount, waitForNonceUpdate } from "./utils" @@ -47,13 +60,20 @@ beforeAll(() => { }) describe("BUNDLER ACTIONS", () => { - let bundlerClient: BundlerClient + let bundlerClient: BundlerClient + let walletClient: WalletClient beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) bundlerClient = getBundlerClient() }) - test("Supported entry points request", async () => { + test.skip("Supported entry points request", async () => { const supportedEntryPoints = await bundlerClient.supportedEntryPoints() expectTypeOf(supportedEntryPoints).toBeArray() @@ -61,7 +81,7 @@ describe("BUNDLER ACTIONS", () => { expect(supportedEntryPoints.includes(getEntryPoint())).toBe(true) }) - test("Chain id call", async () => { + test.skip("Chain id call", async () => { const chainId = await bundlerClient.chainId() const chain = getTestingChain() @@ -71,21 +91,38 @@ describe("BUNDLER ACTIONS", () => { }) test("Estimate user operation gas", async () => { + const publicClient = await getPublicClient() + const eoaWalletClient = getEoaWalletClient() - const userOperation = await buildUserOp(eoaWalletClient) + const simpleAccount = await signerToSimpleSmartAccount(publicClient, { + signer: privateKeyToAccount( + process.env.TEST_PRIVATE_KEY as Address + ), + entryPoint: getEntryPoint(), + factoryAddress: process.env.FACTORY_ADDRESS as Address, + index: 3n + }) - const gasParameters = await bundlerClient.estimateUserOperationGas({ - userOperation, + const smartAccountClient = createSmartAccountClient({ + account: simpleAccount, + chain: getTestingChain(), + transport: http(`${process.env.BUNDLER_RPC_HOST}`), entryPoint: getEntryPoint() }) - expect(gasParameters.callGasLimit).toBeGreaterThan(BigInt(0)) - expect(gasParameters.verificationGasLimit).toBeGreaterThan(BigInt(0)) - expect(gasParameters.preVerificationGas).toBeGreaterThan(BigInt(0)) + await eoaWalletClient.sendTransaction({ + to: simpleAccount.address, + value: parseEther("1") + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n + }) }) - test("Sending user operation", async () => { + test.skip("Sending user operation", async () => { const publicClient = await getPublicClient() const eoaWalletClient = getEoaWalletClient() @@ -111,6 +148,11 @@ describe("BUNDLER ACTIONS", () => { entryPoint: ENTRYPOINT_ADDRESS_V07 }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const userOperation = await smartAccountClient.prepareUserOperationRequest({ userOperation: { @@ -170,7 +212,7 @@ describe("BUNDLER ACTIONS", () => { // expect(newNonce).toBe(userOperation.nonce + BigInt(1)) }, 100000) - test("wait for user operation receipt fail", async () => { + test.skip("wait for user operation receipt fail", async () => { const eoaWalletClient = getEoaWalletClient() const userOperation = await buildUserOp(eoaWalletClient) @@ -178,8 +220,7 @@ describe("BUNDLER ACTIONS", () => { const chain = getTestingChain() const gasParameters = await bundlerClient.estimateUserOperationGas({ - userOperation, - entryPoint: getEntryPoint() + userOperation }) userOperation.callGasLimit = gasParameters.callGasLimit diff --git a/packages/permissionless-test/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ecdsaKernelAccount.test.ts index ddcc71c3..317e80c5 100644 --- a/packages/permissionless-test/ecdsaKernelAccount.test.ts +++ b/packages/permissionless-test/ecdsaKernelAccount.test.ts @@ -4,25 +4,45 @@ import { SignTransactionNotSupportedBySmartAccount, signerToEcdsaKernelSmartAccount } from "permissionless/accounts" -import { Address, Hex, decodeEventLog, getContract, zeroAddress } from "viem" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" import { EntryPointAbi } from "./abis/EntryPoint" import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" import { getBundlerClient, getEntryPoint, getPimlicoPaymasterClient, + getPrivateKeyAccount, getPublicClient, getSignerToEcdsaKernelAccount, getSmartAccountClient, + getTestingChain, + refillSmartAccount, waitForNonceUpdate } from "./utils" dotenv.config() -let testPrivateKey: Hex -let factoryAddress: Address beforeAll(() => { if (!process.env.FACTORY_ADDRESS) { throw new Error("FACTORY_ADDRESS environment variable not set") @@ -36,15 +56,23 @@ beforeAll(() => { if (!process.env.ENTRYPOINT_ADDRESS) { throw new Error("ENTRYPOINT_ADDRESS environment variable not set") } - - testPrivateKey = process.env.TEST_PRIVATE_KEY as Hex - factoryAddress = process.env.FACTORY_ADDRESS as Address }) /** * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) */ describe("ECDSA kernel Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + test("Account address", async () => { const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() @@ -125,6 +153,11 @@ describe("ECDSA kernel Account", () => { account: await getSignerToEcdsaKernelAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransactions({ transactions: [ { @@ -149,6 +182,10 @@ describe("ECDSA kernel Account", () => { const smartAccountClient = await getSmartAccountClient({ account: await getSignerToEcdsaKernelAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const entryPointContract = getContract({ abi: EntryPointAbi, @@ -192,7 +229,7 @@ describe("ECDSA kernel Account", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, @@ -255,7 +292,7 @@ describe("ECDSA kernel Account", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, @@ -323,7 +360,7 @@ describe("ECDSA kernel Account", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, diff --git a/packages/permissionless-test/index.test.ts b/packages/permissionless-test/index.test.ts index 44d8b99d..6f940823 100644 --- a/packages/permissionless-test/index.test.ts +++ b/packages/permissionless-test/index.test.ts @@ -1,9 +1,11 @@ import dotenv from "dotenv" import { + UserOperation, deepHexlify, getSenderAddress, getUserOperationHash } from "permissionless" +import { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/_types/types" import { getRequiredPrefund, signUserOperationHashWithECDSA @@ -82,7 +84,7 @@ describe("test public actions and utils", () => { eoaWalletClient ) const publicClient = await getPublicClient() - const entryPoint = "0x0000000" + const entryPoint = getEntryPoint() await expect(async () => getSenderAddress(publicClient, { @@ -100,8 +102,7 @@ describe("test public actions and utils", () => { const userOperation = await buildUserOp(eoaWalletClient) const gasParameters = await bundlerClient.estimateUserOperationGas({ - userOperation, - entryPoint: entryPoint + userOperation }) userOperation.callGasLimit = gasParameters.callGasLimit @@ -122,14 +123,14 @@ describe("test public actions and utils", () => { test("signUserOperationHashWithECDSA", async () => { const bundlerClient = getBundlerClient() const eoaWalletClient = getEoaWalletClient() - const userOperation = await buildUserOp(eoaWalletClient) + const userOperation: UserOperation<"v0.6"> = + await buildUserOp(eoaWalletClient) const entryPoint = getEntryPoint() const chain = getTestingChain() const gasParameters = await bundlerClient.estimateUserOperationGas({ - userOperation, - entryPoint: getEntryPoint() + userOperation }) userOperation.callGasLimit = gasParameters.callGasLimit @@ -189,8 +190,7 @@ describe("test public actions and utils", () => { const userOperation = await buildUserOp(eoaWalletClient) const gasParameters = await bundlerClient.estimateUserOperationGas({ - userOperation, - entryPoint: getEntryPoint() + userOperation }) userOperation.callGasLimit = gasParameters.callGasLimit @@ -198,7 +198,8 @@ describe("test public actions and utils", () => { userOperation.preVerificationGas = gasParameters.preVerificationGas const requiredGas = getRequiredPrefund({ - userOperation + userOperation, + entryPoint: getEntryPoint() }) expect(requiredGas).toBe( diff --git a/packages/permissionless-test/pimlicoActions.test.ts b/packages/permissionless-test/pimlicoActions.test.ts index c2653e5c..00b5f42d 100644 --- a/packages/permissionless-test/pimlicoActions.test.ts +++ b/packages/permissionless-test/pimlicoActions.test.ts @@ -4,6 +4,7 @@ import { PimlicoBundlerClient, PimlicoPaymasterClient } from "permissionless/clients/pimlico" +import { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { getUserOperationHash } from "permissionless/utils" import { Hash, Hex } from "viem" import { @@ -43,8 +44,8 @@ beforeAll(() => { }) describe("Pimlico Actions tests", () => { - let pimlicoBundlerClient: PimlicoBundlerClient - let pimlicoPaymasterClient: PimlicoPaymasterClient + let pimlicoBundlerClient: PimlicoBundlerClient + let pimlicoPaymasterClient: PimlicoPaymasterClient beforeEach(async () => { pimlicoBundlerClient = getPimlicoBundlerClient() @@ -92,7 +93,7 @@ describe("Pimlico Actions tests", () => { const { maxFeePerGas, maxPriorityFeePerGas } = await publicClient.estimateFeesPerGas() const partialUserOp = await buildUserOp(eoaWalletClient) - const userOperation: UserOperation = { + const userOperation: UserOperation<"v0.6"> = { ...partialUserOp, maxFeePerGas: maxFeePerGas || 0n, maxPriorityFeePerGas: maxPriorityFeePerGas || 0n, @@ -163,8 +164,7 @@ describe("Pimlico Actions tests", () => { message: { raw: userOperationHash } }) const userOpHash = await pimlicoBundlerClient.sendUserOperation({ - userOperation: userOperation, - entryPoint: entryPoint + userOperation: userOperation }) expectTypeOf(userOpHash).toBeString() expectTypeOf(userOpHash).toMatchTypeOf() @@ -221,7 +221,7 @@ describe("Pimlico Actions tests", () => { const partialUserOp = await buildUserOp(eoaWalletClient) - const userOperation: UserOperation = { + const userOperation: UserOperation<"v0.6"> = { ...partialUserOp, maxFeePerGas: maxFeePerGas || 0n, maxPriorityFeePerGas: maxPriorityFeePerGas || 0n, diff --git a/packages/permissionless-test/safeSmartAccount.test.ts b/packages/permissionless-test/safeSmartAccount.test.ts index 901e9d86..1adfa0b2 100644 --- a/packages/permissionless-test/safeSmartAccount.test.ts +++ b/packages/permissionless-test/safeSmartAccount.test.ts @@ -1,15 +1,28 @@ import dotenv from "dotenv" import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" import { + http, + Account, Address, BaseError, + Chain, + Transport, + WalletClient, + createWalletClient, decodeEventLog, getContract, hashMessage, hashTypedData, zeroAddress } from "viem" -import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" import { EntryPointAbi } from "./abis/EntryPoint" import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" import { @@ -18,9 +31,12 @@ import { getEntryPoint, getPimlicoBundlerClient, getPimlicoPaymasterClient, + getPrivateKeyAccount, getPublicClient, getSignerToSafeSmartAccount, getSmartAccountClient, + getTestingChain, + refillSmartAccount, waitForNonceUpdate } from "./utils" @@ -42,6 +58,17 @@ beforeAll(() => { }) describe("Safe Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + test("Safe Account address", async () => { const safeSmartAccount = await getSignerToSafeSmartAccount() @@ -107,6 +134,11 @@ describe("Safe Account", () => { account: await getSignerToSafeSmartAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const entryPointContract = getContract({ abi: EntryPointAbi, address: getEntryPoint(), @@ -141,6 +173,10 @@ describe("Safe Account", () => { const smartAccountClient = await getSmartAccountClient({ account: await getSignerToSafeSmartAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const pimlicoBundlerClient = getPimlicoBundlerClient() @@ -172,6 +208,10 @@ describe("Safe Account", () => { const smartAccountClient = await getSmartAccountClient({ account: await getSignerToSafeSmartAccount() }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const response = await smartAccountClient.sendTransaction({ to: zeroAddress, value: 0n, diff --git a/packages/permissionless-test/simpleAccount.test.ts b/packages/permissionless-test/simpleAccount.test.ts index 676c6865..36deef14 100644 --- a/packages/permissionless-test/simpleAccount.test.ts +++ b/packages/permissionless-test/simpleAccount.test.ts @@ -1,25 +1,44 @@ import dotenv from "dotenv" import { UserOperation } from "permissionless" import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" -import { Address, Hex, decodeEventLog, getContract, zeroAddress } from "viem" -import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" import { EntryPointAbi } from "./abis/EntryPoint" import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" import { getBundlerClient, getEntryPoint, getPimlicoPaymasterClient, + getPrivateKeyAccount, getPublicClient, getSignerToSimpleSmartAccount, getSmartAccountClient, + getTestingChain, + refillSmartAccount, waitForNonceUpdate } from "./utils" dotenv.config() -let testPrivateKey: Hex -let factoryAddress: Address - beforeAll(() => { if (!process.env.FACTORY_ADDRESS) { throw new Error("FACTORY_ADDRESS environment variable not set") @@ -33,12 +52,20 @@ beforeAll(() => { if (!process.env.ENTRYPOINT_ADDRESS) { throw new Error("ENTRYPOINT_ADDRESS environment variable not set") } - - testPrivateKey = process.env.TEST_PRIVATE_KEY as Hex - factoryAddress = process.env.FACTORY_ADDRESS as Address }) describe("Simple Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + test("Simple Account address", async () => { const simpleSmartAccount = await getSignerToSimpleSmartAccount() @@ -110,6 +137,10 @@ describe("Simple Account", () => { test("Smart account client send multiple transactions", async () => { const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const response = await smartAccountClient.sendTransactions({ transactions: [ { @@ -132,7 +163,10 @@ describe("Simple Account", () => { test("Smart account write contract", async () => { const smartAccountClient = await getSmartAccountClient() - + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const entryPointContract = getContract({ abi: EntryPointAbi, address: getEntryPoint(), @@ -165,6 +199,10 @@ describe("Simple Account", () => { test("Smart account client send transaction", async () => { const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const response = await smartAccountClient.sendTransaction({ to: zeroAddress, value: 0n, @@ -184,6 +222,10 @@ describe("Simple Account", () => { address: oldSmartAccountClient.account.address }) }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const response = await smartAccountClient.sendTransaction({ to: smartAccountClient.account.address, @@ -199,6 +241,10 @@ describe("Simple Account", () => { test("test prepareUserOperationRequest", async () => { const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const userOperation = await smartAccountClient.prepareUserOperationRequest({ @@ -211,7 +257,7 @@ describe("Simple Account", () => { } }) - // smartAccountClient.sendUserOperation() + smartAccountClient.sendUserOperation({ userOperation }) }, 1000000) test("smart account client send Transaction with paymaster", async () => { @@ -223,7 +269,7 @@ describe("Simple Account", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, @@ -280,7 +326,7 @@ describe("Simple Account", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, diff --git a/packages/permissionless-test/userOp.ts b/packages/permissionless-test/userOp.ts index 643fd26e..230a7d46 100644 --- a/packages/permissionless-test/userOp.ts +++ b/packages/permissionless-test/userOp.ts @@ -38,7 +38,7 @@ const getInitCode = async ( export const getAccountInitCode = async ( factoryAddress: Address, owner: WalletClient, - index: bigint + index = 0n ): Promise => { if (!owner.account) throw new Error("Owner account not found") return concatHex([ @@ -81,7 +81,7 @@ const encodeExecute = async ( export const buildUserOp = async ( eoaWalletClient: WalletClient, index = 0n -): Promise => { +) => { await new Promise((resolve) => { setTimeout(() => { // wait for prev user op to be added to make sure we get correct nonce @@ -109,7 +109,7 @@ export const buildUserOp = async ( const { maxFeePerGas, maxPriorityFeePerGas } = await publicClient.estimateFeesPerGas() - const userOperation: UserOperation = { + const userOperation: UserOperation<"v0.6"> = { sender: accountAddress, nonce: nonce, initCode: await getInitCode(factoryAddress, eoaWalletClient, index), diff --git a/packages/permissionless-test/utils.ts b/packages/permissionless-test/utils.ts index 05cee0dc..7986ebbd 100644 --- a/packages/permissionless-test/utils.ts +++ b/packages/permissionless-test/utils.ts @@ -16,14 +16,17 @@ import { createPimlicoBundlerClient, createPimlicoPaymasterClient } from "permissionless/clients/pimlico" +import { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { UserOperation } from "permissionless/types" import { walletClientToSmartAccountSigner } from "permissionless/utils" import { http, Account, Address, + Chain, Hex, Transport, + WalletClient, createPublicClient, createWalletClient, defineChain, @@ -163,8 +166,8 @@ export const getSmartAccountClient = async ({ account, sponsorUserOperation, preFund = false -}: SponsorUserOperationMiddleware & { - account?: SmartAccount +}: SponsorUserOperationMiddleware & { + account?: SmartAccount preFund?: boolean } = {}) => { if (!process.env.BUNDLER_RPC_HOST) @@ -175,6 +178,7 @@ export const getSmartAccountClient = async ({ const bundlerClient = getBundlerClient() const smartAccountClient = createSmartAccountClient({ + entryPoint: getEntryPoint(), account: account ?? (await getSignerToSimpleSmartAccount()), chain, transport: http(`${process.env.BUNDLER_RPC_HOST}`), @@ -182,7 +186,7 @@ export const getSmartAccountClient = async ({ const gasPrice = await pimlicoBundlerClient.getUserOperationGasPrice() - let newUserOperation: UserOperation = { + let newUserOperation: UserOperation<"v0.6"> = { ...userOperation, maxFeePerGas: gasPrice.fast.maxFeePerGas, maxPriorityFeePerGas: gasPrice.fast.maxPriorityFeePerGas @@ -196,8 +200,7 @@ export const getSmartAccountClient = async ({ } const gasLimits = await bundlerClient.estimateUserOperationGas({ - userOperation: newUserOperation, - entryPoint + userOperation: newUserOperation }) newUserOperation = { @@ -271,7 +274,8 @@ export const getBundlerClient = () => { return createBundlerClient({ chain: chain, - transport: http(`${process.env.BUNDLER_RPC_HOST}`) + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + entryPoint: getEntryPoint() }) } @@ -283,7 +287,8 @@ export const getPimlicoBundlerClient = () => { return createPimlicoBundlerClient({ chain: chain, - transport: http(`${process.env.PIMLICO_BUNDLER_RPC_HOST}`) + transport: http(`${process.env.PIMLICO_BUNDLER_RPC_HOST}`), + entryPoint: getEntryPoint() }) } @@ -297,7 +302,8 @@ export const getPimlicoPaymasterClient = () => { return createPimlicoPaymasterClient({ chain: chain, - transport: http(`${process.env.PIMLICO_PAYMASTER_RPC_HOST}`) + transport: http(`${process.env.PIMLICO_PAYMASTER_RPC_HOST}`), + entryPoint: getEntryPoint() }) } @@ -350,3 +356,17 @@ export const generateApproveCallData = (paymasterAddress: Address) => { return approveData } + +export const refillSmartAccount = async ( + walletClient: WalletClient, + address +) => { + const publicClient = await getPublicClient() + const balance = await publicClient.getBalance({ address }) + if (balance === 0n) { + await walletClient.sendTransaction({ + to: address, + value: parseEther("1") + }) + } +} diff --git a/packages/permissionless-test/walletClientToCustomSigner.test.ts b/packages/permissionless-test/walletClientToCustomSigner.test.ts index ad701f23..031f66c9 100644 --- a/packages/permissionless-test/walletClientToCustomSigner.test.ts +++ b/packages/permissionless-test/walletClientToCustomSigner.test.ts @@ -1,8 +1,27 @@ import dotenv from "dotenv" import { UserOperation } from "permissionless" import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" -import { Address, Hex, decodeEventLog, getContract, zeroAddress } from "viem" -import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" import { EntryPointAbi } from "./abis/EntryPoint" import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" import { @@ -10,9 +29,12 @@ import { getCustomSignerToSimpleSmartAccount, getEntryPoint, getPimlicoPaymasterClient, + getPrivateKeyAccount, getPublicClient, getSignerToSimpleSmartAccount, getSmartAccountClient, + getTestingChain, + refillSmartAccount, waitForNonceUpdate } from "./utils" @@ -34,6 +56,17 @@ beforeAll(() => { }) describe("Simple Account from walletClient", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + test("Simple Account address", async () => { const simpleSmartAccount = await getSignerToSimpleSmartAccount() @@ -122,6 +155,11 @@ describe("Simple Account from walletClient", () => { }) }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransactions({ transactions: [ { @@ -149,6 +187,11 @@ describe("Simple Account from walletClient", () => { }) }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const entryPointContract = getContract({ abi: EntryPointAbi, address: getEntryPoint(), @@ -185,6 +228,10 @@ describe("Simple Account from walletClient", () => { signer: await getCustomSignerToSimpleSmartAccount() }) }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) const response = await smartAccountClient.sendTransaction({ to: zeroAddress, value: 0n, @@ -208,7 +255,7 @@ describe("Simple Account from walletClient", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, @@ -268,7 +315,7 @@ describe("Simple Account from walletClient", () => { sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation - }): Promise => { + }) => { const pimlicoPaymaster = getPimlicoPaymasterClient() return pimlicoPaymaster.sponsorUserOperation({ userOperation, From 153ff9ea1c7da3676922b66dc90b1b461d1b3020 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Thu, 22 Feb 2024 13:45:25 +0530 Subject: [PATCH 08/35] Add 0.7 tests too --- .../{ => ep-0.6}/biconomySmartaccount.test.ts | 0 .../{ => ep-0.6}/bundlerActions.test.ts | 0 .../{ => ep-0.6}/ecdsaKernelAccount.test.ts | 0 .../{ => ep-0.6}/index.test.ts | 0 .../{ => ep-0.6}/package.json | 0 .../{ => ep-0.6}/pimlicoActions.test.ts | 0 .../{ => ep-0.6}/safeSmartAccount.test.ts | 4 +- .../permissionless-test/{ => ep-0.6}/setup.ts | 0 .../{ => ep-0.6}/simpleAccount.test.ts | 4 +- .../{ => ep-0.6}/userOp.ts | 4 +- .../permissionless-test/{ => ep-0.6}/utils.ts | 0 .../walletClientToCustomSigner.test.ts | 4 +- .../ep-0.7/biconomySmartaccount.test.ts | 392 +++++++++++++ .../ep-0.7/bundlerActions.test.ts | 253 +++++++++ .../ep-0.7/ecdsaKernelAccount.test.ts | 407 +++++++++++++ .../permissionless-test/ep-0.7/index.test.ts | 268 +++++++++ .../permissionless-test/ep-0.7/package.json | 21 + .../ep-0.7/pimlicoActions.test.ts | 255 +++++++++ .../ep-0.7/safeSmartAccount.test.ts | 534 ++++++++++++++++++ packages/permissionless-test/ep-0.7/setup.ts | 0 .../ep-0.7/simpleAccount.test.ts | 382 +++++++++++++ packages/permissionless-test/ep-0.7/utils.ts | 372 ++++++++++++ .../ep-0.7/walletClientToCustomSigner.test.ts | 374 ++++++++++++ 23 files changed, 3266 insertions(+), 8 deletions(-) rename packages/permissionless-test/{ => ep-0.6}/biconomySmartaccount.test.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/bundlerActions.test.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/ecdsaKernelAccount.test.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/index.test.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/package.json (100%) rename packages/permissionless-test/{ => ep-0.6}/pimlicoActions.test.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/safeSmartAccount.test.ts (99%) rename packages/permissionless-test/{ => ep-0.6}/setup.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/simpleAccount.test.ts (99%) rename packages/permissionless-test/{ => ep-0.6}/userOp.ts (96%) rename packages/permissionless-test/{ => ep-0.6}/utils.ts (100%) rename packages/permissionless-test/{ => ep-0.6}/walletClientToCustomSigner.test.ts (99%) create mode 100644 packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts create mode 100644 packages/permissionless-test/ep-0.7/bundlerActions.test.ts create mode 100644 packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts create mode 100644 packages/permissionless-test/ep-0.7/index.test.ts create mode 100644 packages/permissionless-test/ep-0.7/package.json create mode 100644 packages/permissionless-test/ep-0.7/pimlicoActions.test.ts create mode 100644 packages/permissionless-test/ep-0.7/safeSmartAccount.test.ts create mode 100644 packages/permissionless-test/ep-0.7/setup.ts create mode 100644 packages/permissionless-test/ep-0.7/simpleAccount.test.ts create mode 100644 packages/permissionless-test/ep-0.7/utils.ts create mode 100644 packages/permissionless-test/ep-0.7/walletClientToCustomSigner.test.ts diff --git a/packages/permissionless-test/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts similarity index 100% rename from packages/permissionless-test/biconomySmartaccount.test.ts rename to packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts diff --git a/packages/permissionless-test/bundlerActions.test.ts b/packages/permissionless-test/ep-0.6/bundlerActions.test.ts similarity index 100% rename from packages/permissionless-test/bundlerActions.test.ts rename to packages/permissionless-test/ep-0.6/bundlerActions.test.ts diff --git a/packages/permissionless-test/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts similarity index 100% rename from packages/permissionless-test/ecdsaKernelAccount.test.ts rename to packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts diff --git a/packages/permissionless-test/index.test.ts b/packages/permissionless-test/ep-0.6/index.test.ts similarity index 100% rename from packages/permissionless-test/index.test.ts rename to packages/permissionless-test/ep-0.6/index.test.ts diff --git a/packages/permissionless-test/package.json b/packages/permissionless-test/ep-0.6/package.json similarity index 100% rename from packages/permissionless-test/package.json rename to packages/permissionless-test/ep-0.6/package.json diff --git a/packages/permissionless-test/pimlicoActions.test.ts b/packages/permissionless-test/ep-0.6/pimlicoActions.test.ts similarity index 100% rename from packages/permissionless-test/pimlicoActions.test.ts rename to packages/permissionless-test/ep-0.6/pimlicoActions.test.ts diff --git a/packages/permissionless-test/safeSmartAccount.test.ts b/packages/permissionless-test/ep-0.6/safeSmartAccount.test.ts similarity index 99% rename from packages/permissionless-test/safeSmartAccount.test.ts rename to packages/permissionless-test/ep-0.6/safeSmartAccount.test.ts index 1adfa0b2..d884dbfd 100644 --- a/packages/permissionless-test/safeSmartAccount.test.ts +++ b/packages/permissionless-test/ep-0.6/safeSmartAccount.test.ts @@ -23,8 +23,8 @@ import { expectTypeOf, test } from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { EntryPointAbi } from "../abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" import { generateApproveCallData, getBundlerClient, diff --git a/packages/permissionless-test/setup.ts b/packages/permissionless-test/ep-0.6/setup.ts similarity index 100% rename from packages/permissionless-test/setup.ts rename to packages/permissionless-test/ep-0.6/setup.ts diff --git a/packages/permissionless-test/simpleAccount.test.ts b/packages/permissionless-test/ep-0.6/simpleAccount.test.ts similarity index 99% rename from packages/permissionless-test/simpleAccount.test.ts rename to packages/permissionless-test/ep-0.6/simpleAccount.test.ts index 36deef14..9d89beed 100644 --- a/packages/permissionless-test/simpleAccount.test.ts +++ b/packages/permissionless-test/ep-0.6/simpleAccount.test.ts @@ -22,8 +22,8 @@ import { expectTypeOf, test } from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { EntryPointAbi } from "../abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" import { getBundlerClient, getEntryPoint, diff --git a/packages/permissionless-test/userOp.ts b/packages/permissionless-test/ep-0.6/userOp.ts similarity index 96% rename from packages/permissionless-test/userOp.ts rename to packages/permissionless-test/ep-0.6/userOp.ts index 230a7d46..e24ea055 100644 --- a/packages/permissionless-test/userOp.ts +++ b/packages/permissionless-test/ep-0.6/userOp.ts @@ -12,8 +12,8 @@ import { zeroAddress } from "viem" import { PartialBy } from "viem/types/utils" -import { SimpleAccountAbi } from "./abis/SimpleAccount" -import { SimpleAccountFactoryAbi } from "./abis/SimpleAccountFactory" +import { SimpleAccountAbi } from "../abis/SimpleAccount" +import { SimpleAccountFactoryAbi } from "../abis/SimpleAccountFactory" import { getDummySignature, getEntryPoint, diff --git a/packages/permissionless-test/utils.ts b/packages/permissionless-test/ep-0.6/utils.ts similarity index 100% rename from packages/permissionless-test/utils.ts rename to packages/permissionless-test/ep-0.6/utils.ts diff --git a/packages/permissionless-test/walletClientToCustomSigner.test.ts b/packages/permissionless-test/ep-0.6/walletClientToCustomSigner.test.ts similarity index 99% rename from packages/permissionless-test/walletClientToCustomSigner.test.ts rename to packages/permissionless-test/ep-0.6/walletClientToCustomSigner.test.ts index 031f66c9..5c7168fa 100644 --- a/packages/permissionless-test/walletClientToCustomSigner.test.ts +++ b/packages/permissionless-test/ep-0.6/walletClientToCustomSigner.test.ts @@ -22,8 +22,8 @@ import { expectTypeOf, test } from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { EntryPointAbi } from "../abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" import { getBundlerClient, getCustomSignerToSimpleSmartAccount, diff --git a/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts new file mode 100644 index 00000000..d8fdb7bc --- /dev/null +++ b/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts @@ -0,0 +1,392 @@ +import dotenv from "dotenv" +import { + SignTransactionNotSupportedBySmartAccount, + signerToBiconomySmartAccount +} from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "./abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToBiconomyAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +/** + * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) + */ +describe("Biconomy Modular Smart Account (ECDSA module)", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Account address", async () => { + const ecdsaSmartAccount = await getSignerToBiconomyAccount() + + expectTypeOf(ecdsaSmartAccount.address).toBeString() + expect(ecdsaSmartAccount.address).toHaveLength(42) + expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + ecdsaSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError("Doesn't support account deployment") + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Client send Transaction with paymaster", async () => { + const account = await getSignerToBiconomyAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Client send multiple Transactions with paymaster", async () => { + const account = await getSignerToBiconomyAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Can use a deployed account", async () => { + const initialEcdsaSmartAccount = await getSignerToBiconomyAccount() + const publicClient = await getPublicClient() + const smartAccountClient = await getSmartAccountClient({ + account: initialEcdsaSmartAccount, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + // Send an initial tx to deploy the account + const hash = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // Wait for the tx to be done (so we are sure that the account is deployed) + await publicClient.waitForTransactionReceipt({ hash }) + + // Build a new account with a valid owner + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + const alreadyDeployedEcdsaSmartAccount = + await signerToBiconomySmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer + }) + + // Ensure the two account have the same address + expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( + initialEcdsaSmartAccount.address + ) + }, 1000000) +}) diff --git a/packages/permissionless-test/ep-0.7/bundlerActions.test.ts b/packages/permissionless-test/ep-0.7/bundlerActions.test.ts new file mode 100644 index 00000000..fdd2486a --- /dev/null +++ b/packages/permissionless-test/ep-0.7/bundlerActions.test.ts @@ -0,0 +1,253 @@ +import dotenv from "dotenv" +import { + BundlerClient, + ENTRYPOINT_ADDRESS_V07, + UserOperation, + WaitForUserOperationReceiptTimeoutError, + createBundlerClient, + createSmartAccountClient, + getAccountNonce, + walletClientToSmartAccountSigner +} from "permissionless" +import { signerToSimpleSmartAccount } from "permissionless/accounts" +import { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" +import { getUserOperationHash } from "permissionless/utils" +import { + http, + Account, + Address, + Chain, + type Hash, + Transport, + WalletClient, + createWalletClient, + parseEther, + zeroAddress +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { + getBundlerClient, + getEntryPoint, + getEoaWalletClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToSimpleSmartAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) + throw new Error("FACTORY_ADDRESS environment variable not set") + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + if (!process.env.RPC_URL) + throw new Error("RPC_URL environment variable not set") + if (!process.env.ENTRYPOINT_ADDRESS) + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") +}) + +describe("BUNDLER ACTIONS", () => { + let bundlerClient: BundlerClient + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + bundlerClient = getBundlerClient() + }) + + test.skip("Supported entry points request", async () => { + const supportedEntryPoints = await bundlerClient.supportedEntryPoints() + + expectTypeOf(supportedEntryPoints).toBeArray() + expect(supportedEntryPoints.length).toBeGreaterThan(0) + expect(supportedEntryPoints.includes(getEntryPoint())).toBe(true) + }) + + test.skip("Chain id call", async () => { + const chainId = await bundlerClient.chainId() + const chain = getTestingChain() + + expectTypeOf(chainId).toBeNumber() + expect(chainId).toBeGreaterThan(0) + expect(chainId === chain.id).toBe(true) + }) + + test("Estimate user operation gas", async () => { + const publicClient = await getPublicClient() + + const eoaWalletClient = getEoaWalletClient() + + const simpleAccount = await signerToSimpleSmartAccount(publicClient, { + signer: privateKeyToAccount( + process.env.TEST_PRIVATE_KEY as Address + ), + entryPoint: getEntryPoint(), + factoryAddress: process.env.FACTORY_ADDRESS as Address, + index: 3n + }) + + const smartAccountClient = createSmartAccountClient({ + account: simpleAccount, + chain: getTestingChain(), + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + entryPoint: getEntryPoint() + }) + + await eoaWalletClient.sendTransaction({ + to: simpleAccount.address, + value: parseEther("1") + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n + }) + }) + + test.skip("Sending user operation", async () => { + const publicClient = await getPublicClient() + const eoaWalletClient = getEoaWalletClient() + + const bundlerClient = createBundlerClient({ + chain: getTestingChain(), + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const simpleAccount = await signerToSimpleSmartAccount(publicClient, { + signer: walletClientToSmartAccountSigner(eoaWalletClient), + entryPoint: ENTRYPOINT_ADDRESS_V07, + factoryAddress: process.env.FACTORY_ADDRESS as Address + }) + + const smartAccountClient = createSmartAccountClient({ + account: simpleAccount, + chain: getTestingChain(), + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + sponsorUserOperation: async (args) => { + return args.userOperation + }, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: "0x" + } + }) + + const userOpHash = await bundlerClient.sendUserOperation({ + userOperation: userOperation + }) + + expectTypeOf(userOpHash).toBeString() + expectTypeOf(userOpHash).toMatchTypeOf() + + const userOperationReceipt = + await bundlerClient.waitForUserOperationReceipt({ + hash: userOpHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(userOpHash) + expect(userOperationReceipt?.receipt.transactionHash).not.toBeNull() + expect( + userOperationReceipt?.receipt.transactionHash + ).not.toBeUndefined() + + const receipt = await bundlerClient.getUserOperationReceipt({ + hash: userOpHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + + const userOperationFromUserOpHash = + await bundlerClient.getUserOperationByHash({ hash: userOpHash }) + + expect(userOperationFromUserOpHash).not.toBeNull() + expect(userOperationFromUserOpHash?.entryPoint).toBe( + ENTRYPOINT_ADDRESS_V07 + ) + expect(userOperationFromUserOpHash?.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + + for (const key in userOperationFromUserOpHash?.userOperation) { + expect(userOperationFromUserOpHash?.userOperation[key]).toBe( + userOperation[key] + ) + } + await waitForNonceUpdate() + + const newNonce = getAccountNonce(publicClient, { + sender: userOperation.sender, + entryPoint: getEntryPoint() + }) + + // expect(newNonce).toBe(userOperation.nonce + BigInt(1)) + }, 100000) + + test.skip("wait for user operation receipt fail", async () => { + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const entryPoint = getEntryPoint() + const chain = getTestingChain() + + const gasParameters = await bundlerClient.estimateUserOperationGas({ + userOperation + }) + + userOperation.callGasLimit = gasParameters.callGasLimit + userOperation.verificationGasLimit = gasParameters.verificationGasLimit + userOperation.preVerificationGas = gasParameters.preVerificationGas + + const userOpHash = getUserOperationHash({ + userOperation, + entryPoint, + chainId: chain.id + }) + + await expect(async () => + bundlerClient.waitForUserOperationReceipt({ + hash: userOpHash, + timeout: 100 + }) + ).rejects.toThrow(WaitForUserOperationReceiptTimeoutError) + }) +}) diff --git a/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts new file mode 100644 index 00000000..317e80c5 --- /dev/null +++ b/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts @@ -0,0 +1,407 @@ +import dotenv from "dotenv" +import { UserOperation } from "permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToEcdsaKernelSmartAccount +} from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "./abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToEcdsaKernelAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +/** + * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) + */ +describe("ECDSA kernel Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Account address", async () => { + const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() + + expectTypeOf(ecdsaSmartAccount.address).toBeString() + expect(ecdsaSmartAccount.address).toHaveLength(42) + expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + ecdsaSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError( + "Simple account doesn't support account deployment" + ) + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Client send Transaction with paymaster", async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Client send multiple Transactions with paymaster", async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Can use a deployed account", async () => { + const initialEcdsaSmartAccount = await getSignerToEcdsaKernelAccount() + const publicClient = await getPublicClient() + const smartAccountClient = await getSmartAccountClient({ + account: initialEcdsaSmartAccount, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + // Send an initial tx to deploy the account + const hash = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // Wait for the tx to be done (so we are sure that the account is deployed) + await publicClient.waitForTransactionReceipt({ hash }) + const deployedAccountAddress = initialEcdsaSmartAccount.address + + // Build a new account with a valid owner + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + const alreadyDeployedEcdsaSmartAccount = + await signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer, + deployedAccountAddress + }) + + // Ensure the two account have the same address + expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( + initialEcdsaSmartAccount.address + ) + + // Ensure that it will fail with an invalid owner address + const invalidOwner = privateKeyToAccount(generatePrivateKey()) + await expect(async () => + signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: invalidOwner, + deployedAccountAddress + }) + ).rejects.toThrowError("Invalid owner for the already deployed account") + }, 1000000) +}) diff --git a/packages/permissionless-test/ep-0.7/index.test.ts b/packages/permissionless-test/ep-0.7/index.test.ts new file mode 100644 index 00000000..5db7166b --- /dev/null +++ b/packages/permissionless-test/ep-0.7/index.test.ts @@ -0,0 +1,268 @@ +import dotenv from "dotenv" +import { + UserOperation, + deepHexlify, + getSenderAddress, + getUserOperationHash +} from "permissionless" +import { + getRequiredPrefund, + signUserOperationHashWithECDSA +} from "permissionless/utils" +import { + Address, + Hash, + Hex, + WalletClient, + encodeFunctionData, + zeroAddress +} from "viem" +import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { SimpleAccountFactoryAbi } from "../abis/SimpleAccountFactory" +import { + getBundlerClient, + getEntryPoint, + getEoaWalletClient, + getFactoryAddress, + getPrivateKeyAccount, + getPublicClient, + getSmartAccountClient, + getTestingChain +} from "./utils" + +dotenv.config() + +export const getAccountInitCode = async ( + factoryAddress: Address, + owner: WalletClient, + index = 0n +) => { + if (!owner.account) throw new Error("Owner account not found") + return { + factory: factoryAddress, + factoryData: encodeFunctionData({ + abi: SimpleAccountFactoryAbi, + functionName: "createAccount", + args: [owner.account.address, index] + }) + } +} + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) + throw new Error("FACTORY_ADDRESS environment variable not set") + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + if (!process.env.RPC_URL) + throw new Error("RPC_URL environment variable not set") + if (!process.env.ENTRYPOINT_ADDRESS) + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") +}) + +describe("test public actions and utils", () => { + test("Test deep Hexlify", async () => { + console.log("Testing deep hexlify") + expect(deepHexlify("abcd")).toBe("abcd") + expect(deepHexlify(null)).toBe(null) + expect(deepHexlify(true)).toBe(true) + expect(deepHexlify(false)).toBe(false) + expect(deepHexlify(1n)).toBe("0x1") + expect( + deepHexlify({ + name: "Garvit", + balance: 1n + }) + ).toEqual({ + name: "Garvit", + balance: "0x1" + }) + }) + test("get sender address", async () => { + const eoaWalletClient = getEoaWalletClient() + const factoryAddress = getFactoryAddress() + + const { factory, factoryData } = await getAccountInitCode( + factoryAddress, + eoaWalletClient + ) + const publicClient = await getPublicClient() + const entryPoint = getEntryPoint() + + const sender = await getSenderAddress(publicClient, { + factory, + factoryData, + entryPoint + }) + + expect(sender).not.toBeNull() + expect(sender).not.toBeUndefined() + expectTypeOf(sender).toMatchTypeOf
() + }) + + test("get sender address with invalid entry point", async () => { + const eoaWalletClient = getEoaWalletClient() + const factoryAddress = getFactoryAddress() + + const simpleAccountClient = await getSmartAccountClient() + + const { factory, factoryData } = await getAccountInitCode( + factoryAddress, + eoaWalletClient + ) + const publicClient = await getPublicClient() + const entryPoint = getEntryPoint() + + await expect(async () => + getSenderAddress(publicClient, { + factory, + factoryData, + entryPoint + }) + ).rejects.toThrow() + }) + + test("getUserOperationHash", async () => { + const chain = getTestingChain() + const entryPoint = getEntryPoint() + const bundlerClient = getBundlerClient() + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const gasParameters = await bundlerClient.estimateUserOperationGas({ + userOperation + }) + + userOperation.callGasLimit = gasParameters.callGasLimit + userOperation.verificationGasLimit = gasParameters.verificationGasLimit + userOperation.preVerificationGas = gasParameters.preVerificationGas + + const userOpHash = getUserOperationHash({ + userOperation, + entryPoint, + chainId: chain.id + }) + + expect(userOpHash).length.greaterThan(0) + expectTypeOf(userOpHash).toBeString() + expectTypeOf(userOpHash).toMatchTypeOf() + }) + + test("signUserOperationHashWithECDSA", async () => { + const bundlerClient = getBundlerClient() + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const entryPoint = getEntryPoint() + const chain = getTestingChain() + + const gasParameters = await bundlerClient.estimateUserOperationGas({ + userOperation + }) + + userOperation.callGasLimit = gasParameters.callGasLimit + userOperation.verificationGasLimit = gasParameters.verificationGasLimit + userOperation.preVerificationGas = gasParameters.preVerificationGas + + const userOpHash = getUserOperationHash({ + userOperation, + entryPoint, + chainId: chain.id + }) + + userOperation.signature = await signUserOperationHashWithECDSA({ + client: simpleAccountClient, + userOperation, + entryPoint: entryPoint, + chainId: chain.id + }) + + expectTypeOf(userOperation.signature).toBeString() + expectTypeOf(userOperation.signature).toMatchTypeOf() + + const signature = await signUserOperationHashWithECDSA({ + client: simpleAccountClient, + hash: userOpHash + }) + + await signUserOperationHashWithECDSA({ + account: simpleAccountClient.account, + hash: userOpHash + }) + + await signUserOperationHashWithECDSA({ + account: simpleAccountClient.account, + userOperation, + entryPoint: entryPoint, + chainId: chain.id + }) + + await signUserOperationHashWithECDSA({ + account: getPrivateKeyAccount(), + userOperation, + entryPoint: entryPoint, + chainId: chain.id + }) + + expectTypeOf(userOpHash).toBeString() + expectTypeOf(userOpHash).toMatchTypeOf() + expect(userOpHash).length.greaterThan(0) + + expect(signature).toEqual(userOperation.signature) + }) + + test("getRequiredGas", async () => { + const bundlerClient = getBundlerClient() + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const gasParameters = await bundlerClient.estimateUserOperationGas({ + userOperation + }) + + userOperation.callGasLimit = gasParameters.callGasLimit + userOperation.verificationGasLimit = gasParameters.verificationGasLimit + userOperation.preVerificationGas = gasParameters.preVerificationGas + + const requiredGas = getRequiredPrefund({ + userOperation, + entryPoint: getEntryPoint() + }) + + expect(requiredGas).toBe( + (gasParameters.callGasLimit + + gasParameters.verificationGasLimit + + gasParameters.preVerificationGas) * + userOperation.maxFeePerGas + ) + }) +}) diff --git a/packages/permissionless-test/ep-0.7/package.json b/packages/permissionless-test/ep-0.7/package.json new file mode 100644 index 00000000..aac544b5 --- /dev/null +++ b/packages/permissionless-test/ep-0.7/package.json @@ -0,0 +1,21 @@ +{ + "name": "test", + "author": "Pimlico", + "repository": "github:pimlicolabs/permissionless.js", + "homepage": "https://docs.pimlico.io/permissionless", + "private": true, + "type": "module", + "devDependencies": { + "vitest": "^1.2.0" + }, + "dependencies": { + "@types/node": "^20.11.5", + "@viem/anvil": "^0.0.7", + "@vitest/coverage-v8": "^1.2.0", + "dotenv": "^16.3.1", + "execa": "^8.0.1", + "get-port": "^7.0.0", + "permissionless": "workspace:packages/permissionless", + "viem": "^2.0.0" + } +} diff --git a/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts b/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts new file mode 100644 index 00000000..647f6016 --- /dev/null +++ b/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts @@ -0,0 +1,255 @@ +import dotenv from "dotenv" +import { + PimlicoBundlerClient, + PimlicoPaymasterClient +} from "permissionless/clients/pimlico" +import { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" +import { Address, Hash, zeroAddress } from "viem" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { + getEntryPoint, + getPimlicoBundlerClient, + getPimlicoPaymasterClient, + getPublicClient, + getSmartAccountClient, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) + throw new Error("FACTORY_ADDRESS environment variable not set") + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + if (!process.env.RPC_URL) + throw new Error("RPC_URL environment variable not set") + if (!process.env.ENTRYPOINT_ADDRESS) + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + if (!process.env.ACTIVE_SPONSORSHIP_POLICY) + throw new Error( + "ACTIVE_SPONSORSHIP_POLICY environment variable not set" + ) +}) + +describe("Pimlico Actions tests", () => { + let pimlicoBundlerClient: PimlicoBundlerClient + let pimlicoPaymasterClient: PimlicoPaymasterClient + + beforeEach(async () => { + pimlicoBundlerClient = getPimlicoBundlerClient() + pimlicoPaymasterClient = getPimlicoPaymasterClient() + }) + + describe("Pimlico Bundler actions", () => { + test("fetch gas price", async () => { + const gasPrice = + await pimlicoBundlerClient.getUserOperationGasPrice() + expect(gasPrice).not.toBeUndefined() + expect(gasPrice).not.toBeNull() + expect(gasPrice.slow).not.toBeNull() + expect(gasPrice.slow).not.toBeUndefined() + expect(gasPrice.standard).not.toBeNull() + expect(gasPrice.standard).not.toBeUndefined() + expect(gasPrice.fast).not.toBeNull() + expect(gasPrice.fast).not.toBeUndefined() + expect(typeof gasPrice.slow.maxFeePerGas).toBe("bigint") + expect(gasPrice.slow.maxFeePerGas).toBeGreaterThan(BigInt(0)) + expect(typeof gasPrice.slow.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.slow.maxPriorityFeePerGas).toBeGreaterThan( + BigInt(0) + ) + expect(typeof gasPrice.standard.maxFeePerGas).toBe("bigint") + expect(gasPrice.standard.maxFeePerGas).toBeGreaterThan(BigInt(0)) + expect(typeof gasPrice.standard.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.standard.maxPriorityFeePerGas).toBeGreaterThan( + BigInt(0) + ) + expect(typeof gasPrice.fast.maxFeePerGas).toBe("bigint") + expect(gasPrice.fast.maxFeePerGas).toBeGreaterThan(BigInt(0)) + expect(typeof gasPrice.fast.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.fast.maxPriorityFeePerGas).toBeGreaterThan( + BigInt(0) + ) + }) + test("fetch user operation status", async () => {}) + }) + + describe("Pimlico paymaster actions ", () => { + test("Fetching paymaster and data", async () => { + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: + await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const entryPoint = getEntryPoint() + const sponsorUserOperationPaymasterAndData = + await pimlicoPaymasterClient.sponsorUserOperation({ + userOperation: userOperation, + entryPoint: entryPoint + }) + expect(sponsorUserOperationPaymasterAndData).not.toBeNull() + expect(sponsorUserOperationPaymasterAndData).not.toBeUndefined() + expect(sponsorUserOperationPaymasterAndData).not.toBeUndefined() + expect( + typeof sponsorUserOperationPaymasterAndData.callGasLimit + ).toBe("bigint") + expect( + sponsorUserOperationPaymasterAndData.callGasLimit + ).toBeGreaterThan(BigInt(0)) + expect( + typeof sponsorUserOperationPaymasterAndData.preVerificationGas + ).toBe("bigint") + expect( + sponsorUserOperationPaymasterAndData.preVerificationGas + ).toBeGreaterThan(BigInt(0)) + expect( + typeof sponsorUserOperationPaymasterAndData.verificationGasLimit + ).toBe("bigint") + expect( + sponsorUserOperationPaymasterAndData.verificationGasLimit + ).toBeGreaterThan(BigInt(0)) + expect( + sponsorUserOperationPaymasterAndData.paymasterData + ).length.greaterThan(0) + expectTypeOf( + sponsorUserOperationPaymasterAndData.paymaster + ).toMatchTypeOf
() + await waitForNonceUpdate() + }, 100000) + test("Sending user op with paymaster and data", async () => { + const entryPoint = getEntryPoint() + + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: + await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const sponsorUserOperationPaymasterAndData = + await pimlicoPaymasterClient.sponsorUserOperation({ + userOperation: userOperation, + entryPoint: entryPoint + }) + userOperation.paymasterAndData = + sponsorUserOperationPaymasterAndData.paymasterAndData + userOperation.callGasLimit = + sponsorUserOperationPaymasterAndData.callGasLimit + userOperation.verificationGasLimit = + sponsorUserOperationPaymasterAndData.verificationGasLimit + userOperation.preVerificationGas = + sponsorUserOperationPaymasterAndData.preVerificationGas + userOperation.signature = + await simpleAccountClient.account.signUserOperation( + userOperation + ) + const userOpHash = await pimlicoBundlerClient.sendUserOperation({ + userOperation: userOperation + }) + expectTypeOf(userOpHash).toBeString() + expectTypeOf(userOpHash).toMatchTypeOf() + const userOperationReceipt = + await pimlicoBundlerClient.waitForUserOperationReceipt({ + hash: userOpHash + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(userOpHash) + expect( + userOperationReceipt?.receipt.transactionHash + ).length.greaterThan(0) + expect(userOperationReceipt?.receipt.transactionHash).not.toBeNull() + expect( + userOperationReceipt?.receipt.transactionHash + ).not.toBeUndefined() + const userOperationFromUserOpHash = + await pimlicoBundlerClient.getUserOperationByHash({ + hash: userOpHash + }) + expect(userOperationFromUserOpHash).not.toBeNull() + expect(userOperationFromUserOpHash?.entryPoint).toBe(entryPoint) + expect(userOperationFromUserOpHash?.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + await waitForNonceUpdate() + // for (const key in userOperationFromUserOpHash?.userOperation) { + // expect(userOperationFromUserOpHash?.userOperation[key]).toBe(userOperation[key]) + // } + const userOperationStatus = + await pimlicoBundlerClient.getUserOperationStatus({ + hash: userOpHash + }) + expect(userOperationStatus).not.toBeNull() + expect(userOperationStatus).not.toBeUndefined() + expect(userOperationStatus.status).toBe("included") + expect(userOperationStatus.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + await waitForNonceUpdate() + }, 100000) + }) + + test("Validating sponsorship policies", async () => { + const publicClient = await getPublicClient() + + if (!process.env.ACTIVE_SPONSORSHIP_POLICY) + throw new Error( + "ACTIVE_SPONSORSHIP_POLICY environment variable not set" + ) + + const simpleAccountClient = await getSmartAccountClient() + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + const entryPoint = getEntryPoint() + + const validateSponsorshipPolicies = + await pimlicoPaymasterClient.validateSponsorshipPolicies({ + userOperation: userOperation, + entryPoint: entryPoint, + sponsorshipPolicyIds: [ + process.env.ACTIVE_SPONSORSHIP_POLICY, + "sp_fake_policy" + ] + }) + + expect(validateSponsorshipPolicies).not.toBeNull() + expect(validateSponsorshipPolicies).not.toBeUndefined() + expect(validateSponsorshipPolicies).length.greaterThan(0) + expectTypeOf(validateSponsorshipPolicies).toBeArray() + expect(validateSponsorshipPolicies.length).toBe(1) + await waitForNonceUpdate() + }, 100000) +}) diff --git a/packages/permissionless-test/ep-0.7/safeSmartAccount.test.ts b/packages/permissionless-test/ep-0.7/safeSmartAccount.test.ts new file mode 100644 index 00000000..d884dbfd --- /dev/null +++ b/packages/permissionless-test/ep-0.7/safeSmartAccount.test.ts @@ -0,0 +1,534 @@ +import dotenv from "dotenv" +import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" +import { + http, + Account, + Address, + BaseError, + Chain, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + hashMessage, + hashTypedData, + zeroAddress +} from "viem" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "../abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" +import { + generateApproveCallData, + getBundlerClient, + getEntryPoint, + getPimlicoBundlerClient, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToSafeSmartAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +describe("Safe Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Safe Account address", async () => { + const safeSmartAccount = await getSignerToSafeSmartAccount() + + expectTypeOf(safeSmartAccount.address).toBeString() + expect(safeSmartAccount.address).toHaveLength(42) + expect(safeSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + safeSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("safe smart account client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount() + }) + + await expect(() => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError(/doesn't support account deployment/) + }) + + test("safe Smart account deploy with setup Txs", async () => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + + const usdcTokenAddress = "0x07865c6E87B9F70255377e024ace6630C1Eaa37F" + const erc20PaymasterAddress = + "0xEc43912D8C772A0Eba5a27ea5804Ba14ab502009" + + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount({ + setupTransactions: [ + { + to: usdcTokenAddress, + data: generateApproveCallData(erc20PaymasterAddress), + value: 0n + } + ] + }), + sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + }, 1000000) + + test("safe Smart account write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("safe Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const pimlicoBundlerClient = getPimlicoBundlerClient() + + const gasPrices = await pimlicoBundlerClient.getUserOperationGasPrice() + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: smartAccountClient.account.address, + value: 10n, + data: "0x" + }, + { + to: smartAccountClient.account.address, + value: 10n, + data: "0x" + } + ], + maxFeePerGas: gasPrices.fast.maxFeePerGas, + maxPriorityFeePerGas: gasPrices.fast.maxPriorityFeePerGas + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("safe Smart account client send transaction", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + await new Promise((res) => { + setTimeout(res, 1000) + }) + await waitForNonceUpdate() + }, 1000000) + + test("safe smart account client send Transaction with paymaster", async () => { + const publicClient = await getPublicClient() + + const pimlicoPaymaster = getPimlicoPaymasterClient() + + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount(), + sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + const bundlerClient = getBundlerClient() + for (const log of transactionReceipt.logs) { + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch (e) { + const error = e as BaseError + if (error.name !== "AbiEventSignatureNotFoundError") throw e + } + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("safe smart account client send Transaction with paymaster", async () => { + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + const pimlicoPaymaster = getPimlicoPaymasterClient() + + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount(), + sponsorUserOperation: pimlicoPaymaster.sponsorUserOperation + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch (e) { + const error = e as BaseError + if (error.name !== "AbiEventSignatureNotFoundError") throw e + } + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("safe Smart account client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount() + }) + + const messageToSign = "hello world" + const signature = await smartAccountClient.signMessage({ + message: messageToSign + }) + + expectTypeOf(signature).toBeString() + expect(signature).toHaveLength(132) + expect(signature).toMatch(/^0x[0-9a-fA-F]{130}$/) + + const publicClient = await getPublicClient() + + const response = await publicClient.readContract({ + address: smartAccountClient.account.address, + abi: [ + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes" + }, + { + internalType: "bytes", + name: "_signature", + type: "bytes" + } + ], + name: "isValidSignature", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes32", + name: "_dataHash", + type: "bytes32" + }, + { + internalType: "bytes", + name: "_signature", + type: "bytes" + } + ], + name: "isValidSignature", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4" + } + ], + stateMutability: "view", + type: "function" + } + ], + functionName: "isValidSignature", + args: [hashMessage(messageToSign), signature] + }) + + expect(response).toBe("0x1626ba7e") + }) + + test("safe Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSafeSmartAccount() + }) + + const signature = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(signature).toBeString() + expect(signature).toHaveLength(132) + expect(signature).toMatch(/^0x[0-9a-fA-F]{130}$/) + + const publicClient = await getPublicClient() + + const response = await publicClient.readContract({ + address: smartAccountClient.account.address, + abi: [ + { + inputs: [ + { + internalType: "bytes", + name: "_data", + type: "bytes" + }, + { + internalType: "bytes", + name: "_signature", + type: "bytes" + } + ], + name: "isValidSignature", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + internalType: "bytes32", + name: "_dataHash", + type: "bytes32" + }, + { + internalType: "bytes", + name: "_signature", + type: "bytes" + } + ], + name: "isValidSignature", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4" + } + ], + stateMutability: "view", + type: "function" + } + ], + functionName: "isValidSignature", + args: [ + hashTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }), + signature + ] + }) + + expect(response).toBe("0x1626ba7e") + }) +}) diff --git a/packages/permissionless-test/ep-0.7/setup.ts b/packages/permissionless-test/ep-0.7/setup.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/permissionless-test/ep-0.7/simpleAccount.test.ts b/packages/permissionless-test/ep-0.7/simpleAccount.test.ts new file mode 100644 index 00000000..076263a0 --- /dev/null +++ b/packages/permissionless-test/ep-0.7/simpleAccount.test.ts @@ -0,0 +1,382 @@ +import dotenv from "dotenv" +import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" +import { + http, + Account, + Chain, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "../abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToSimpleSmartAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +describe("Simple Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Simple Account address", async () => { + const simpleSmartAccount = await getSignerToSimpleSmartAccount() + + expectTypeOf(simpleSmartAccount.address).toBeString() + expect(simpleSmartAccount.address).toHaveLength(42) + expect(simpleSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + simpleSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Smart account client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient() + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient() + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("smart account client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient() + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError( + "Simple account doesn't support account deployment" + ) + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Smart account write contract", async () => { + const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Smart account client send transaction", async () => { + const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Smart account client send transaction with address", async () => { + const oldSmartAccountClient = await getSmartAccountClient() + + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + address: oldSmartAccountClient.account.address + }) + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransaction({ + to: smartAccountClient.account.address, + data: "0x", + value: 0n + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("test prepareUserOperationRequest", async () => { + const smartAccountClient = await getSmartAccountClient() + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await smartAccountClient.account.encodeCallData({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + } + }) + + smartAccountClient.sendUserOperation({ userOperation }) + }, 1000000) + + test("smart account client send Transaction with paymaster", async () => { + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect(userOperation?.userOperation.paymasterAndData).not.toBe( + "0x" + ) + } + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("smart account client send multiple Transactions with paymaster", async () => { + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect(userOperation?.userOperation.paymasterAndData).not.toBe( + "0x" + ) + } + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) +}) diff --git a/packages/permissionless-test/ep-0.7/utils.ts b/packages/permissionless-test/ep-0.7/utils.ts new file mode 100644 index 00000000..842cc579 --- /dev/null +++ b/packages/permissionless-test/ep-0.7/utils.ts @@ -0,0 +1,372 @@ +import { + ENTRYPOINT_ADDRESS_V07, + createBundlerClient, + createSmartAccountClient +} from "permissionless" +import { + SmartAccount, + SmartAccountSigner, + signerToBiconomySmartAccount, + signerToEcdsaKernelSmartAccount, + signerToSafeSmartAccount, + signerToSimpleSmartAccount +} from "permissionless/accounts" +import { SponsorUserOperationMiddleware } from "permissionless/actions/smartAccount" +import { + createPimlicoBundlerClient, + createPimlicoPaymasterClient +} from "permissionless/clients/pimlico" +import { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" +import { UserOperation } from "permissionless/types" +import { walletClientToSmartAccountSigner } from "permissionless/utils" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createPublicClient, + createWalletClient, + defineChain, + encodeFunctionData, + parseEther +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import * as allChains from "viem/chains" + +export const getFactoryAddress = () => { + if (!process.env.FACTORY_ADDRESS) + throw new Error("FACTORY_ADDRESS environment variable not set") + const factoryAddress = process.env.FACTORY_ADDRESS as Address + return factoryAddress +} + +export const getPrivateKeyAccount = () => { + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + return privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) +} + +export const getTestingChain = () => { + // If custom chain specified in environment variable, use that + + if (!process.env.TEST_CHAIN_ID) + throw new Error("TEST_CHAIN_ID environment variable not set") + + const chainId = parseInt(process.env.TEST_CHAIN_ID) + const chain = Object.values(allChains).find((chain) => chain.id === chainId) + if (chain) return chain + + // Otherwise, use fallback to goerli + return defineChain({ + id: chainId, + network: "goerli", + name: "Goerli", + nativeCurrency: { name: "Goerli Ether", symbol: "ETH", decimals: 18 }, + rpcUrls: { + default: { + http: ["http://0.0.0.0:3000"] + }, + public: { + http: ["http://0.0.0.0:3000"] + } + }, + testnet: true + }) +} + +export const getSignerToSimpleSmartAccount = async ({ + signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex), + address +}: { + signer?: SmartAccountSigner + address?: Address +} = {}) => { + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + + const publicClient = await getPublicClient() + + return await signerToSimpleSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + factoryAddress: getFactoryAddress(), + signer: signer, + address + }) +} + +export const getSignerToSafeSmartAccount = async (args?: { + setupTransactions?: { + to: Address + data: Address + value: bigint + }[] +}) => { + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + + const publicClient = await getPublicClient() + + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + + return await signerToSafeSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer, + safeVersion: "1.4.1", + saltNonce: 100n, + setupTransactions: args?.setupTransactions + }) +} +export const getSignerToEcdsaKernelAccount = async () => { + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + + const publicClient = await getPublicClient() + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + + return await signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer, + index: 100n + }) +} + +export const getSignerToBiconomyAccount = async () => { + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + + const publicClient = await getPublicClient() + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + + return await signerToBiconomySmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer, + index: 0n + }) +} + +export const getCustomSignerToSimpleSmartAccount = async () => { + if (!process.env.TEST_PRIVATE_KEY) + throw new Error("TEST_PRIVATE_KEY environment variable not set") + + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + + const walletClient = createWalletClient({ + chain: getTestingChain(), + account: signer, + transport: http(process.env.RPC_URL as string) + }) + + return walletClientToSmartAccountSigner(walletClient) +} + +export const getSmartAccountClient = async ({ + account, + sponsorUserOperation, + preFund = false +}: SponsorUserOperationMiddleware & { + account?: SmartAccount + preFund?: boolean +} = {}) => { + if (!process.env.BUNDLER_RPC_HOST) + throw new Error("BUNDLER_RPC_HOST environment variable not set") + const chain = getTestingChain() + + const pimlicoBundlerClient = getPimlicoBundlerClient() + const bundlerClient = getBundlerClient() + + const smartAccountClient = createSmartAccountClient({ + entryPoint: getEntryPoint(), + account: account ?? (await getSignerToSimpleSmartAccount()), + chain, + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + sponsorUserOperation: async ({ userOperation, entryPoint }) => { + const gasPrice = + await pimlicoBundlerClient.getUserOperationGasPrice() + + let newUserOperation: UserOperation<"v0.7"> = { + ...userOperation, + maxFeePerGas: gasPrice.fast.maxFeePerGas, + maxPriorityFeePerGas: gasPrice.fast.maxPriorityFeePerGas + } + + if (sponsorUserOperation) { + return sponsorUserOperation({ + userOperation, + entryPoint + }) + } + + const gasLimits = await bundlerClient.estimateUserOperationGas({ + userOperation: newUserOperation + }) + + newUserOperation = { + ...newUserOperation, + ...gasLimits + } + + return newUserOperation + } + }) + + if (preFund) { + const walletClient = getEoaWalletClient() + const publicClient = await getPublicClient() + + const balance = await publicClient.getBalance({ + address: smartAccountClient.account.address + }) + + if (balance < parseEther("1")) { + await walletClient.sendTransaction({ + to: smartAccountClient.account.address, + value: parseEther("1"), + data: "0x" + }) + } + } + + return smartAccountClient +} + +export const getEoaWalletClient = () => { + return createWalletClient({ + account: getPrivateKeyAccount(), + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) +} + +export const getEntryPoint = () => { + if (!process.env.ENTRYPOINT_ADDRESS) + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + return ENTRYPOINT_ADDRESS_V07 +} + +export const getPublicClient = async () => { + if (!process.env.RPC_URL) + throw new Error("RPC_URL environment variable not set") + + const publicClient = createPublicClient({ + transport: http(process.env.RPC_URL as string) + }) + + const chainId = await publicClient.getChainId() + + if (chainId !== getTestingChain().id) + throw new Error( + `Testing Chain ID: ${ + getTestingChain().id + } not supported by RPC URL, RPC Chain ID: ${chainId}` + ) + + return publicClient +} + +export const getBundlerClient = () => { + if (!process.env.BUNDLER_RPC_HOST) + throw new Error("BUNDLER_RPC_HOST environment variable not set") + + const chain = getTestingChain() + + return createBundlerClient({ + chain: chain, + transport: http(`${process.env.BUNDLER_RPC_HOST}`), + entryPoint: getEntryPoint() + }) +} + +export const getPimlicoBundlerClient = () => { + if (!process.env.PIMLICO_BUNDLER_RPC_HOST) + throw new Error("PIMLICO_BUNDLER_RPC_HOST environment variable not set") + + const chain = getTestingChain() + + return createPimlicoBundlerClient({ + chain: chain, + transport: http(`${process.env.PIMLICO_BUNDLER_RPC_HOST}`), + entryPoint: getEntryPoint() + }) +} + +export const getPimlicoPaymasterClient = () => { + if (!process.env.PIMLICO_PAYMASTER_RPC_HOST) + throw new Error( + "PIMLICO_PAYMASTER_RPC_HOST environment variable not set" + ) + + const chain = getTestingChain() + + return createPimlicoPaymasterClient({ + chain: chain, + transport: http(`${process.env.PIMLICO_PAYMASTER_RPC_HOST}`), + entryPoint: getEntryPoint() + }) +} + +export const isAccountDeployed = async (accountAddress: Address) => { + const publicClient = await getPublicClient() + + const contractCode = await publicClient.getBytecode({ + address: accountAddress + }) + + if ((contractCode?.length ?? 0) > 2) return true + + return false +} + +export const getDummySignature = (): Hex => { + return "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" +} + +export const getOldUserOpHash = (): Hex => { + return "0xe9fad2cd67f9ca1d0b7a6513b2a42066784c8df938518da2b51bb8cc9a89ea34" +} + +export const waitForNonceUpdate = async (time = 10000) => { + return new Promise((res) => { + setTimeout(res, time) + }) +} + +export const generateApproveCallData = (paymasterAddress: Address) => { + const approveData = encodeFunctionData({ + abi: [ + { + inputs: [ + { name: "_spender", type: "address" }, + { name: "_value", type: "uint256" } + ], + name: "approve", + outputs: [{ name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function" + } + ], + args: [ + paymasterAddress, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn + ] + }) + + return approveData +} + +export const refillSmartAccount = async ( + walletClient: WalletClient, + address +) => { + const publicClient = await getPublicClient() + const balance = await publicClient.getBalance({ address }) + if (balance === 0n) { + await walletClient.sendTransaction({ + to: address, + value: parseEther("1") + }) + } +} diff --git a/packages/permissionless-test/ep-0.7/walletClientToCustomSigner.test.ts b/packages/permissionless-test/ep-0.7/walletClientToCustomSigner.test.ts new file mode 100644 index 00000000..5c7168fa --- /dev/null +++ b/packages/permissionless-test/ep-0.7/walletClientToCustomSigner.test.ts @@ -0,0 +1,374 @@ +import dotenv from "dotenv" +import { UserOperation } from "permissionless" +import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "../abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" +import { + getBundlerClient, + getCustomSignerToSimpleSmartAccount, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToSimpleSmartAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +describe("Simple Account from walletClient", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Simple Account address", async () => { + const simpleSmartAccount = await getSignerToSimpleSmartAccount() + + expectTypeOf(simpleSmartAccount.address).toBeString() + expect(simpleSmartAccount.address).toHaveLength(42) + expect(simpleSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + simpleSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(new SignTransactionNotSupportedBySmartAccount()) + }) + + test("Smart account client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }) + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }) + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("smart account client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }) + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError( + "Simple account doesn't support account deployment" + ) + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }) + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Smart account write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }) + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Smart account client send transaction", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }) + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("smart account client send Transaction with paymaster", async () => { + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }), + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect(userOperation?.userOperation.paymasterAndData).not.toBe( + "0x" + ) + } + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("smart account client send multiple Transactions with paymaster", async () => { + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToSimpleSmartAccount({ + signer: await getCustomSignerToSimpleSmartAccount() + }), + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect(userOperation?.userOperation.paymasterAndData).not.toBe( + "0x" + ) + } + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) +}) From d2e796d80c166115d7ce37fb1c665a8775c85e2a Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Thu, 22 Feb 2024 17:37:33 +0530 Subject: [PATCH 09/35] update entryPoint address --- packages/permissionless/types/entrypoint.ts | 2 +- packages/permissionless/utils/getEntryPointVersion.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/permissionless/types/entrypoint.ts b/packages/permissionless/types/entrypoint.ts index 9ca8a3e6..32753e5e 100644 --- a/packages/permissionless/types/entrypoint.ts +++ b/packages/permissionless/types/entrypoint.ts @@ -3,7 +3,7 @@ export type EntryPointVersion = "v0.6" | "v0.7" export type ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" export type ENTRYPOINT_ADDRESS_V07_TYPE = - "0x7547CAC84A1eF4E6FA8bF83cD89404e7BFB72A4d" + "0x0000000071727De22E5E9d8BAf0edAc6f37da032" export type GetEntryPointVersion = entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE ? "v0.6" : "v0.7" diff --git a/packages/permissionless/utils/getEntryPointVersion.ts b/packages/permissionless/utils/getEntryPointVersion.ts index ebf5815a..c201e119 100644 --- a/packages/permissionless/utils/getEntryPointVersion.ts +++ b/packages/permissionless/utils/getEntryPointVersion.ts @@ -7,7 +7,7 @@ import type { EntryPoint, GetEntryPointVersion } from "../types/entrypoint" export const ENTRYPOINT_ADDRESS_V06: ENTRYPOINT_ADDRESS_V06_TYPE = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" export const ENTRYPOINT_ADDRESS_V07: ENTRYPOINT_ADDRESS_V07_TYPE = - "0x7547CAC84A1eF4E6FA8bF83cD89404e7BFB72A4d" + "0x0000000071727De22E5E9d8BAf0edAc6f37da032" export const getEntryPointVersion = ( entryPoint: EntryPoint From 599618b2bfb03878347c7eb37973171cc0b0a0e6 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 23 Feb 2024 02:27:16 +0530 Subject: [PATCH 10/35] Add support for sending multiple transactions --- .../ep-0.7/simpleAccount.test.ts | 21 +++++++++++-------- packages/permissionless-test/ep-0.7/utils.ts | 13 ++++++++---- .../simple/signerToSimpleSmartAccount.ts | 6 ++++++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/packages/permissionless-test/ep-0.7/simpleAccount.test.ts b/packages/permissionless-test/ep-0.7/simpleAccount.test.ts index 076263a0..05db907e 100644 --- a/packages/permissionless-test/ep-0.7/simpleAccount.test.ts +++ b/packages/permissionless-test/ep-0.7/simpleAccount.test.ts @@ -80,7 +80,7 @@ describe("Simple Account", () => { }) test("Smart account client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) const response = await smartAccountClient.signMessage({ message: "hello world" @@ -92,7 +92,7 @@ describe("Simple Account", () => { }) test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) const response = await smartAccountClient.signTypedData({ domain: { @@ -120,7 +120,7 @@ describe("Simple Account", () => { }) test("smart account client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) await expect(async () => smartAccountClient.deployContract({ @@ -133,7 +133,7 @@ describe("Simple Account", () => { }) test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -159,7 +159,7 @@ describe("Simple Account", () => { }, 1000000) test("Smart account write contract", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -195,7 +195,7 @@ describe("Simple Account", () => { }, 1000000) test("Smart account client send transaction", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -212,12 +212,13 @@ describe("Simple Account", () => { }, 1000000) test("Smart account client send transaction with address", async () => { - const oldSmartAccountClient = await getSmartAccountClient() + const oldSmartAccountClient = await getSmartAccountClient({ index: 5n }) const smartAccountClient = await getSmartAccountClient({ account: await getSignerToSimpleSmartAccount({ address: oldSmartAccountClient.account.address - }) + }), + index: 5n }) await refillSmartAccount( walletClient, @@ -237,7 +238,7 @@ describe("Simple Account", () => { }, 1000000) test("test prepareUserOperationRequest", async () => { - const smartAccountClient = await getSmartAccountClient() + const smartAccountClient = await getSmartAccountClient({ index: 5n }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -263,6 +264,7 @@ describe("Simple Account", () => { const bundlerClient = getBundlerClient() const smartAccountClient = await getSmartAccountClient({ + index: 5n, sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation @@ -320,6 +322,7 @@ describe("Simple Account", () => { const bundlerClient = getBundlerClient() const smartAccountClient = await getSmartAccountClient({ + index: 5n, sponsorUserOperation: async ({ entryPoint: _entryPoint, userOperation diff --git a/packages/permissionless-test/ep-0.7/utils.ts b/packages/permissionless-test/ep-0.7/utils.ts index 842cc579..77ddadcf 100644 --- a/packages/permissionless-test/ep-0.7/utils.ts +++ b/packages/permissionless-test/ep-0.7/utils.ts @@ -79,10 +79,12 @@ export const getTestingChain = () => { export const getSignerToSimpleSmartAccount = async ({ signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex), - address + address, + index = 0n }: { signer?: SmartAccountSigner address?: Address + index?: bigint } = {}) => { if (!process.env.TEST_PRIVATE_KEY) throw new Error("TEST_PRIVATE_KEY environment variable not set") @@ -93,7 +95,8 @@ export const getSignerToSimpleSmartAccount = async ({ entryPoint: getEntryPoint(), factoryAddress: getFactoryAddress(), signer: signer, - address + address, + index: index }) } @@ -165,10 +168,12 @@ export const getCustomSignerToSimpleSmartAccount = async () => { export const getSmartAccountClient = async ({ account, sponsorUserOperation, - preFund = false + preFund = false, + index = 0n }: SponsorUserOperationMiddleware & { account?: SmartAccount preFund?: boolean + index?: bigint } = {}) => { if (!process.env.BUNDLER_RPC_HOST) throw new Error("BUNDLER_RPC_HOST environment variable not set") @@ -179,7 +184,7 @@ export const getSmartAccountClient = async ({ const smartAccountClient = createSmartAccountClient({ entryPoint: getEntryPoint(), - account: account ?? (await getSignerToSimpleSmartAccount()), + account: account ?? (await getSignerToSimpleSmartAccount({ index })), chain, transport: http(`${process.env.BUNDLER_RPC_HOST}`), sponsorUserOperation: async ({ userOperation, entryPoint }) => { diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 68236ea5..292e6385 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -264,6 +264,11 @@ export async function signerToSimpleSmartAccount< name: "dest", type: "address[]" }, + { + internalType: "uint256[]", + name: "value", + type: "uint256[]" + }, { internalType: "bytes[]", name: "func", @@ -279,6 +284,7 @@ export async function signerToSimpleSmartAccount< functionName: "executeBatch", args: [ argsArray.map((a) => a.to), + argsArray.map((a) => a.value), argsArray.map((a) => a.data) ] }) From a57f246884d3e09310109d119303a62ee4c69a01 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 23 Feb 2024 02:31:19 +0530 Subject: [PATCH 11/35] Make safe expect only 0.6 ep type --- .../accounts/safe/signerToSafeSmartAccount.ts | 5 ++-- .../simple/signerToSimpleSmartAccount.ts | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index bc97d09b..bce3488e 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -174,7 +174,8 @@ const encodeMultiSend = ( } export type SafeSmartAccount< - entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V06_TYPE, + entryPoint extends + ENTRYPOINT_ADDRESS_V06_TYPE = ENTRYPOINT_ADDRESS_V06_TYPE, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -522,7 +523,7 @@ export type SignerToSafeSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function signerToSafeSmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 292e6385..539b3d55 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -255,6 +255,36 @@ export async function signerToSimpleSmartAccount< value: bigint data: Hex }[] + + if (getEntryPointVersion(entryPointAddress) === "v0.6") { + return encodeFunctionData({ + abi: [ + { + inputs: [ + { + internalType: "address[]", + name: "dest", + type: "address[]" + }, + { + internalType: "bytes[]", + name: "func", + type: "bytes[]" + } + ], + name: "executeBatch", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } + ], + functionName: "executeBatch", + args: [ + argsArray.map((a) => a.to), + argsArray.map((a) => a.data) + ] + }) + } return encodeFunctionData({ abi: [ { From 41857ed5163cf0e5c4a78db95bca7522768d0378 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 23 Feb 2024 03:23:39 +0530 Subject: [PATCH 12/35] change private key to safe for 0.6 also --- .../accounts/safe/privateKeyToSafeSmartAccount.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts index 7b99fceb..e8fff189 100644 --- a/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/privateKeyToSafeSmartAccount.ts @@ -1,6 +1,6 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { EntryPoint, Prettify } from "../../types" +import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { type SafeSmartAccount, type SignerToSafeSmartAccountParameters, @@ -8,7 +8,7 @@ import { } from "./signerToSafeSmartAccount" export type PrivateKeyToSafeSmartAccountParameters< - entryPoint extends EntryPoint + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE > = Prettify< { privateKey: Hex @@ -21,7 +21,7 @@ export type PrivateKeyToSafeSmartAccountParameters< * @returns A Private Key Simple Account. */ export async function privateKeyToSafeSmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( From 6e2fb5aec10700e0a117afb5c2289ea65d810323 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Fri, 23 Feb 2024 06:43:56 +0300 Subject: [PATCH 13/35] use pimlico gas price function --- .../ep-0.7/simpleAccount.test.ts | 217 +++++++++++++++++- 1 file changed, 209 insertions(+), 8 deletions(-) diff --git a/packages/permissionless-test/ep-0.7/simpleAccount.test.ts b/packages/permissionless-test/ep-0.7/simpleAccount.test.ts index 05db907e..0df20282 100644 --- a/packages/permissionless-test/ep-0.7/simpleAccount.test.ts +++ b/packages/permissionless-test/ep-0.7/simpleAccount.test.ts @@ -24,6 +24,7 @@ import { GreeterAbi, GreeterBytecode } from "../abis/Greeter" import { getBundlerClient, getEntryPoint, + getPimlicoBundlerClient, getPimlicoPaymasterClient, getPrivateKeyAccount, getPublicClient, @@ -80,7 +81,32 @@ describe("Simple Account", () => { }) test("Smart account client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) const response = await smartAccountClient.signMessage({ message: "hello world" @@ -92,7 +118,32 @@ describe("Simple Account", () => { }) test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) const response = await smartAccountClient.signTypedData({ domain: { @@ -120,7 +171,32 @@ describe("Simple Account", () => { }) test("smart account client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) await expect(async () => smartAccountClient.deployContract({ @@ -133,7 +209,33 @@ describe("Simple Account", () => { }) test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -159,7 +261,32 @@ describe("Simple Account", () => { }, 1000000) test("Smart account write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -195,7 +322,32 @@ describe("Simple Account", () => { }, 1000000) test("Smart account client send transaction", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -214,12 +366,36 @@ describe("Simple Account", () => { test("Smart account client send transaction with address", async () => { const oldSmartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() const smartAccountClient = await getSmartAccountClient({ account: await getSignerToSimpleSmartAccount({ address: oldSmartAccountClient.account.address }), - index: 5n + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } }) + await refillSmartAccount( walletClient, smartAccountClient.account.address @@ -238,7 +414,32 @@ describe("Simple Account", () => { }, 1000000) test("test prepareUserOperationRequest", async () => { - const smartAccountClient = await getSmartAccountClient({ index: 5n }) + const bundlerClient = getBundlerClient() + const pimlicoBundlerClient = getPimlicoBundlerClient() + const smartAccountClient = await getSmartAccountClient({ + index: 5n, + sponsorUserOperation: async (args) => { + const { userOperation } = args + const gasPrices = + await pimlicoBundlerClient.getUserOperationGasPrice() + + userOperation.maxFeePerGas = gasPrices.fast.maxFeePerGas + userOperation.maxPriorityFeePerGas = + gasPrices.fast.maxPriorityFeePerGas + + const gasEstimates = + await bundlerClient.estimateUserOperationGas({ + userOperation: userOperation + }) + userOperation.callGasLimit = gasEstimates.callGasLimit + userOperation.preVerificationGas = + gasEstimates.preVerificationGas + userOperation.verificationGasLimit = + gasEstimates.verificationGasLimit + + return userOperation + } + }) await refillSmartAccount( walletClient, smartAccountClient.account.address From 806fa153b0a7f8f2a2330e4a9ba9d6cc195a1169 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 11:22:44 -0700 Subject: [PATCH 14/35] simplify the check --- packages/permissionless/actions/public/getSenderAddress.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/permissionless/actions/public/getSenderAddress.ts b/packages/permissionless/actions/public/getSenderAddress.ts index 28146138..ad032d14 100644 --- a/packages/permissionless/actions/public/getSenderAddress.ts +++ b/packages/permissionless/actions/public/getSenderAddress.ts @@ -86,7 +86,7 @@ export const getSenderAddress = async < ): Promise
=> { const { initCode, entryPoint, factory, factoryData } = args - if (!initCode && (!factory || !factoryData)) { + if (!initCode && !factory && !factoryData) { throw new Error( "Either `initCode` or `factory` and `factoryData` must be provided" ) From 5dbb2e283086d49857910cbfcf920e56951206cb Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 11:23:53 -0700 Subject: [PATCH 15/35] simplify name --- .../actions/smartAccount/prepareUserOperationRequest.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index b394dd57..e4c5d5f8 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -70,7 +70,7 @@ export type PrepareUserOperationRequestReturnType< entryPoint extends EntryPoint > = UserOperation> -async function prepareUserOperationRequestForEntryPointV0_6< +async function prepareUserOperationRequestForEntryPointV06< entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, @@ -164,7 +164,7 @@ async function prepareUserOperationRequestForEntryPointV0_6< return userOperation as PrepareUserOperationRequestReturnType } -async function prepareUserOperationRequestEntryPointVersion0_7< +async function prepareUserOperationRequestEntryPointV07< entryPoint extends EntryPoint = ENTRYPOINT_ADDRESS_V07_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, @@ -284,14 +284,14 @@ export async function prepareUserOperationRequest< const entryPointVersion = getEntryPointVersion(account.entryPoint) if (entryPointVersion === "v0.6") { - return prepareUserOperationRequestForEntryPointV0_6( + return prepareUserOperationRequestForEntryPointV06( client, args, stateOverrides ) as Promise> } - return prepareUserOperationRequestEntryPointVersion0_7( + return prepareUserOperationRequestEntryPointV07( client, args, stateOverrides From fa953a8ffa06d10292fc637f5401edf661d7c5de Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 11:25:12 -0700 Subject: [PATCH 16/35] simple name --- .../permissionless/utils/getRequiredPrefund.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/permissionless/utils/getRequiredPrefund.ts b/packages/permissionless/utils/getRequiredPrefund.ts index f8f125ae..7357f934 100644 --- a/packages/permissionless/utils/getRequiredPrefund.ts +++ b/packages/permissionless/utils/getRequiredPrefund.ts @@ -38,18 +38,18 @@ export const getRequiredPrefund = ({ ) } - const userOperationVersion0_7 = userOperation as UserOperation<"v0.7"> - const multiplier = userOperationVersion0_7.paymaster ? 3n : 1n + const userOperationV07 = userOperation as UserOperation<"v0.7"> + const multiplier = userOperationV07.paymaster ? 3n : 1n const verificationGasLimit = - userOperationVersion0_7.verificationGasLimit + - (userOperationVersion0_7.paymasterPostOpGasLimit || 0n) + - (userOperationVersion0_7.paymasterVerificationGasLimit || 0n) + userOperationV07.verificationGasLimit + + (userOperationV07.paymasterPostOpGasLimit || 0n) + + (userOperationV07.paymasterVerificationGasLimit || 0n) const requiredGas = - userOperationVersion0_7.callGasLimit + + userOperationV07.callGasLimit + verificationGasLimit * multiplier + - userOperationVersion0_7.preVerificationGas + userOperationV07.preVerificationGas - return BigInt(requiredGas) * BigInt(userOperationVersion0_7.maxFeePerGas) + return BigInt(requiredGas) * BigInt(userOperationV07.maxFeePerGas) } From 644fd2057ef0d9e437a3f4bda8d4eec58fb915ef Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 12:18:01 -0700 Subject: [PATCH 17/35] Fix return types of gas estimation --- .../bundler/estimateUserOperationGas.ts | 64 ++++++++++++++++--- .../clients/decorators/bundler.ts | 2 +- packages/permissionless/types/bundler.ts | 18 ++++-- 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index 1c8a7185..0111a708 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -3,6 +3,7 @@ import { BaseError, type Chain, type Client, + type Hex, type Transport } from "viem" import type { PartialBy } from "viem/types/utils" @@ -11,6 +12,7 @@ import type { Prettify } from "../../types/" import type { BundlerRpcSchema, StateOverrides } from "../../types/bundler" import type { EntryPoint, GetEntryPointVersion } from "../../types/entrypoint" import type { UserOperation } from "../../types/userOperation" +import { getEntryPointVersion } from "../../utils" import { deepHexlify } from "../../utils/deepHexlify" import { type GetEstimateUserOperationGasErrorReturnType, @@ -35,11 +37,20 @@ export type EstimateUserOperationGasParameters = entryPoint: entryPoint } -export type EstimateUserOperationGasReturnType = { - preVerificationGas: bigint - verificationGasLimit: bigint - callGasLimit: bigint -} +export type EstimateUserOperationGasReturnType = + GetEntryPointVersion extends "v0.6" + ? { + preVerificationGas: bigint + verificationGasLimit: bigint + callGasLimit: bigint + } + : { + preVerificationGas: bigint + verificationGasLimit: bigint + callGasLimit: bigint + paymasterVerificationGasLimit: bigint | null + paymasterPostOpGasLimit: bigint | null + } export type EstimateUserOperationErrorType = GetEstimateUserOperationGasErrorReturnType @@ -80,7 +91,7 @@ export const estimateUserOperationGas = async < client: Client>, args: Prettify>, stateOverrides?: StateOverrides -): Promise> => { +): Promise> => { const { userOperation, entryPoint } = args const userOperationWithBigIntAsHex = deepHexlify(userOperation) @@ -98,11 +109,44 @@ export const estimateUserOperationGas = async < : [userOperationWithBigIntAsHex, entryPoint] }) - return { - preVerificationGas: BigInt(response.preVerificationGas || 0), - verificationGasLimit: BigInt(response.verificationGasLimit || 0), - callGasLimit: BigInt(response.callGasLimit || 0) + const entryPointVersion = getEntryPointVersion(entryPoint) + + if (entryPointVersion === "v0.6") { + const responseV06 = response as { + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + } + + return { + preVerificationGas: BigInt(responseV06.preVerificationGas || 0), + verificationGasLimit: BigInt( + responseV06.verificationGasLimit || 0 + ), + callGasLimit: BigInt(responseV06.callGasLimit || 0) + } as EstimateUserOperationGasReturnType } + + const responseV07 = response as { + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + paymasterVerificationGasLimit: Hex | null + paymasterPostOpGasLimit: Hex | null + } + + return { + preVerificationGas: BigInt(responseV07.preVerificationGas || 0), + verificationGasLimit: BigInt(responseV07.verificationGasLimit || 0), + callGasLimit: BigInt(responseV07.callGasLimit || 0), + paymasterVerificationGasLimit: + responseV07.paymasterVerificationGasLimit + ? BigInt(responseV07.paymasterVerificationGasLimit) + : null, + paymasterPostOpGasLimit: responseV07.paymasterPostOpGasLimit + ? BigInt(responseV07.paymasterPostOpGasLimit) + : null + } as EstimateUserOperationGasReturnType } catch (err) { throw getEstimateUserOperationGasError(err as BaseError, args) } diff --git a/packages/permissionless/clients/decorators/bundler.ts b/packages/permissionless/clients/decorators/bundler.ts index 60b00d03..bd91cef8 100644 --- a/packages/permissionless/clients/decorators/bundler.ts +++ b/packages/permissionless/clients/decorators/bundler.ts @@ -90,7 +90,7 @@ export type BundlerActions = { Omit, "entryPoint"> >, stateOverrides?: StateOverrides - ) => Promise> + ) => Promise>> /** * * Returns the supported entrypoints by the bundler service diff --git a/packages/permissionless/types/bundler.ts b/packages/permissionless/types/bundler.ts index 5596a551..a3b56f50 100644 --- a/packages/permissionless/types/bundler.ts +++ b/packages/permissionless/types/bundler.ts @@ -35,11 +35,19 @@ export type BundlerRpcSchema = [ entryPoint: entryPoint, stateOverrides?: StateOverrides ] - ReturnType: { - preVerificationGas: Hex - verificationGasLimit: Hex - callGasLimit: Hex - } + ReturnType: GetEntryPointVersion extends "v0.6" + ? { + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex + } + : { + preVerificationGas: Hex + verificationGasLimit: Hex + callGasLimit: Hex | null + paymasterVerificationGasLimit: Hex | null + paymasterPostOpGasLimit: Hex | null + } }, { Method: "eth_supportedEntryPoints" From 127fe69c787dad56f7f1e98be6a0a53c321ab0b0 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 12:42:44 -0700 Subject: [PATCH 18/35] Remove accounts - will add them later as packages --- .../biconomy/abi/BiconomySmartAccountAbi.ts | 105 ----- .../privateKeyToBiconomySmartAccount.ts | 44 -- .../biconomy/signerToBiconomySmartAccount.ts | 412 ----------------- .../accounts/kernel/abi/KernelAccountAbi.ts | 87 ---- .../kernel/signerToEcdsaKernelSmartAccount.ts | 433 ------------------ 5 files changed, 1081 deletions(-) delete mode 100644 packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts delete mode 100644 packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts delete mode 100644 packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts delete mode 100644 packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts delete mode 100644 packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts diff --git a/packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts b/packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts deleted file mode 100644 index db6ee1ac..00000000 --- a/packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * The exeuctor abi, used to execute transactions on the Biconomy Modular Smart Account - */ -export const BiconomyExecuteAbi = [ - { - inputs: [ - { - internalType: "address", - name: "dest", - type: "address" - }, - { - internalType: "uint256", - name: "value", - type: "uint256" - }, - { - internalType: "bytes", - name: "func", - type: "bytes" - } - ], - name: "execute_ncC", - outputs: [], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { - internalType: "address[]", - name: "dest", - type: "address[]" - }, - { - internalType: "uint256[]", - name: "value", - type: "uint256[]" - }, - { - internalType: "bytes[]", - name: "func", - type: "bytes[]" - } - ], - name: "executeBatch_y6U", - outputs: [], - stateMutability: "nonpayable", - type: "function" - } -] as const - -/** - * The init abi, used to initialise Biconomy Modular Smart Account / setup default ECDSA module - */ -export const BiconomyInitAbi = [ - { - inputs: [ - { - internalType: "address", - name: "handler", - type: "address" - }, - { - internalType: "address", - name: "moduleSetupContract", - type: "address" - }, - { - internalType: "bytes", - name: "moduleSetupData", - type: "bytes" - } - ], - name: "init", - outputs: [ - { - internalType: "address", - name: "", - type: "address" - } - ], - stateMutability: "nonpayable", - type: "function" - }, - { - inputs: [ - { - internalType: "address", - name: "eoaOwner", - type: "address" - } - ], - name: "initForSmartAccount", - outputs: [ - { - internalType: "address", - name: "", - type: "address" - } - ], - stateMutability: "nonpayable", - type: "function" - } -] diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts deleted file mode 100644 index 802116c4..00000000 --- a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { type Chain, type Client, type Hex, type Transport } from "viem" -import { privateKeyToAccount } from "viem/accounts" -import type { EntryPoint, Prettify } from "../../types" -import { - type BiconomySmartAccount, - type SignerToBiconomySmartAccountParameters, - signerToBiconomySmartAccount -} from "./signerToBiconomySmartAccount" - -export type PrivateKeyToBiconomySmartAccountParameters< - entryPoint extends EntryPoint -> = Prettify< - { - privateKey: Hex - } & Omit, "signer"> -> - -/** - * @description Creates a Biconomy Smart Account from a private key. - * - * @returns A Private Key Biconomy Smart Account using ECDSA as default validation module. - */ -export async function privateKeyToBiconomySmartAccount< - entryPoint extends EntryPoint, - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined ->( - client: Client, - { - privateKey, - ...rest - }: PrivateKeyToBiconomySmartAccountParameters -): Promise> { - const privateKeyAccount = privateKeyToAccount(privateKey) - return signerToBiconomySmartAccount< - entryPoint, - TTransport, - TChain, - "privateKey" - >(client, { - signer: privateKeyAccount, - ...rest - }) -} diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts deleted file mode 100644 index 33df0a1a..00000000 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ /dev/null @@ -1,412 +0,0 @@ -import type { TypedData } from "viem" -import { - type Address, - type Chain, - type Client, - type Hex, - type LocalAccount, - type Transport, - type TypedDataDefinition, - concatHex, - encodeAbiParameters, - encodeFunctionData, - encodePacked, - getContractAddress, - hexToBigInt, - keccak256, - parseAbiParameters -} from "viem" -import { toAccount } from "viem/accounts" -import { getChainId, signMessage, signTypedData } from "viem/actions" -import { getAccountNonce } from "../../actions/public/getAccountNonce" -import type { Prettify } from "../../types" -import type { EntryPoint } from "../../types/entrypoint" -import { getUserOperationHash } from "../../utils/getUserOperationHash" -import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" -import { - SignTransactionNotSupportedBySmartAccount, - type SmartAccount, - type SmartAccountSigner -} from "../types" -import { - BiconomyExecuteAbi, - BiconomyInitAbi -} from "./abi/BiconomySmartAccountAbi" - -export type BiconomySmartAccount< - entryPoint extends EntryPoint, - transport extends Transport = Transport, - chain extends Chain | undefined = Chain | undefined -> = SmartAccount - -/** - * The account creation ABI for Biconomy Smart Account (from the biconomy SmartAccountFactory) - */ - -const createAccountAbi = [ - { - inputs: [ - { - internalType: "address", - name: "moduleSetupContract", - type: "address" - }, - { - internalType: "bytes", - name: "moduleSetupData", - type: "bytes" - }, - { - internalType: "uint256", - name: "index", - type: "uint256" - } - ], - name: "deployCounterFactualAccount", - outputs: [ - { - internalType: "address", - name: "proxy", - type: "address" - } - ], - stateMutability: "nonpayable", - type: "function" - } -] as const - -/** - * Default addresses for Biconomy Smart Account - */ -const BICONOMY_ADDRESSES: { - ECDSA_OWNERSHIP_REGISTRY_MODULE: Address - ACCOUNT_V2_0_LOGIC: Address - FACTORY_ADDRESS: Address - DEFAULT_FALLBACK_HANDLER_ADDRESS: Address -} = { - ECDSA_OWNERSHIP_REGISTRY_MODULE: - "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", - ACCOUNT_V2_0_LOGIC: "0x0000002512019Dafb59528B82CB92D3c5D2423aC", - FACTORY_ADDRESS: "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5", - DEFAULT_FALLBACK_HANDLER_ADDRESS: - "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1" -} - -const BICONOMY_PROXY_CREATION_CODE = - "0x6080346100aa57601f61012038819003918201601f19168301916001600160401b038311848410176100af578084926020946040528339810103126100aa57516001600160a01b0381168082036100aa5715610065573055604051605a90816100c68239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405230546000808092368280378136915af43d82803e156020573d90f35b3d90fdfea2646970667358221220a03b18dce0be0b4c9afe58a9eb85c35205e2cf087da098bbf1d23945bf89496064736f6c63430008110033" - -/** - * Get the account initialization code for Biconomy smart account with ECDSA as default authorization module - * @param owner - * @param index - * @param factoryAddress - * @param ecdsaValidatorAddress - */ -const getAccountInitCode = async ({ - owner, - index, - ecdsaModuleAddress -}: { - owner: Address - index: bigint - ecdsaModuleAddress: Address -}): Promise => { - if (!owner) throw new Error("Owner account not found") - - // Build the module setup data - const ecdsaOwnershipInitData = encodeFunctionData({ - abi: BiconomyInitAbi, - functionName: "initForSmartAccount", - args: [owner] - }) - - // Build the account init code - return encodeFunctionData({ - abi: createAccountAbi, - functionName: "deployCounterFactualAccount", - args: [ecdsaModuleAddress, ecdsaOwnershipInitData, index] - }) -} - -const getAccountAddress = async ({ - factoryAddress, - accountLogicAddress, - fallbackHandlerAddress, - ecdsaModuleAddress, - owner, - index = 0n -}: { - factoryAddress: Address - accountLogicAddress: Address - fallbackHandlerAddress: Address - ecdsaModuleAddress: Address - owner: Address - index?: bigint -}): Promise
=> { - // Build the module setup data - const ecdsaOwnershipInitData = encodeFunctionData({ - abi: BiconomyInitAbi, - functionName: "initForSmartAccount", - args: [owner] - }) - - // Build account init code - const initialisationData = encodeFunctionData({ - abi: BiconomyInitAbi, - functionName: "init", - args: [ - fallbackHandlerAddress, - ecdsaModuleAddress, - ecdsaOwnershipInitData - ] - }) - - const deploymentCode = encodePacked( - ["bytes", "uint256"], - [BICONOMY_PROXY_CREATION_CODE, hexToBigInt(accountLogicAddress)] - ) - - const salt = keccak256( - encodePacked( - ["bytes32", "uint256"], - [keccak256(encodePacked(["bytes"], [initialisationData])), index] - ) - ) - - return getContractAddress({ - from: factoryAddress, - salt, - bytecode: deploymentCode, - opcode: "CREATE2" - }) -} - -export type SignerToBiconomySmartAccountParameters< - entryPoint extends EntryPoint, - TSource extends string = "custom", - TAddress extends Address = Address -> = Prettify<{ - signer: SmartAccountSigner - entryPoint: entryPoint - address?: Address - index?: bigint - factoryAddress?: Address - accountLogicAddress?: Address - fallbackHandlerAddress?: Address - ecdsaModuleAddress?: Address -}> - -/** - * Build a Biconomy modular smart account from a private key, that use the ECDSA signer behind the scene - * @param client - * @param privateKey - * @param entryPoint - * @param index - * @param factoryAddress - * @param accountLogicAddress - * @param ecdsaModuleAddress - */ -export async function signerToBiconomySmartAccount< - entryPoint extends EntryPoint, - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined, - TSource extends string = "custom", - TAddress extends Address = Address ->( - client: Client, - { - signer, - address, - entryPoint: entryPointAddress, - index = 0n, - factoryAddress = BICONOMY_ADDRESSES.FACTORY_ADDRESS, - accountLogicAddress = BICONOMY_ADDRESSES.ACCOUNT_V2_0_LOGIC, - fallbackHandlerAddress = BICONOMY_ADDRESSES.DEFAULT_FALLBACK_HANDLER_ADDRESS, - ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE - }: SignerToBiconomySmartAccountParameters -): Promise> { - // Get the private key related account - const viemSigner: LocalAccount = { - ...signer, - signTransaction: (_, __) => { - throw new SignTransactionNotSupportedBySmartAccount() - } - } as LocalAccount - - // Helper to generate the init code for the smart account - const generateInitCode = () => - getAccountInitCode({ - owner: viemSigner.address, - index, - ecdsaModuleAddress - }) - - // Fetch account address and chain id - const [accountAddress, chainId] = await Promise.all([ - address ?? - getAccountAddress({ - owner: viemSigner.address, - ecdsaModuleAddress, - factoryAddress, - accountLogicAddress, - fallbackHandlerAddress, - index - }), - getChainId(client) - ]) - - if (!accountAddress) throw new Error("Account address not found") - - let smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - // Build the EOA Signer - const account = toAccount({ - address: accountAddress, - 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, - client: client, - publicKey: accountAddress, - entryPoint: entryPointAddress, - source: "biconomySmartAccount", - - // Get the nonce of the smart account - async getNonce() { - return getAccountNonce(client, { - sender: accountAddress, - entryPoint: entryPointAddress - }) - }, - - // Sign a user operation - async signUserOperation(userOperation) { - const hash = getUserOperationHash({ - userOperation: { - ...userOperation, - signature: "0x" - }, - entryPoint: entryPointAddress, - chainId: chainId - }) - const signature = await signMessage(client, { - account: viemSigner, - message: { raw: hash } - }) - // userOp signature is encoded module signature + module address - const signatureWithModuleAddress = encodeAbiParameters( - parseAbiParameters("bytes, address"), - [signature, ecdsaModuleAddress] - ) - return signatureWithModuleAddress - }, - - async getFactory() { - if (smartAccountDeployed) return null - - smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - if (smartAccountDeployed) return null - - return factoryAddress - }, - - async getFactoryData() { - if (smartAccountDeployed) return null - - smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - if (smartAccountDeployed) return null - return generateInitCode() - }, - - // Encode the init code - async getInitCode() { - if (smartAccountDeployed) return "0x" - - smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - if (smartAccountDeployed) return "0x" - - return concatHex([factoryAddress, await generateInitCode()]) - }, - - // Encode the deploy call data - async encodeDeployCallData(_) { - throw new Error("Doesn't support account deployment") - }, - - // Encode a call - async encodeCallData(args) { - if (Array.isArray(args)) { - // Encode a batched call - const argsArray = args as { - to: Address - value: bigint - data: Hex - }[] - - return encodeFunctionData({ - abi: BiconomyExecuteAbi, - functionName: "executeBatch_y6U", - args: [ - argsArray.map((a) => a.to), - argsArray.map((a) => a.value), - argsArray.map((a) => a.data) - ] - }) - } - const { to, value, data } = args as { - to: Address - value: bigint - data: Hex - } - // Encode a simple call - return encodeFunctionData({ - abi: BiconomyExecuteAbi, - functionName: "execute_ncC", - args: [to, value, data] - }) - }, - - // Get simple dummy signature for ECDSA module authorization - async getDummySignature(_userOperation) { - const moduleAddress = - BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE - const dynamicPart = moduleAddress.substring(2).padEnd(40, "0") - return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000` - } - } -} diff --git a/packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts b/packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts deleted file mode 100644 index 7ceb6e7d..00000000 --- a/packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * The exeute abi, used to execute a transaction on the kernel smart account - */ -export const KernelExecuteAbi = [ - { - inputs: [ - { - internalType: "address", - name: "to", - type: "address" - }, - { - internalType: "uint256", - name: "value", - type: "uint256" - }, - { - internalType: "bytes", - name: "data", - type: "bytes" - }, - { - internalType: "enum Operation", - name: "", - type: "uint8" - } - ], - name: "execute", - outputs: [], - stateMutability: "payable", - type: "function" - }, - { - inputs: [ - { - components: [ - { - internalType: "address", - name: "to", - type: "address" - }, - { - internalType: "uint256", - name: "value", - type: "uint256" - }, - { - internalType: "bytes", - name: "data", - type: "bytes" - } - ], - internalType: "struct Call[]", - name: "calls", - type: "tuple[]" - } - ], - name: "executeBatch", - outputs: [], - stateMutability: "payable", - type: "function" - } -] as const - -/** - * The init abi, used to initialise kernel account - */ -export const KernelInitAbi = [ - { - inputs: [ - { - internalType: "contract IKernelValidator", - name: "_defaultValidator", - type: "address" - }, - { - internalType: "bytes", - name: "_data", - type: "bytes" - } - ], - name: "initialize", - outputs: [], - stateMutability: "payable", - type: "function" - } -] as const diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts deleted file mode 100644 index b5dd9e6d..00000000 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ /dev/null @@ -1,433 +0,0 @@ -import type { TypedData } from "viem" -import { - type Address, - type Chain, - type Client, - type Hex, - type LocalAccount, - type Transport, - type TypedDataDefinition, - concatHex, - encodeFunctionData, - isAddressEqual -} from "viem" -import { toAccount } from "viem/accounts" -import { - getChainId, - readContract, - signMessage, - signTypedData -} from "viem/actions" -import { getAccountNonce } from "../../actions/public/getAccountNonce" -import { getSenderAddress } from "../../actions/public/getSenderAddress" -import type { Prettify } from "../../types" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE, - EntryPoint -} from "../../types/entrypoint" -import { getEntryPointVersion } from "../../utils" -import { getUserOperationHash } from "../../utils/getUserOperationHash" -import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" -import type { SmartAccount } from "../types" -import { - SignTransactionNotSupportedBySmartAccount, - type SmartAccountSigner -} from "../types" -import { KernelExecuteAbi, KernelInitAbi } from "./abi/KernelAccountAbi" - -export type KernelEcdsaSmartAccount< - entryPoint extends EntryPoint, - transport extends Transport = Transport, - chain extends Chain | undefined = Chain | undefined -> = SmartAccount - -/** - * The account creation ABI for a kernel smart account (from the KernelFactory) - */ -const createAccountAbi = [ - { - inputs: [ - { - internalType: "address", - name: "_implementation", - type: "address" - }, - { - internalType: "bytes", - name: "_data", - type: "bytes" - }, - { - internalType: "uint256", - name: "_index", - type: "uint256" - } - ], - name: "createAccount", - outputs: [ - { - internalType: "address", - name: "proxy", - type: "address" - } - ], - stateMutability: "payable", - type: "function" - } -] as const - -/** - * Default addresses for kernel smart account - */ -const KERNEL_ADDRESSES: { - ECDSA_VALIDATOR: Address - ACCOUNT_V2_2_LOGIC: Address - FACTORY_ADDRESS: Address -} = { - ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", - ACCOUNT_V2_2_LOGIC: "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5", - FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" -} - -/** - * Get the account initialization code for a kernel smart account - * @param owner - * @param index - * @param factoryAddress - * @param accountLogicAddress - * @param ecdsaValidatorAddress - */ -const getAccountInitCode = async ({ - owner, - index, - accountLogicAddress, - ecdsaValidatorAddress -}: { - owner: Address - index: bigint - accountLogicAddress: Address - ecdsaValidatorAddress: Address -}): Promise => { - if (!owner) throw new Error("Owner account not found") - - // Build the account initialization data - const initialisationData = encodeFunctionData({ - abi: KernelInitAbi, - functionName: "initialize", - args: [ecdsaValidatorAddress, owner] - }) - - // Build the account init code - return encodeFunctionData({ - abi: createAccountAbi, - functionName: "createAccount", - args: [accountLogicAddress, initialisationData, index] - }) -} - -/** - * Check the validity of an existing account address, or fetch the pre-deterministic account address for a kernel smart wallet - * @param client - * @param owner - * @param entryPoint - * @param ecdsaValidatorAddress - * @param initCodeProvider - * @param deployedAccountAddress - */ -const getAccountAddress = async < - entryPoint extends EntryPoint, - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined ->({ - client, - owner, - entryPoint: entryPointAddress, - initCodeProvider, - ecdsaValidatorAddress, - deployedAccountAddress, - factoryAddress -}: { - client: Client - owner: Address - initCodeProvider: () => Promise - factoryAddress: Address - entryPoint: entryPoint - ecdsaValidatorAddress: Address - deployedAccountAddress?: Address -}): Promise
=> { - // If we got an already deployed account, ensure it's well deployed, and the validator & signer are correct - if (deployedAccountAddress !== undefined) { - // Get the owner of the deployed account, ensure it's the same as the owner given in params - const deployedAccountOwner = await readContract(client, { - address: ecdsaValidatorAddress, - abi: [ - { - inputs: [ - { - internalType: "address", - name: "", - type: "address" - } - ], - name: "ecdsaValidatorStorage", - outputs: [ - { - internalType: "address", - name: "owner", - type: "address" - } - ], - stateMutability: "view", - type: "function" - } - ], - functionName: "ecdsaValidatorStorage", - args: [deployedAccountAddress] - }) - - // Ensure the address match - if (!isAddressEqual(deployedAccountOwner, owner)) { - throw new Error("Invalid owner for the already deployed account") - } - - // If ok, return the address - return deployedAccountAddress - } - - // Find the init code for this account - const factoryData = await initCodeProvider() - - const entryPointVersion = getEntryPointVersion(entryPointAddress) - - if (entryPointVersion === "v0.6") { - return getSenderAddress(client, { - initCode: concatHex([factoryAddress, factoryData]), - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE - }) - } - - // Get the sender address based on the init code - return getSenderAddress(client, { - factory: factoryAddress, - factoryData, - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V07_TYPE - }) -} - -export type SignerToEcdsaKernelSmartAccountParameters< - entryPoint extends EntryPoint, - TSource extends string = "custom", - TAddress extends Address = Address -> = Prettify<{ - signer: SmartAccountSigner - entryPoint: entryPoint - address?: Address - index?: bigint - factoryAddress?: Address - accountLogicAddress?: Address - ecdsaValidatorAddress?: Address - deployedAccountAddress?: Address -}> -/** - * Build a kernel smart account from a private key, that use the ECDSA signer behind the scene - * @param client - * @param privateKey - * @param entryPoint - * @param index - * @param factoryAddress - * @param accountLogicAddress - * @param ecdsaValidatorAddress - * @param deployedAccountAddress - */ -export async function signerToEcdsaKernelSmartAccount< - entryPoint extends EntryPoint, - TTransport extends Transport = Transport, - TChain extends Chain | undefined = Chain | undefined, - TSource extends string = "custom", - TAddress extends Address = Address ->( - client: Client, - { - signer, - address, - entryPoint: entryPointAddress, - index = 0n, - factoryAddress = KERNEL_ADDRESSES.FACTORY_ADDRESS, - accountLogicAddress = KERNEL_ADDRESSES.ACCOUNT_V2_2_LOGIC, - ecdsaValidatorAddress = KERNEL_ADDRESSES.ECDSA_VALIDATOR, - deployedAccountAddress - }: SignerToEcdsaKernelSmartAccountParameters -): Promise> { - // Get the private key related account - const viemSigner: LocalAccount = { - ...signer, - signTransaction: (_, __) => { - throw new SignTransactionNotSupportedBySmartAccount() - } - } as LocalAccount - - // Helper to generate the init code for the smart account - const generateInitCode = () => - getAccountInitCode({ - owner: viemSigner.address, - index, - accountLogicAddress, - ecdsaValidatorAddress - }) - - // Fetch account address and chain id - const [accountAddress, chainId] = await Promise.all([ - address ?? - getAccountAddress({ - client, - entryPoint: entryPointAddress, - owner: viemSigner.address, - ecdsaValidatorAddress, - initCodeProvider: generateInitCode, - deployedAccountAddress, - factoryAddress - }), - getChainId(client) - ]) - - if (!accountAddress) throw new Error("Account address not found") - - let smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - // Build the EOA Signer - const account = toAccount({ - address: accountAddress, - 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, - client: client, - publicKey: accountAddress, - entryPoint: entryPointAddress, - source: "kernelEcdsaSmartAccount", - - // Get the nonce of the smart account - async getNonce() { - return getAccountNonce(client, { - sender: accountAddress, - entryPoint: entryPointAddress - }) - }, - - // Sign a user operation - async signUserOperation(userOperation) { - const hash = getUserOperationHash({ - userOperation: { - ...userOperation, - signature: "0x" - }, - entryPoint: entryPointAddress, - chainId: chainId - }) - const signature = await signMessage(client, { - account: viemSigner, - message: { raw: hash } - }) - // Always use the sudo mode, since we will use external paymaster - return concatHex(["0x00000000", signature]) - }, - - // Encode the init code - async getInitCode() { - if (smartAccountDeployed) return "0x" - - smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - if (smartAccountDeployed) return "0x" - - return concatHex([factoryAddress, await generateInitCode()]) - }, - - async getFactory() { - if (smartAccountDeployed) return null - - smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - if (smartAccountDeployed) return null - - return factoryAddress - }, - - async getFactoryData() { - if (smartAccountDeployed) return null - - smartAccountDeployed = await isSmartAccountDeployed( - client, - accountAddress - ) - - if (smartAccountDeployed) return null - - return generateInitCode() - }, - - // Encode the deploy call data - async encodeDeployCallData(_) { - throw new Error("Simple account doesn't support account deployment") - }, - - // Encode a call - async encodeCallData(_tx) { - if (Array.isArray(_tx)) { - // Encode a batched call - return encodeFunctionData({ - abi: KernelExecuteAbi, - functionName: "executeBatch", - args: [ - _tx.map((tx) => ({ - to: tx.to, - value: tx.value, - data: tx.data - })) - ] - }) - } - // Encode a simple call - return encodeFunctionData({ - abi: KernelExecuteAbi, - functionName: "execute", - args: [_tx.to, _tx.value, _tx.data, 0] - }) - }, - - // Get simple dummy signature - async getDummySignature(_userOperation) { - return "0x00000000fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" - } - } -} From 9b7297ed5c358b068e405e5c58f36dbf88ed355b Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 12:44:36 -0700 Subject: [PATCH 19/35] fix build --- packages/permissionless/accounts/index.ts | 27 +---------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/packages/permissionless/accounts/index.ts b/packages/permissionless/accounts/index.ts index 0213ea31..a0cffa66 100644 --- a/packages/permissionless/accounts/index.ts +++ b/packages/permissionless/accounts/index.ts @@ -21,23 +21,6 @@ import { signerToSafeSmartAccount } from "./safe/signerToSafeSmartAccount" -import { - type KernelEcdsaSmartAccount, - type SignerToEcdsaKernelSmartAccountParameters, - signerToEcdsaKernelSmartAccount -} from "./kernel/signerToEcdsaKernelSmartAccount" - -import { - type BiconomySmartAccount, - type SignerToBiconomySmartAccountParameters, - signerToBiconomySmartAccount -} from "./biconomy/signerToBiconomySmartAccount" - -import { - type PrivateKeyToBiconomySmartAccountParameters, - privateKeyToBiconomySmartAccount -} from "./biconomy/privateKeyToBiconomySmartAccount" - import { SignTransactionNotSupportedBySmartAccount, type SmartAccount, @@ -52,19 +35,11 @@ export { type SimpleSmartAccount, signerToSimpleSmartAccount, SignTransactionNotSupportedBySmartAccount, - privateKeyToBiconomySmartAccount, privateKeyToSimpleSmartAccount, type SmartAccount, privateKeyToSafeSmartAccount, - type KernelEcdsaSmartAccount, - signerToEcdsaKernelSmartAccount, - type BiconomySmartAccount, - signerToBiconomySmartAccount, type SignerToSimpleSmartAccountParameters, type SignerToSafeSmartAccountParameters, type PrivateKeyToSimpleSmartAccountParameters, - type PrivateKeyToSafeSmartAccountParameters, - type SignerToEcdsaKernelSmartAccountParameters, - type SignerToBiconomySmartAccountParameters, - type PrivateKeyToBiconomySmartAccountParameters + type PrivateKeyToSafeSmartAccountParameters } From c4df3977fcc97b325f195d91fc0be1c3db512984 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 12:46:21 -0700 Subject: [PATCH 20/35] remove tests for accounts --- .../ep-0.6/biconomySmartaccount.test.ts | 392 ----------------- .../ep-0.6/ecdsaKernelAccount.test.ts | 407 ------------------ .../ep-0.7/biconomySmartaccount.test.ts | 392 ----------------- .../ep-0.7/ecdsaKernelAccount.test.ts | 407 ------------------ 4 files changed, 1598 deletions(-) delete mode 100644 packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts delete mode 100644 packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts delete mode 100644 packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts delete mode 100644 packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts diff --git a/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts deleted file mode 100644 index d8fdb7bc..00000000 --- a/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts +++ /dev/null @@ -1,392 +0,0 @@ -import dotenv from "dotenv" -import { - SignTransactionNotSupportedBySmartAccount, - signerToBiconomySmartAccount -} from "permissionless/accounts" -import { - http, - Account, - Address, - Chain, - Hex, - Transport, - WalletClient, - createWalletClient, - decodeEventLog, - getContract, - zeroAddress -} from "viem" -import { privateKeyToAccount } from "viem/accounts" -import { - beforeAll, - beforeEach, - describe, - expect, - expectTypeOf, - test -} from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" -import { - getBundlerClient, - getEntryPoint, - getPimlicoPaymasterClient, - getPrivateKeyAccount, - getPublicClient, - getSignerToBiconomyAccount, - getSmartAccountClient, - getTestingChain, - refillSmartAccount, - waitForNonceUpdate -} from "./utils" - -dotenv.config() - -beforeAll(() => { - if (!process.env.FACTORY_ADDRESS) { - throw new Error("FACTORY_ADDRESS environment variable not set") - } - if (!process.env.TEST_PRIVATE_KEY) { - throw new Error("TEST_PRIVATE_KEY environment variable not set") - } - if (!process.env.RPC_URL) { - throw new Error("RPC_URL environment variable not set") - } - if (!process.env.ENTRYPOINT_ADDRESS) { - throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - } -}) - -/** - * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) - */ -describe("Biconomy Modular Smart Account (ECDSA module)", () => { - let walletClient: WalletClient - - beforeEach(async () => { - const owner = getPrivateKeyAccount() - walletClient = createWalletClient({ - account: owner, - chain: getTestingChain(), - transport: http(process.env.RPC_URL as string) - }) - }) - - test("Account address", async () => { - const ecdsaSmartAccount = await getSignerToBiconomyAccount() - - expectTypeOf(ecdsaSmartAccount.address).toBeString() - expect(ecdsaSmartAccount.address).toHaveLength(42) - expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) - - await expect(async () => - ecdsaSmartAccount.signTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) - }) - - test("Client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - const response = await smartAccountClient.signMessage({ - message: "hello world" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - const response = await smartAccountClient.signTypedData({ - domain: { - chainId: 1, - name: "Test", - verifyingContract: zeroAddress - }, - primaryType: "Test", - types: { - Test: [ - { - name: "test", - type: "string" - } - ] - }, - message: { - test: "hello world" - } - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - await expect(async () => - smartAccountClient.deployContract({ - abi: GreeterAbi, - bytecode: GreeterBytecode - }) - ).rejects.toThrowError("Doesn't support account deployment") - }) - - test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - await waitForNonceUpdate() - }, 1000000) - - test("Write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const entryPointContract = getContract({ - abi: EntryPointAbi, - address: getEntryPoint(), - client: { - public: await getPublicClient(), - wallet: smartAccountClient - } - }) - - const oldBalance = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - const txHash = await entryPointContract.write.depositTo( - [smartAccountClient.account.address], - { - value: 10n - } - ) - - expectTypeOf(txHash).toBeString() - expect(txHash).toHaveLength(66) - - const newBalnce = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - await waitForNonceUpdate() - }, 1000000) - - test("Client send Transaction with paymaster", async () => { - const account = await getSignerToBiconomyAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Client send multiple Transactions with paymaster", async () => { - const account = await getSignerToBiconomyAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Can use a deployed account", async () => { - const initialEcdsaSmartAccount = await getSignerToBiconomyAccount() - const publicClient = await getPublicClient() - const smartAccountClient = await getSmartAccountClient({ - account: initialEcdsaSmartAccount, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - // Send an initial tx to deploy the account - const hash = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // Wait for the tx to be done (so we are sure that the account is deployed) - await publicClient.waitForTransactionReceipt({ hash }) - - // Build a new account with a valid owner - const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) - const alreadyDeployedEcdsaSmartAccount = - await signerToBiconomySmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: signer - }) - - // Ensure the two account have the same address - expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( - initialEcdsaSmartAccount.address - ) - }, 1000000) -}) diff --git a/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts deleted file mode 100644 index 317e80c5..00000000 --- a/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -import dotenv from "dotenv" -import { UserOperation } from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToEcdsaKernelSmartAccount -} from "permissionless/accounts" -import { - http, - Account, - Address, - Chain, - Hex, - Transport, - WalletClient, - createWalletClient, - decodeEventLog, - getContract, - zeroAddress -} from "viem" -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { - beforeAll, - beforeEach, - describe, - expect, - expectTypeOf, - test -} from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" -import { - getBundlerClient, - getEntryPoint, - getPimlicoPaymasterClient, - getPrivateKeyAccount, - getPublicClient, - getSignerToEcdsaKernelAccount, - getSmartAccountClient, - getTestingChain, - refillSmartAccount, - waitForNonceUpdate -} from "./utils" - -dotenv.config() - -beforeAll(() => { - if (!process.env.FACTORY_ADDRESS) { - throw new Error("FACTORY_ADDRESS environment variable not set") - } - if (!process.env.TEST_PRIVATE_KEY) { - throw new Error("TEST_PRIVATE_KEY environment variable not set") - } - if (!process.env.RPC_URL) { - throw new Error("RPC_URL environment variable not set") - } - if (!process.env.ENTRYPOINT_ADDRESS) { - throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - } -}) - -/** - * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) - */ -describe("ECDSA kernel Account", () => { - let walletClient: WalletClient - - beforeEach(async () => { - const owner = getPrivateKeyAccount() - walletClient = createWalletClient({ - account: owner, - chain: getTestingChain(), - transport: http(process.env.RPC_URL as string) - }) - }) - - test("Account address", async () => { - const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() - - expectTypeOf(ecdsaSmartAccount.address).toBeString() - expect(ecdsaSmartAccount.address).toHaveLength(42) - expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) - - await expect(async () => - ecdsaSmartAccount.signTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) - }) - - test("Client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - const response = await smartAccountClient.signMessage({ - message: "hello world" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - const response = await smartAccountClient.signTypedData({ - domain: { - chainId: 1, - name: "Test", - verifyingContract: zeroAddress - }, - primaryType: "Test", - types: { - Test: [ - { - name: "test", - type: "string" - } - ] - }, - message: { - test: "hello world" - } - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - await expect(async () => - smartAccountClient.deployContract({ - abi: GreeterAbi, - bytecode: GreeterBytecode - }) - ).rejects.toThrowError( - "Simple account doesn't support account deployment" - ) - }) - - test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - await waitForNonceUpdate() - }, 1000000) - - test("Write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const entryPointContract = getContract({ - abi: EntryPointAbi, - address: getEntryPoint(), - client: { - public: await getPublicClient(), - wallet: smartAccountClient - } - }) - - const oldBalance = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - const txHash = await entryPointContract.write.depositTo( - [smartAccountClient.account.address], - { - value: 10n - } - ) - - expectTypeOf(txHash).toBeString() - expect(txHash).toHaveLength(66) - - const newBalnce = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - await waitForNonceUpdate() - }, 1000000) - - test("Client send Transaction with paymaster", async () => { - const account = await getSignerToEcdsaKernelAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Client send multiple Transactions with paymaster", async () => { - const account = await getSignerToEcdsaKernelAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Can use a deployed account", async () => { - const initialEcdsaSmartAccount = await getSignerToEcdsaKernelAccount() - const publicClient = await getPublicClient() - const smartAccountClient = await getSmartAccountClient({ - account: initialEcdsaSmartAccount, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - // Send an initial tx to deploy the account - const hash = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // Wait for the tx to be done (so we are sure that the account is deployed) - await publicClient.waitForTransactionReceipt({ hash }) - const deployedAccountAddress = initialEcdsaSmartAccount.address - - // Build a new account with a valid owner - const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) - const alreadyDeployedEcdsaSmartAccount = - await signerToEcdsaKernelSmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: signer, - deployedAccountAddress - }) - - // Ensure the two account have the same address - expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( - initialEcdsaSmartAccount.address - ) - - // Ensure that it will fail with an invalid owner address - const invalidOwner = privateKeyToAccount(generatePrivateKey()) - await expect(async () => - signerToEcdsaKernelSmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: invalidOwner, - deployedAccountAddress - }) - ).rejects.toThrowError("Invalid owner for the already deployed account") - }, 1000000) -}) diff --git a/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts deleted file mode 100644 index d8fdb7bc..00000000 --- a/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts +++ /dev/null @@ -1,392 +0,0 @@ -import dotenv from "dotenv" -import { - SignTransactionNotSupportedBySmartAccount, - signerToBiconomySmartAccount -} from "permissionless/accounts" -import { - http, - Account, - Address, - Chain, - Hex, - Transport, - WalletClient, - createWalletClient, - decodeEventLog, - getContract, - zeroAddress -} from "viem" -import { privateKeyToAccount } from "viem/accounts" -import { - beforeAll, - beforeEach, - describe, - expect, - expectTypeOf, - test -} from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" -import { - getBundlerClient, - getEntryPoint, - getPimlicoPaymasterClient, - getPrivateKeyAccount, - getPublicClient, - getSignerToBiconomyAccount, - getSmartAccountClient, - getTestingChain, - refillSmartAccount, - waitForNonceUpdate -} from "./utils" - -dotenv.config() - -beforeAll(() => { - if (!process.env.FACTORY_ADDRESS) { - throw new Error("FACTORY_ADDRESS environment variable not set") - } - if (!process.env.TEST_PRIVATE_KEY) { - throw new Error("TEST_PRIVATE_KEY environment variable not set") - } - if (!process.env.RPC_URL) { - throw new Error("RPC_URL environment variable not set") - } - if (!process.env.ENTRYPOINT_ADDRESS) { - throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - } -}) - -/** - * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) - */ -describe("Biconomy Modular Smart Account (ECDSA module)", () => { - let walletClient: WalletClient - - beforeEach(async () => { - const owner = getPrivateKeyAccount() - walletClient = createWalletClient({ - account: owner, - chain: getTestingChain(), - transport: http(process.env.RPC_URL as string) - }) - }) - - test("Account address", async () => { - const ecdsaSmartAccount = await getSignerToBiconomyAccount() - - expectTypeOf(ecdsaSmartAccount.address).toBeString() - expect(ecdsaSmartAccount.address).toHaveLength(42) - expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) - - await expect(async () => - ecdsaSmartAccount.signTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) - }) - - test("Client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - const response = await smartAccountClient.signMessage({ - message: "hello world" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - const response = await smartAccountClient.signTypedData({ - domain: { - chainId: 1, - name: "Test", - verifyingContract: zeroAddress - }, - primaryType: "Test", - types: { - Test: [ - { - name: "test", - type: "string" - } - ] - }, - message: { - test: "hello world" - } - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - await expect(async () => - smartAccountClient.deployContract({ - abi: GreeterAbi, - bytecode: GreeterBytecode - }) - ).rejects.toThrowError("Doesn't support account deployment") - }) - - test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - await waitForNonceUpdate() - }, 1000000) - - test("Write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const entryPointContract = getContract({ - abi: EntryPointAbi, - address: getEntryPoint(), - client: { - public: await getPublicClient(), - wallet: smartAccountClient - } - }) - - const oldBalance = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - const txHash = await entryPointContract.write.depositTo( - [smartAccountClient.account.address], - { - value: 10n - } - ) - - expectTypeOf(txHash).toBeString() - expect(txHash).toHaveLength(66) - - const newBalnce = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - await waitForNonceUpdate() - }, 1000000) - - test("Client send Transaction with paymaster", async () => { - const account = await getSignerToBiconomyAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Client send multiple Transactions with paymaster", async () => { - const account = await getSignerToBiconomyAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Can use a deployed account", async () => { - const initialEcdsaSmartAccount = await getSignerToBiconomyAccount() - const publicClient = await getPublicClient() - const smartAccountClient = await getSmartAccountClient({ - account: initialEcdsaSmartAccount, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - // Send an initial tx to deploy the account - const hash = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // Wait for the tx to be done (so we are sure that the account is deployed) - await publicClient.waitForTransactionReceipt({ hash }) - - // Build a new account with a valid owner - const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) - const alreadyDeployedEcdsaSmartAccount = - await signerToBiconomySmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: signer - }) - - // Ensure the two account have the same address - expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( - initialEcdsaSmartAccount.address - ) - }, 1000000) -}) diff --git a/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts deleted file mode 100644 index 317e80c5..00000000 --- a/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -import dotenv from "dotenv" -import { UserOperation } from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToEcdsaKernelSmartAccount -} from "permissionless/accounts" -import { - http, - Account, - Address, - Chain, - Hex, - Transport, - WalletClient, - createWalletClient, - decodeEventLog, - getContract, - zeroAddress -} from "viem" -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { - beforeAll, - beforeEach, - describe, - expect, - expectTypeOf, - test -} from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" -import { - getBundlerClient, - getEntryPoint, - getPimlicoPaymasterClient, - getPrivateKeyAccount, - getPublicClient, - getSignerToEcdsaKernelAccount, - getSmartAccountClient, - getTestingChain, - refillSmartAccount, - waitForNonceUpdate -} from "./utils" - -dotenv.config() - -beforeAll(() => { - if (!process.env.FACTORY_ADDRESS) { - throw new Error("FACTORY_ADDRESS environment variable not set") - } - if (!process.env.TEST_PRIVATE_KEY) { - throw new Error("TEST_PRIVATE_KEY environment variable not set") - } - if (!process.env.RPC_URL) { - throw new Error("RPC_URL environment variable not set") - } - if (!process.env.ENTRYPOINT_ADDRESS) { - throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - } -}) - -/** - * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) - */ -describe("ECDSA kernel Account", () => { - let walletClient: WalletClient - - beforeEach(async () => { - const owner = getPrivateKeyAccount() - walletClient = createWalletClient({ - account: owner, - chain: getTestingChain(), - transport: http(process.env.RPC_URL as string) - }) - }) - - test("Account address", async () => { - const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() - - expectTypeOf(ecdsaSmartAccount.address).toBeString() - expect(ecdsaSmartAccount.address).toHaveLength(42) - expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) - - await expect(async () => - ecdsaSmartAccount.signTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) - }) - - test("Client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - const response = await smartAccountClient.signMessage({ - message: "hello world" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - const response = await smartAccountClient.signTypedData({ - domain: { - chainId: 1, - name: "Test", - verifyingContract: zeroAddress - }, - primaryType: "Test", - types: { - Test: [ - { - name: "test", - type: "string" - } - ] - }, - message: { - test: "hello world" - } - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - await expect(async () => - smartAccountClient.deployContract({ - abi: GreeterAbi, - bytecode: GreeterBytecode - }) - ).rejects.toThrowError( - "Simple account doesn't support account deployment" - ) - }) - - test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - await waitForNonceUpdate() - }, 1000000) - - test("Write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const entryPointContract = getContract({ - abi: EntryPointAbi, - address: getEntryPoint(), - client: { - public: await getPublicClient(), - wallet: smartAccountClient - } - }) - - const oldBalance = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - const txHash = await entryPointContract.write.depositTo( - [smartAccountClient.account.address], - { - value: 10n - } - ) - - expectTypeOf(txHash).toBeString() - expect(txHash).toHaveLength(66) - - const newBalnce = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - await waitForNonceUpdate() - }, 1000000) - - test("Client send Transaction with paymaster", async () => { - const account = await getSignerToEcdsaKernelAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Client send multiple Transactions with paymaster", async () => { - const account = await getSignerToEcdsaKernelAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Can use a deployed account", async () => { - const initialEcdsaSmartAccount = await getSignerToEcdsaKernelAccount() - const publicClient = await getPublicClient() - const smartAccountClient = await getSmartAccountClient({ - account: initialEcdsaSmartAccount, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - // Send an initial tx to deploy the account - const hash = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // Wait for the tx to be done (so we are sure that the account is deployed) - await publicClient.waitForTransactionReceipt({ hash }) - const deployedAccountAddress = initialEcdsaSmartAccount.address - - // Build a new account with a valid owner - const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) - const alreadyDeployedEcdsaSmartAccount = - await signerToEcdsaKernelSmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: signer, - deployedAccountAddress - }) - - // Ensure the two account have the same address - expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( - initialEcdsaSmartAccount.address - ) - - // Ensure that it will fail with an invalid owner address - const invalidOwner = privateKeyToAccount(generatePrivateKey()) - await expect(async () => - signerToEcdsaKernelSmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: invalidOwner, - deployedAccountAddress - }) - ).rejects.toThrowError("Invalid owner for the already deployed account") - }, 1000000) -}) From 68366ba7f70996dcb62dbb647afd73cbc05fb945 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:16:23 -0700 Subject: [PATCH 21/35] Revert "Remove accounts - will add them later as packages" This reverts commit 127fe69c787dad56f7f1e98be6a0a53c321ab0b0. --- .../biconomy/abi/BiconomySmartAccountAbi.ts | 105 +++++ .../privateKeyToBiconomySmartAccount.ts | 44 ++ .../biconomy/signerToBiconomySmartAccount.ts | 412 +++++++++++++++++ .../accounts/kernel/abi/KernelAccountAbi.ts | 87 ++++ .../kernel/signerToEcdsaKernelSmartAccount.ts | 433 ++++++++++++++++++ 5 files changed, 1081 insertions(+) create mode 100644 packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts create mode 100644 packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts create mode 100644 packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts create mode 100644 packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts create mode 100644 packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts diff --git a/packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts b/packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts new file mode 100644 index 00000000..db6ee1ac --- /dev/null +++ b/packages/permissionless/accounts/biconomy/abi/BiconomySmartAccountAbi.ts @@ -0,0 +1,105 @@ +/** + * The exeuctor abi, used to execute transactions on the Biconomy Modular Smart Account + */ +export const BiconomyExecuteAbi = [ + { + inputs: [ + { + internalType: "address", + name: "dest", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "func", + type: "bytes" + } + ], + name: "execute_ncC", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address[]", + name: "dest", + type: "address[]" + }, + { + internalType: "uint256[]", + name: "value", + type: "uint256[]" + }, + { + internalType: "bytes[]", + name: "func", + type: "bytes[]" + } + ], + name: "executeBatch_y6U", + outputs: [], + stateMutability: "nonpayable", + type: "function" + } +] as const + +/** + * The init abi, used to initialise Biconomy Modular Smart Account / setup default ECDSA module + */ +export const BiconomyInitAbi = [ + { + inputs: [ + { + internalType: "address", + name: "handler", + type: "address" + }, + { + internalType: "address", + name: "moduleSetupContract", + type: "address" + }, + { + internalType: "bytes", + name: "moduleSetupData", + type: "bytes" + } + ], + name: "init", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + internalType: "address", + name: "eoaOwner", + type: "address" + } + ], + name: "initForSmartAccount", + outputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + } +] diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts new file mode 100644 index 00000000..802116c4 --- /dev/null +++ b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts @@ -0,0 +1,44 @@ +import { type Chain, type Client, type Hex, type Transport } from "viem" +import { privateKeyToAccount } from "viem/accounts" +import type { EntryPoint, Prettify } from "../../types" +import { + type BiconomySmartAccount, + type SignerToBiconomySmartAccountParameters, + signerToBiconomySmartAccount +} from "./signerToBiconomySmartAccount" + +export type PrivateKeyToBiconomySmartAccountParameters< + entryPoint extends EntryPoint +> = Prettify< + { + privateKey: Hex + } & Omit, "signer"> +> + +/** + * @description Creates a Biconomy Smart Account from a private key. + * + * @returns A Private Key Biconomy Smart Account using ECDSA as default validation module. + */ +export async function privateKeyToBiconomySmartAccount< + entryPoint extends EntryPoint, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined +>( + client: Client, + { + privateKey, + ...rest + }: PrivateKeyToBiconomySmartAccountParameters +): Promise> { + const privateKeyAccount = privateKeyToAccount(privateKey) + return signerToBiconomySmartAccount< + entryPoint, + TTransport, + TChain, + "privateKey" + >(client, { + signer: privateKeyAccount, + ...rest + }) +} diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts new file mode 100644 index 00000000..33df0a1a --- /dev/null +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -0,0 +1,412 @@ +import type { TypedData } from "viem" +import { + type Address, + type Chain, + type Client, + type Hex, + type LocalAccount, + type Transport, + type TypedDataDefinition, + concatHex, + encodeAbiParameters, + encodeFunctionData, + encodePacked, + getContractAddress, + hexToBigInt, + keccak256, + parseAbiParameters +} from "viem" +import { toAccount } from "viem/accounts" +import { getChainId, signMessage, signTypedData } from "viem/actions" +import { getAccountNonce } from "../../actions/public/getAccountNonce" +import type { Prettify } from "../../types" +import type { EntryPoint } from "../../types/entrypoint" +import { getUserOperationHash } from "../../utils/getUserOperationHash" +import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" +import { + SignTransactionNotSupportedBySmartAccount, + type SmartAccount, + type SmartAccountSigner +} from "../types" +import { + BiconomyExecuteAbi, + BiconomyInitAbi +} from "./abi/BiconomySmartAccountAbi" + +export type BiconomySmartAccount< + entryPoint extends EntryPoint, + transport extends Transport = Transport, + chain extends Chain | undefined = Chain | undefined +> = SmartAccount + +/** + * The account creation ABI for Biconomy Smart Account (from the biconomy SmartAccountFactory) + */ + +const createAccountAbi = [ + { + inputs: [ + { + internalType: "address", + name: "moduleSetupContract", + type: "address" + }, + { + internalType: "bytes", + name: "moduleSetupData", + type: "bytes" + }, + { + internalType: "uint256", + name: "index", + type: "uint256" + } + ], + name: "deployCounterFactualAccount", + outputs: [ + { + internalType: "address", + name: "proxy", + type: "address" + } + ], + stateMutability: "nonpayable", + type: "function" + } +] as const + +/** + * Default addresses for Biconomy Smart Account + */ +const BICONOMY_ADDRESSES: { + ECDSA_OWNERSHIP_REGISTRY_MODULE: Address + ACCOUNT_V2_0_LOGIC: Address + FACTORY_ADDRESS: Address + DEFAULT_FALLBACK_HANDLER_ADDRESS: Address +} = { + ECDSA_OWNERSHIP_REGISTRY_MODULE: + "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e", + ACCOUNT_V2_0_LOGIC: "0x0000002512019Dafb59528B82CB92D3c5D2423aC", + FACTORY_ADDRESS: "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5", + DEFAULT_FALLBACK_HANDLER_ADDRESS: + "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1" +} + +const BICONOMY_PROXY_CREATION_CODE = + "0x6080346100aa57601f61012038819003918201601f19168301916001600160401b038311848410176100af578084926020946040528339810103126100aa57516001600160a01b0381168082036100aa5715610065573055604051605a90816100c68239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405230546000808092368280378136915af43d82803e156020573d90f35b3d90fdfea2646970667358221220a03b18dce0be0b4c9afe58a9eb85c35205e2cf087da098bbf1d23945bf89496064736f6c63430008110033" + +/** + * Get the account initialization code for Biconomy smart account with ECDSA as default authorization module + * @param owner + * @param index + * @param factoryAddress + * @param ecdsaValidatorAddress + */ +const getAccountInitCode = async ({ + owner, + index, + ecdsaModuleAddress +}: { + owner: Address + index: bigint + ecdsaModuleAddress: Address +}): Promise => { + if (!owner) throw new Error("Owner account not found") + + // Build the module setup data + const ecdsaOwnershipInitData = encodeFunctionData({ + abi: BiconomyInitAbi, + functionName: "initForSmartAccount", + args: [owner] + }) + + // Build the account init code + return encodeFunctionData({ + abi: createAccountAbi, + functionName: "deployCounterFactualAccount", + args: [ecdsaModuleAddress, ecdsaOwnershipInitData, index] + }) +} + +const getAccountAddress = async ({ + factoryAddress, + accountLogicAddress, + fallbackHandlerAddress, + ecdsaModuleAddress, + owner, + index = 0n +}: { + factoryAddress: Address + accountLogicAddress: Address + fallbackHandlerAddress: Address + ecdsaModuleAddress: Address + owner: Address + index?: bigint +}): Promise
=> { + // Build the module setup data + const ecdsaOwnershipInitData = encodeFunctionData({ + abi: BiconomyInitAbi, + functionName: "initForSmartAccount", + args: [owner] + }) + + // Build account init code + const initialisationData = encodeFunctionData({ + abi: BiconomyInitAbi, + functionName: "init", + args: [ + fallbackHandlerAddress, + ecdsaModuleAddress, + ecdsaOwnershipInitData + ] + }) + + const deploymentCode = encodePacked( + ["bytes", "uint256"], + [BICONOMY_PROXY_CREATION_CODE, hexToBigInt(accountLogicAddress)] + ) + + const salt = keccak256( + encodePacked( + ["bytes32", "uint256"], + [keccak256(encodePacked(["bytes"], [initialisationData])), index] + ) + ) + + return getContractAddress({ + from: factoryAddress, + salt, + bytecode: deploymentCode, + opcode: "CREATE2" + }) +} + +export type SignerToBiconomySmartAccountParameters< + entryPoint extends EntryPoint, + TSource extends string = "custom", + TAddress extends Address = Address +> = Prettify<{ + signer: SmartAccountSigner + entryPoint: entryPoint + address?: Address + index?: bigint + factoryAddress?: Address + accountLogicAddress?: Address + fallbackHandlerAddress?: Address + ecdsaModuleAddress?: Address +}> + +/** + * Build a Biconomy modular smart account from a private key, that use the ECDSA signer behind the scene + * @param client + * @param privateKey + * @param entryPoint + * @param index + * @param factoryAddress + * @param accountLogicAddress + * @param ecdsaModuleAddress + */ +export async function signerToBiconomySmartAccount< + entryPoint extends EntryPoint, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TSource extends string = "custom", + TAddress extends Address = Address +>( + client: Client, + { + signer, + address, + entryPoint: entryPointAddress, + index = 0n, + factoryAddress = BICONOMY_ADDRESSES.FACTORY_ADDRESS, + accountLogicAddress = BICONOMY_ADDRESSES.ACCOUNT_V2_0_LOGIC, + fallbackHandlerAddress = BICONOMY_ADDRESSES.DEFAULT_FALLBACK_HANDLER_ADDRESS, + ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE + }: SignerToBiconomySmartAccountParameters +): Promise> { + // Get the private key related account + const viemSigner: LocalAccount = { + ...signer, + signTransaction: (_, __) => { + throw new SignTransactionNotSupportedBySmartAccount() + } + } as LocalAccount + + // Helper to generate the init code for the smart account + const generateInitCode = () => + getAccountInitCode({ + owner: viemSigner.address, + index, + ecdsaModuleAddress + }) + + // Fetch account address and chain id + const [accountAddress, chainId] = await Promise.all([ + address ?? + getAccountAddress({ + owner: viemSigner.address, + ecdsaModuleAddress, + factoryAddress, + accountLogicAddress, + fallbackHandlerAddress, + index + }), + getChainId(client) + ]) + + if (!accountAddress) throw new Error("Account address not found") + + let smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + // Build the EOA Signer + const account = toAccount({ + address: accountAddress, + 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, + client: client, + publicKey: accountAddress, + entryPoint: entryPointAddress, + source: "biconomySmartAccount", + + // Get the nonce of the smart account + async getNonce() { + return getAccountNonce(client, { + sender: accountAddress, + entryPoint: entryPointAddress + }) + }, + + // Sign a user operation + async signUserOperation(userOperation) { + const hash = getUserOperationHash({ + userOperation: { + ...userOperation, + signature: "0x" + }, + entryPoint: entryPointAddress, + chainId: chainId + }) + const signature = await signMessage(client, { + account: viemSigner, + message: { raw: hash } + }) + // userOp signature is encoded module signature + module address + const signatureWithModuleAddress = encodeAbiParameters( + parseAbiParameters("bytes, address"), + [signature, ecdsaModuleAddress] + ) + return signatureWithModuleAddress + }, + + async getFactory() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + + return factoryAddress + }, + + async getFactoryData() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + return generateInitCode() + }, + + // Encode the init code + async getInitCode() { + if (smartAccountDeployed) return "0x" + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return "0x" + + return concatHex([factoryAddress, await generateInitCode()]) + }, + + // Encode the deploy call data + async encodeDeployCallData(_) { + throw new Error("Doesn't support account deployment") + }, + + // Encode a call + async encodeCallData(args) { + if (Array.isArray(args)) { + // Encode a batched call + const argsArray = args as { + to: Address + value: bigint + data: Hex + }[] + + return encodeFunctionData({ + abi: BiconomyExecuteAbi, + functionName: "executeBatch_y6U", + args: [ + argsArray.map((a) => a.to), + argsArray.map((a) => a.value), + argsArray.map((a) => a.data) + ] + }) + } + const { to, value, data } = args as { + to: Address + value: bigint + data: Hex + } + // Encode a simple call + return encodeFunctionData({ + abi: BiconomyExecuteAbi, + functionName: "execute_ncC", + args: [to, value, data] + }) + }, + + // Get simple dummy signature for ECDSA module authorization + async getDummySignature(_userOperation) { + const moduleAddress = + BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE + const dynamicPart = moduleAddress.substring(2).padEnd(40, "0") + return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000` + } + } +} diff --git a/packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts b/packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts new file mode 100644 index 00000000..7ceb6e7d --- /dev/null +++ b/packages/permissionless/accounts/kernel/abi/KernelAccountAbi.ts @@ -0,0 +1,87 @@ +/** + * The exeute abi, used to execute a transaction on the kernel smart account + */ +export const KernelExecuteAbi = [ + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "data", + type: "bytes" + }, + { + internalType: "enum Operation", + name: "", + type: "uint8" + } + ], + name: "execute", + outputs: [], + stateMutability: "payable", + type: "function" + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "to", + type: "address" + }, + { + internalType: "uint256", + name: "value", + type: "uint256" + }, + { + internalType: "bytes", + name: "data", + type: "bytes" + } + ], + internalType: "struct Call[]", + name: "calls", + type: "tuple[]" + } + ], + name: "executeBatch", + outputs: [], + stateMutability: "payable", + type: "function" + } +] as const + +/** + * The init abi, used to initialise kernel account + */ +export const KernelInitAbi = [ + { + inputs: [ + { + internalType: "contract IKernelValidator", + name: "_defaultValidator", + type: "address" + }, + { + internalType: "bytes", + name: "_data", + type: "bytes" + } + ], + name: "initialize", + outputs: [], + stateMutability: "payable", + type: "function" + } +] as const diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts new file mode 100644 index 00000000..b5dd9e6d --- /dev/null +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -0,0 +1,433 @@ +import type { TypedData } from "viem" +import { + type Address, + type Chain, + type Client, + type Hex, + type LocalAccount, + type Transport, + type TypedDataDefinition, + concatHex, + encodeFunctionData, + isAddressEqual +} from "viem" +import { toAccount } from "viem/accounts" +import { + getChainId, + readContract, + signMessage, + signTypedData +} from "viem/actions" +import { getAccountNonce } from "../../actions/public/getAccountNonce" +import { getSenderAddress } from "../../actions/public/getSenderAddress" +import type { Prettify } from "../../types" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, + EntryPoint +} from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" +import { getUserOperationHash } from "../../utils/getUserOperationHash" +import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" +import type { SmartAccount } from "../types" +import { + SignTransactionNotSupportedBySmartAccount, + type SmartAccountSigner +} from "../types" +import { KernelExecuteAbi, KernelInitAbi } from "./abi/KernelAccountAbi" + +export type KernelEcdsaSmartAccount< + entryPoint extends EntryPoint, + transport extends Transport = Transport, + chain extends Chain | undefined = Chain | undefined +> = SmartAccount + +/** + * The account creation ABI for a kernel smart account (from the KernelFactory) + */ +const createAccountAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_implementation", + type: "address" + }, + { + internalType: "bytes", + name: "_data", + type: "bytes" + }, + { + internalType: "uint256", + name: "_index", + type: "uint256" + } + ], + name: "createAccount", + outputs: [ + { + internalType: "address", + name: "proxy", + type: "address" + } + ], + stateMutability: "payable", + type: "function" + } +] as const + +/** + * Default addresses for kernel smart account + */ +const KERNEL_ADDRESSES: { + ECDSA_VALIDATOR: Address + ACCOUNT_V2_2_LOGIC: Address + FACTORY_ADDRESS: Address +} = { + ECDSA_VALIDATOR: "0xd9AB5096a832b9ce79914329DAEE236f8Eea0390", + ACCOUNT_V2_2_LOGIC: "0x0DA6a956B9488eD4dd761E59f52FDc6c8068E6B5", + FACTORY_ADDRESS: "0x5de4839a76cf55d0c90e2061ef4386d962E15ae3" +} + +/** + * Get the account initialization code for a kernel smart account + * @param owner + * @param index + * @param factoryAddress + * @param accountLogicAddress + * @param ecdsaValidatorAddress + */ +const getAccountInitCode = async ({ + owner, + index, + accountLogicAddress, + ecdsaValidatorAddress +}: { + owner: Address + index: bigint + accountLogicAddress: Address + ecdsaValidatorAddress: Address +}): Promise => { + if (!owner) throw new Error("Owner account not found") + + // Build the account initialization data + const initialisationData = encodeFunctionData({ + abi: KernelInitAbi, + functionName: "initialize", + args: [ecdsaValidatorAddress, owner] + }) + + // Build the account init code + return encodeFunctionData({ + abi: createAccountAbi, + functionName: "createAccount", + args: [accountLogicAddress, initialisationData, index] + }) +} + +/** + * Check the validity of an existing account address, or fetch the pre-deterministic account address for a kernel smart wallet + * @param client + * @param owner + * @param entryPoint + * @param ecdsaValidatorAddress + * @param initCodeProvider + * @param deployedAccountAddress + */ +const getAccountAddress = async < + entryPoint extends EntryPoint, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined +>({ + client, + owner, + entryPoint: entryPointAddress, + initCodeProvider, + ecdsaValidatorAddress, + deployedAccountAddress, + factoryAddress +}: { + client: Client + owner: Address + initCodeProvider: () => Promise + factoryAddress: Address + entryPoint: entryPoint + ecdsaValidatorAddress: Address + deployedAccountAddress?: Address +}): Promise
=> { + // If we got an already deployed account, ensure it's well deployed, and the validator & signer are correct + if (deployedAccountAddress !== undefined) { + // Get the owner of the deployed account, ensure it's the same as the owner given in params + const deployedAccountOwner = await readContract(client, { + address: ecdsaValidatorAddress, + abi: [ + { + inputs: [ + { + internalType: "address", + name: "", + type: "address" + } + ], + name: "ecdsaValidatorStorage", + outputs: [ + { + internalType: "address", + name: "owner", + type: "address" + } + ], + stateMutability: "view", + type: "function" + } + ], + functionName: "ecdsaValidatorStorage", + args: [deployedAccountAddress] + }) + + // Ensure the address match + if (!isAddressEqual(deployedAccountOwner, owner)) { + throw new Error("Invalid owner for the already deployed account") + } + + // If ok, return the address + return deployedAccountAddress + } + + // Find the init code for this account + const factoryData = await initCodeProvider() + + const entryPointVersion = getEntryPointVersion(entryPointAddress) + + if (entryPointVersion === "v0.6") { + return getSenderAddress(client, { + initCode: concatHex([factoryAddress, factoryData]), + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE + }) + } + + // Get the sender address based on the init code + return getSenderAddress(client, { + factory: factoryAddress, + factoryData, + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V07_TYPE + }) +} + +export type SignerToEcdsaKernelSmartAccountParameters< + entryPoint extends EntryPoint, + TSource extends string = "custom", + TAddress extends Address = Address +> = Prettify<{ + signer: SmartAccountSigner + entryPoint: entryPoint + address?: Address + index?: bigint + factoryAddress?: Address + accountLogicAddress?: Address + ecdsaValidatorAddress?: Address + deployedAccountAddress?: Address +}> +/** + * Build a kernel smart account from a private key, that use the ECDSA signer behind the scene + * @param client + * @param privateKey + * @param entryPoint + * @param index + * @param factoryAddress + * @param accountLogicAddress + * @param ecdsaValidatorAddress + * @param deployedAccountAddress + */ +export async function signerToEcdsaKernelSmartAccount< + entryPoint extends EntryPoint, + TTransport extends Transport = Transport, + TChain extends Chain | undefined = Chain | undefined, + TSource extends string = "custom", + TAddress extends Address = Address +>( + client: Client, + { + signer, + address, + entryPoint: entryPointAddress, + index = 0n, + factoryAddress = KERNEL_ADDRESSES.FACTORY_ADDRESS, + accountLogicAddress = KERNEL_ADDRESSES.ACCOUNT_V2_2_LOGIC, + ecdsaValidatorAddress = KERNEL_ADDRESSES.ECDSA_VALIDATOR, + deployedAccountAddress + }: SignerToEcdsaKernelSmartAccountParameters +): Promise> { + // Get the private key related account + const viemSigner: LocalAccount = { + ...signer, + signTransaction: (_, __) => { + throw new SignTransactionNotSupportedBySmartAccount() + } + } as LocalAccount + + // Helper to generate the init code for the smart account + const generateInitCode = () => + getAccountInitCode({ + owner: viemSigner.address, + index, + accountLogicAddress, + ecdsaValidatorAddress + }) + + // Fetch account address and chain id + const [accountAddress, chainId] = await Promise.all([ + address ?? + getAccountAddress({ + client, + entryPoint: entryPointAddress, + owner: viemSigner.address, + ecdsaValidatorAddress, + initCodeProvider: generateInitCode, + deployedAccountAddress, + factoryAddress + }), + getChainId(client) + ]) + + if (!accountAddress) throw new Error("Account address not found") + + let smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + // Build the EOA Signer + const account = toAccount({ + address: accountAddress, + 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, + client: client, + publicKey: accountAddress, + entryPoint: entryPointAddress, + source: "kernelEcdsaSmartAccount", + + // Get the nonce of the smart account + async getNonce() { + return getAccountNonce(client, { + sender: accountAddress, + entryPoint: entryPointAddress + }) + }, + + // Sign a user operation + async signUserOperation(userOperation) { + const hash = getUserOperationHash({ + userOperation: { + ...userOperation, + signature: "0x" + }, + entryPoint: entryPointAddress, + chainId: chainId + }) + const signature = await signMessage(client, { + account: viemSigner, + message: { raw: hash } + }) + // Always use the sudo mode, since we will use external paymaster + return concatHex(["0x00000000", signature]) + }, + + // Encode the init code + async getInitCode() { + if (smartAccountDeployed) return "0x" + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return "0x" + + return concatHex([factoryAddress, await generateInitCode()]) + }, + + async getFactory() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + + return factoryAddress + }, + + async getFactoryData() { + if (smartAccountDeployed) return null + + smartAccountDeployed = await isSmartAccountDeployed( + client, + accountAddress + ) + + if (smartAccountDeployed) return null + + return generateInitCode() + }, + + // Encode the deploy call data + async encodeDeployCallData(_) { + throw new Error("Simple account doesn't support account deployment") + }, + + // Encode a call + async encodeCallData(_tx) { + if (Array.isArray(_tx)) { + // Encode a batched call + return encodeFunctionData({ + abi: KernelExecuteAbi, + functionName: "executeBatch", + args: [ + _tx.map((tx) => ({ + to: tx.to, + value: tx.value, + data: tx.data + })) + ] + }) + } + // Encode a simple call + return encodeFunctionData({ + abi: KernelExecuteAbi, + functionName: "execute", + args: [_tx.to, _tx.value, _tx.data, 0] + }) + }, + + // Get simple dummy signature + async getDummySignature(_userOperation) { + return "0x00000000fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c" + } + } +} From 4f939df7c03231d71bcbade3a4a5d0d63020915a Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:16:45 -0700 Subject: [PATCH 22/35] Revert "fix build" This reverts commit 9b7297ed5c358b068e405e5c58f36dbf88ed355b. --- packages/permissionless/accounts/index.ts | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/permissionless/accounts/index.ts b/packages/permissionless/accounts/index.ts index a0cffa66..0213ea31 100644 --- a/packages/permissionless/accounts/index.ts +++ b/packages/permissionless/accounts/index.ts @@ -21,6 +21,23 @@ import { signerToSafeSmartAccount } from "./safe/signerToSafeSmartAccount" +import { + type KernelEcdsaSmartAccount, + type SignerToEcdsaKernelSmartAccountParameters, + signerToEcdsaKernelSmartAccount +} from "./kernel/signerToEcdsaKernelSmartAccount" + +import { + type BiconomySmartAccount, + type SignerToBiconomySmartAccountParameters, + signerToBiconomySmartAccount +} from "./biconomy/signerToBiconomySmartAccount" + +import { + type PrivateKeyToBiconomySmartAccountParameters, + privateKeyToBiconomySmartAccount +} from "./biconomy/privateKeyToBiconomySmartAccount" + import { SignTransactionNotSupportedBySmartAccount, type SmartAccount, @@ -35,11 +52,19 @@ export { type SimpleSmartAccount, signerToSimpleSmartAccount, SignTransactionNotSupportedBySmartAccount, + privateKeyToBiconomySmartAccount, privateKeyToSimpleSmartAccount, type SmartAccount, privateKeyToSafeSmartAccount, + type KernelEcdsaSmartAccount, + signerToEcdsaKernelSmartAccount, + type BiconomySmartAccount, + signerToBiconomySmartAccount, type SignerToSimpleSmartAccountParameters, type SignerToSafeSmartAccountParameters, type PrivateKeyToSimpleSmartAccountParameters, - type PrivateKeyToSafeSmartAccountParameters + type PrivateKeyToSafeSmartAccountParameters, + type SignerToEcdsaKernelSmartAccountParameters, + type SignerToBiconomySmartAccountParameters, + type PrivateKeyToBiconomySmartAccountParameters } From 8ab45ac305f7e8a6664d4277aa1f905e0791dad6 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:17:35 -0700 Subject: [PATCH 23/35] Revert "remove tests for accounts" This reverts commit c4df3977fcc97b325f195d91fc0be1c3db512984. --- .../ep-0.6/biconomySmartaccount.test.ts | 392 +++++++++++++++++ .../ep-0.6/ecdsaKernelAccount.test.ts | 407 ++++++++++++++++++ .../ep-0.7/biconomySmartaccount.test.ts | 392 +++++++++++++++++ .../ep-0.7/ecdsaKernelAccount.test.ts | 407 ++++++++++++++++++ 4 files changed, 1598 insertions(+) create mode 100644 packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts create mode 100644 packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts create mode 100644 packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts create mode 100644 packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts diff --git a/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts new file mode 100644 index 00000000..d8fdb7bc --- /dev/null +++ b/packages/permissionless-test/ep-0.6/biconomySmartaccount.test.ts @@ -0,0 +1,392 @@ +import dotenv from "dotenv" +import { + SignTransactionNotSupportedBySmartAccount, + signerToBiconomySmartAccount +} from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "./abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToBiconomyAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +/** + * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) + */ +describe("Biconomy Modular Smart Account (ECDSA module)", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Account address", async () => { + const ecdsaSmartAccount = await getSignerToBiconomyAccount() + + expectTypeOf(ecdsaSmartAccount.address).toBeString() + expect(ecdsaSmartAccount.address).toHaveLength(42) + expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + ecdsaSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError("Doesn't support account deployment") + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Client send Transaction with paymaster", async () => { + const account = await getSignerToBiconomyAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Client send multiple Transactions with paymaster", async () => { + const account = await getSignerToBiconomyAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Can use a deployed account", async () => { + const initialEcdsaSmartAccount = await getSignerToBiconomyAccount() + const publicClient = await getPublicClient() + const smartAccountClient = await getSmartAccountClient({ + account: initialEcdsaSmartAccount, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + // Send an initial tx to deploy the account + const hash = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // Wait for the tx to be done (so we are sure that the account is deployed) + await publicClient.waitForTransactionReceipt({ hash }) + + // Build a new account with a valid owner + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + const alreadyDeployedEcdsaSmartAccount = + await signerToBiconomySmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer + }) + + // Ensure the two account have the same address + expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( + initialEcdsaSmartAccount.address + ) + }, 1000000) +}) diff --git a/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts new file mode 100644 index 00000000..317e80c5 --- /dev/null +++ b/packages/permissionless-test/ep-0.6/ecdsaKernelAccount.test.ts @@ -0,0 +1,407 @@ +import dotenv from "dotenv" +import { UserOperation } from "permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToEcdsaKernelSmartAccount +} from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "./abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToEcdsaKernelAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +/** + * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) + */ +describe("ECDSA kernel Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Account address", async () => { + const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() + + expectTypeOf(ecdsaSmartAccount.address).toBeString() + expect(ecdsaSmartAccount.address).toHaveLength(42) + expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + ecdsaSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError( + "Simple account doesn't support account deployment" + ) + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Client send Transaction with paymaster", async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Client send multiple Transactions with paymaster", async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Can use a deployed account", async () => { + const initialEcdsaSmartAccount = await getSignerToEcdsaKernelAccount() + const publicClient = await getPublicClient() + const smartAccountClient = await getSmartAccountClient({ + account: initialEcdsaSmartAccount, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + // Send an initial tx to deploy the account + const hash = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // Wait for the tx to be done (so we are sure that the account is deployed) + await publicClient.waitForTransactionReceipt({ hash }) + const deployedAccountAddress = initialEcdsaSmartAccount.address + + // Build a new account with a valid owner + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + const alreadyDeployedEcdsaSmartAccount = + await signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer, + deployedAccountAddress + }) + + // Ensure the two account have the same address + expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( + initialEcdsaSmartAccount.address + ) + + // Ensure that it will fail with an invalid owner address + const invalidOwner = privateKeyToAccount(generatePrivateKey()) + await expect(async () => + signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: invalidOwner, + deployedAccountAddress + }) + ).rejects.toThrowError("Invalid owner for the already deployed account") + }, 1000000) +}) diff --git a/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts new file mode 100644 index 00000000..d8fdb7bc --- /dev/null +++ b/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts @@ -0,0 +1,392 @@ +import dotenv from "dotenv" +import { + SignTransactionNotSupportedBySmartAccount, + signerToBiconomySmartAccount +} from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "./abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToBiconomyAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +/** + * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) + */ +describe("Biconomy Modular Smart Account (ECDSA module)", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Account address", async () => { + const ecdsaSmartAccount = await getSignerToBiconomyAccount() + + expectTypeOf(ecdsaSmartAccount.address).toBeString() + expect(ecdsaSmartAccount.address).toHaveLength(42) + expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + ecdsaSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError("Doesn't support account deployment") + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToBiconomyAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Client send Transaction with paymaster", async () => { + const account = await getSignerToBiconomyAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Client send multiple Transactions with paymaster", async () => { + const account = await getSignerToBiconomyAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Can use a deployed account", async () => { + const initialEcdsaSmartAccount = await getSignerToBiconomyAccount() + const publicClient = await getPublicClient() + const smartAccountClient = await getSmartAccountClient({ + account: initialEcdsaSmartAccount, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + // Send an initial tx to deploy the account + const hash = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // Wait for the tx to be done (so we are sure that the account is deployed) + await publicClient.waitForTransactionReceipt({ hash }) + + // Build a new account with a valid owner + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + const alreadyDeployedEcdsaSmartAccount = + await signerToBiconomySmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer + }) + + // Ensure the two account have the same address + expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( + initialEcdsaSmartAccount.address + ) + }, 1000000) +}) diff --git a/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts new file mode 100644 index 00000000..317e80c5 --- /dev/null +++ b/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts @@ -0,0 +1,407 @@ +import dotenv from "dotenv" +import { UserOperation } from "permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToEcdsaKernelSmartAccount +} from "permissionless/accounts" +import { + http, + Account, + Address, + Chain, + Hex, + Transport, + WalletClient, + createWalletClient, + decodeEventLog, + getContract, + zeroAddress +} from "viem" +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" +import { + beforeAll, + beforeEach, + describe, + expect, + expectTypeOf, + test +} from "vitest" +import { EntryPointAbi } from "./abis/EntryPoint" +import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" +import { + getBundlerClient, + getEntryPoint, + getPimlicoPaymasterClient, + getPrivateKeyAccount, + getPublicClient, + getSignerToEcdsaKernelAccount, + getSmartAccountClient, + getTestingChain, + refillSmartAccount, + waitForNonceUpdate +} from "./utils" + +dotenv.config() + +beforeAll(() => { + if (!process.env.FACTORY_ADDRESS) { + throw new Error("FACTORY_ADDRESS environment variable not set") + } + if (!process.env.TEST_PRIVATE_KEY) { + throw new Error("TEST_PRIVATE_KEY environment variable not set") + } + if (!process.env.RPC_URL) { + throw new Error("RPC_URL environment variable not set") + } + if (!process.env.ENTRYPOINT_ADDRESS) { + throw new Error("ENTRYPOINT_ADDRESS environment variable not set") + } +}) + +/** + * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) + */ +describe("ECDSA kernel Account", () => { + let walletClient: WalletClient + + beforeEach(async () => { + const owner = getPrivateKeyAccount() + walletClient = createWalletClient({ + account: owner, + chain: getTestingChain(), + transport: http(process.env.RPC_URL as string) + }) + }) + + test("Account address", async () => { + const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() + + expectTypeOf(ecdsaSmartAccount.address).toBeString() + expect(ecdsaSmartAccount.address).toHaveLength(42) + expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) + + await expect(async () => + ecdsaSmartAccount.signTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) + }) + + test("Client signMessage", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + const response = await smartAccountClient.signMessage({ + message: "hello world" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Smart account client signTypedData", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + const response = await smartAccountClient.signTypedData({ + domain: { + chainId: 1, + name: "Test", + verifyingContract: zeroAddress + }, + primaryType: "Test", + types: { + Test: [ + { + name: "test", + type: "string" + } + ] + }, + message: { + test: "hello world" + } + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(132) + expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) + }) + + test("Client deploy contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + await expect(async () => + smartAccountClient.deployContract({ + abi: GreeterAbi, + bytecode: GreeterBytecode + }) + ).rejects.toThrowError( + "Simple account doesn't support account deployment" + ) + }) + + test("Smart account client send multiple transactions", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + await waitForNonceUpdate() + }, 1000000) + + test("Write contract", async () => { + const smartAccountClient = await getSmartAccountClient({ + account: await getSignerToEcdsaKernelAccount() + }) + await refillSmartAccount( + walletClient, + smartAccountClient.account.address + ) + + const entryPointContract = getContract({ + abi: EntryPointAbi, + address: getEntryPoint(), + client: { + public: await getPublicClient(), + wallet: smartAccountClient + } + }) + + const oldBalance = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + const txHash = await entryPointContract.write.depositTo( + [smartAccountClient.account.address], + { + value: 10n + } + ) + + expectTypeOf(txHash).toBeString() + expect(txHash).toHaveLength(66) + + const newBalnce = await entryPointContract.read.balanceOf([ + smartAccountClient.account.address + ]) + + await waitForNonceUpdate() + }, 1000000) + + test("Client send Transaction with paymaster", async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Client send multiple Transactions with paymaster", async () => { + const account = await getSignerToEcdsaKernelAccount() + + const publicClient = await getPublicClient() + + const bundlerClient = getBundlerClient() + + const smartAccountClient = await getSmartAccountClient({ + account, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + const response = await smartAccountClient.sendTransactions({ + transactions: [ + { + to: zeroAddress, + value: 0n, + data: "0x" + }, + { + to: zeroAddress, + value: 0n, + data: "0x" + } + ] + }) + + expectTypeOf(response).toBeString() + expect(response).toHaveLength(66) + expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) + + const transactionReceipt = await publicClient.waitForTransactionReceipt( + { + hash: response + } + ) + + let eventFound = false + + for (const log of transactionReceipt.logs) { + // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error + try { + const event = decodeEventLog({ + abi: EntryPointAbi, + ...log + }) + if (event.eventName === "UserOperationEvent") { + eventFound = true + const userOperation = + await bundlerClient.getUserOperationByHash({ + hash: event.args.userOpHash + }) + expect( + userOperation?.userOperation.paymasterAndData + ).not.toBe("0x") + } + } catch {} + } + + expect(eventFound).toBeTruthy() + await waitForNonceUpdate() + }, 1000000) + + test("Can use a deployed account", async () => { + const initialEcdsaSmartAccount = await getSignerToEcdsaKernelAccount() + const publicClient = await getPublicClient() + const smartAccountClient = await getSmartAccountClient({ + account: initialEcdsaSmartAccount, + sponsorUserOperation: async ({ + entryPoint: _entryPoint, + userOperation + }) => { + const pimlicoPaymaster = getPimlicoPaymasterClient() + return pimlicoPaymaster.sponsorUserOperation({ + userOperation, + entryPoint: getEntryPoint() + }) + } + }) + + // Send an initial tx to deploy the account + const hash = await smartAccountClient.sendTransaction({ + to: zeroAddress, + value: 0n, + data: "0x" + }) + + // Wait for the tx to be done (so we are sure that the account is deployed) + await publicClient.waitForTransactionReceipt({ hash }) + const deployedAccountAddress = initialEcdsaSmartAccount.address + + // Build a new account with a valid owner + const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) + const alreadyDeployedEcdsaSmartAccount = + await signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: signer, + deployedAccountAddress + }) + + // Ensure the two account have the same address + expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( + initialEcdsaSmartAccount.address + ) + + // Ensure that it will fail with an invalid owner address + const invalidOwner = privateKeyToAccount(generatePrivateKey()) + await expect(async () => + signerToEcdsaKernelSmartAccount(publicClient, { + entryPoint: getEntryPoint(), + signer: invalidOwner, + deployedAccountAddress + }) + ).rejects.toThrowError("Invalid owner for the already deployed account") + }, 1000000) +}) From adb70ce9e6a23bf43410f8cdf3ff9b6f2a3a64fb Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:22:19 -0700 Subject: [PATCH 24/35] make accoutns support only 0.7 --- bun.lockb | Bin 499560 -> 518672 bytes package.json | 1 + .../ep-0.7/biconomySmartaccount.test.ts | 392 ----------------- .../ep-0.7/ecdsaKernelAccount.test.ts | 407 ------------------ .../permissionless-test/ep-0.7/package.json | 4 + .../privateKeyToBiconomySmartAccount.ts | 10 +- .../biconomy/signerToBiconomySmartAccount.ts | 18 +- .../kernel/signerToEcdsaKernelSmartAccount.ts | 29 +- 8 files changed, 39 insertions(+), 822 deletions(-) delete mode 100644 packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts delete mode 100644 packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts diff --git a/bun.lockb b/bun.lockb index 0f24ede98e7d36b2459539f66d5d508e2bbace99..f6088cccbe6400ffdb83a6a7f2d78985ebc5e8d1 100755 GIT binary patch delta 115719 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 R8LAfVcUNF0-DS*&{|^P7s;>Y5 delta 103594 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 diff --git a/package.json b/package.json index f1cc4cec..7ca208ef 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "type": "module", "sideEffects": false, "devDependencies": { + "vitest": "^1.2.0", "@biomejs/biome": "^1.0.0", "@changesets/changelog-git": "^0.1.14", "@changesets/changelog-github": "^0.4.8", diff --git a/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts b/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts deleted file mode 100644 index d8fdb7bc..00000000 --- a/packages/permissionless-test/ep-0.7/biconomySmartaccount.test.ts +++ /dev/null @@ -1,392 +0,0 @@ -import dotenv from "dotenv" -import { - SignTransactionNotSupportedBySmartAccount, - signerToBiconomySmartAccount -} from "permissionless/accounts" -import { - http, - Account, - Address, - Chain, - Hex, - Transport, - WalletClient, - createWalletClient, - decodeEventLog, - getContract, - zeroAddress -} from "viem" -import { privateKeyToAccount } from "viem/accounts" -import { - beforeAll, - beforeEach, - describe, - expect, - expectTypeOf, - test -} from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" -import { - getBundlerClient, - getEntryPoint, - getPimlicoPaymasterClient, - getPrivateKeyAccount, - getPublicClient, - getSignerToBiconomyAccount, - getSmartAccountClient, - getTestingChain, - refillSmartAccount, - waitForNonceUpdate -} from "./utils" - -dotenv.config() - -beforeAll(() => { - if (!process.env.FACTORY_ADDRESS) { - throw new Error("FACTORY_ADDRESS environment variable not set") - } - if (!process.env.TEST_PRIVATE_KEY) { - throw new Error("TEST_PRIVATE_KEY environment variable not set") - } - if (!process.env.RPC_URL) { - throw new Error("RPC_URL environment variable not set") - } - if (!process.env.ENTRYPOINT_ADDRESS) { - throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - } -}) - -/** - * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) - */ -describe("Biconomy Modular Smart Account (ECDSA module)", () => { - let walletClient: WalletClient - - beforeEach(async () => { - const owner = getPrivateKeyAccount() - walletClient = createWalletClient({ - account: owner, - chain: getTestingChain(), - transport: http(process.env.RPC_URL as string) - }) - }) - - test("Account address", async () => { - const ecdsaSmartAccount = await getSignerToBiconomyAccount() - - expectTypeOf(ecdsaSmartAccount.address).toBeString() - expect(ecdsaSmartAccount.address).toHaveLength(42) - expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) - - await expect(async () => - ecdsaSmartAccount.signTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) - }) - - test("Client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - const response = await smartAccountClient.signMessage({ - message: "hello world" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - const response = await smartAccountClient.signTypedData({ - domain: { - chainId: 1, - name: "Test", - verifyingContract: zeroAddress - }, - primaryType: "Test", - types: { - Test: [ - { - name: "test", - type: "string" - } - ] - }, - message: { - test: "hello world" - } - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - await expect(async () => - smartAccountClient.deployContract({ - abi: GreeterAbi, - bytecode: GreeterBytecode - }) - ).rejects.toThrowError("Doesn't support account deployment") - }) - - test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - await waitForNonceUpdate() - }, 1000000) - - test("Write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToBiconomyAccount() - }) - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const entryPointContract = getContract({ - abi: EntryPointAbi, - address: getEntryPoint(), - client: { - public: await getPublicClient(), - wallet: smartAccountClient - } - }) - - const oldBalance = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - const txHash = await entryPointContract.write.depositTo( - [smartAccountClient.account.address], - { - value: 10n - } - ) - - expectTypeOf(txHash).toBeString() - expect(txHash).toHaveLength(66) - - const newBalnce = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - await waitForNonceUpdate() - }, 1000000) - - test("Client send Transaction with paymaster", async () => { - const account = await getSignerToBiconomyAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Client send multiple Transactions with paymaster", async () => { - const account = await getSignerToBiconomyAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Can use a deployed account", async () => { - const initialEcdsaSmartAccount = await getSignerToBiconomyAccount() - const publicClient = await getPublicClient() - const smartAccountClient = await getSmartAccountClient({ - account: initialEcdsaSmartAccount, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - // Send an initial tx to deploy the account - const hash = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // Wait for the tx to be done (so we are sure that the account is deployed) - await publicClient.waitForTransactionReceipt({ hash }) - - // Build a new account with a valid owner - const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) - const alreadyDeployedEcdsaSmartAccount = - await signerToBiconomySmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: signer - }) - - // Ensure the two account have the same address - expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( - initialEcdsaSmartAccount.address - ) - }, 1000000) -}) diff --git a/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts b/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts deleted file mode 100644 index 317e80c5..00000000 --- a/packages/permissionless-test/ep-0.7/ecdsaKernelAccount.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -import dotenv from "dotenv" -import { UserOperation } from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToEcdsaKernelSmartAccount -} from "permissionless/accounts" -import { - http, - Account, - Address, - Chain, - Hex, - Transport, - WalletClient, - createWalletClient, - decodeEventLog, - getContract, - zeroAddress -} from "viem" -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" -import { - beforeAll, - beforeEach, - describe, - expect, - expectTypeOf, - test -} from "vitest" -import { EntryPointAbi } from "./abis/EntryPoint" -import { GreeterAbi, GreeterBytecode } from "./abis/Greeter" -import { - getBundlerClient, - getEntryPoint, - getPimlicoPaymasterClient, - getPrivateKeyAccount, - getPublicClient, - getSignerToEcdsaKernelAccount, - getSmartAccountClient, - getTestingChain, - refillSmartAccount, - waitForNonceUpdate -} from "./utils" - -dotenv.config() - -beforeAll(() => { - if (!process.env.FACTORY_ADDRESS) { - throw new Error("FACTORY_ADDRESS environment variable not set") - } - if (!process.env.TEST_PRIVATE_KEY) { - throw new Error("TEST_PRIVATE_KEY environment variable not set") - } - if (!process.env.RPC_URL) { - throw new Error("RPC_URL environment variable not set") - } - if (!process.env.ENTRYPOINT_ADDRESS) { - throw new Error("ENTRYPOINT_ADDRESS environment variable not set") - } -}) - -/** - * TODO: Should generify the basics test for every smart account & smart account client (address, signature, etc) - */ -describe("ECDSA kernel Account", () => { - let walletClient: WalletClient - - beforeEach(async () => { - const owner = getPrivateKeyAccount() - walletClient = createWalletClient({ - account: owner, - chain: getTestingChain(), - transport: http(process.env.RPC_URL as string) - }) - }) - - test("Account address", async () => { - const ecdsaSmartAccount = await getSignerToEcdsaKernelAccount() - - expectTypeOf(ecdsaSmartAccount.address).toBeString() - expect(ecdsaSmartAccount.address).toHaveLength(42) - expect(ecdsaSmartAccount.address).toMatch(/^0x[0-9a-fA-F]{40}$/) - - await expect(async () => - ecdsaSmartAccount.signTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - ).rejects.toThrow(SignTransactionNotSupportedBySmartAccount) - }) - - test("Client signMessage", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - const response = await smartAccountClient.signMessage({ - message: "hello world" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Smart account client signTypedData", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - const response = await smartAccountClient.signTypedData({ - domain: { - chainId: 1, - name: "Test", - verifyingContract: zeroAddress - }, - primaryType: "Test", - types: { - Test: [ - { - name: "test", - type: "string" - } - ] - }, - message: { - test: "hello world" - } - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(132) - expect(response).toMatch(/^0x[0-9a-fA-F]{130}$/) - }) - - test("Client deploy contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - await expect(async () => - smartAccountClient.deployContract({ - abi: GreeterAbi, - bytecode: GreeterBytecode - }) - ).rejects.toThrowError( - "Simple account doesn't support account deployment" - ) - }) - - test("Smart account client send multiple transactions", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - await waitForNonceUpdate() - }, 1000000) - - test("Write contract", async () => { - const smartAccountClient = await getSmartAccountClient({ - account: await getSignerToEcdsaKernelAccount() - }) - await refillSmartAccount( - walletClient, - smartAccountClient.account.address - ) - - const entryPointContract = getContract({ - abi: EntryPointAbi, - address: getEntryPoint(), - client: { - public: await getPublicClient(), - wallet: smartAccountClient - } - }) - - const oldBalance = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - const txHash = await entryPointContract.write.depositTo( - [smartAccountClient.account.address], - { - value: 10n - } - ) - - expectTypeOf(txHash).toBeString() - expect(txHash).toHaveLength(66) - - const newBalnce = await entryPointContract.read.balanceOf([ - smartAccountClient.account.address - ]) - - await waitForNonceUpdate() - }, 1000000) - - test("Client send Transaction with paymaster", async () => { - const account = await getSignerToEcdsaKernelAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Client send multiple Transactions with paymaster", async () => { - const account = await getSignerToEcdsaKernelAccount() - - const publicClient = await getPublicClient() - - const bundlerClient = getBundlerClient() - - const smartAccountClient = await getSmartAccountClient({ - account, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - const response = await smartAccountClient.sendTransactions({ - transactions: [ - { - to: zeroAddress, - value: 0n, - data: "0x" - }, - { - to: zeroAddress, - value: 0n, - data: "0x" - } - ] - }) - - expectTypeOf(response).toBeString() - expect(response).toHaveLength(66) - expect(response).toMatch(/^0x[0-9a-fA-F]{64}$/) - - const transactionReceipt = await publicClient.waitForTransactionReceipt( - { - hash: response - } - ) - - let eventFound = false - - for (const log of transactionReceipt.logs) { - // Encapsulated inside a try catch since if a log isn't wanted from this abi it will throw an error - try { - const event = decodeEventLog({ - abi: EntryPointAbi, - ...log - }) - if (event.eventName === "UserOperationEvent") { - eventFound = true - const userOperation = - await bundlerClient.getUserOperationByHash({ - hash: event.args.userOpHash - }) - expect( - userOperation?.userOperation.paymasterAndData - ).not.toBe("0x") - } - } catch {} - } - - expect(eventFound).toBeTruthy() - await waitForNonceUpdate() - }, 1000000) - - test("Can use a deployed account", async () => { - const initialEcdsaSmartAccount = await getSignerToEcdsaKernelAccount() - const publicClient = await getPublicClient() - const smartAccountClient = await getSmartAccountClient({ - account: initialEcdsaSmartAccount, - sponsorUserOperation: async ({ - entryPoint: _entryPoint, - userOperation - }) => { - const pimlicoPaymaster = getPimlicoPaymasterClient() - return pimlicoPaymaster.sponsorUserOperation({ - userOperation, - entryPoint: getEntryPoint() - }) - } - }) - - // Send an initial tx to deploy the account - const hash = await smartAccountClient.sendTransaction({ - to: zeroAddress, - value: 0n, - data: "0x" - }) - - // Wait for the tx to be done (so we are sure that the account is deployed) - await publicClient.waitForTransactionReceipt({ hash }) - const deployedAccountAddress = initialEcdsaSmartAccount.address - - // Build a new account with a valid owner - const signer = privateKeyToAccount(process.env.TEST_PRIVATE_KEY as Hex) - const alreadyDeployedEcdsaSmartAccount = - await signerToEcdsaKernelSmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: signer, - deployedAccountAddress - }) - - // Ensure the two account have the same address - expect(alreadyDeployedEcdsaSmartAccount.address).toMatch( - initialEcdsaSmartAccount.address - ) - - // Ensure that it will fail with an invalid owner address - const invalidOwner = privateKeyToAccount(generatePrivateKey()) - await expect(async () => - signerToEcdsaKernelSmartAccount(publicClient, { - entryPoint: getEntryPoint(), - signer: invalidOwner, - deployedAccountAddress - }) - ).rejects.toThrowError("Invalid owner for the already deployed account") - }, 1000000) -}) diff --git a/packages/permissionless-test/ep-0.7/package.json b/packages/permissionless-test/ep-0.7/package.json index aac544b5..bfced29d 100644 --- a/packages/permissionless-test/ep-0.7/package.json +++ b/packages/permissionless-test/ep-0.7/package.json @@ -5,6 +5,10 @@ "homepage": "https://docs.pimlico.io/permissionless", "private": true, "type": "module", + "scripts": { + "test": "vitest dev -c ./packages/permissionless-test/vitest.config.ts", + "test:ci": "CI=true vitest -c ./packages/permissionless-test/vitest.config.ts --coverage" + }, "devDependencies": { "vitest": "^1.2.0" }, diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts index 802116c4..e4654573 100644 --- a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts @@ -1,6 +1,10 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { EntryPoint, Prettify } from "../../types" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + EntryPoint, + Prettify +} from "../../types" import { type BiconomySmartAccount, type SignerToBiconomySmartAccountParameters, @@ -8,7 +12,7 @@ import { } from "./signerToBiconomySmartAccount" export type PrivateKeyToBiconomySmartAccountParameters< - entryPoint extends EntryPoint + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE > = Prettify< { privateKey: Hex @@ -21,7 +25,7 @@ export type PrivateKeyToBiconomySmartAccountParameters< * @returns A Private Key Biconomy Smart Account using ECDSA as default validation module. */ export async function privateKeyToBiconomySmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >( diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 33df0a1a..19defc16 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -20,7 +20,11 @@ import { toAccount } from "viem/accounts" import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import type { Prettify } from "../../types" -import type { EntryPoint } from "../../types/entrypoint" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + EntryPoint +} from "../../types/entrypoint" +import { getEntryPointVersion } from "../../utils" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" import { @@ -34,7 +38,7 @@ import { } from "./abi/BiconomySmartAccountAbi" export type BiconomySmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -182,7 +186,7 @@ const getAccountAddress = async ({ } export type SignerToBiconomySmartAccountParameters< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ @@ -207,7 +211,7 @@ export type SignerToBiconomySmartAccountParameters< * @param ecdsaModuleAddress */ export async function signerToBiconomySmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -225,6 +229,12 @@ export async function signerToBiconomySmartAccount< ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE }: SignerToBiconomySmartAccountParameters ): Promise> { + const entryPointVersion = getEntryPointVersion(entryPointAddress) + + if (entryPointVersion !== "v0.6") { + throw new Error("Only EntryPoint 0.6 is supported") + } + // Get the private key related account const viemSigner: LocalAccount = { ...signer, diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index b5dd9e6d..7a1a2d26 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -37,7 +37,7 @@ import { import { KernelExecuteAbi, KernelInitAbi } from "./abi/KernelAccountAbi" export type KernelEcdsaSmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined > = SmartAccount @@ -136,7 +136,7 @@ const getAccountInitCode = async ({ * @param deployedAccountAddress */ const getAccountAddress = async < - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined >({ @@ -200,23 +200,14 @@ const getAccountAddress = async < const entryPointVersion = getEntryPointVersion(entryPointAddress) - if (entryPointVersion === "v0.6") { - return getSenderAddress(client, { - initCode: concatHex([factoryAddress, factoryData]), - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE - }) - } - - // Get the sender address based on the init code - return getSenderAddress(client, { - factory: factoryAddress, - factoryData, - entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V07_TYPE + return getSenderAddress(client, { + initCode: concatHex([factoryAddress, factoryData]), + entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE }) } export type SignerToEcdsaKernelSmartAccountParameters< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TSource extends string = "custom", TAddress extends Address = Address > = Prettify<{ @@ -241,7 +232,7 @@ export type SignerToEcdsaKernelSmartAccountParameters< * @param deployedAccountAddress */ export async function signerToEcdsaKernelSmartAccount< - entryPoint extends EntryPoint, + entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE, TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TSource extends string = "custom", @@ -259,6 +250,12 @@ export async function signerToEcdsaKernelSmartAccount< deployedAccountAddress }: SignerToEcdsaKernelSmartAccountParameters ): Promise> { + const entryPointVersion = getEntryPointVersion(entryPointAddress) + + if (entryPointVersion !== "v0.6") { + throw new Error("Only EntryPoint 0.6 is supported") + } + // Get the private key related account const viemSigner: LocalAccount = { ...signer, From 3a5b441bd8224d4d98be96112ac636218cdc313b Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:24:50 -0700 Subject: [PATCH 25/35] fix build --- .../accounts/biconomy/privateKeyToBiconomySmartAccount.ts | 6 +----- .../accounts/biconomy/signerToBiconomySmartAccount.ts | 5 +---- .../accounts/kernel/signerToEcdsaKernelSmartAccount.ts | 8 +------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts index e4654573..155af1db 100644 --- a/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/privateKeyToBiconomySmartAccount.ts @@ -1,10 +1,6 @@ import { type Chain, type Client, type Hex, type Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - EntryPoint, - Prettify -} from "../../types" +import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { type BiconomySmartAccount, type SignerToBiconomySmartAccountParameters, diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 19defc16..3fd0e7bd 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -20,10 +20,7 @@ import { toAccount } from "viem/accounts" import { getChainId, signMessage, signTypedData } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import type { Prettify } from "../../types" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - EntryPoint -} from "../../types/entrypoint" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 7a1a2d26..650a1daf 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -21,11 +21,7 @@ import { import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" import type { Prettify } from "../../types" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE, - EntryPoint -} from "../../types/entrypoint" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" import { getEntryPointVersion } from "../../utils" import { getUserOperationHash } from "../../utils/getUserOperationHash" import { isSmartAccountDeployed } from "../../utils/isSmartAccountDeployed" @@ -198,8 +194,6 @@ const getAccountAddress = async < // Find the init code for this account const factoryData = await initCodeProvider() - const entryPointVersion = getEntryPointVersion(entryPointAddress) - return getSenderAddress(client, { initCode: concatHex([factoryAddress, factoryData]), entryPoint: entryPointAddress as ENTRYPOINT_ADDRESS_V06_TYPE From 55c78893e5f0c852bfe32416759088645f1fac7a Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:34:57 -0700 Subject: [PATCH 26/35] make types undefined --- .../ep-0.7/pimlicoActions.test.ts | 2 +- .../biconomy/signerToBiconomySmartAccount.ts | 8 ++++---- .../kernel/signerToEcdsaKernelSmartAccount.ts | 8 ++++---- .../accounts/safe/signerToSafeSmartAccount.ts | 8 ++++---- .../accounts/simple/signerToSimpleSmartAccount.ts | 8 ++++---- packages/permissionless/accounts/types.ts | 4 ++-- .../actions/bundler/estimateUserOperationGas.ts | 12 ++++++------ .../smartAccount/prepareUserOperationRequest.ts | 12 ++++++------ packages/permissionless/types/bundler.ts | 6 +++--- packages/permissionless/types/userOperation.ts | 12 ++++++------ 10 files changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts b/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts index 647f6016..099366a2 100644 --- a/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts +++ b/packages/permissionless-test/ep-0.7/pimlicoActions.test.ts @@ -130,7 +130,7 @@ describe("Pimlico Actions tests", () => { ).length.greaterThan(0) expectTypeOf( sponsorUserOperationPaymasterAndData.paymaster - ).toMatchTypeOf

() + ).toMatchTypeOf
() await waitForNonceUpdate() }, 100000) test("Sending user op with paymaster and data", async () => { diff --git a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts index 3fd0e7bd..ca1ca398 100644 --- a/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts +++ b/packages/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts @@ -332,27 +332,27 @@ export async function signerToBiconomySmartAccount< }, async getFactory() { - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined smartAccountDeployed = await isSmartAccountDeployed( client, accountAddress ) - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined return factoryAddress }, async getFactoryData() { - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined smartAccountDeployed = await isSmartAccountDeployed( client, accountAddress ) - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined return generateInitCode() }, diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index 650a1daf..03c98489 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -362,27 +362,27 @@ export async function signerToEcdsaKernelSmartAccount< }, async getFactory() { - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined smartAccountDeployed = await isSmartAccountDeployed( client, accountAddress ) - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined return factoryAddress }, async getFactoryData() { - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined smartAccountDeployed = await isSmartAccountDeployed( client, accountAddress ) - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined return generateInitCode() }, diff --git a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts index b65fdd63..09e8fa87 100644 --- a/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts +++ b/packages/permissionless/accounts/safe/signerToSafeSmartAccount.ts @@ -737,20 +737,20 @@ export async function signerToSafeSmartAccount< return concatHex([safeProxyFactoryAddress, initCodeCallData]) }, async getFactory() { - if (safeDeployed) return null + if (safeDeployed) return undefined safeDeployed = await isSmartAccountDeployed(client, accountAddress) - if (safeDeployed) return null + if (safeDeployed) return undefined return safeProxyFactoryAddress }, async getFactoryData() { - if (safeDeployed) return null + if (safeDeployed) return undefined safeDeployed = await isSmartAccountDeployed(client, accountAddress) - if (safeDeployed) return null + if (safeDeployed) return undefined return await getAccountInitCode({ owner: viemSigner.address, diff --git a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts index 539b3d55..40d7feb0 100644 --- a/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts +++ b/packages/permissionless/accounts/simple/signerToSimpleSmartAccount.ts @@ -228,21 +228,21 @@ export async function signerToSimpleSmartAccount< ]) }, async getFactory() { - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined smartAccountDeployed = await isSmartAccountDeployed( client, accountAddress ) - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined return factoryAddress }, async getFactoryData() { - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined smartAccountDeployed = await isSmartAccountDeployed( client, accountAddress ) - if (smartAccountDeployed) return null + if (smartAccountDeployed) return undefined return getAccountInitCode(viemSigner.address, index) }, async encodeDeployCallData(_) { diff --git a/packages/permissionless/accounts/types.ts b/packages/permissionless/accounts/types.ts index f1c34fac..d755073b 100644 --- a/packages/permissionless/accounts/types.ts +++ b/packages/permissionless/accounts/types.ts @@ -37,8 +37,8 @@ export type SmartAccount< entryPoint: entryPoint getNonce: () => Promise getInitCode: () => Promise - getFactory: () => Promise
- getFactoryData: () => Promise + getFactory: () => Promise
+ getFactoryData: () => Promise encodeCallData: ( args: | { diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts index 0111a708..dba9df40 100644 --- a/packages/permissionless/actions/bundler/estimateUserOperationGas.ts +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.ts @@ -48,8 +48,8 @@ export type EstimateUserOperationGasReturnType = preVerificationGas: bigint verificationGasLimit: bigint callGasLimit: bigint - paymasterVerificationGasLimit: bigint | null - paymasterPostOpGasLimit: bigint | null + paymasterVerificationGasLimit: bigint | undefined + paymasterPostOpGasLimit: bigint | undefined } export type EstimateUserOperationErrorType = @@ -131,8 +131,8 @@ export const estimateUserOperationGas = async < preVerificationGas: Hex verificationGasLimit: Hex callGasLimit: Hex - paymasterVerificationGasLimit: Hex | null - paymasterPostOpGasLimit: Hex | null + paymasterVerificationGasLimit: Hex | undefined + paymasterPostOpGasLimit: Hex | undefined } return { @@ -142,10 +142,10 @@ export const estimateUserOperationGas = async < paymasterVerificationGasLimit: responseV07.paymasterVerificationGasLimit ? BigInt(responseV07.paymasterVerificationGasLimit) - : null, + : undefined, paymasterPostOpGasLimit: responseV07.paymasterPostOpGasLimit ? BigInt(responseV07.paymasterPostOpGasLimit) - : null + : undefined } as EstimateUserOperationGasReturnType } catch (err) { throw getEstimateUserOperationGasError(err as BaseError, args) diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index e4c5d5f8..6b5125aa 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -203,8 +203,8 @@ async function prepareUserOperationRequestEntryPointV07< let userOperation: UserOperation<"v0.7"> = { sender, nonce, - factory: factory || null, - factoryData: factoryData || null, + factory: factory || undefined, + factoryData: factoryData || undefined, callData, callGasLimit: partialUserOperation.callGasLimit || 0n, verificationGasLimit: partialUserOperation.verificationGasLimit || 0n, @@ -217,10 +217,10 @@ async function prepareUserOperationRequestEntryPointV07< partialUserOperation.maxPriorityFeePerGas || gasEstimation?.maxPriorityFeePerGas || 0n, - paymaster: null, - paymasterVerificationGasLimit: null, - paymasterPostOpGasLimit: null, - paymasterData: null, + paymaster: undefined, + paymasterVerificationGasLimit: undefined, + paymasterPostOpGasLimit: undefined, + paymasterData: undefined, signature: partialUserOperation.signature || "0x" } diff --git a/packages/permissionless/types/bundler.ts b/packages/permissionless/types/bundler.ts index a3b56f50..5e7f9bcf 100644 --- a/packages/permissionless/types/bundler.ts +++ b/packages/permissionless/types/bundler.ts @@ -44,9 +44,9 @@ export type BundlerRpcSchema = [ : { preVerificationGas: Hex verificationGasLimit: Hex - callGasLimit: Hex | null - paymasterVerificationGasLimit: Hex | null - paymasterPostOpGasLimit: Hex | null + callGasLimit: Hex | null | undefined + paymasterVerificationGasLimit: Hex | null | undefined + paymasterPostOpGasLimit: Hex | null | undefined } }, { diff --git a/packages/permissionless/types/userOperation.ts b/packages/permissionless/types/userOperation.ts index 282b2a28..29682cf0 100644 --- a/packages/permissionless/types/userOperation.ts +++ b/packages/permissionless/types/userOperation.ts @@ -70,18 +70,18 @@ export type UserOperation = : { sender: Address nonce: bigint - factory: Address | null - factoryData: Hex | null + factory: Address | undefined + factoryData: Hex | undefined callData: Hex callGasLimit: bigint verificationGasLimit: bigint preVerificationGas: bigint maxFeePerGas: bigint maxPriorityFeePerGas: bigint - paymaster: Address | null - paymasterVerificationGasLimit: bigint | null - paymasterPostOpGasLimit: bigint | null - paymasterData: Hex | null + paymaster: Address | undefined + paymasterVerificationGasLimit: bigint | undefined + paymasterPostOpGasLimit: bigint | undefined + paymasterData: Hex | undefined signature: Hex initCode?: never paymasterAndData?: never From d1cfac97f6fbbf730baeaa59e53ba15a2eea3307 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:44:31 -0700 Subject: [PATCH 27/35] fix changeset --- .changeset/config.json | 3 +-- bun.lockb | Bin 518672 -> 517488 bytes .../.env.example | 0 .../index.html | 0 .../package.json | 2 +- .../src/App.tsx | 0 .../src/index.css | 0 .../src/main.tsx | 0 .../src/vite-env.d.ts | 0 packages/wagmi/package.json | 3 --- 10 files changed, 2 insertions(+), 6 deletions(-) rename packages/{wagmi-demo => wagmi-test-demo}/.env.example (100%) rename packages/{wagmi-demo => wagmi-test-demo}/index.html (100%) rename packages/{wagmi-demo => wagmi-test-demo}/package.json (95%) rename packages/{wagmi-demo => wagmi-test-demo}/src/App.tsx (100%) rename packages/{wagmi-demo => wagmi-test-demo}/src/index.css (100%) rename packages/{wagmi-demo => wagmi-test-demo}/src/main.tsx (100%) rename packages/{wagmi-demo => wagmi-test-demo}/src/vite-env.d.ts (100%) diff --git a/.changeset/config.json b/.changeset/config.json index 8e45b1bf..41859999 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,6 +7,5 @@ "updateInternalDependencies": "patch", "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { "onlyUpdatePeerDependentsWhenOutOfRange": true - }, - "ignore": ["test"] + } } diff --git a/bun.lockb b/bun.lockb index f6088cccbe6400ffdb83a6a7f2d78985ebc5e8d1..69e23e125d164fad61243c8767ec5c205a81ee78 100755 GIT binary patch delta 105892 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
QA0;hu!yrg$QRutW&+6Cr$NZcDf&p_V_w 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 delta 105390 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 diff --git a/packages/wagmi-demo/.env.example b/packages/wagmi-test-demo/.env.example similarity index 100% rename from packages/wagmi-demo/.env.example rename to packages/wagmi-test-demo/.env.example diff --git a/packages/wagmi-demo/index.html b/packages/wagmi-test-demo/index.html similarity index 100% rename from packages/wagmi-demo/index.html rename to packages/wagmi-test-demo/index.html diff --git a/packages/wagmi-demo/package.json b/packages/wagmi-test-demo/package.json similarity index 95% rename from packages/wagmi-demo/package.json rename to packages/wagmi-test-demo/package.json index a5aff509..c577dd1a 100644 --- a/packages/wagmi-demo/package.json +++ b/packages/wagmi-test-demo/package.json @@ -16,7 +16,7 @@ "viem": "^2.0.0", "@tanstack/react-query": "5.0.5", "react": "^18.2.0", - "permissionless": "0.0.35", + "permissionless": "0.0.36", "vite": "^4.4.9", "@types/react": "^18.2.22", "@types/react-dom": "^18.2.7", diff --git a/packages/wagmi-demo/src/App.tsx b/packages/wagmi-test-demo/src/App.tsx similarity index 100% rename from packages/wagmi-demo/src/App.tsx rename to packages/wagmi-test-demo/src/App.tsx diff --git a/packages/wagmi-demo/src/index.css b/packages/wagmi-test-demo/src/index.css similarity index 100% rename from packages/wagmi-demo/src/index.css rename to packages/wagmi-test-demo/src/index.css diff --git a/packages/wagmi-demo/src/main.tsx b/packages/wagmi-test-demo/src/main.tsx similarity index 100% rename from packages/wagmi-demo/src/main.tsx rename to packages/wagmi-test-demo/src/main.tsx diff --git a/packages/wagmi-demo/src/vite-env.d.ts b/packages/wagmi-test-demo/src/vite-env.d.ts similarity index 100% rename from packages/wagmi-demo/src/vite-env.d.ts rename to packages/wagmi-test-demo/src/vite-env.d.ts diff --git a/packages/wagmi/package.json b/packages/wagmi/package.json index 7718cc71..d71c3b26 100644 --- a/packages/wagmi/package.json +++ b/packages/wagmi/package.json @@ -20,9 +20,6 @@ "default": "./_cjs/index.js" } }, - "dependencies": { - "permissionless": "0.0.35" - }, "peerDependencies": { "wagmi": "^2.5.1", "viem": "^2.0.0", From be2929a3ad655475510e136c4289269b86ce0714 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:45:23 -0700 Subject: [PATCH 28/35] add changeset --- .changeset/big-adults-act.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/big-adults-act.md diff --git a/.changeset/big-adults-act.md b/.changeset/big-adults-act.md new file mode 100644 index 00000000..9c22d18d --- /dev/null +++ b/.changeset/big-adults-act.md @@ -0,0 +1,5 @@ +--- +"permissionless": minor +--- + +Add EntryPoint v0.7 support From 39f909b34363a46ed943331b71349cb194231dc8 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:47:22 -0700 Subject: [PATCH 29/35] fix wagmi build --- packages/wagmi/package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/wagmi/package.json b/packages/wagmi/package.json index d71c3b26..fad4764f 100644 --- a/packages/wagmi/package.json +++ b/packages/wagmi/package.json @@ -20,9 +20,11 @@ "default": "./_cjs/index.js" } }, + "dependencies": { + "permissionless": "0.0.36" + }, "peerDependencies": { "wagmi": "^2.5.1", - "viem": "^2.0.0", - "permissionless": "^0.0.36" + "viem": "^2.0.0" } } From ac6f36ee16a6fcd3311277064a7f0d3359cd847d Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:50:47 -0700 Subject: [PATCH 30/35] fix wagmi dependendency --- packages/wagmi/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wagmi/package.json b/packages/wagmi/package.json index fad4764f..1f8e9983 100644 --- a/packages/wagmi/package.json +++ b/packages/wagmi/package.json @@ -21,7 +21,7 @@ } }, "dependencies": { - "permissionless": "0.0.36" + "permissionless": "^0.0.36" }, "peerDependencies": { "wagmi": "^2.5.1", From 84eca4d9355b55bc47330cb55b01516cc65a84fe Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 13:55:05 -0700 Subject: [PATCH 31/35] update bun --- bun.lockb | Bin 517488 -> 517904 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bun.lockb b/bun.lockb index 69e23e125d164fad61243c8767ec5c205a81ee78..aeabca53fbe8ac589addc6b71432edd8cab47b61 100755 GIT binary patch delta 64158 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 z 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 Mwn|z3fz|o{2cg2hEdT%j From d1fe49c5d6311b831a84b815ff9274a42fd90c6a Mon Sep 17 00:00:00 2001 From: plusminushalf Date: Sat, 24 Feb 2024 21:22:58 +0000 Subject: [PATCH 32/35] chore: format --- bun.lockb | Bin 0 -> 510584 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 bun.lockb diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..fef872699e6fb689220c0496df55c2ae1d9417b5 GIT binary patch literal 510584 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 HFaQ0&9Xr1O literal 0 HcmV?d00001 From bb3422ff5a5a59e51ffc2b5624f89448d527f9b6 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 14:37:20 -0700 Subject: [PATCH 33/35] fix ci --- bun.lockb | Bin 510584 -> 517888 bytes packages/permissionless/package.json | 10 ++-------- packages/wagmi/package.json | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/bun.lockb b/bun.lockb index fef872699e6fb689220c0496df55c2ae1d9417b5..6ede2fb0373ff19e602877639568dc302176d688 100755 GIT binary patch delta 79746 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 z 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πEu|#xHr!Nq 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�pRt%-^sMHMb7+07{o{ib~6L@k<5)e}ve|L;_D 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 L9w~U$_viluuQBf6 diff --git a/packages/permissionless/package.json b/packages/permissionless/package.json index 6a7e298d..d67c0e54 100644 --- a/packages/permissionless/package.json +++ b/packages/permissionless/package.json @@ -1,6 +1,6 @@ { "name": "permissionless", - "version": "0.0.36", + "version": "0.0.37", "author": "Pimlico", "homepage": "https://docs.pimlico.io/permissionless", "repository": "github:pimlicolabs/permissionless.js", @@ -11,13 +11,7 @@ "type": "module", "sideEffects": false, "description": "A utility library for working with ERC-4337", - "keywords": [ - "ethereum", - "erc-4337", - "eip-4337", - "paymaster", - "bundler" - ], + "keywords": ["ethereum", "erc-4337", "eip-4337", "paymaster", "bundler"], "license": "MIT", "exports": { ".": { diff --git a/packages/wagmi/package.json b/packages/wagmi/package.json index 1f8e9983..fad4764f 100644 --- a/packages/wagmi/package.json +++ b/packages/wagmi/package.json @@ -21,7 +21,7 @@ } }, "dependencies": { - "permissionless": "^0.0.36" + "permissionless": "0.0.36" }, "peerDependencies": { "wagmi": "^2.5.1", From 986e1441ed9922dc35c6dff920a5ab4ecee4dab2 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Sat, 24 Feb 2024 14:41:13 -0700 Subject: [PATCH 34/35] add @vitest/coverage-v8 as dev dependency --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 7ca208ef..75ea41d9 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "sideEffects": false, "devDependencies": { "vitest": "^1.2.0", + "@vitest/coverage-v8": "^1.2.0", "@biomejs/biome": "^1.0.0", "@changesets/changelog-git": "^0.1.14", "@changesets/changelog-github": "^0.4.8", From f58e2831d2bc42fb001d2a33c5fec21eb1bc6252 Mon Sep 17 00:00:00 2001 From: plusminushalf Date: Sat, 24 Feb 2024 21:41:37 +0000 Subject: [PATCH 35/35] chore: format --- bun.lockb | Bin 517888 -> 522712 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bun.lockb b/bun.lockb index 6ede2fb0373ff19e602877639568dc302176d688..0a20298756c6be7a87bdfab57591f4f712b91518 100755 GIT binary patch delta 107614 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�}PGq(R6#sWfyO&{C7I>tTxjdQyGlQcl zqhml8cmjw&+FSfm$cDb7IFT8?t9VId#m_+}UQ+m}vi}T-KiU_iFg!H44o084tqgu- zEUuEsf__r*KLc5jJIbykQo4sP;-4!1zeNuWnDJjKft9)9Dv2B-{!e-M=|&p|v1X;j5*mKC{16lA=mA)i0 z-zT9nYL!HfwpJMuX|P^KXq$n|Xq$>BvViT1mqb?Jd8L;`>N}K9B;N^SIlE27_`iq% zGv2FkpTd_Ez6@l7SAopnHKo6<@UV(Ms^X6+{REI*eOmE%fb{wcK>X1zD7QtP($(Biq}Ry@$AH8ES>P6-{AfkRSEAlOHB`FXMa%UJ6J^zWi)uW;t>i*0ckf*;UpmKqJa3L#o~+YaVwk(WPFn1DGJjR zX4tS!F~Kw?WCJ;3IY1_y31oq}Dt<1o8u(fjzaGeo$aEVNZUi#jGm1Z}a0`&v1B9P2 z;Z{U&sCOy@A}f{$WJU6Uw0lwE9u;2zH zQ1~X0EqEKqjNViF`$|8r^ot5F1G%Su1>{9!e%~lw61l|`sd (ae2fGvS_S*?E{ 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�|1TDmE1Ps(+(Et#Dx1Px+~IQDb#W*7F05iM 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 F{{!#S98&-Q