Introduction
Why is a bundler needed? What is it exactly doing to a UserOperation? We continue our EIP-4337 journey. This time by clearing out what a UserOperation typically goes through in a bundler.
After publishing the previous post detailing UserOperation CallData, a few folks reached out asking Exactly why is a BUNDLER needed if I can just relay the UserOp to the entrypoint from an EOA.
Let's break down the checks a bundler performs upon receiving a UserOp through its RPC URL.
Would like to thank the Ethereum Foundation and ERC4337 community for their support. JiffyScan and these articles wouldn't have existed without their aid.
Overview
The job of a bundler is to accept signed calldata representing a UserOperation and submit it to the chain (triggering  entrypoint.handleOps()), potentially along with other independent UserOperations.
We break down this process in this post into 2 phases:
- Pre-Bundling Phase: Validating a UserOperation before adding it to the pool of UserOperations ready to create a bundle
- Bundling Phase: Submitting a subset from the UserOperations pending to be added to the chain
Note: We've used Eth-infinitism's bundler as a reference for this post.
Pre-Bundling Phase
When a UserOperation is received by the bundler's RPC endpoint, it runs a few checks before adding it to the set of valid UserOperations to be ready to be submitted to the chain. The checks are carried out in the following stages:
Validate Input Parameters
Bundler checks for the presence & validity of all the fields of a UserOp at an individual level. These are as follows:
- The entrypoint parameter in the RPC call is not null and is supported by the bundler
- UserOperation is not null and all the fields have hexadecimal values:- Sender
- nonce
- initCode
- callData
- paymasterAndData
- signature (if required)
 
- UserOperations has all the gas parameters and the values are valid hexadecimal values:- preVerificationGas
- verificationGasLimit
- callGasLimit
- maxFeePerGas
- maxPriorityFeePerGas
 
- The paymasterAndData field is either 0xor the length is greater than or equal to42(to store at least an address)
- The initCode field is either 0xor the length is greater than or equal to42(to store at least an address)
- Ensure preVerificationGasis the minimum required by the bundler to process the request.
You may refer to the code to validate input parameters here. For some reason, steps 1-3 are performed once before redundantly here in the v1.6 of the Eth-infinitism's bundler implementation.
Simulate UserOp and Validate the trace
The bundler next checks the changes the operation would've on the state of the blockchain and that it meets the restrictions suggested by the standard.
This is achieved by using debug_tracecall offered by certain node providers, the dominant being by geth. It allows you to simulate a transaction on the latest state of the blockchain and collect any information related to addresses, opcodes involved, memory accessed, value transferred, etc. that one is interested in. 
A tracer is a javascript program passed in the debug_tracecall API call specifying the information you want to collect and receive in the response. You can see the script used in the current implementation here.
The steps in this stage are as follows:
- Simulate the UserOp and generate the validation result and trace output:- entrypoint's simulateValidation()method is invoked for this.
- Any return value apart from REVERTis invalid.
- Additional logic checks whether the data returned is a genuine result or an error and handles it accordingly
 
- entrypoint's 
- Parse Trace Result to ensure no security compromises are made and the bundler can not be cheated out of being reimbursed for gas:- There's at least one call from the entrypoint
- No illegal calls are made to the entrypoint from an external contract
- A CALLis not made without specifying a value to an external contract
- A banned opcode is not used
- There's only one CREATE2call from the factory address
- No entity apart from Factory uses a CREATE2opcode
- An unstaked entity is not accessing forbidden storage slots of external contracts/accounts
- All the referenced contracts have code deployed unless it's the sender of the UserOp
 
- Perform validity of additional meta parameters:- Both UserOp and Paymaster Signature are valid
- validAfteris in the past
- validUntilis either- nullor in the future
- the validUntilis sufficiently in the future to not expire while being added to the chain
 
These complete the bulk of the checks needed to accept a UserOp.
Perform Mempool level checks
After initial validation, the bundler proceeds to add UserOperation to the valid pool which can be submitted to the chain next time it's ready to do so.
The checks performed at this stage depend on whether a previous UserOperation with the same nonce and sender exists already or not:
- Found a pending UserOp from the same senderwith the samenoncevalue:- It's a straightforward check that the new operation gives sufficient incentive to replace the previous UserOp. In the reference implementation, the old UserOp is replaced if the maxPriorityFeePerGas&maxFeePerGasvalues are 1.1 times more in the new UserOp.
 
- It's a straightforward check that the new operation gives sufficient incentive to replace the previous UserOp. In the reference implementation, the old UserOp is replaced if the 
- No Existing UserOp with the same sender&noncevalue found:- The reputation Status of the account, paymaster, factory & aggregator are checked first.
- The entities shouldn't be banned, throttled, or exceed the maximum allowed UserOps from an unstaked entity.
- The senderaddress shouldn't be present as thefactoryorpaymasterfor another UserOp in the Mempool
- The factoryorpaymasteraddresses shouldn't be present assenderfor another UserOp in the Mempool
 
Bundling Phase
Depending on the bundler, certain conditions will trigger the bundler to package the pending UserOps from the pool in a bundle and add them to the chain. The trigger condition could be as simple as submitting every UserOp to the chain the moment it is added to the mempool to wait for a certain period or cumulative gasFee reward from UserOps.
Due to the delay, UserOps could become invalid, thus being dropped or never being added to a bundle.
In this section, we break down what happens when a bundler decides to create a new bundle from the pool of pending UserOps.
Create Bundle Checks
The process to select UserOperations into the next bundle is as follows:
- Sort the pending UserOps in decreasing order of incentive. In the reference implementation, UserOperations are sorted based on the maxPriorityFeePerGasvalue.
- Each UserOperation in the sorted list is iterated over. While iterating, the following checks are made:- If the paymasterorfactoryis banned, the UserOperation is dropped from the mempool
- If the paymasterorfactoryhas been throttled to limit the number of UserOperations from them, the UserOperation is skipped for the current bundle
- If there's already a UserOperation from the same senderadded to the bundle in the previous iterations, the UserOperation is skipped for the current bundle.
- The UserOperation is again validated by simulating it. If the simulation fails now, the UserOperation is dropped from the pool
- If the UserOperation accesses the storage of a senderfrom the UserOperations already included from previous iterations, it is skipped
- If the cumulative gas from all the UserOps accepted so far is less than the maximum Gas the bundle can have, skips the current UserOperation and stops iterating over the remaining ones.
- Skips the UserOperation if the paymasterbalance is not sufficient to sponsor all the UserOperations if the current is also added to the bundle
 
- If the 
The UserOps selected after the iteration process ends are added to a bundle and sent as a transaction to the entrypoint to be added to the chain and later removed from the mempool.
What's Next
Try running a bundler yourself. You can try the Eth-Infinitism Bundler to get started.
Remember you can use the JiffyScan interface to share your UserOps with your friends and community.
Also, if you need real-time data on 4337, do check out our leading API.
We will be releasing more deep dives, walkthroughs, and quickstart tutorials for 4337 regularly in the coming weeks. Follow me on Twitter or JiffyScan to stay updated.
