All examples from this article are available on Github.
Log to the console
Most commonly used to print common values: transactions and get-method results.- Use
findTransaction()to find a transaction by its properties. - Use
flattenTransaction()to inspect transactions in a more human-readable format.
TypeScript
Dump values from a contract
There are three TVM debug instructions:DUMPSTK, STRDUMP, and DUMP.
These instructions are wrapped in functions with different names in each language:
- Tolk: Functions on a global
debugobject. - FunC: Global functions from
stdlib.fc. - Tact:
dumpStackforDUMPSTKand the dump function for the other two. Tact also prints the exact line wheredumpis called, so it can quickly be found in the code.
Debug instructions consume gas and affect gas measurement. Remove them before measuring gas or deploying to production.
Explore TVM logs
TypeScript
vm_logs— outputs VM logs for each transaction; includes executed instructions and occurred exceptions.vm_logs_full— outputs full VM logs for each transaction; includes executed instructions with binary offsets, the current stack for each instruction, and gas used by each instruction.
vm_logs looks like this:
LDU 64. Since there is not enough data, execution stops with exit code 9.
Inspect the same code with the vm_logs_full verbosity level. The output is heavily truncated at the top.
To investigate the error in more detail, examine the TVM source code for the
LDU instruction.
Sometimes several instructions are implemented within a single exec_* method. For example, LDU (load_uint), LDI (load_int) and it’s preload versions (preload_uintandpreload_int).Check how LDU is implemented.[bottom, ..., top], where top is the top of the stack.
Here, the stack contains two values:
- Top: the slice from which data is being read —
CS{Cell{...} bits: 711..725; refs: 2..2} - Bottom: an integer value —
500000000
725 bits, of which 711 bits and both references have already been read. The contract attempted to read 64 more bits, but the slice did not contain enough remaining data.
In FunC, locate the load_uint(64) call causing the issue and ensure enough bits are available or adjust the read width.
TVM log limits
The size of TVM debug output depends on the verbosity level:| Level | Setting | Max size |
|---|---|---|
| 0 | none | 256 bytes (default) |
| 1–4 | vm_logs vm_logs_location vm_logs_gas vm_logs_full | 1 MB |
| 5 | vm_logs_verbose | 32 MB |
Explore the trace
For traces that are not too large, print all transactions and inspect them.TypeScript
- TonDevWallet trace view — requires the TonDevWallet application; does not require a custom
@ton/sandbox; requires the@tondevwallet/tracespackage. - TxTracer Sandbox — requires a custom
@ton/sandboxpackage; runs in the browser.
Debugging with TVM Retracer
Even when a contract executes successfully (exit code =0) with no errors, the actions may not produce the expected on-chain result. TVM Retracer replays the transaction and displays VM-level execution in detail.
Scenarios for retracing
- All execution phases complete without errors, yet the expected outcome is missing.
- An action is skipped, or a transfer does not reach its destination.
- A step-by-step view of how the TVM executes contract logic is required, i.e. to trace a bug in a high-level smart-contract language compiler.
How to analyze a transaction
- Obtain the transaction hash from a blockchain explorer.
- Open TVM Retracer and enter the transaction hash.
- Review the execution:
- Inspect Logs section for executed instructions and exceptions.
- Examine Actions cell (C5) to review data passed between contracts.
- Check message modes — some modes can suppress errors, causing actions to be skipped.