Appearance
Abstract 
Defines new JSON-RPC API methods which enable ERC-4337 wallets to communicate with UserOpeation mempool nodes and bundlers, matching the functionality that exists for Ethereum transactions.
Additionally, a set of debug JSON-RPC API methods is defined in order to facilitate development, testing and debugging issues with ERC-4337 implementations.
Motivation 
In ERC-4337, user transactions as defined in Ethereum are replaced with UserOperation objects, which contain all the information needed to perform the operations requested by the users.
However, existing Ethereum JSON-RPC API methods are not suited to working with UserOperation objects. In order to facilitate the operation of the alternative UserOperation mempool it is important that all implementations of the ERC-4337 protocol have a standardized set of APIs that can be used interchangeably.
Specification 
Definitions 
- bundler: a node exposing the APIs, in order to submit them to the network. A bundler collects one or more UserOperations into a bundle and submits them together to the EntryPointin a singlehandleOpscall.
RPC methods (eth namespace) 
eth_sendUserOperation 
The eth_sendUserOperation method submits a UserOperation object to the UserOperation mempool. The client MUST validate the UserOperation, and return a result accordingly.
The result SHOULD be set to the userOpHash if and only if the request passed simulation and was accepted in the client's UserOperation pool.
If the validation, simulation, or UserOperation pool inclusion fails, userOpHash SHOULD NOT be returned. Rather, the client SHOULD return the failure reason.
Parameters: 
- UserOperation a full user-operation struct.
 All fields MUST be set as hex values.
 Emptybytesblock (e.g. emptyinitCode) MUST be set to"0x"\
- factory and factoryData
 Must provide either both of these parameters, or none.
- paymaster, paymasterData, paymasterValidationGasLimit, paymasterPostOpGasLimit
 Must provide either all of these parameters, or none.
- entryPoint the EntryPointcontract address the request should be sent through.
 This MUST be one of the entry points returned by thesupportedEntryPointsRPC call.
Return value: 
- If the UserOperation is valid, the client MUST return the calculated userOpHashfor it
- in case of failure, MUST return an errorresult object, withcodeandmessage.
 The error code and message SHOULD be set as follows:- code: -32602 - invalid UserOperationstruct/fields
- code: -32500 - transaction rejected by EntryPointcontract'ssimulateValidationfunction during wallet creation or validation- The messagefield MUST be set to the emittedFailedOpevent's "AAxx" error message from theEntryPoint
 
- The 
- code: -32501 - transaction rejected by paymastercontract'svalidatePaymasterUserOpfunction- The messagefield SHOULD be set to the revert message from thepaymastercontract
- The datafield MUST contain apaymastervalue
 
- The 
- code: -32502 - transaction rejected because of ERC-7562 opcode validation rule violation
- code: -32503 - UserOperation out of time-range:
 either wallet or paymaster returned a time-range, and it has already expired or will expire soon.- The datafield SHOULD contain thevalidUntilandvalidAftervalues
- The datafield SHOULD contain apaymasteraddress if this error was triggered by thepaymastercontract
 
- The 
- code: -32504 - transaction rejected because paymasteris throttled or banned due to ERC-7562 reputation rules- The datafield SHOULD contain apaymasteraddress
 
- The 
- code: -32505 - transaction rejected because paymastercontract's ERC-7562 stake or unstake-delay is too low- The datafield SHOULD contain apaymasteraddress
- The datafield SHOULD contain aminimumStakeandminimumUnstakeDelay
 
- The 
- code: -32507 - transaction rejected because of wallet signature check failed
- code: -32508 - transaction rejected because paymaster balance can't cover all pending UserOperations.
 
