diff --git a/.changeset/red-dodos-dress.md b/.changeset/red-dodos-dress.md new file mode 100644 index 00000000..76da7cf1 --- /dev/null +++ b/.changeset/red-dodos-dress.md @@ -0,0 +1,5 @@ +--- +"permissionless": patch +--- + +Added Base Paymaster actions diff --git a/src/actions/base.ts b/src/actions/base.ts new file mode 100644 index 00000000..0aa9d533 --- /dev/null +++ b/src/actions/base.ts @@ -0,0 +1,22 @@ +import { + type GetPaymasterAndDataForEstimateGasParameters, + type GetPaymasterAndDataForEstimateGasReturnType, + getPaymasterAndDataForEstimateGas +} from "./base/getPaymasterAndDataForEstimateGas.js" +import { + type GetPaymasterAndDataForUserOperationParameters, + type GetPaymasterAndDataForUserOperationReturnType, + getPaymasterAndDataForUserOperation +} from "./base/getPaymasterAndDataForUserOperation.js" + +export type { + GetPaymasterAndDataForEstimateGasParameters, + GetPaymasterAndDataForEstimateGasReturnType, + GetPaymasterAndDataForUserOperationParameters, + GetPaymasterAndDataForUserOperationReturnType +} + +export { + getPaymasterAndDataForEstimateGas, + getPaymasterAndDataForUserOperation +} diff --git a/src/actions/base/getPaymasterAndDataForEstimateGas.ts b/src/actions/base/getPaymasterAndDataForEstimateGas.ts new file mode 100644 index 00000000..8e767c58 --- /dev/null +++ b/src/actions/base/getPaymasterAndDataForEstimateGas.ts @@ -0,0 +1,46 @@ +import type { Address, Hash, Hex } from "viem" +import { BasePaymasterClient } from "../../clients/base.js" +import { type UserOperationWithBigIntAsHex } from "../../types/userOperation.js" + +export type GetPaymasterAndDataForEstimateGasParameters = { + userOperation: UserOperationWithBigIntAsHex + entryPoint: Address + chainId: Hex +} + +export type GetPaymasterAndDataForEstimateGasReturnType = Hash + +/** + * Returns paymasterAndData for gas estimation. Note that this is a dummy signature that won't be accepted by the paymaster, except for gas estimation. + * + * @param client {@link BasePaymasterClient} that you created using viem's createClient whose transport url is pointing to the Base paymaster. + * @param args {@link GetPaymasterAndDataForEstimateGasParameters} UserOperation you want to sponsor, entryPoint, and chain ID. + * @returns paymasterAndData with a dummy signature just for gas estimation. + * + * + * @example + * import { createClient } from "viem" + * import { getPaymasterAndDataForEstimateGas } from "permissionless/actions/base" + * + * const paymasterClient = createClient({ + * transport: http("https://paymaster.base.org") + * }) + * + * await getPaymasterAndDataForEstimateGas(bundlerClient, { + * userOperation: userOperationWithoutPaymaster, + * entryPoint: entryPoint, + * chainId: toHex(chainId) + * }}) + * + */ +export const getPaymasterAndDataForEstimateGas = async ( + client: BasePaymasterClient, + args: GetPaymasterAndDataForEstimateGasParameters +): Promise => { + const response = await client.request({ + method: "eth_paymasterAndDataForEstimateGas", + params: [args.userOperation, args.entryPoint, args.chainId] + }) + + return response +} diff --git a/src/actions/base/getPaymasterAndDataForUserOperation.ts b/src/actions/base/getPaymasterAndDataForUserOperation.ts new file mode 100644 index 00000000..5c4c9f26 --- /dev/null +++ b/src/actions/base/getPaymasterAndDataForUserOperation.ts @@ -0,0 +1,46 @@ +import type { Account, Address, Chain, Hash, Hex, Transport } from "viem" +import { BasePaymasterClient } from "../../clients/base.js" +import { type UserOperationWithBigIntAsHex } from "../../types/userOperation.js" + +export type GetPaymasterAndDataForUserOperationParameters = { + userOperation: UserOperationWithBigIntAsHex + entryPoint: Address + chainId: Hex +} + +export type GetPaymasterAndDataForUserOperationReturnType = Hash + +/** + * Returns paymasterAndData for sponsoring a userOp. + * + * @param client {@link BasePaymasterClient} that you created using viem's createClient whose transport url is pointing to the Base paymaster. + * @param args {@link GetPaymasterAndDataForUserOperationParameters} UserOperation you want to sponsor, entryPoint, and chain ID. + * @returns paymasterAndData for sponsoring a userOp. + * + * + * @example + * import { createClient } from "viem" + * import { getPaymasterAndDataForUserOperation } from "permissionless/actions/base" + * + * const paymasterClient = createClient({ + * transport: http("https://paymaster.base.org") + * }) + * + * await getPaymasterAndDataForUserOperation(bundlerClient, { + * userOperation: userOperation, + * entryPoint: entryPoint, + * chainId: toHex(chainId) + * }}) + * + */ +export const getPaymasterAndDataForUserOperation = async ( + client: BasePaymasterClient, + args: GetPaymasterAndDataForUserOperationParameters +): Promise => { + const response = await client.request({ + method: "eth_paymasterAndDataForUserOperation", + params: [args.userOperation, args.entryPoint, args.chainId] + }) + + return response +} diff --git a/src/clients/base.ts b/src/clients/base.ts new file mode 100644 index 00000000..bcfa2342 --- /dev/null +++ b/src/clients/base.ts @@ -0,0 +1,54 @@ +import { + type Account, + type Chain, + type Client, + type PublicClientConfig, + type Transport, + createClient, + http +} from "viem" +import type { PartialBy } from "viem/types/utils" +import { type BasePaymasterRpcSchema } from "../types/base.js" +import { + type BasePaymasterClientActions, + basePaymasterActions +} from "./decorators/base.js" + +export type BasePaymasterClient = Client< + Transport, + Chain | undefined, + Account | undefined, + BasePaymasterRpcSchema, + BasePaymasterClientActions +> + +/** + * Creates a Base paymaster client. + * + * - Docs: https://github.com/base-org/paymaster + * + * @param config - {@link PublicClientConfig} + * @returns A Base Paymaster Client. {@link BasePaymasterClient} + * + * @example + * import { createPublicClient, http } from 'viem' + * + * const basePaymasterClient = createBasePaymasterClient({ + * transport: http("https://paymaster.base.org"), + * }) + */ +export const createBasePaymasterClient = < + transport extends Transport, + chain extends Chain | undefined = undefined +>( + parameters?: PartialBy, 'transport'> +): BasePaymasterClient => { + const client = createClient({ + ...parameters, + key: parameters?.key ?? "public", + name: parameters?.name ?? "Base Paymaster Client", + type: "basePaymasterClient", + transport: parameters?.transport ?? http("https://paymaster.base.org") + }) + return client.extend(basePaymasterActions) +} diff --git a/src/clients/decorators/base.ts b/src/clients/decorators/base.ts new file mode 100644 index 00000000..970fa647 --- /dev/null +++ b/src/clients/decorators/base.ts @@ -0,0 +1,76 @@ +import type { Client } from "viem" +import { + type GetPaymasterAndDataForEstimateGasParameters, + type GetPaymasterAndDataForEstimateGasReturnType, + getPaymasterAndDataForEstimateGas +} from "../../actions/base/getPaymasterAndDataForEstimateGas.js" +import { + type GetPaymasterAndDataForUserOperationParameters, + type GetPaymasterAndDataForUserOperationReturnType, + getPaymasterAndDataForUserOperation +} from "../../actions/base/getPaymasterAndDataForUserOperation.js" +import { type BasePaymasterClient } from "../base.js" + +export type BasePaymasterClientActions = { + /** + * Returns paymasterAndData for gas estimation. Note that this is a dummy signature that won't be accepted by the paymaster, except for gas estimation. + * + * @param args {@link GetPaymasterAndDataForEstimateGasParameters} UserOperation you want to sponsor, entryPoint, and chain ID. + * @returns paymasterAndData with a dummy signature just for gas estimation. + * + * @example + * import { createClient } from "viem" + * import { basePaymasterActions } from "permissionless/actions/base" + * + * const basePaymasterClient = createClient({ + * transport: http("https://paymaster.base.org") + * }).extend(basePaymasterActions) + * + * await basePaymasterClient.getPaymasterAndDataForEstimateGas({ + * userOperation: userOperationWithoutPaymaster,, + * entryPoint: entryPoint, + * chainId: toHex(chainId) + * }) + * + */ + getPaymasterAndDataForEstimateGas: ( + args: GetPaymasterAndDataForEstimateGasParameters + ) => Promise + + /** + * Returns paymasterAndData for sponsoring a userOp. + * + * @param args {@link GetPaymasterAndDataForUserOperationParameters} UserOperation you want to sponsor, entryPoint, and chain ID. + * @returns paymasterAndData for sponsoring a userOp. + * + * @example + * import { createClient } from "viem" + * import { basePaymasterActions } from "permissionless/actions/base" + * + * const basePaymasterClient = createClient({ + * transport: http("https://paymaster.base.org") + * }).extend(basePaymasterActions) + * + * await basePaymasterClient.getPaymasterAndDataForUserOperation({ + * userOperation: userOperation, + * entryPoint: entryPoint, + * chainId: toHex(chainId) + * }) + * + */ + getPaymasterAndDataForUserOperation: ( + args: GetPaymasterAndDataForUserOperationParameters + ) => Promise +} + +export const basePaymasterActions = ( + client: Client +): BasePaymasterClientActions => ({ + getPaymasterAndDataForEstimateGas: async ( + args: GetPaymasterAndDataForEstimateGasParameters + ) => getPaymasterAndDataForEstimateGas(client as BasePaymasterClient, args), + getPaymasterAndDataForUserOperation: async ( + args: GetPaymasterAndDataForUserOperationParameters + ) => + getPaymasterAndDataForUserOperation(client as BasePaymasterClient, args) +}) diff --git a/src/package.json b/src/package.json index 415c8c23..71199a73 100644 --- a/src/package.json +++ b/src/package.json @@ -48,6 +48,11 @@ "import": "./_esm/actions/smartAccount.js", "default": "./_cjs/actions/smartAccount.js" }, + "./actions/base": { + "types": "./_types/actions/base.d.ts", + "import": "./_esm/actions/base.js", + "default": "./_cjs/actions/base.js" + }, "./clients": { "types": "./_types/clients/index.d.ts", "import": "./_esm/clients/index.js", @@ -63,6 +68,11 @@ "import": "./_esm/clients/stackup.js", "default": "./_cjs/clients/stackup.js" }, + "./clients/base": { + "types": "./_types/clients/base.d.ts", + "import": "./_esm/clients/base.js", + "default": "./_cjs/clients/base.js" + }, "./utils": { "types": "./_types/utils/index.d.ts", "import": "./_esm/utils/index.js", diff --git a/src/types/base.ts b/src/types/base.ts new file mode 100644 index 00000000..e0244207 --- /dev/null +++ b/src/types/base.ts @@ -0,0 +1,23 @@ +import type { Address, Hash, Hex } from "viem" +import type { UserOperationWithBigIntAsHex } from "./userOperation.js" + +export type BasePaymasterRpcSchema = [ + { + Method: "eth_paymasterAndDataForEstimateGas" + Parameters: [ + userOperation: UserOperationWithBigIntAsHex, + entryPoint: Address, + chainId: Hex + ] + ReturnType: Hash + }, + { + Method: "eth_paymasterAndDataForUserOperation" + Parameters: [ + userOperation: UserOperationWithBigIntAsHex, + entryPoint: Address, + chainId: Hex + ] + ReturnType: Hash + } +]