@@ -13,11 +13,8 @@ import { EVM_CHAIN_CONFIG, getEvmChainConfig, isEvmBlockchainSupported } from '.
1313// Source: https://github.com/MetaMask/delegation-framework
1414const METAMASK_DELEGATOR_ADDRESS = '0x63c0c19a282a1b52b07dd5a65b58948a07dae32b' as Address ;
1515
16- // ERC-4337 EntryPoint v0.7 - canonical address on all chains
17- const ENTRY_POINT_V07 = '0x0000000071727De22E5E9d8BAf0edAc6f37da032' as Address ;
18-
19- // EIP-7702 factory marker - signals to bundler that this is an EIP-7702 UserOperation
20- const EIP7702_FACTORY = '0x0000000000000000000000000000000000007702' as Address ;
16+ // ERC-4337 EntryPoint v0.8 - required for EIP-7702 support
17+ const ENTRY_POINT_V08 = '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108' as Address ;
2118
2219// MetaMask Delegator ABI - ERC-7821 BatchExecutor interface
2320const DELEGATOR_ABI = parseAbi ( [ 'function execute((bytes32 mode, bytes executionData) execution) external payable' ] ) ;
@@ -40,11 +37,11 @@ export interface GaslessTransferResult {
4037 userOpHash : string ;
4138}
4239
43- interface UserOperationV07 {
40+ interface UserOperationV08 {
4441 sender : Address ;
4542 nonce : Hex ;
46- factory : Address ;
47- factoryData : Hex ;
43+ factory ? : Address | null ;
44+ factoryData ? : Hex ;
4845 callData : Hex ;
4946 callGasLimit : Hex ;
5047 verificationGasLimit : Hex ;
@@ -56,6 +53,16 @@ interface UserOperationV07 {
5653 paymasterPostOpGasLimit : Hex ;
5754 paymasterData : Hex ;
5855 signature : Hex ;
56+ // EIP-7702 authorization - separate field per ERC-7769
57+ // Pimlico expects 'contractAddress' not 'address'
58+ eip7702Auth ?: {
59+ contractAddress : Address ;
60+ chainId : Hex ;
61+ nonce : Hex ;
62+ r : Hex ;
63+ s : Hex ;
64+ yParity : Hex ;
65+ } ;
5966}
6067
6168@Injectable ( )
@@ -234,19 +241,17 @@ export class PimlicoBundlerService {
234241 // 2. Encode the execute() call for MetaMask Delegator (ERC-7821 format)
235242 const callData = this . encodeExecuteCall ( token . chainId as Address , transferData ) ;
236243
237- // 3. Encode the EIP-7702 authorization as factoryData
238- const factoryData = this . encodeAuthorizationAsFactoryData ( authorization ) ;
239-
240- // 4. Build the UserOperation
241- const userOp = await this . buildUserOperation ( userAddress as Address , callData , factoryData , pimlicoUrl ) ;
244+ // 3. Build the UserOperation with EIP-7702 authorization
245+ // Authorization is included before gas estimation for accurate estimates
246+ const userOp = await this . buildUserOperation ( userAddress as Address , callData , authorization , pimlicoUrl ) ;
242247
243- // 5 . Sponsor the UserOperation via Pimlico Paymaster
248+ // 4 . Sponsor the UserOperation via Pimlico Paymaster
244249 const sponsoredUserOp = await this . sponsorUserOperation ( userOp , pimlicoUrl ) ;
245250
246- // 6 . Submit the UserOperation via Pimlico Bundler
251+ // 5 . Submit the UserOperation via Pimlico Bundler
247252 const userOpHash = await this . sendUserOperation ( sponsoredUserOp , pimlicoUrl ) ;
248253
249- // 7 . Wait for the transaction to be mined
254+ // 6 . Wait for the transaction to be mined
250255 const txHash = await this . waitForUserOperation ( userOpHash , pimlicoUrl ) ;
251256
252257 return { txHash, userOpHash } ;
@@ -298,49 +303,25 @@ export class PimlicoBundlerService {
298303 }
299304
300305 /**
301- * Encode EIP-7702 authorization as factoryData for UserOperation
302- *
303- * When factory = 0x7702, the bundler expects factoryData to contain
304- * the signed EIP-7702 authorization that delegates the smart account
305- * implementation to the EOA.
306- */
307- private encodeAuthorizationAsFactoryData ( authorization : Eip7702Authorization ) : Hex {
308- // factoryData format for EIP-7702:
309- // abi.encodePacked(address delegatee, uint256 nonce, bytes signature)
310- // where signature = abi.encodePacked(r, s, yParity)
311- const signature = concat ( [
312- authorization . r as Hex ,
313- authorization . s as Hex ,
314- toHex ( authorization . yParity , { size : 1 } ) ,
315- ] ) ;
316-
317- return concat ( [
318- authorization . address as Hex , // delegatee (MetaMask Delegator)
319- pad ( toHex ( BigInt ( authorization . nonce ) ) , { size : 32 } ) , // nonce
320- signature , // signature (r, s, yParity)
321- ] ) ;
322- }
323-
324- /**
325- * Build UserOperation v0.7 structure
306+ * Build UserOperation v0.8 structure for EIP-7702
307+ * Note: factory is intentionally left null/undefined - Pimlico expects this for EIP-7702
326308 */
327309 private async buildUserOperation (
328310 sender : Address ,
329311 callData : Hex ,
330- factoryData : Hex ,
312+ authorization : Eip7702Authorization ,
331313 pimlicoUrl : string ,
332- ) : Promise < UserOperationV07 > {
314+ ) : Promise < UserOperationV08 > {
333315 // Get current gas prices from Pimlico
334316 const gasPrice = await this . getGasPrice ( pimlicoUrl ) ;
335317
336318 // Get sender nonce from EntryPoint
337319 const nonce = await this . getSenderNonce ( sender , pimlicoUrl ) ;
338320
339- const userOp : UserOperationV07 = {
321+ const userOp : UserOperationV08 = {
340322 sender,
341323 nonce : toHex ( nonce ) ,
342- factory : EIP7702_FACTORY ,
343- factoryData,
324+ // For EIP-7702, do NOT set factory - Pimlico expects it to be null/undefined
344325 callData,
345326 callGasLimit : toHex ( 200000n ) ,
346327 verificationGasLimit : toHex ( 500000n ) ,
@@ -352,9 +333,19 @@ export class PimlicoBundlerService {
352333 paymasterPostOpGasLimit : toHex ( 0n ) ,
353334 paymasterData : '0x' as Hex ,
354335 signature : '0x' as Hex , // Will be filled by sponsorship or left empty for EIP-7702
336+ // EIP-7702 authorization must be included BEFORE gas estimation
337+ // Pimlico expects 'contractAddress' not 'address'
338+ eip7702Auth : {
339+ contractAddress : authorization . address as Address ,
340+ chainId : toHex ( authorization . chainId ) ,
341+ nonce : toHex ( authorization . nonce ) ,
342+ r : authorization . r as Hex ,
343+ s : authorization . s as Hex ,
344+ yParity : toHex ( authorization . yParity ) ,
345+ } ,
355346 } ;
356347
357- // Estimate gas limits
348+ // Estimate gas limits (now includes eip7702Auth)
358349 const estimated = await this . estimateUserOperationGas ( userOp , pimlicoUrl ) ;
359350 userOp . callGasLimit = estimated . callGasLimit ;
360351 userOp . verificationGasLimit = estimated . verificationGasLimit ;
@@ -366,8 +357,8 @@ export class PimlicoBundlerService {
366357 /**
367358 * Sponsor UserOperation via Pimlico Paymaster
368359 */
369- private async sponsorUserOperation ( userOp : UserOperationV07 , pimlicoUrl : string ) : Promise < UserOperationV07 > {
370- const response = await this . jsonRpc ( pimlicoUrl , 'pm_sponsorUserOperation' , [ userOp , ENTRY_POINT_V07 ] ) ;
360+ private async sponsorUserOperation ( userOp : UserOperationV08 , pimlicoUrl : string ) : Promise < UserOperationV08 > {
361+ const response = await this . jsonRpc ( pimlicoUrl , 'pm_sponsorUserOperation' , [ userOp , ENTRY_POINT_V08 ] ) ;
371362
372363 return {
373364 ...userOp ,
@@ -384,8 +375,8 @@ export class PimlicoBundlerService {
384375 /**
385376 * Submit UserOperation to Pimlico Bundler
386377 */
387- private async sendUserOperation ( userOp : UserOperationV07 , pimlicoUrl : string ) : Promise < string > {
388- return this . jsonRpc ( pimlicoUrl , 'eth_sendUserOperation' , [ userOp , ENTRY_POINT_V07 ] ) ;
378+ private async sendUserOperation ( userOp : UserOperationV08 , pimlicoUrl : string ) : Promise < string > {
379+ return this . jsonRpc ( pimlicoUrl , 'eth_sendUserOperation' , [ userOp , ENTRY_POINT_V08 ] ) ;
389380 }
390381
391382 /**
@@ -435,7 +426,7 @@ export class PimlicoBundlerService {
435426 try {
436427 const response = await this . jsonRpc ( pimlicoUrl , 'eth_call' , [
437428 {
438- to : ENTRY_POINT_V07 ,
429+ to : ENTRY_POINT_V08 ,
439430 data : encodeFunctionData ( {
440431 abi : parseAbi ( [ 'function getNonce(address sender, uint192 key) view returns (uint256)' ] ) ,
441432 functionName : 'getNonce' ,
@@ -454,11 +445,11 @@ export class PimlicoBundlerService {
454445 * Estimate gas for UserOperation
455446 */
456447 private async estimateUserOperationGas (
457- userOp : UserOperationV07 ,
448+ userOp : UserOperationV08 ,
458449 pimlicoUrl : string ,
459450 ) : Promise < { callGasLimit : Hex ; verificationGasLimit : Hex ; preVerificationGas : Hex } > {
460451 try {
461- const response = await this . jsonRpc ( pimlicoUrl , 'eth_estimateUserOperationGas' , [ userOp , ENTRY_POINT_V07 ] ) ;
452+ const response = await this . jsonRpc ( pimlicoUrl , 'eth_estimateUserOperationGas' , [ userOp , ENTRY_POINT_V08 ] ) ;
462453 return {
463454 callGasLimit : response . callGasLimit ,
464455 verificationGasLimit : response . verificationGasLimit ,
0 commit comments