- code: -32602 - invalid 
Example: 
Request:
js
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_sendUserOperation",
  "params": [
    {
      eip7702Auth, // an EIP-7702 authorization tuple
      sender, // address
      nonce, // uint256
      factory, // address
      factoryData, // bytes
      callData, // bytes
      callGasLimit, // uint256
      verificationGasLimit, // uint256
      preVerificationGas, // uint256
      maxFeePerGas, // uint256
      maxPriorityFeePerGas, // uint256
      paymaster, // address
      paymasterVerificationGasLimit, // uint256
      paymasterPostOpGasLimit, // uint256
      paymasterData, // bytes
      signature // bytes
    },
    entryPoint // address
  ]
}Response:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x123456789012345678901234567890123456789012345678901234567890abcd"
}Example failure responses: 
json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "message": "AA21 didn't pay prefund",
    "code": -32500
  }
}json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "message": "paymaster stake too low",
    "data": {
      "paymaster": "0x123456789012345678901234567890123456790",
      "minimumStake": "0xde0b6b3a7640000",
      "minimumUnstakeDelay": "0x15180"
    },
    "code": -32504
  }
}Support for EIP-7702 authorizations 
On networks with EIP-7702 activated, the UserOperation object may also contain an eip7702Auth tuple. Notice that according to EIP-7702 an eip7702Auth tuple must be provided only to perform a change of the authorization address. Once the necessary eip7702Auth tuple was stored on-chain, users are not required to provide the same eip7702Auth tuple for any consequent UserOperation.
Separately, the fields factory and factoryData have a modified behaviour when using an EIP-7702 authorized sender.
The factory field SHOULD be set to exactly the INITCODE_EIP7702_MARKER = 0x7702 flag when using an EIP-7702 authorized sender. Passing his flag instructs the EntryPoint contract to verify the sender address contains a valid EIP-7702 authorization.
When INITCODE_EIP7702_MARKER is specified, the factoryData value is passed directly to the sender contract, instead of the factory contract. This is done as a separate call before the validateUserOp is called, meaning the sender contract will be called two times during validation.
The factoryData value can be left empty. In this case, the call will not be performed.
The purpose of this factoryData call is to provide the EIP-7702 sender contract an ability to initialize its storage before accepting the UserOperation via the validateUserOp function.
eth_estimateUserOperationGas 
Estimate the gas values for a UserOperation. Given UserOperation optionally without gas limits and gas prices, return the needed gas limits. The signature field is ignored by the wallet, so that the operation will not require the user's approval. Still, it might require putting a "stub" signature value, e.g. a signature byte array of the right length. If the UserOperation contains an eip7702Auth tuple, for the purpose of estimation the signature should be ignored, and the tuple should be evaluated as if it was signed by the sender
Parameters:
- Same as eth_sendUserOperation
 All gas limits and fees parameters are optional, but are used if specified.maxFeePerGasandmaxPriorityFeePerGasdefault to zero, so no payment is required by neither account nor paymaster.
- Optionally accepts the State Override Setto allow users to modify the state during the gas estimation.
 This field as well as its behavior is equivalent to the ones defined foreth_callRPC method.
Return Values:
- preVerificationGas gas overhead of this UserOperation
- verificationGasLimit estimation of gas limit required by the validation of this UserOperation
- paymasterVerificationGasLimit estimation of gas limit required by the paymaster verification
 Returned only if theUserOperationspecifies aPaymasteraddress
- callGasLimit estimation of gas limit required by the inner account execution
Note: actual postOpGasLimit cannot be reliably estimated.
 Paymasters should provide this value to account, and require that specific value on-chain during validation.
Error Codes: 
Same as eth_sendUserOperation This operation may also return an error if either the inner call to the account contract reverts, or paymaster's postOp call reverts.
eth_getUserOperationByHash 
Return a UserOperationobject based on a userOpHash value returned by eth_sendUserOperation.
Parameters
- hash a userOpHashvalue returned byeth_sendUserOperation
Return value:
- If the - UserOperationis included in a block:- Return a full UserOperation, with the addition of entryPoint,blockNumber,blockHashandtransactionHash.
 
- Return a full UserOperation, with the addition of 
- Else if the - UserOperationis pending in the bundler's mempool:- MAY return null, or a fullUserOperation, with the addition of theentryPointfield and anullvalue forblockNumber,blockHashandtransactionHash.
 
- MAY return 
- Else: - Return null
 
