Настройка отладки транзакций через Tenderly Debugger
Транзакция вернула execution reverted без reason string. Или списала в 3 раза больше газа, чем ожидалось. Или в multisig что-то отработало не так, и непонятно на каком именно вызове. console.log в Solidity работает только в локальном окружении — в mainnet его нет. Tenderly Debugger — инструмент, который даёт полную EVM трассировку для любой транзакции в любой совместимой сети.
Что показывает Tenderly Debugger
На каждую транзакцию Tenderly строит:
- Execution trace — пошаговое выполнение EVM opcodes с состоянием стека и памяти
- Call tree — дерево вложенных вызовов (internal calls, delegatecall, staticcall)
- State changes — какие storage слоты изменились и с какого значения на какое
- Event logs — все эмитированные события, включая из вложенных вызовов
- Gas breakdown — сколько газа потребил каждый вызов в дереве
Для контрактов с верифицированным исходным кодом — дебаггер показывает Solidity исходники построчно, а не raw opcodes.
Настройка проекта в Tenderly
Добавление контракта
npm install -g @tenderly/cli
tenderly login
tenderly init # создаёт tenderly.yaml в проекте
# tenderly.yaml
account_id: "your-account"
project_slug: "your-project"
Импорт контракта с верификацией:
tenderly verify --network 1 --address 0xYourContract
Для Hardhat-проектов — плагин автоматически пушит артефакты:
// hardhat.config.js
require("@tenderly/hardhat-tenderly");
module.exports = {
tenderly: {
username: "your-username",
project: "your-project",
privateVerification: false
}
};
После этого npx hardhat run scripts/deploy.js --network mainnet автоматически верифицирует контракты в Tenderly.
Fork для отладки
Tenderly Fork — снапшот состояния сети в конкретном блоке. Можно отправлять транзакции в fork и видеть полную трассировку без реальных средств:
const axios = require('axios');
// Создаём fork mainnet
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}`;
Теперь подключаемся к forkRpc как к обычному JSON-RPC — все транзакции записываются в Tenderly и доступны для анализа.
Практика: отладка reverted транзакции
Частый сценарий: пользователь сообщает о failed транзакции, transaction hash есть, reason string — нет (контракт старый, без custom errors, просто require(condition) без сообщения).
В Tenderly вставляем hash → видим точную строку в исходнике, где произошёл revert, с актуальными значениями переменных в этот момент.
Ещё более полезно для атак: когда контракт был дренирован через reentrancy, Tenderly показывает полное call tree с вложенными вызовами — видно, сколько раз withdraw() был вызван рекурсивно и сколько ETH ушло на каждой итерации.
Simulation API для тестирования
Tenderly Simulation API позволяет симулировать транзакцию перед отправкой:
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 // сохраняем в проект для анализа
},
{ headers: { 'X-Access-Key': process.env.TENDERLY_ACCESS_KEY } }
);
console.log(simulation.data.transaction.status); // success/failed
console.log(simulation.data.transaction.gas_used);
Используем в CI для проверки, что апгрейд контракта не сломает существующие вызовы.
Ориентиры по срокам
Базовая настройка Tenderly с верификацией контрактов и подключением Hardhat плагина: 1 день. Включает настройку fork окружения, Simulation API для CI, и алерты через Tenderly Monitoring.







