diff --git a/cspell-config/cspell-misc.txt b/cspell-config/cspell-misc.txt index 28f192ef..90567d90 100644 --- a/cspell-config/cspell-misc.txt +++ b/cspell-config/cspell-misc.txt @@ -11,6 +11,7 @@ testid vueuse dockerized ethereum +foundryup // examples/bank-demo ctap @@ -28,3 +29,11 @@ usdc Fren fren nfts + +// examples/demo-app +zkout +cancun +EVMLA + +// paymasters +zyfi \ No newline at end of file diff --git a/packages/sdk/package.json b/packages/sdk/package.json index c6ff9925..b5f84f57 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -104,6 +104,11 @@ "import": "./dist/_esm/abi/index.js", "require": "./dist/_cjs/abi/index.js" }, + "./paymaster": { + "types": "./dist/_types/paymaster/index.d.ts", + "import": "./dist/_esm/paymaster/index.js", + "require": "./dist/_cjs/paymaster/index.js" + }, "./package.json": "./package.json" }, "typesVersions": { diff --git a/packages/sdk/src/client-auth-server/Signer.ts b/packages/sdk/src/client-auth-server/Signer.ts index ac9ccd3c..c1514d62 100644 --- a/packages/sdk/src/client-auth-server/Signer.ts +++ b/packages/sdk/src/client-auth-server/Signer.ts @@ -1,7 +1,9 @@ import { type Address, type Chain, createWalletClient, custom, type Hash, http, type RpcSchema as RpcSchemaGeneric, type SendTransactionParameters, type Transport, type WalletClient } from "viem"; +import type { TransactionRequestEIP712 } from "viem/chains"; import { createZksyncSessionClient, type ZksyncSsoSessionClient } from "../client/index.js"; import type { Communicator } from "../communicator/index.js"; +import { type CustomPaymasterHandler, getTransactionWithPaymasterData } from "../paymaster/index.js"; import { StorageItem } from "../utils/storage.js"; import type { AppMetadata, RequestArguments } from "./interface.js"; import type { AuthServerRpcSchema, ExtractParams, ExtractReturnType, Method, RPCRequestMessage, RPCResponseMessage, RpcSchema } from "./rpc.js"; @@ -38,6 +40,7 @@ type SignerConstructorParams = { chains: readonly Chain[]; transports?: Record; session?: () => SessionPreferences | Promise; + paymasterHandler?: CustomPaymasterHandler; }; type ChainsInfo = ExtractReturnType<"eth_requestAccounts", AuthServerRpcSchema>["chainsInfo"]; @@ -49,12 +52,13 @@ export class Signer implements SignerInterface { private readonly chains: readonly Chain[]; private readonly transports: Record = {}; private readonly sessionParameters?: () => (SessionPreferences | Promise); + private readonly paymasterHandler?: CustomPaymasterHandler; private _account: StorageItem; private _chainsInfo = new StorageItem(StorageItem.scopedStorageKey("chainsInfo"), []); private client: { instance: ZksyncSsoSessionClient; type: "session" } | { instance: WalletClient; type: "auth-server" } | undefined; - constructor({ metadata, communicator, updateListener, session, chains, transports }: SignerConstructorParams) { + constructor({ metadata, communicator, updateListener, session, chains, transports, paymasterHandler }: SignerConstructorParams) { if (!chains.length) throw new Error("At least one chain must be included in the config"); this.getMetadata = metadata; @@ -63,6 +67,7 @@ export class Signer implements SignerInterface { this.sessionParameters = session; this.chains = chains; this.transports = transports || {}; + this.paymasterHandler = paymasterHandler; this._account = new StorageItem(StorageItem.scopedStorageKey("account"), null, { onChange: (newValue) => { @@ -136,6 +141,7 @@ export class Signer implements SignerInterface { contracts: chainInfo.contracts, chain, transport: this.transports[chain.id] || http(), + paymasterHandler: this.paymasterHandler, }), }; } else { @@ -266,6 +272,23 @@ export class Signer implements SignerInterface { // Open popup immediately to make sure popup won't be blocked by Safari await this.communicator.ready(); + if (request.method === "eth_sendTransaction") { + const params = request.params![0] as TransactionRequestEIP712; + if (params) { + /* eslint-disable @typescript-eslint/no-unused-vars */ + const { chainId: _, ...transaction } = await getTransactionWithPaymasterData( + this.chain.id, + params.from, + params, + this.paymasterHandler, + ); + request = { + method: request.method, + params: [transaction] as ExtractParams, + }; + } + } + const message = this.createRequestMessage({ action: request, chainId: this.chain.id, diff --git a/packages/sdk/src/client-auth-server/WalletProvider.ts b/packages/sdk/src/client-auth-server/WalletProvider.ts index 693bf6d7..35279ae6 100644 --- a/packages/sdk/src/client-auth-server/WalletProvider.ts +++ b/packages/sdk/src/client-auth-server/WalletProvider.ts @@ -4,6 +4,7 @@ import { toHex } from "viem"; import { PopupCommunicator } from "../communicator/PopupCommunicator.js"; import { serializeError, standardErrors } from "../errors/index.js"; +import type { CustomPaymasterHandler } from "../paymaster/index.js"; import { getFavicon, getWebsiteName } from "../utils/helpers.js"; import type { AppMetadata, @@ -22,13 +23,14 @@ export type WalletProviderConstructorOptions = { transports?: Record; session?: SessionPreferences | (() => SessionPreferences | Promise); authServerUrl?: string; + paymasterHandler?: CustomPaymasterHandler; }; export class WalletProvider extends EventEmitter implements ProviderInterface { readonly isZksyncSso = true; private signer: Signer; - constructor({ metadata, chains, transports, session, authServerUrl }: WalletProviderConstructorOptions) { + constructor({ metadata, chains, transports, session, authServerUrl, paymasterHandler }: WalletProviderConstructorOptions) { super(); const communicator = new PopupCommunicator(authServerUrl || DEFAULT_AUTH_SERVER_URL); this.signer = new Signer({ @@ -41,6 +43,7 @@ export class WalletProvider extends EventEmitter implements ProviderInterface { chains, transports, session: typeof session === "object" ? () => session : session, + paymasterHandler, }); } diff --git a/packages/sdk/src/client/passkey/client.ts b/packages/sdk/src/client/passkey/client.ts index 05c38fbc..ef06d2da 100644 --- a/packages/sdk/src/client/passkey/client.ts +++ b/packages/sdk/src/client/passkey/client.ts @@ -1,6 +1,7 @@ import { type Account, type Address, type Chain, type Client, createClient, getAddress, type Prettify, type PublicActions, publicActions, type PublicRpcSchema, type RpcSchema, type Transport, type WalletActions, walletActions, type WalletClientConfig, type WalletRpcSchema } from "viem"; import { eip712WalletActions } from "viem/zksync"; +import type { CustomPaymasterHandler } from "../../paymaster/index.js"; import { passkeyHashSignatureResponseFormat } from "../../utils/passkey.js"; import { toPasskeyAccount } from "./account.js"; import { requestPasskeyAuthentication } from "./actions/passkey.js"; @@ -63,6 +64,7 @@ type ZksyncSsoPasskeyData = { userName: string; // Basically unique user id (which is called `userName` in webauthn) userDisplayName: string; // Also option required for webauthn contracts: PasskeyRequiredContracts; + paymasterHandler?: CustomPaymasterHandler; }; export type ClientWithZksyncSsoPasskeyData< diff --git a/packages/sdk/src/client/passkey/decorators/wallet.ts b/packages/sdk/src/client/passkey/decorators/wallet.ts index 066d8243..970fc66b 100644 --- a/packages/sdk/src/client/passkey/decorators/wallet.ts +++ b/packages/sdk/src/client/passkey/decorators/wallet.ts @@ -1,7 +1,8 @@ -import { type Account, bytesToHex, type Chain, formatTransaction, type Transport, type WalletActions } from "viem"; +import { type Account, bytesToHex, type Chain, type ExactPartial, formatTransaction, type RpcTransaction, type Transport, type WalletActions } from "viem"; import { deployContract, getAddresses, getChainId, sendRawTransaction, signMessage, signTypedData, writeContract } from "viem/actions"; -import { signTransaction, type ZksyncEip712Meta } from "viem/zksync"; +import { signTransaction, type TransactionRequestEIP712, type ZksyncEip712Meta } from "viem/zksync"; +import { getTransactionWithPaymasterData } from "../../../paymaster/index.js"; import { sendEip712Transaction } from "../../session/actions/sendEip712Transaction.js"; import type { ClientWithZksyncSsoPasskeyData } from "../client.js"; @@ -33,19 +34,39 @@ export function zksyncSsoPasskeyWalletActions< delete unformattedTx.eip712Meta; } + /* eslint-disable @typescript-eslint/no-unused-vars */ + const { chainId: _, ...unformattedTxWithPaymaster } = await getTransactionWithPaymasterData( + client.chain.id, + client.account.address, + unformattedTx, + client.paymasterHandler, + ); + const formatters = client.chain?.formatters; const format = formatters?.transaction?.format || formatTransaction; const tx = { - ...format(unformattedTx), + ...format(unformattedTxWithPaymaster as ExactPartial), type: "eip712", }; return await sendEip712Transaction(client, tx); }, signMessage: (args) => signMessage(client, args), - // eslint-disable-next-line @typescript-eslint/no-explicit-any - signTransaction: (args) => signTransaction(client, args as any), + + signTransaction: async (args) => { + /* eslint-disable @typescript-eslint/no-unused-vars */ + const { chainId: _, ...unformattedTxWithPaymaster } = await getTransactionWithPaymasterData( + client.chain.id, + client.account.address, + args as TransactionRequestEIP712, + client.paymasterHandler, + ); + return signTransaction(client, { + ...args, + unformattedTxWithPaymaster, + } as any); + }, signTypedData: (args) => signTypedData(client, args), writeContract: (args) => writeContract(client, args), }; diff --git a/packages/sdk/src/client/session/actions/session.ts b/packages/sdk/src/client/session/actions/session.ts index e7929154..5f63e505 100644 --- a/packages/sdk/src/client/session/actions/session.ts +++ b/packages/sdk/src/client/session/actions/session.ts @@ -3,6 +3,7 @@ import { waitForTransactionReceipt } from "viem/actions"; import { getGeneralPaymasterInput, sendTransaction } from "viem/zksync"; import { SessionKeyModuleAbi } from "../../../abi/SessionKeyModule.js"; +import { type CustomPaymasterHandler, getTransactionWithPaymasterData } from "../../../paymaster/index.js"; import { noThrow } from "../../../utils/helpers.js"; import type { SessionConfig } from "../../../utils/session.js"; @@ -16,6 +17,7 @@ export type CreateSessionArgs = { paymasterInput?: Hex; }; onTransactionSent?: (hash: Hash) => void; + paymasterHandler?: CustomPaymasterHandler; }; export type CreateSessionReturnType = { transactionReceipt: TransactionReceipt; @@ -41,7 +43,14 @@ export const createSession = async < // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; - const transactionHash = await sendTransaction(client, sendTransactionArgs); + const transactionWithPaymasterData: any = await getTransactionWithPaymasterData( + client.chain.id, + client.account.address, + sendTransactionArgs, + args.paymasterHandler, + ); + + const transactionHash = await sendTransaction(client, transactionWithPaymasterData); if (args.onTransactionSent) { noThrow(() => args.onTransactionSent?.(transactionHash)); } @@ -64,6 +73,7 @@ export type RevokeSessionArgs = { paymasterInput?: Hex; }; onTransactionSent?: (hash: Hash) => void; + paymasterHandler?: CustomPaymasterHandler; }; export type RevokeSessionReturnType = { transactionReceipt: TransactionReceipt; @@ -89,7 +99,15 @@ export const revokeSession = async < // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; - const transactionHash = await sendTransaction(client, sendTransactionArgs); + const transactionWithPaymasterData: any = await getTransactionWithPaymasterData( + client.chain.id, + client.account.address, + sendTransactionArgs, + args.paymasterHandler, + ); + + const transactionHash = await sendTransaction(client, transactionWithPaymasterData); + if (args.onTransactionSent) { noThrow(() => args.onTransactionSent?.(transactionHash)); } diff --git a/packages/sdk/src/client/session/client.ts b/packages/sdk/src/client/session/client.ts index 1aa76162..6a1fa324 100644 --- a/packages/sdk/src/client/session/client.ts +++ b/packages/sdk/src/client/session/client.ts @@ -2,6 +2,7 @@ import { type Account, type Address, type Chain, type Client, createClient, crea import { privateKeyToAccount } from "viem/accounts"; import { zksyncInMemoryNode } from "viem/chains"; +import type { CustomPaymasterHandler } from "../../paymaster/index.js"; import { encodeSessionTx } from "../../utils/encoding.js"; import type { SessionConfig } from "../../utils/session.js"; import { toSessionAccount } from "./account.js"; @@ -88,6 +89,7 @@ export function createZksyncSessionClient< sessionKey: parameters.sessionKey, sessionConfig: parameters.sessionConfig, contracts: parameters.contracts, + paymasterHandler: parameters.paymasterHandler, })) .extend(publicActions) .extend(publicActionsRewrite) @@ -102,6 +104,7 @@ type ZksyncSsoSessionData = { sessionKey: Hash; sessionConfig: SessionConfig; contracts: SessionRequiredContracts; + paymasterHandler?: CustomPaymasterHandler; }; export type ClientWithZksyncSsoSessionData< @@ -139,4 +142,5 @@ export interface ZksyncSsoSessionClientConfig< contracts: SessionRequiredContracts; key?: string; name?: string; + paymasterHandler?: CustomPaymasterHandler; } diff --git a/packages/sdk/src/client/session/decorators/wallet.ts b/packages/sdk/src/client/session/decorators/wallet.ts index 4ff85980..ccea7d99 100644 --- a/packages/sdk/src/client/session/decorators/wallet.ts +++ b/packages/sdk/src/client/session/decorators/wallet.ts @@ -1,7 +1,14 @@ -import { type Account, bytesToHex, type Chain, formatTransaction, type Transport, type WalletActions } from "viem"; -import { deployContract, getAddresses, getChainId, sendRawTransaction, signMessage, signTypedData, writeContract } from "viem/actions"; -import { signTransaction, type ZksyncEip712Meta } from "viem/zksync"; - +import { + type Account, bytesToHex, + type Chain, type ExactPartial, formatTransaction, type RpcTransaction, + type Transport, type WalletActions } from "viem"; +import { + deployContract, getAddresses, getChainId, sendRawTransaction, + signMessage, signTypedData, writeContract, +} from "viem/actions"; +import { signTransaction, type TransactionRequestEIP712, type ZksyncEip712Meta } from "viem/zksync"; + +import { getTransactionWithPaymasterData } from "../../../paymaster/index.js"; import { sendEip712Transaction } from "../actions/sendEip712Transaction.js"; import type { ClientWithZksyncSsoSessionData } from "../client.js"; @@ -33,19 +40,38 @@ export function zksyncSsoWalletActions< delete unformattedTx.eip712Meta; } + /* eslint-disable @typescript-eslint/no-unused-vars */ + const { chainId: _, ...unformattedTxWithPaymaster } = await getTransactionWithPaymasterData( + client.chain.id, + client.account.address, + unformattedTx, + client.paymasterHandler, + ); + const formatters = client.chain?.formatters; const format = formatters?.transaction?.format || formatTransaction; const tx = { - ...format(unformattedTx), + ...format(unformattedTxWithPaymaster as ExactPartial), type: "eip712", }; return await sendEip712Transaction(client, tx); }, signMessage: (args) => signMessage(client, args), - // eslint-disable-next-line @typescript-eslint/no-explicit-any - signTransaction: (args) => signTransaction(client, args as any), + + signTransaction: async (args) => { + const { chainId: _, ...unformattedTxWithPaymaster } = await getTransactionWithPaymasterData( + client.chain.id, + client.account.address, + args as TransactionRequestEIP712, + client.paymasterHandler, + ); + return signTransaction(client, { + ...args, + unformattedTxWithPaymaster, + } as any); + }, signTypedData: (args) => signTypedData(client, args), writeContract: (args) => writeContract(client, args), }; diff --git a/packages/sdk/src/connector/index.ts b/packages/sdk/src/connector/index.ts index 3167c4bf..1bf05254 100644 --- a/packages/sdk/src/connector/index.ts +++ b/packages/sdk/src/connector/index.ts @@ -19,12 +19,14 @@ import { import type { ZksyncSsoSessionClient } from "../client/index.js"; import { EthereumProviderError } from "../errors/errors.js"; import { type AppMetadata, type ProviderInterface, type SessionPreferences, WalletProvider } from "../index.js"; +import type { CustomPaymasterHandler } from "../paymaster/index.js"; export { callPolicy } from "../client-auth-server/index.js"; export type ZksyncSsoConnectorOptions = { metadata?: Partial; session?: SessionPreferences | (() => SessionPreferences | Promise); authServerUrl?: string; + paymasterHandler?: CustomPaymasterHandler; }; export const zksyncSsoConnector = (parameters: ZksyncSsoConnectorOptions) => { @@ -140,6 +142,7 @@ export const zksyncSsoConnector = (parameters: ZksyncSsoConnectorOptions) => { session: parameters.session, transports: config.transports, chains: config.chains, + paymasterHandler: parameters.paymasterHandler, }); } return walletProvider; diff --git a/packages/sdk/src/paymaster/handlers/general.ts b/packages/sdk/src/paymaster/handlers/general.ts new file mode 100644 index 00000000..96163f29 --- /dev/null +++ b/packages/sdk/src/paymaster/handlers/general.ts @@ -0,0 +1,14 @@ +import type { Address } from "viem"; +import { getGeneralPaymasterInput } from "viem/zksync"; + +import type { CustomPaymasterHandler, CustomPaymasterHandlerResponse, CustomPaymasterParameters } from "../index.js"; + +export function createGeneralPaymaster(paymaster: Address): CustomPaymasterHandler { + /* eslint-disable @typescript-eslint/no-unused-vars */ + return async (_: CustomPaymasterParameters): CustomPaymasterHandlerResponse => { + return { + paymaster, + paymasterInput: getGeneralPaymasterInput({ innerInput: "0x" }), + }; + }; +} diff --git a/packages/sdk/src/paymaster/handlers/index.ts b/packages/sdk/src/paymaster/handlers/index.ts new file mode 100644 index 00000000..cc7e4dd1 --- /dev/null +++ b/packages/sdk/src/paymaster/handlers/index.ts @@ -0,0 +1,2 @@ +export * from "./general.js"; +export * from "./zyfi.js"; diff --git a/packages/sdk/src/paymaster/handlers/zyfi.ts b/packages/sdk/src/paymaster/handlers/zyfi.ts new file mode 100644 index 00000000..f0e277e6 --- /dev/null +++ b/packages/sdk/src/paymaster/handlers/zyfi.ts @@ -0,0 +1,108 @@ +import type { Address, Hex } from "viem"; + +import type { CustomPaymasterHandler, CustomPaymasterHandlerResponse, CustomPaymasterParameters } from "../index.js"; + +const ZYFI_ENDPOINT = "https://api.zyfi.org/api/"; +const ERC20_PAYMASTER = `${ZYFI_ENDPOINT}erc20_paymaster/v1`; +const SPONSORED_PAYMASTER = `${ZYFI_ENDPOINT}erc20_sponsored_paymaster/v1`; + +export interface ZyfiPaymasterParams { + /** Your API key. Get it from Dashboard on https://www.zyfi.org/ */ + apiKey: string; + /** The address of the token to be used for fee payment */ + feeTokenAddress?: Address; + /** Whether to check for NFT ownership for fee payment */ + checkNFT?: boolean; + /** Whether the transaction is on a testnet */ + isTestnet?: boolean; + /** The ratio of fees to be sponsored by the paymaster (0-100) */ + sponsorshipRatio?: number; + /** determines the user nonces interval for which the response will be valid (current nonce + replayLimit). */ + replayLimit?: number; +} + +export function createZyfiPaymaster(params: ZyfiPaymasterParams): CustomPaymasterHandler { + if (!params.apiKey) throw new Error("ZyFi: Provide API KEY"); + if ( + params.sponsorshipRatio !== undefined + && (params.sponsorshipRatio > 100 + || params.sponsorshipRatio < 0) + ) throw new Error("ZyFi: Sponsorship ratio must be between 0-100"); + + return async function zyfiPaymaster(args: CustomPaymasterParameters): CustomPaymasterHandlerResponse { + const url = params.sponsorshipRatio ? SPONSORED_PAYMASTER : ERC20_PAYMASTER; + const payload = { + replayLimit: params.replayLimit, + sponsorshipRatio: params.sponsorshipRatio, + chainId: args.chainId, + checkNFT: params.checkNFT, + feeTokenAddress: params.feeTokenAddress, + isTestnet: params.isTestnet, + gasLimit: args.gas || undefined, + txData: { + from: args.from, + to: args.to, + data: args.data ?? "0x", + value: args.value, + }, + }; + const response: ApiResponse = await fetch( + url, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-API-Key": params.apiKey, + }, + body: stringify(payload), + }, + ).then((response) => { + if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); + return response.json(); + }); + + const { paymasterParams, gasPerPubdata } = response.txData.customData; + return { + paymaster: paymasterParams.paymaster, + paymasterInput: paymasterParams.paymasterInput, + maxFeePerGas: BigInt(response.txData.maxFeePerGas), + gas: BigInt(response.txData.gasLimit), + maxPriorityFeePerGas: BigInt(response.txData.maxPriorityFeePerGas ?? 0), + gasPerPubdata: gasPerPubdata ? BigInt(gasPerPubdata) : undefined, + }; + }; +} + +type ApiResponse = { + txData: { + customData: { + paymasterParams: { + paymaster: Address; + paymasterInput: Hex; + }; + gasPerPubdata?: number; + }; + maxFeePerGas: string; + maxPriorityFeePerGas?: string; + gasLimit: number; + }; + gasLimit: string; + gasPrice: string; + tokenAddress: Address; + tokenPrice: string; + feeTokenAmount: string; + feeTokendecimals: string; + feeUSD: string; + expirationTime: string; + expiresIn: string; + paymasterAddress: Address; + messageHash: string; + maxNonce?: string; + protocolAddress?: Address; + sponsorshipRatio?: string; + warnings?: string[]; +}; + +function stringify(payload: any) { + return JSON.stringify(payload, (_, v) => typeof v === "bigint" ? v.toString() : v); +} diff --git a/packages/sdk/src/paymaster/index.ts b/packages/sdk/src/paymaster/index.ts new file mode 100644 index 00000000..f778d691 --- /dev/null +++ b/packages/sdk/src/paymaster/index.ts @@ -0,0 +1,76 @@ +import type { Address, Hex, UnionRequiredBy } from "viem"; +import type { TransactionRequestEIP712 } from "viem/chains"; + +export interface CustomPaymasterParameters { + nonce: number; + from: Address; + to: Address; + gas: bigint; + gasPrice: bigint; + gasPerPubdata: bigint; + value: bigint; + data: Hex | undefined; + maxFeePerGas: bigint; + maxPriorityFeePerGas: bigint; + chainId: number; +} + +export type CustomPaymasterHandlerResponse = Promise<{ + paymaster: Address; + paymasterInput: Hex; + maxFeePerGas?: bigint; + maxPriorityFeePerGas?: bigint; + gasPerPubdata?: bigint; + gas?: bigint; +}>; + +export type CustomPaymasterHandler = ( + args: CustomPaymasterParameters, +) => CustomPaymasterHandlerResponse; + +export async function getTransactionWithPaymasterData( + chainId: number, + fromAccount: Address, + transaction: TransactionRequestEIP712, + customPaymasterHandler: CustomPaymasterHandler | undefined = undefined, +): Promise< + UnionRequiredBy & { chainId: number } + > { + if ( + customPaymasterHandler + && !transaction.paymaster + && !transaction.paymasterInput + ) { + const paymasterResult = await customPaymasterHandler({ + chainId, + from: fromAccount, + data: transaction.data, + gas: transaction.gas ?? 0n, + gasPrice: transaction.gasPrice ?? 0n, + gasPerPubdata: transaction.gasPerPubdata ?? 0n, + maxFeePerGas: transaction.maxFeePerGas ?? 0n, + maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ?? 0n, + nonce: transaction.nonce ?? 0, + to: transaction.to ?? "0x0", + value: transaction.value ?? 0n, + }); + return { + ...transaction, + paymaster: paymasterResult.paymaster, + paymasterInput: paymasterResult.paymasterInput, + gas: paymasterResult.gas ?? transaction.gas, + maxFeePerGas: paymasterResult.maxFeePerGas ?? transaction.maxFeePerGas, + maxPriorityFeePerGas: paymasterResult.maxPriorityFeePerGas ?? transaction.maxPriorityFeePerGas, + gasPerPubdata: paymasterResult.gasPerPubdata ?? transaction.gasPerPubdata, + from: fromAccount, + chainId, + }; + } + return { + ...transaction, + from: fromAccount, + chainId, + }; +} + +export * from "./handlers/index.js";