Top 9 Smart Contract Pitfalls to Avoid in TON’s Tact Language

Top 9 Smart Contract Pitfalls to Avoid in TON’s Tact Language

Source: Secure Contract Development in TON: Top 9 Pitfalls in Tact & FunC


As of July 2025, Tact has emerged as a leading smart contract language within the TON ecosystem, powering about a third of the 28,000+ deployed contracts. It offers a modern, safer development experience featuring static typing, clear syntax, and growing tool support-including integration with Visual Studio Code for syntax highlighting, diagnostics, and project scaffolding.

This guide highlights frequent mistakes and challenges spotted during code audits and security reviews of TON contracts written in Tact, helping developers build safer, more reliable applications.


1. Understanding TON’s Smart Contract Lifecycle

TON differs significantly from Ethereum with its decentralized, parallel transaction processing:

  • No shared global state between messages
  • Partial execution is normal: some operations may succeed while others silently fail within the same transaction
  • Contracts are responsible for gas management, differing from protocols where gas is managed network-wide

Developers need to keep these unique features in mind to avoid unexpected behavior.


2. Handling Bounced Messages and Recovering Balances

When sending TON coins fails, funds are not lost but bounced back to the sender contract flagged with a special bounce flag. Contracts must implement an onBounce handler to correctly recover the bounced value.

This approach safeguards against coin loss during failed transfers by refunding the sender.


3. Type-Safe Struct Design and Serialization Warnings

Tact uses a powerful serialization scheme but can cause issues if types aren’t explicitly declared:

  • By default, an `Int` is serialized as a 257-bit signed integer
  • This may clash with receivers expecting `uint256`, leading to deserialization errors or vulnerabilities
  • Always explicitly specify types in public APIs and standard-compliant messages

4. Gas Accounting Best Practices

Without strict gas control, contracts may partially execute, leaving inconsistent state and causing fund losses. A typical deposit handler pattern includes:

Key design points:

  • Gas precheck: Check upfront if sufficient gas is available using tools like `printTransactionFees()`
  • Forward excess gas: Return remaining gas to sender to avoid silent losses or storage bloat
  • Update state safely: Update balances only after confirming gas sufficiency to ensure transaction atomicity

5. Efficient State Management via Nested Storage Blocks

Flattened storage structures cause expensive load operations. Instead, use nested storage blocks (records) to group related state logically and reduce gas costs:

Efficient state design improves gas efficiency and contract responsiveness.


6. Avoid Message Race Conditions - Use Carry-Value Pattern

TON’s asynchronous transaction model means message order is non-deterministic. Relying on global contract state to hold message context is unsafe and leads to race conditions.

Consequences of ignoring async behavior:

  • Concurrent messages can overwrite shared state fields like `received_jetton_amount`
  • This can cause double spends, logic errors, or incorrect accounting

Best Practices:

  • Avoid relying on stored state to persist user context across messages
  • Always carry critical values inside the message payload to ensure stateless, self-contained handlers
  • Assume any stored state value may be outdated and design accordingly

7. End-to-End Jetton Transfer Handler Example

A robust base pattern for Jetton-compatible contracts includes:

  • Limiting potential attacker control
  • Guaranteeing account balances remain consistent even under failure conditions

This approach serves as a reliable standard when building Tact applications at scale.


8. Developer Tips: From Prototype to Production

While Tact enhances ergonomics, common unsafe habits from Solidity and FunC persist:

  • Avoid unchecked int/uint serialization errors
  • Don’t assume message processing order
  • Always perform explicit gas estimation before execution
  • Use carry-value to bind critical data to messages
  • Don’t rely on receiving “Excesses” messages; always test rejection handling

Testing tools such as @ton/sandbox and gas reporting utilities improve development rigour.


9. Utilize Tooling to Maintain Code Quality

Popular tools that help enforce correctness include:

  • VS Code plugin for real-time syntax validation and auto-completion
  • @ton/sandbox for simulating contract flows and behavior
  • `printTransactionFees()` for precise gas budgeting

Today, Tact powers roughly 33% of all TON smart contracts, highlighting its significant growth and importance.


Conclusion

TON’s parallel, asynchronous execution model offers superior performance and composability but requires disciplined engineering patterns. Tact provides strong language support, but secure contract development depends on:

  • Understanding message isolation
  • Handling failures carefully
  • Designing gas-aware, stateless message handlers

Security firms like Spearbit support teams building on TON by validating flows, improving state safety, and enforcing consistent communication patterns to build resilient decentralized systems.


This overview should guide developers, project leads, and security researchers to avoid common pitfalls and build stronger contracts in the TON ecosystem using Tact.