Smart Contract Development in FunC (TON)
TON is not another EVM clone. A developer coming from Solidity experience spends the first two weeks in a state of mild shock: a stack-oriented virtual machine TVM, a cellular data storage model through Cell, asynchronous message passing between contracts, and FunC — a language that looks like functional C with elements of Lisp. These are not drawbacks; they are architectural decisions that give TON unique scalability properties. But the learning curve is steep.
How TON Works Internally
TVM and Cell — Not What You're Used to
In EVM, a contract is bytecode, storage is a key-value store with 32-byte slots. In TVM, a contract is stored as a tree of Cell objects. Each Cell contains up to 1023 bits of data and up to 4 references to other Cells. A contract's storage is also a Cell tree, which is fully loaded on each invocation and fully saved back.
This has concrete consequences. There are no slot collisions like in EVM proxies. There's no unbounded storage growth problem in the same sense. But there's its own pain: reading a deeply nested data structure requires sequential parsing of Cells through begin_parse() / load_uint() / load_ref(). Forget the field order during deserialization — you get incorrect data without a compiler error.
Asynchronous Message Model
In Solidity, contractA.functionB() is a synchronous call within a single transaction. In TON, everything is different: contracts communicate through messages, each of which is processed in a separate transaction. If contract A sends a message to contract B, which sends a message to contract C — these are three separate transactions in three separate blocks.
This breaks familiar patterns. The atomic operation "check balance — transfer — update state" becomes a sequence of messages with intermediate states. You need an explicit state machine in contract storage. You need timeout mechanisms for incomplete operations. You need to handle bounce messages — when the target contract cannot accept a message and returns it to the sender.
Missing bounce handling is a typical beginner mistake in TON. A contract sends TON to another contract, which reverts, coins return as a bounce message. If the sender didn't handle the bounce — coins disappear (more precisely, are processed by the default receive handler and lost from logic).
Gas Model in TON
TON doesn't have the familiar gas limit per transaction in the same sense. There are storage fees — a contract pays for storing its state every second. A contract with large storage and zero balance will eventually freeze. This must be considered when designing: data storage contracts (e.g., individual Jetton wallets) must have a replenishment mechanism or minimum balance.
How We Write Contracts in FunC
Development Stack
Blueprint is the standard tool for developing and testing TON contracts. Provides an environment for running TVM locally, writing tests in TypeScript, deploying through customizable scripts.
toncli we use for rapid prototyping and working with legacy code. For new projects — Blueprint is preferable due to better TypeScript integration.
Tact is a high-level language on top of FunC that significantly lowers the entry barrier and reduces errors when working with Cell structures. We consider it for projects where development speed matters more than maximum control over bytecode. FunC — where manual optimization is needed.
Official standards: TEP-74 (Jetton — an ERC-20 analogue), TEP-62 (NFT — an ERC-721 analogue), TEP-64 (token metadata). There is no OpenZeppelin analogue in TON — there are reference implementations from the TON Foundation team, which we use as a base.
Patterns for Asynchronous Operations
State machine in storage. Each multi-step operation has an explicit status: pending, processing, completed, failed. Messages check the current status before transitioning to the next state. Without this, parallel messages can lead to unpredictable results.
Timeout and cleanup. An operation in processing status for more than N seconds — automatic rollback through a separate message from the contract itself (through send_raw_message with delay through external tools or storing timestamp in storage).
Outgoing message routing. All bounce handlers are explicitly documented in the code. Pattern: a separate dispatcher function that determines what to do with a bounce by op-code. Losing funds due to unhandled bounce is uncompensable.
Typical Error When Working with Jetton
Jetton architecture in TON is sharded: each user has a separate wallet contract (Jetton Wallet) managed by the Jetton Minter. Transfer is two messages: from the sender's wallet to the recipient's wallet. If the recipient is a contract that wants to "know" about received jettons, it must handle the transfer_notification message.
Standard error: a recipient contract doesn't implement the transfer_notification handler — jettons arrive, but the contract doesn't "know" about it and doesn't change state. Then — a business logic bug that appears not immediately.
Comparing TON and EVM for Development Tasks
| Characteristic | TON / FunC | EVM / Solidity |
|---|---|---|
| Execution model | Asynchronous messages | Synchronous calls |
| Data storage | Cell trees | Key-value slots |
| Language | FunC / Tact | Solidity / Vyper |
| Token standards | TEP-74 (Jetton), TEP-62 (NFT) | ERC-20, ERC-721, ERC-1155 |
| Operation atomicity | No (multiple transactions) | Yes (single transaction) |
| Storage fees | Yes (periodic) | No |
| Transaction speed | <5 seconds | 12-60 seconds (Ethereum) |
| Audit tools | Limited set | Slither, Mythril, Echidna |
The table shows that TON is not "better" or "worse" — it's different. For tasks with high TPS and cheap transactions (payments, gamefi, miniapps in Telegram) — TON's architecture is optimal. For complex DeFi logic with atomic composability — EVM ecosystem is simpler to implement.
TON Contract Development Process
Design message flow (3-5 days). Before writing code — a complete diagram of all messages: op-codes, direction, what happens on bounce. This is critical for TON due to asynchronicity.
Development in FunC + tests in TypeScript (1-3 weeks). Blueprint tests cover happy path and all bounce scenarios. TVM emulation locally gives full transaction tracing.
Review storage layout. Check the order of Cell serialization/deserialization, correctness of bounce handling, absence of stub handlers for unknown op-codes.
Deploy to testnet (Testnet TON) → mainnet. Source code verification through TON Verifier.
Timeline Guidelines
A basic Jetton contract (TEP-74 compatible) — 3-5 days. NFT collection with custom logic (TEP-62) — 1-2 weeks. Complex protocol with multiple interacting contracts and state machine — from 4 weeks. Integration with Telegram Mini App through tonconnect — adds 3-7 days to the client side.
Cost is calculated individually after reviewing the architecture.







