From 447e575397617d071f7b54657f7c26e4c8382f75 Mon Sep 17 00:00:00 2001 From: roushou Date: Fri, 21 Jun 2024 23:02:01 +0700 Subject: [PATCH] feat: add Paymaster client --- .../bundler/estimate-user-operation-gas.ts | 33 ++++ .../src/bundler/get-supported-entrypoints.ts | 30 ++++ .../src/bundler/get-user-operation-receipt.ts | 41 +++++ .../bundler/get-user-operations-by-hash.ts | 41 +++++ .../src/bundler/send-user-operation.ts | 31 ++++ packages/paymaster/src/client.ts | 150 ++++++++++++++++++ .../src/sponsor/sponser-user-operation.ts | 31 ++++ 7 files changed, 357 insertions(+) create mode 100644 packages/paymaster/src/bundler/estimate-user-operation-gas.ts create mode 100644 packages/paymaster/src/bundler/get-supported-entrypoints.ts create mode 100644 packages/paymaster/src/bundler/get-user-operation-receipt.ts create mode 100644 packages/paymaster/src/bundler/get-user-operations-by-hash.ts create mode 100644 packages/paymaster/src/bundler/send-user-operation.ts create mode 100644 packages/paymaster/src/client.ts create mode 100644 packages/paymaster/src/sponsor/sponser-user-operation.ts diff --git a/packages/paymaster/src/bundler/estimate-user-operation-gas.ts b/packages/paymaster/src/bundler/estimate-user-operation-gas.ts new file mode 100644 index 0000000..ae82ad9 --- /dev/null +++ b/packages/paymaster/src/bundler/estimate-user-operation-gas.ts @@ -0,0 +1,33 @@ +import type { RpcClient, RpcRequestConfig } from "../rpc"; + +export type EstimateUserOperationGasParameters = Extract< + RpcRequestConfig, + { method: "eth_estimateUserOperationGas" } +>["parameters"]; + +export type EstimateUserOperationGasResponse = Extract< + RpcRequestConfig, + { method: "eth_estimateUserOperationGas" } +>["response"]["result"]; + +/** + * @returns The gas estimates of the operation + * + * @param rpc - RPC Client {@link RpcClient} + * @param parameters - User operation {@link EstimateUserOperationGasParameters} + * + * @example + * + * TODO + * + */ +export async function estimateUserOperationGas( + rpc: RpcClient, + params: EstimateUserOperationGasParameters, +): Promise { + const response = await rpc.request({ + method: "eth_estimateUserOperationGas", + parameters: params, + }); + return response.result; +} diff --git a/packages/paymaster/src/bundler/get-supported-entrypoints.ts b/packages/paymaster/src/bundler/get-supported-entrypoints.ts new file mode 100644 index 0000000..0c5d991 --- /dev/null +++ b/packages/paymaster/src/bundler/get-supported-entrypoints.ts @@ -0,0 +1,30 @@ +import type { RpcClient, RpcRequestConfig } from "../rpc"; + +export type GetSupportedEntrypointsResponse = Extract< + RpcRequestConfig, + { method: "eth_supportedEntryPoints" } +>["response"]["result"]; + +/** + * @returns The list of supported entrypoints + * + * @param rpc - RPC Client {@link RpcClient} + * + * @example + * + * const rpcClient = createRpcClient({ + * apiKey: API_KEY, + * rpcUrl: "https://api.developer.coinbase.com/rpc/v1/base", + * }); + * + * await getSupportedEntrypoints(rpcClient); + * + */ +export async function getSupportedEntrypoints( + rpc: RpcClient, +): Promise { + const response = await rpc.request({ + method: "eth_supportedEntryPoints", + }); + return response.result; +} diff --git a/packages/paymaster/src/bundler/get-user-operation-receipt.ts b/packages/paymaster/src/bundler/get-user-operation-receipt.ts new file mode 100644 index 0000000..ca1c622 --- /dev/null +++ b/packages/paymaster/src/bundler/get-user-operation-receipt.ts @@ -0,0 +1,41 @@ +import type { RpcClient, RpcRequestConfig } from "../rpc"; + +export type GetUserOperationReceiptParameters = Extract< + RpcRequestConfig, + { method: "eth_getUserOperationReceipt" } +>["parameters"]; + +export type GetUserOperationReceiptResponse = Extract< + RpcRequestConfig, + { method: "eth_getUserOperationReceipt" } +>["response"]["result"]; + +/** + * @returns The user operation receipt + * + * @param rpc - RPC Client {@link RpcClient} + * @param parameters - Operation hash {@link GetUserOperationReceiptParameters} + * + * @example + * + * const rpcClient = createRpcClient({ + * apiKey: API_KEY, + * rpcUrl: "https://api.developer.coinbase.com/rpc/v1/base", + * }); + * + * await getUserOperationReceipt( + * rpcClient, + * ["0x77c0b560eb0b042902abc5613f768d2a6b2d67481247e9663bf4d68dec0ca122"], + * ); + * + */ +export async function getUserOperationReceipt( + rpc: RpcClient, + params: GetUserOperationReceiptParameters, +): Promise { + const response = await rpc.request({ + method: "eth_getUserOperationReceipt", + parameters: params, + }); + return response.result; +} diff --git a/packages/paymaster/src/bundler/get-user-operations-by-hash.ts b/packages/paymaster/src/bundler/get-user-operations-by-hash.ts new file mode 100644 index 0000000..3a338cb --- /dev/null +++ b/packages/paymaster/src/bundler/get-user-operations-by-hash.ts @@ -0,0 +1,41 @@ +import type { RpcClient, RpcRequestConfig } from "../rpc"; + +export type GetUserOperationByHashParameters = Extract< + RpcRequestConfig, + { method: "eth_getUserOperationByHash" } +>["parameters"]; + +export type GetUserOperationByHashResponse = Extract< + RpcRequestConfig, + { method: "eth_getUserOperationByHash" } +>["response"]["result"]; + +/** + * @returns The user operation + * + * @param rpc - RPC Client {@link RpcClient} + * @param parameters - Operation hash {@link GetUserOperationByHashParameters} + * + * @example + * + * const rpcClient = createRpcClient({ + * apiKey: API_KEY, + * rpcUrl: "https://api.developer.coinbase.com/rpc/v1/base", + * }); + * + * await getUserOperationByhash( + * rpcClient, + * ["0x77c0b560eb0b042902abc5613f768d2a6b2d67481247e9663bf4d68dec0ca122"], + * ); + * + */ +export async function getUserOperationByHash( + rpc: RpcClient, + params: GetUserOperationByHashParameters, +): Promise { + const response = await rpc.request({ + method: "eth_getUserOperationByHash", + parameters: params, + }); + return response.result; +} diff --git a/packages/paymaster/src/bundler/send-user-operation.ts b/packages/paymaster/src/bundler/send-user-operation.ts new file mode 100644 index 0000000..b85e71f --- /dev/null +++ b/packages/paymaster/src/bundler/send-user-operation.ts @@ -0,0 +1,31 @@ +import type { RpcClient, RpcRequestConfig } from "../rpc"; + +export type SendUserOperationParameters = Extract< + RpcRequestConfig, + { method: "eth_sendUserOperation" } +>["parameters"]; + +export type SendUserOperationResponse = Extract< + RpcRequestConfig, + { method: "eth_sendUserOperation" } +>["response"]["result"]; + +/** + * @param rpc - RPC Client {@link RpcClient} + * @param parameters - Operation {@link SendUserOperationParameters} + * + * @example + * + * TODO + * + */ +export async function sendUserOperation( + rpc: RpcClient, + params: SendUserOperationParameters, +): Promise { + const response = await rpc.request({ + method: "eth_sendUserOperation", + parameters: params, + }); + return response.result; +} diff --git a/packages/paymaster/src/client.ts b/packages/paymaster/src/client.ts new file mode 100644 index 0000000..d9d3068 --- /dev/null +++ b/packages/paymaster/src/client.ts @@ -0,0 +1,150 @@ +import { + type EstimateUserOperationGasParameters, + type EstimateUserOperationGasResponse, + estimateUserOperationGas, +} from "./bundler/estimate-user-operation-gas"; +import { + type GetSupportedEntrypointsResponse, + getSupportedEntrypoints, +} from "./bundler/get-supported-entrypoints"; +import { + type GetUserOperationReceiptParameters, + type GetUserOperationReceiptResponse, + getUserOperationReceipt, +} from "./bundler/get-user-operation-receipt"; +import { + type GetUserOperationByHashParameters, + type GetUserOperationByHashResponse, + getUserOperationByHash, +} from "./bundler/get-user-operations-by-hash"; +import { + type SendUserOperationParameters, + type SendUserOperationResponse, + sendUserOperation, +} from "./bundler/send-user-operation"; +import { createRpcClient } from "./rpc"; +import { + type SponsorUserOperationParameters, + type SponsorUserOperationResponse, + sponsorUserOperation, +} from "./sponsor/sponser-user-operation"; + +export type Client = { + /** + * @example + * + * TODO + * + */ + estimateUserOperationGas: ( + parameters: EstimateUserOperationGasParameters, + ) => Promise; + /** + * @example + * + * client.getUserOperationByHash([ + * "0x77c0b560eb0b042902abc5613f768d2a6b2d67481247e9663bf4d68dec0ca122", + * ]); + * + */ + /** + * @example + * + * client.getSupportedEntrypoints(); + * + */ + getSupportedEntrypoints: () => Promise; + /** + * @example + * + * client.getUserOperationByHash([ + * "0x77c0b560eb0b042902abc5613f768d2a6b2d67481247e9663bf4d68dec0ca122", + * ]); + * + */ + getUserOperationByHash: ( + parameters: GetUserOperationByHashParameters, + ) => Promise; + /** + * @example + * + * client.getUserOperationReceipt([ + * "0x77c0b560eb0b042902abc5613f768d2a6b2d67481247e9663bf4d68dec0ca122", + * ]); + * + */ + getUserOperationReceipt: ( + parameters: GetUserOperationReceiptParameters, + ) => Promise; + /** + * @example + * + * TODO + * + */ + sendUserOperation: ( + parameters: SendUserOperationParameters, + ) => Promise; + /** + * @example + * + * TODO + * + */ + sponsorUserOperation: ( + parameters: SponsorUserOperationParameters, + ) => Promise; +}; + +export type ClientConfig = { + apiKey: string; + /** + * Coinbase platform RPC endpoint. + * Defaults to `https://api.developer.coinbase.com/rpc/v1/base` + */ + rpcUrl?: string; +}; + +/** + * @returns The Client + * + * @param apiKey - Your API key + * @param rpcUrl - Your RPC url. Defaults to `https://api.developer.coinbase.com/rpc/v1/base` + * + * @example + * + * const client = createClient({ + * apiKey: API_KEY, + * rpcUrl: "https://api.developer.coinbase.com/rpc/v1/base", + * }); + * + */ +export function createClient(config: ClientConfig): Client { + const rpcClient = createRpcClient({ + apiKey: config.apiKey, + url: config.rpcUrl, + }); + + const client: Client = { + estimateUserOperationGas: async (parameters) => { + return await estimateUserOperationGas(rpcClient, parameters); + }, + getSupportedEntrypoints: async () => { + return await getSupportedEntrypoints(rpcClient); + }, + getUserOperationByHash: async (parameters) => { + return await getUserOperationByHash(rpcClient, parameters); + }, + getUserOperationReceipt: async (parameters) => { + return await getUserOperationReceipt(rpcClient, parameters); + }, + sendUserOperation: async (parameters) => { + return await sendUserOperation(rpcClient, parameters); + }, + sponsorUserOperation: async (parameters) => { + return await sponsorUserOperation(rpcClient, parameters); + }, + }; + + return client; +} diff --git a/packages/paymaster/src/sponsor/sponser-user-operation.ts b/packages/paymaster/src/sponsor/sponser-user-operation.ts new file mode 100644 index 0000000..cdcdbfe --- /dev/null +++ b/packages/paymaster/src/sponsor/sponser-user-operation.ts @@ -0,0 +1,31 @@ +import type { RpcClient, RpcRequestConfig } from "../rpc"; + +export type SponsorUserOperationParameters = Extract< + RpcRequestConfig, + { method: "pm_sponsorUserOperation" } +>["parameters"]; + +export type SponsorUserOperationResponse = Extract< + RpcRequestConfig, + { method: "pm_sponsorUserOperation" } +>["response"]["result"]; + +/** + * @param rpc - RPC Client {@link RpcClient} + * @param parameters - Operation {@link SponsorUserOperationParameters} + * + * @example + * + * TODO + * + */ +export async function sponsorUserOperation( + rpc: RpcClient, + params: SponsorUserOperationParameters, +): Promise { + const response = await rpc.request({ + method: "pm_sponsorUserOperation", + parameters: params, + }); + return response.result; +}