diff --git a/src/gasless-provider.ts b/src/gasless-provider.ts index 171c425..3f22359 100644 --- a/src/gasless-provider.ts +++ b/src/gasless-provider.ts @@ -9,6 +9,8 @@ import { UserOperation } from 'permissionless/types'; import { getSenderAddress, signUserOperationHashWithECDSA } from 'permissionless'; import * as constants from '../src/constants'; import { BasePaymaster } from './paymasters'; +import { PartialBy } from 'viem/types/utils'; +import { SponsorUserOperationReturnType } from 'permissionless/actions/pimlico'; const log = init('hardhat:plugin:gasless'); @@ -125,7 +127,10 @@ export class GaslessProvider extends ProviderWrapper { }); // Construct UserOperation - const userOperation = { + const userOperation: PartialBy< + UserOperation, + 'callGasLimit' | 'preVerificationGas' | 'verificationGasLimit' | 'paymasterAndData' + > = { sender: this.senderAddress, nonce: this._nonce, initCode: this._nonce === 0n ? this._initCode : '0x', @@ -140,9 +145,22 @@ export class GaslessProvider extends ProviderWrapper { verificationGasLimit: 0n, // dummy value }; - // REQUEST PIMLICO VERIFYING PAYMASTER SPONSORSHIP - const sponsorUserOperationResult = await this.paymasterClient.sponsorUserOperation(userOperation, this._entryPoint); - const sponsoredUserOperation: UserOperation = Object.assign(userOperation, sponsorUserOperationResult); + const paymasterAndData: `0x${string}` | SponsorUserOperationReturnType = + await this.paymasterClient.sponsorUserOperation(userOperation, this._entryPoint); + + let sponsoredUserOperation: UserOperation; + + if (typeof paymasterAndData === 'string') { + // If our paymaster only returns its paymasterAndData and not the gas parameters, we need to estimate them ourselves + const gasConfig = await this.bundlerClient.estimateUserOperationGas({ + userOperation: Object.assign(userOperation, { paymasterAndData: paymasterAndData }), + entryPoint: this._entryPoint, + }); + + sponsoredUserOperation = Object.assign(userOperation, gasConfig, { paymasterAndData: paymasterAndData }); + } else { + sponsoredUserOperation = Object.assign(userOperation, paymasterAndData); + } // SIGN THE USER OPERATION const signature = await signUserOperationHashWithECDSA({ diff --git a/src/paymasters/BasePaymaster.ts b/src/paymasters/BasePaymaster.ts index e8a31aa..32e7b9b 100644 --- a/src/paymasters/BasePaymaster.ts +++ b/src/paymasters/BasePaymaster.ts @@ -1,3 +1,4 @@ +import { SponsorUserOperationReturnType } from 'permissionless/actions/pimlico'; import { PartialUserOperation } from '../types'; export class BasePaymaster { @@ -7,8 +8,12 @@ export class BasePaymaster { this.endpoint = endpoint; } - // eslint-disable-next-line - public async sponsorUserOperation(userOp: PartialUserOperation, entryPoint: `0x${string}`): Promise { + // eslint-disable + public async sponsorUserOperation( + userOp: PartialUserOperation, + entryPoint: `0x${string}`, + ): Promise<`0x${string}` | SponsorUserOperationReturnType> { throw new Error('This is a base class and should not be called directly.'); } + // eslint-enable } diff --git a/src/paymasters/PimlicoPaymaster.ts b/src/paymasters/PimlicoPaymaster.ts index 6f15b2d..d6115c1 100644 --- a/src/paymasters/PimlicoPaymaster.ts +++ b/src/paymasters/PimlicoPaymaster.ts @@ -17,7 +17,7 @@ export class PimlicoPaymaster extends BasePaymaster { public async sponsorUserOperation( userOperation: PartialUserOperation, entryPoint: `0x${string}`, - ): Promise { + ): Promise<`0x${string}` | SponsorUserOperationReturnType> { return await this.paymasterClient.sponsorUserOperation({ userOperation, entryPoint, diff --git a/src/paymasters/StackUpPaymaster.ts b/src/paymasters/StackUpPaymaster.ts index 77dd8dc..966bc11 100644 --- a/src/paymasters/StackUpPaymaster.ts +++ b/src/paymasters/StackUpPaymaster.ts @@ -18,7 +18,7 @@ export class StackUpPaymaster extends BasePaymaster { public async sponsorUserOperation( userOperation: PartialUserOperation, entryPoint: `0x${string}`, - ): Promise { + ): Promise<`0x${string}` | SponsorUserOperationReturnType> { return await this.paymasterClient.sponsorUserOperation({ userOperation, entryPoint,