Setting Up Transaction Debugging with Tenderly Debugger
The transaction returned execution reverted with no reason string. Or it consumed 3 times more gas than expected. Or something went wrong in the multisig, but it's unclear which exact call failed. console.log in Solidity only works in local environments — it doesn't exist on mainnet. Tenderly Debugger is a tool that provides complete EVM tracing for any transaction on any compatible network.
What Tenderly Debugger Shows
For each transaction, Tenderly builds:
- Execution trace — step-by-step EVM opcode execution with stack and memory state
- Call tree — hierarchy of nested calls (internal calls, delegatecall, staticcall)
- State changes — which storage slots changed and from what value to what
- Event logs — all emitted events, including from nested calls
- Gas breakdown — how much gas each call in the tree consumed
For contracts with verified source code, the debugger shows Solidity sources line-by-line instead of raw opcodes.
Setting Up a Project in Tenderly
Adding a Contract
npm install -g @tenderly/cli
tenderly login
tenderly init # creates tenderly.yaml in the project
# tenderly.yaml
account_id: "your-account"
project_slug: "your-project"
Importing a contract with verification:
tenderly verify --network 1 --address 0xYourContract
For Hardhat projects, the plugin automatically pushes artifacts:
// hardhat.config.js
require("@tenderly/hardhat-tenderly");
module.exports = {
tenderly: {
username: "your-username",
project: "your-project",
privateVerification: false
}
};
After this, npx hardhat run scripts/deploy.js --network mainnet automatically verifies contracts in Tenderly.
Fork for Debugging
Tenderly Fork is a snapshot of the network state at a specific block. You can send transactions to the fork and see full tracing without real funds:
const axios = require('axios');
// Create mainnet fork
const response = await axios.post(
`https://api.tenderly.co/api/v1/account/${username}/project/${project}/fork`,
{
network_id: "1",
block_number: 19500000
},
{ headers: { 'X-Access-Key': process.env.TENDERLY_ACCESS_KEY } }
);
const forkId = response.data.simulation_fork.id;
const forkRpc = `https://rpc.tenderly.co/fork/${forkId}`;
Now connect to forkRpc as a regular JSON-RPC — all transactions are recorded in Tenderly and available for analysis.
Practice: Debugging a Reverted Transaction
Common scenario: a user reports a failed transaction, you have the transaction hash, but no reason string (old contract without custom errors, just require(condition) without a message).
In Tenderly, paste the hash and see the exact line in the source where the revert happened, with actual variable values at that moment.
Even more useful for attacks: when a contract was drained through reentrancy, Tenderly shows the full call tree with nested calls — you can see how many times withdraw() was called recursively and how much ETH was transferred on each iteration.
Simulation API for Testing
Tenderly Simulation API allows you to simulate a transaction before sending it:
const simulation = await axios.post(
`https://api.tenderly.co/api/v1/account/${username}/project/${project}/simulate`,
{
network_id: "1",
from: "0xSenderAddress",
to: "0xContractAddress",
input: contractInterface.encodeFunctionData("transfer", [recipient, amount]),
gas: 200000,
gas_price: "20000000000",
value: "0",
save: true // save to project for analysis
},
{ headers: { 'X-Access-Key': process.env.TENDERLY_ACCESS_KEY } }
);
console.log(simulation.data.transaction.status); // success/failed
console.log(simulation.data.transaction.gas_used);
Use in CI to verify that a contract upgrade won't break existing calls.
Timeline Estimates
Basic Tenderly setup with contract verification and Hardhat plugin integration: 1 day. Includes fork environment setup, Simulation API for CI, and alerts through Tenderly Monitoring.