- Return 
eth_getUserOperationReceipt 
Return a UserOperation receipt object based on a userOpHash value returned by eth_sendUserOperation.
Parameters
- hash a userOpHashvalue returned byeth_sendUserOperation
Return value:
null in case the UserOperation is not yet included in a block, or:
- userOpHash the request hash
- entryPoint
- sender
- nonce
- paymaster the paymaster used for this userOp (or empty)
- actualGasCost - the actual amount paid (by account or paymaster) for this UserOperation
- actualGasUsed - total gas used by this UserOperation, including pre-verification, creation, validation and execution
- success boolean - whether this execution completed without a revert
- reason - in case of reverted UserOperation, the returned revert reason byte array
- logs - the logs generated by this particular UserOperation, not including logs of otherUserOperationsin the same bundle
- receipt the TransactionReceiptobject. Note that the returnedTransactionReceiptis for the entire bundle, not only for thisUserOperation.
eth_supportedEntryPoints 
Returns an array of the EntryPoint contracts' addresses supported by the client. The first element of the array SHOULD be the EntryPoint contract addressed preferred by the client.
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_supportedEntryPoints",
  "params": []
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    "0xcd01C8aa8995A59eB7B2627E69b40e0524B5ecf8",
    "0x7A0A0d159218E6a2f407B99173A2b12A6DDfC2a6"
  ]
}eth_chainId 
Returns EIP-155 Chain ID.
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_chainId",
  "params": []
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x1"
}RPC methods (debug Namespace) 
This api must only be available in testing mode and is required by the compatibility test suite. In production, any debug_* rpc calls should be blocked.
debug_bundler_clearState 
Clears the bundler mempool and reputation data of paymasters/accounts/factories.
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_clearState",
  "params": []
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "ok"
}debug_bundler_dumpMempool 
Dumps the current UserOperation mempool
Parameters:
- EntryPoint the entrypoint used by eth_sendUserOperation
Returns:
array - Array of UserOperation objects currently in the mempool.
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_dumpMempool",
  "params": ["0x1306b01bC3e4AD202612D3843387e94737673F53"]
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
        sender, // address
        nonce, // uint256
        factory, // address
        factoryData, // bytes
        callData, // bytes
        callGasLimit, // uint256
        verificationGasLimit, // uint256
        preVerificationGas, // uint256
        maxFeePerGas, // uint256
        maxPriorityFeePerGas, // uint256
        signature // bytes
    }
  ]
}debug_bundler_sendBundleNow 
Forces the bundler to build and execute a bundle from the mempool as handleOps() transaction.
Returns: transactionHash
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_sendBundleNow",
  "params": []
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xdead9e43632ac70c46b4003434058b18db0ad809617bd29f3448d46ca9085576"
}debug_bundler_setBundlingMode 
Sets bundling mode.
After setting mode to "manual", an explicit call to debug_bundler_sendBundleNow is required to send a bundle.
parameters: 
mode - 'manual' | 'auto'
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_setBundlingMode",
  "params": ["manual"]
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "ok"
}debug_bundler_setReputation 
Sets the reputation of given addresses.
Parameters:
- An array of reputation entries to add/replace, with the fields: - address- the address to set the reputation for
- opsSeen- number of times a user operations with that entity was seen and added to the mempool
- opsIncluded- number of times user operations that use this entity was included on-chain
 
- EntryPoint the entrypoint used by - eth_sendUserOperation
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_setReputation",
  "params": [
    [
      {
        "address": "0x7A0A0d159218E6a2f407B99173A2b12A6DDfC2a6",
        "opsSeen": "0x14",
        "opsIncluded": "0x0D"
      }
    ],
    "0x1306b01bC3e4AD202612D3843387e94737673F53"
  ]
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "ok"
}debug_bundler_dumpReputation 
Returns the reputation data of all observed addresses. Returns an array of reputation objects, each with the fields described above in debug_bundler_setReputation.
Parameters:
- EntryPoint the entrypoint used by eth_sendUserOperation
Return value:
An array of reputation entries with the fields:
- address- the address to set the reputation for
- opsSeen- number of times a user operations with that entity was seen and added to the mempool
- opsIncluded- number of times user operation that use this entity was included on-chain
- status- (string) The status of the address in the bundler (- 'ok'|- 'throttled'|- 'banned')
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_dumpReputation",
  "params": ["0x1306b01bC3e4AD202612D3843387e94737673F53"]
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    { "address": "0x7A0A0d159218E6a2f407B99173A2b12A6DDfC2a6",
      "opsSeen": "0x14",
      "opsIncluded": "0x13",
      "status": "ok"
    }
  ]
}debug_bundler_addUserOps 
Inject UserOperation objects array into the mempool. Assume the given UserOperation objects all pass validation without actually validating them, and accept them directly into the mempool.
Parameters:
- An array of UserOperationobjects
json
# Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "debug_bundler_addUserOps",
  "params": [
    [
      { sender: "0xa...", ... },
      { sender: "0xb...", ... }
    ]
  ]
}
# Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "ok"
}Rationale 
- explicit debug functions: bundlers are required to provide a set of debug functions, so that the "bundler specification test suite" can be used to verify its adherance to the spec.
Backwards Compatibility 
This proposal defines a new JSON-RPC API standard that does not pose any backwards compatibility challenges.
Security Considerations 
Preventing DoS attacks on UserOperation mempool 
Operating a public production ERC-4337 node is a computationally intensive task and may be a target of a DoS attack. This is addressed by the ERC-7562 validation rules, which defines a way for the ERC-4337 node to track participants' reputation as well as preventing nodes from accepting maliciously crafted UserOperations.
It is strictly recommended that all ERC-4337 nodes also implement ERC-7562 validation rules to minimize DoS risks.
Disabling debug API in production servers 
The API defined in the debug namespace is not intended to ever be publicly available. Production implementations of ERC-4337 must never make it available by default, and in fact enabling it should result in a clear warning of the potential dangers of exposing this API.
Copyright 
Copyright and related rights waived via CC0.