Virtual TestNets are live! ⚡️ Test and stage dapps on real-time production data.
Get started →

All Products

Debugger
Guides
Investigating a Failed Transaction

Investigating a Failed Transaction

In this guide, we’ll investigate the root cause of transaction failure and verify the fix.

We’ll look into a Uniswap transaction. This transaction attempts to swapExactTokensForTokens.

Paste the transaction hash in search of Tenderly dashboard

0xbe082dcc8ae59868f5b2330173902bb88c6643b5c2fdf0d8a9f43d03dbca0c36

Explore the error

The revert happened in swapExactTokensForTokens, checking a condition involving amountOutMin that is an input parameter. It reverted with the following error message:

Error Message: UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT

From the inputs section, we can see that amountOutMin had value 1102820622890207119.

Explore revert condition

Hop into the debugger view. Notice that require involves amounts[amounts.length - 1].

Evaluate the expression

To get the value of this expression, you can use Evaluate:

  1. Make sure debugger is at the line of revert,
  2. Paste the expression `amounts[amounts.length - 1],
  3. press “Evaluate” button.

The value is:

1029855063181377015

Obtain the value from call information

You can also extract the value of the expression in question by analyzing the function that produced the value:

  1. Move the debugger to the getAmountsOut from the Execution trace on the left
  2. Find the output in the lower pane
  3. Since the expression amounts[amounts.length - 1] gets the last element of the array, we conclude that the value in question is 1029855063181377015.

Potential solution

This transaction would have succeeded if the value of amountOutMin was 1029855063181377015.

Verifying the solution

To verify the solution, click the “Re-Simulate” button:

  1. Paste the value 1029855063181377015 to the second argument
  2. Click Simulate.

The simulation has succeeded, meaning we found the correct argument value.

Swap transactions are time-sensitive, they take into account the block.timestamp value. Simulations are by default executed on the original block and at the original timestamp. Only if you need custom block and timestamp values, you can use block header overrides for that purpose.