# Debugging UserOps with Tenderly (/sdk/v5_3_x/faqs/debug-userop)

> For the complete documentation index, see [llms.txt](/llms.txt)



<VersionWarning version="5.3.x" />

In account abstraction (ERC-4337), the transactions sent by smart accounts are known as "UserOps."  UserOps are similar to but not the same as regular transactions, so it may not be clear how to debug them.

In this guide, we will be using [Tenderly](https://dashboard.tenderly.co/) to debug UserOps.  Make sure you have signed up and created a Tenderly account.

## The UserOp Structure [#the-userop-structure]

Let's begin by examining a typical UserOp example:

```json
{
  "sender": "0xd2f1a28cc13c95ac4671cee806593c920d81c1f8",
  "nonce": "330",
  "initCode": "0x",
  "callData": "0x51945447000000000000000000000000a02cddfa44b8c01b4257f54ac1c43f75801e81750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "callGasLimit": "55000",
  "verificationGasLimit": "1000000",
  "preVerificationGas": "100000",
  "maxFeePerGas": "39459600032",
  "maxPriorityFeePerGas": "39459600000",
  "paymasterAndData": "0x",
  "signature": "0x00000000bb864a968f25011aeb6574bef934726c066e9b47c261f6e40a49a3065da7deb57b0b40fffe70ec9ff0c1572358cd09d14cf8e671fdb66facfae0cb0a2db3a9cb1c"
}

```

This UserOp structure will be our reference point as we navigate through the process of simulating and debugging UserOps. Understanding the components of this example is key to effectively using Tenderly's tools for our debugging needs.

## UserOp Lifecycle [#userop-lifecycle]

Before delving into the nuances of debugging UserOps, it's helpful to learn the lifecycle of a UserOp.  Here it is:

<p align="center">
  <Image src="/img/userop_flow.png" width="4000" height="827" sizes="(max-width: 768px) 100vw, 768px" className="h-auto w-full" />
</p>

If this looks daunting, let's focus on only the high level:

* A UserOp, with no gas estimates nor signature, is sent to a paymaster server, who simulates the UserOp and returns the gas estimates.
  * If the UserOp has any errors in the validation or execution phase, the paymaster server will return an error since it can't properly simulate it.
* Now, the UserOp, with gas estimates and a proper signature, is sent to the bundler.
  * At this point, the UserOp is not expected to revert during the validation phase, but it may nevertheless revert during the execution phase due to the on-chain state having changed between when the UserOp was sent to the paymaster and when it's submitted by the bundler.

## Understanding UserOp Failures [#understanding-userop-failures]

A UserOp can fail at various stages, including during the paymaster call (if sponsored), the gas estimation call, or the final execution call. Identifying the failure point is straightforward by examining the method indicated in the error log of the failed UserOp. For instance:

* **Paymaster Call Failures*&#x2A; might involve methods such as &#x2A;*`zd_sponsorUserOperation`*&#x2A; (ZeroDev meta-paymaster), &#x2A;*`pm_sponsorUserOperation`*&#x2A; (Pimlico), or &#x2A;*`alchemy_requestPaymasterAndData`** (Alchemy).
* **Gas Estimation Call Failures*&#x2A; are indicated by the &#x2A;*`eth_estimateUserOperationGas`** method.
* **Execution Call Failures*&#x2A; are marked by the &#x2A;*`eth_sendUserOperation`** method.

Failures are generally classified into two categories:

* **Validation Errors**: These occur during the validation phase when transactions are deemed invalid due to issues like incorrect signatures or nonce values. They typically present as EntryPoint error codes (e.g., AA23: XXXX).
* **Execution Errors*&#x2A;: These occur during the execution phase when transactions are valid, but the contract interaction is reverted, often noted as &#x2A;*`execution reverted`**.

## Using Tenderly for Simulation and Debugging [#using-tenderly-for-simulation-and-debugging]

### Adjusting Gas Limits for Simulation [#adjusting-gas-limits-for-simulation]

For failures during paymaster or gas estimation calls, the UserOp gas limits (&#x2A;*`preVerificationGas`*&#x2A;, &#x2A;*`callGasLimit`*&#x2A;, &#x2A;*`verificationGasLimit`*&#x2A;) may default to &#x2A;*`0x`**. Before simulating the UserOp, adjust these gas limits as shown below. Increase these values based on error feedback if the simulation fails:

```json

{
 "preVerificationGas": "0x186A0",
 "callGasLimit": "0xD6D8",
 "verificationGasLimit": "0xF4240"
}
```

If the failure occurs during &#x2A;*`eth_sendUserOperation`**, the UserOp should already contain all necessary values for accurate simulation.

### Debugging Execution Errors [#debugging-execution-errors]

To simulate a UserOp in Tenderly, follow these steps:

1. Log in to your Tenderly account.

<p align="center">
  <Image src="/img/tenderly_account.png" width="2994" height="1344" sizes="(max-width: 768px) 100vw, 768px" className="h-auto w-full" />
</p>

2. Navigate to &#x2A;*`Simulator`*&#x2A; and click &#x2A;*`New Simulation`**.

<p align="center">
  <Image src="/img/new_simulation.png" width="1670" height="1348" sizes="(max-width: 768px) 100vw, 768px" className="h-auto w-full" />
</p>

3. Enter the EntryPoint contract address in `Insert any address` input and select the appropriate chain.
   * The EntryPoint address is `0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789` for v0.6 (default for ZeroDev SDK v5.1.x or below) and `0x0000000071727De22E5E9d8BAf0edAc6f37da032` for v0.7 (default for ZeroDev SDK v5.2.x or above)
4. Choose &#x2A;*`simulateHandleOp`**, input the UserOp into the tuple field, and commence the simulation.

If the simulation fails, it typically indicates a problem with the end contract. Verify the initial calldata thoroughly.

### Simulating End Contract Calls [#simulating-end-contract-calls]

<p align="center">
  <Image src="/img/new_simulation_2.png" width="1670" height="1348" sizes="(max-width: 768px) 100vw, 768px" className="h-auto w-full" />
</p>

To simulate an end contract call:

1. Insert the Smart Contract Wallet address in `Insert any address&#x60; input (&#x2A;*`sender`** field from UserOp).
2. Select the chain and enter the EntryPoint contract address in the &#x2A;*`From`** field.
3. Enter the &#x2A;*`calldata`*&#x2A; field from UserOp into the &#x2A;*`Raw input data`** field and simulate the transaction.

### Debugging Validation Errors [#debugging-validation-errors]

For validation errors, simulate the validation process by:

<p align="center">
  <Image src="/img/new_simulation_3.png" width="1670" height="1362" sizes="(max-width: 768px) 100vw, 768px" className="h-auto w-full" />
</p>

1. Inserting the EntryPoint contract address and selecting the chain.
2. Choosing &#x2A;*`simulateValidation`*&#x2A;, inputting the UserOp into the tuple field, and filling in the &#x2A;*`sender`*&#x2A; and &#x2A;*`calldata`** fields accordingly before simulating the transaction.

When simulating the validation process for a UserOp in Tenderly, the output can provide insightful details into potential issues. For instance, after simulating a UserOp, you might receive a &#x2A;*`ValidationResult`** like the one below:

```json
ValidationResult[{"preOpGas":"437497","prefund":"2118037380807816","sigFailed":true,"validAfter":"0","validUntil":"1708466460","paymasterContext":"0x"},{"stake":"0","unstakeDelaySec":"0"},{"stake":"0","unstakeDelaySec":"0"},{"stake":"100000000000000000000","unstakeDelaySec":"86400"}]
```

On Tenderly, it might look like this:

<p align="center">
  <Image src="/img/tenderly_error.png" width="3704" height="282" sizes="(max-width: 768px) 100vw, 768px" className="h-auto w-full" />
</p>

This result indicates various aspects of the validation process, with a particular focus on the failure due to signature validation (&#x2A;*`"sigFailed": true`**). Such output suggests that the UserOp failed validation because the signature did not match the expected parameters or was otherwise invalid.

## Other resources [#other-resources]

There are some resources that we find helpful:

* [StackUp's UserOp debugger](https://userop.dev/)
* [Pimlico's UserOp debugger/simulator](https://dashboard.pimlico.io/debugging)
* [StackUp docs on AA error codes](https://docs.stackup.sh/docs/entrypoint-errors)
* [Pimlico error codes](https://docs.pimlico.io/bundler/reference/entrypoint-errors/aa10)
