The RPC
task is the main interface into the Rundler. It consists of 4 namespaces:
Each of which can be enabled/disabled via configuration.
It also supports a health check endpoint.
Methods defined by the ERC-4337 spec.
Method | Supported |
---|---|
eth_chainId |
✅ |
eth_supportedEntryPoints |
✅ |
eth_estimateUserOperationGas |
✅ |
eth_sendUserOperation |
✅ |
eth_getUserOperationByHash |
✅ |
eth_getUserOperationReceipt |
✅ |
Method defined by the ERC-4337 spec. Used only for debugging/testing and should be disabled on production APIs.
Method | Supported | Non-Standard |
---|---|---|
debug_bundler_clearState |
✅ | |
debug_bundler_dumpMempool |
✅ | |
debug_bundler_sendBundleNow |
✅ | |
debug_bundler_setBundlingMode |
✅ | |
debug_bundler_setReputation |
✅ | |
debug_bundler_dumpReputation |
✅ | |
debug_bundler_addUserOps |
🚧 | |
debug_bundler_getStakeStatus |
✅ | ✅ |
debug_bundler_clearMempool |
✅ | ✅ |
debug_bundler_dumpPaymasterBalances |
✅ | ✅ |
This method is used by the ERC-4337 bundler-spec-tests
but is not (yet) part of the standard.
This method gets the stake status of a certain address with a particular entry point contract.
- Address to get stake status for
- Entry point address
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_clearMempool",
"params": ["0x...", "0x..."] // address, entry point address
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
isStaked: bool,
stakeInfo: {
addr: address,
stake: uint128,
unstakeDelaySec: uint32
}
}
]
}
This method is used by the ERC-4337 bundler-spec-tests
but is not (yet) part of the standard.
This method triggers a the mempool to drop all pending user operations, but keeps the rest of its state. In contrast to debug_bundler_clearState
which drops all state.
- Entry point address
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_clearMempool",
"params": ["0x...."] // entry point address
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
Dump the paymaster balances from the paymaster tracker in the mempool for a given entry point.
- Entry point address
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "debug_bundler_clearMempool",
"params": ["0x...."] // entry point address
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
address: address // paymaster address
pendingBalance: uint256 // paymaster balance including pending UOs in pool
confirmedBalance: uint256 // paymaster confirmed balance onchain
},
{ ... }, ...
]
}
Rundler specific methods that are not specified by the ERC-4337 spec. This namespace may be opened publicly.
Method | Supported |
---|---|
rundler_maxPriorityFeePerGas |
✅ |
rundler_dropLocalUserOperation |
✅ |
This method returns the minimum maxPriorityFeePerGas
that the bundler will accept at the current block height. This is based on the fees of the network as well as the priority fee mode configuration of the bundle builder.
Users of this method should typically increase their priority fee values by a buffer value in order to handle price fluctuations.
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "rundler_maxPriorityFeePerGas",
"params": []
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": ["0x..."] // uint256
}
Drops a user operation from the local mempool for the given sender/nonce. The user must send a signed UO that passes validation and matches the requirements below.
NOTE: there is no guarantee that this method effectively cancels a user operation. If the user operation has been bundled prior to the drop attempt it may still be mined. If the user operation has been sent to the P2P network it may be mined by another bundler after being dropped locally.
Requirements:
sender
andnonce
match the UO that is being dropped.preVerificationGas
,callGasLimit
,maxFeePerGas
must all be 0.- This is to ensure this UO is not viable onchain.
callData
must be0x
.- This is to ensure this UO is not viable onchain.
- If an
initCode
was used on the UO to be dropped, the request must also supply that sameinitCode
, else0x
,- This is required for signature verification.
verificationGasLimit
must be high enough to run the account verification step.signature
must be valid on a UO with the above requirements.- User operation must be in the pool for at least N blocks before it is dropped. N is configurable via a CLI setting.
- This is to ensure that the bundler has had sufficient time to attempt to bundle the UO and get compensated for its initial simulation. This prevents DOS attacks.
Notes:
paymasterAndData
is not required to be0x
, but there is little use for it here, its recommended to set to0x
.verificationGasLimit
doesn't require estimation, just set to a high number that is lower than the bundler's max verification gas, i.e. 1M.
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "rundler_dropLocalUserOperation",
"params": [
{
... // UO with the requirements above
},
"0x..." // entry point address
]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": ["0x..."] // hash of UO if dropped, or empty if a UO is not found for the sender/ID
}
Administration methods specific to Rundler. This namespace should not be open to the public.
Method |
---|
admin_clearState |
admin_setTracking |
Clears the state of various Rundler components associated with an entry point address.
- Entry point address
- Admin clear state object
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "admin_clearState",
"params": [
"0x....", // entry point address
{
clearMempool: bool, // optional, clears the UOs from the pool
clearPaymaster: bool, // optional, clears the paymaster balances
clearReputation: bool // optional, clears the reputation manager
}
]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
Turns various mempool features on/off.
- Entry point address
- Admin set tracking object
# Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "admin_clearState",
"params": [
"0x....", // entry point address
{
paymasterTracking: bool, // required, enables paymaster balance tracking/enforcement
reputationTracking: bool, // required, enables reputation tracking/enforcement
}
]
}
# Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "ok"
}
The health check endpoint can be used by infrastructure to ensure that Rundler is up and running.
Currently, it simply queries each the Pool
and the Builder
servers to check if they are responding to requests. If yes, Rundler is healthy, else unhealthy.
Route | Supported |
---|---|
/health |
✅ |
Status | Code | Message |
---|---|---|
Healthy | 200 | ok |
Unhealthy | 500 | JSON-RPC formatted error message |
To serve eth_estimateUserOperationGas
Rundler attempts to estimate gas as accurately as possible, while always erroring to over-estimation.
preVerificationGas
(PVG) is meant to capture any gas that cannot be metred by the entry point during execution. Rundler splits PVG into two separate calculations, static and dynamic.
To run these calculations Rundler currently assumes a bundle size of 1.
The static portion of PVG accounts for:
- Calldata costs associated with the UO.
- The UOs portion of shared entry point gas usage.
This calculation is static as the result should never change for a given UO.
The dynamic portion of PVG is meant to capture any portion that may change based on network conditions. Currently, its only use is to capture the data availability calldata costs on L2 networks that post their data to a separate network.
For example, on Arbitrum One transactions are charged extra gas at the very beginning of transaction processing to pay for L1 Ethereum calldata costs. This value can be estimated by calling a precompiled contract on any Arbitrum One node. This value will change based on the current L1 gas fees as well as the current L2 gas fees. Rundler will estimate this value for a bundle of size 1 and set it to the dynamic portion of pvg.
NOTE: Since the dynamic portion of PVG can change, users on networks that contain dynamic PVG should add a buffer to their PVG estimates in order to ensure that their UOs will be mined when price fluctuates.
To estimate verificationGasLimit
Rundler uses binary search to find the minimum gas value where verification succeeds. The procedure follows:
- Run an initial attempt at max limit using the gas measurement helper contract. If verification fails here it will never succeed and the UO is rejected.
- Set the initial guess to the gas used in the initial attempt * 2 to account for the 63/64ths rule.
- Run the binary search algorithm until the minimum successful gas value and the maximum failure gas value are within 10%.
This approach allows for minimal eth_call
requests while providing an accurate gas limit.
During ERC-4337 verification a transfer of an asset to pay for gas always occurs. For example:
- When there is no paymaster and the sender's deposit is less than the maximum gas cost, the sender must transfer ETH to the entrypoint.
- When an ERC-20 paymaster is used, there is typically an ERC-20 token transfer from the sender to the paymaster and then the paymaster transfers ETH to the entry point.
We split this into two cases for estimation: no paymaster, and paymaster.
When no paymaster is used, verification gas is always estimated using zero fees. The cost of a native transfer is added to the result of the binary search to account for the transfer of funds from the account to the entry point.
Note: This may overestimate the verification gas by the cost of a native transfer in the case where the account has enough deposited on the entry point to cover the full prefund cost. This will not impact the onchain cost of the operation.
Paymasters may perform more complicated logic on the fee fields, including triggering ERC-20 transfers, that must be accounted for during estimation. Unlike the no paymaster case, this gas cost cannot be known beforehand as it varies by paymaster implementation.
To correctly estimate the verification gas, a non-zero gas fee must be used. This fee must be:
- Large enough that it triggers a transfer of tokens.
- I.e. USDC only uses 6 decimals, if the gas fee in USDC is < 1e-6 the transfer won't trigger. Its reasonable to assume that users will have a few USD cents worth of their fee token to avoid this case.
- Small enough that a fee-payer with a small amount of the fee token can pay for the maximum gas.
During estimation the gas cost is kept constant by varying the maxFeePerGas
based on the current binary search guess. Therefore, as long as the fee-payer can pay for the gas cost initially, Rundler should be able to successfully estimate gas.
This value can be controlled by the VERIFICATION_ESTIMATION_GAS_FEE
configuration variable. A default value of 10K gwei is provided.
Paymasters should ensure that they have at least this value available in order for estimation to succeed. If the paymaster is causing token transfers from the account (ERC-20 paymaster case), they'll need to handle when the account doesn't have enough tokens. Three possible ways to do this:
- The paymaster can absorb the balance error, and write their contract in such a way that it will estimate the correct amount of gas even when the transfer fails. If the transfer fails the paymaster can return the signature invalid code.
- Use state overrides to ensure that the account has the full gas fee. See below.
- Use hardcoded values for paymaster gas. The paymaster provider can decide beforehand a maximum gas limit. The client can estimate gas without a paymaster, and then account for this hardcoded paymaster gas limit.
- In entry point v0.6 the client should set
verificationGasLimit
to the maximum of the account verification gas limit estimation and the paymaster hardcoded value. - In entry point v0.7 the client can directly set the
paymasterVerificationGasLimit
and use the estimation only for theverificationGasLimit
.
- In entry point v0.6 the client should set
callGasLimit
estimation is similar to verificationGasLimit
estimation in that it also uses a binary search. The majority of the binary search, however, is performed in Solidity to limit network calls. Call gas is always estimated with zero gas fees.
This scheme requires the use of a spoofed entry point contract via eth_call
state overrides. The original entry point contract is moved and a proxy is loaded in its place. This allows us to write additional logic to support gas estimation into the entry point contract.
More information on gas estimation can be found here.
The eth_estimateUserOperationGas
accepts an optional state override set as the 3rd positional RPC parameter. It accepts the same format as Geth's eth_call
state overrides.
This parameter can be used to modify the state of the chain before preforming gas estimation.
A typical use case for this could be to spoof some funds into a user's account while using an ERC-20 paymaster. Callers can override the balance (ETH, ERC20, or any arbitrary payment method) such that the fee-payer can pay the verification_estimation_gas_fee
.
Fee estimation is done by applying the configured priority fee mode to the estimated network fees.