SlowMist: Best Practices for Toncoin Smart Contract Security

SlowMist
8 min readSep 12, 2024

--

TON (The Open Network) is a decentralized blockchain platform initially designed and developed by the Telegram team, which gained significant attention upon its launch. TON aims to offer a high-performance and scalable blockchain to support large-scale decentralized applications (DApps) and smart contracts. For a foundational understanding of TON, including accounts, tokens, transactions, and asset security, refer to the guide: *Introduction to TON*.

What sets TON apart from other blockchains is its unique architecture. TON smart contracts are primarily programmed in the FunC language but can also be written in higher-level languages like Tact or lower-level ones like Fift. These are highly original languages, making the security of smart contracts on the platform a critical concern.

The SlowMist Security Team has combined security practices shared by the TON community with its own extensive experience in security audits to release the “Best Practices for Toncoin Smart Contract Security.” This guide is designed to help developers better understand the security risks associated with Toncoin smart contracts and offer practical solutions to mitigate potential threats.

Due to space constraints, only a portion of the “Best Practices for Toncoin Smart Contract Security” is listed here. For the full guide, feel free to Watch, Fork, and Star the project on GitHub: https://github.com/slowmist/Toncoin-Smart-Contract-Security-Best-Practices

Common Pitfalls in Toncoin Smart Contracts

1. Missing ‘impure’ Modifier

- Severity: High

- Description: An attacker might exploit the absence of the “impure” modifier in the “authorize” function. Without this modifier, the compiler may skip the function if it doesn’t return a value or if the returned value isn’t used.

- Attack Scenario:

- Recommendation: Always use the “impure” modifier for relevant functions.

2. Incorrect Use of Mutating/Non-mutating Methods

- Severity: High

- Description: The function “udict_delete_get?” is mistakenly invoked with “.” instead of “~”, leaving the dictionary unmodified.

- Attack Scenario:

- Recommendation: Double-check whether a method is mutating or non-mutating before invoking it.

3. Misuse of Signed/Unsigned Integers

- Severity: High

- Description: Voting power is stored as an integer in the message. An attacker could send a negative value during the power transfer to gain unlimited voting rights.

- Attack Scenario:

- Recommendation: Use unsigned integers where appropriate, as they trigger errors upon overflow. Only use signed integers when necessary.

4. Insecure Randomness

- Severity: High

- Description: The seed is derived from the logical time of the transaction, which an attacker can brute force within the block’s boundaries to manipulate the result.

- Attack Scenario:

- Recommendation: Always randomize the seed before using “rand()”, and avoid on-chain randomness, as validators may manipulate the seed.

5. Sending Private Data On-chain

- Severity: High

- Description: All data on the blockchain is stored publicly.

- Attack Scenario: Wallet passwords are hashed and stored in contract data, but since the blockchain records everything, passwords appear in transaction history.

- Recommendation: Avoid sending private data on-chain.

6. Failing to Handle Returned Messages

- Severity: High

- Description: When a user sends a “check” request, the Vault lacks a handler to process the return message or proxy it to the database.

- Attack Scenario:

- Recommendation: Always handle returned messages and strictly check conditions to avoid errors.

7. Risk of Account Destruction in Race Conditions

- Severity: High

- Description: Avoid destroying accounts too readily.

- Attack Scenario: You can deposit funds and attempt to withdraw them twice in parallel messages. If one of the withdrawal messages closes the account, the remaining funds can be accessed improperly.

- Recommendation: Use “raw_reserve” instead of sending funds to yourself. Be cautious of gas consumption with hashmaps.

8. Avoid Executing Third-party Code

- Severity: High

- Description: It’s unsafe to execute third-party code in your contract, as gas depletion can occur, allowing attackers to manipulate the state.

- Attack Scenario:

- Recommendation: Do not execute third-party code within your contract.

9. Name Conflicts

- Severity: Medium

- Description: Func variables and functions can contain nearly any legal character, which can lead to confusion.

- Attack Scenario: Names like “var++”, “~bits”, or “foo-bar+baz” are valid but potentially confusing.

- Recommendation: Use Linter tools to check Func code for clarity.

10. Check ‘throw’ Values

- Severity: Medium

- Description: TVM stops with exit codes “0” or “1” for normal termination, but using “throw(0)” or “throw(1)” can cause unintended interruptions.

- Attack Scenario:

- Recommendation: Avoid using “0” or “1” as throw values.

11. Read/Write the Correct Data Type

- Severity: Medium

- Description: Incorrectly reading or writing unexpected data types can lead to runtime errors, as TVM may reject incompatible data.

- Attack Scenario: Attempting to read an unexpected value may result in errors like “integer out of range”.

- Recommendation: Closely track code operations and expected return values.

12. Contract Code Can Be Updated

- Severity: Medium

- Description: TON implements the Actor model, allowing contracts to update code.

- Attack Scenario: Malicious developers could update the contract code to steal funds.

- Recommendation: Ensure contract updates follow secure practices and utilize governance models or multisig approvals.

13. Transactions and Phases

Severity: Medium

Description: In the computation phase, smart contract code is executed, followed by actions such as sending messages, modifying code, or updating libraries. Unlike Ethereum-based blockchains, if you expect a message to fail, you won’t see the exit code in the computation phase, as messages are not executed during this phase but in the subsequent operation phase.

Attack Scenario: Unexpected behavior may occur when a message fails during the operation phase, leading to incorrect assumptions about the transaction state.

Recommendation: Understand that each transaction consists of up to five phases: storage phase, credit phase, computation phase, operation phase, and bounce phase. Ensure that assumptions about transaction outcomes account for these phases.

14. Cannot Fetch Data from Other Contracts

- Severity: Medium

- Description: Contracts reside on different shards and are handled by different validators, meaning synchronous data fetches aren’t possible.

- Attack Scenario:

- Recommendation: Design contract logic around asynchronous messaging.

15. Two Predefined Method IDs

- Severity: Medium

- Description: There are two predefined method IDs: “(0)” for internal messages, and “(-1)” for external messages.

- Attack Scenario:

- Recommendation: Use methods like “force_chain(to_address)” to validate that addresses belong to the correct chain.

16. Use Bounceable Messages

- Severity: High

- Description: TON blockchain messages are asynchronous, and messages can fail to arrive in sequence.

- Attack Scenario:

- Recommendation: Always use bounceable messages (“0x18”) to handle message failures properly.

17. Replay Protection

- Severity: High

- Description: Implement replay protection for wallets by using sequence numbers (“seqno”) or unique transaction identifiers with expiry to prevent repeated message processing.

- Attack Scenario:

- Recommendation: Use methods like sequence numbers to protect against replay attacks.

18. Race Conditions in Messages

- Severity: High

- Description: Message cascading can span across multiple blocks, and an attacker may initiate parallel message streams, leading to race conditions.

- Attack Scenario: An attacker could exploit timing discrepancies to manipulate the behavior of a smart contract.

- Recommendation: Prevent race conditions by verifying the contract’s state at each step and avoiding assumptions about the consistency of the message flow. Always ensure that the state is validated and updated appropriately after every message execution.

19. Use Carry-value Mode

- Severity: High

- Description: In token transfers (e.g., TON Jetton), balances should be transferred using carry-value mode, ensuring correct value transfer between sender and receiver.

- Attack Scenario: Mishandling can lead to manipulated Jetton balances.

- Recommendation: Implement carry-value mode for proper value transfer.

20. Refund Excess Gas Fees Carefully

- Severity: High

- Description: Failing to refund excess gas fees can lead to funds accumulating in the contract.

- Recommendation: Implement features to refund excess fees, as seen in popular contracts like TON Jetton.

21. Check Function Return Values

- Severity: High

- Description: Ignoring function return values can cause critical logic errors.

- Attack Scenario:

- Recommendation: Always verify function return values.

22. Beware of Fake Jetton Tokens

- Severity: High

- Description: Jetton tokens consist of two parts: “jetton-minter” and “jetton-wallet”. Attackers could deplete a vault by depositing fake tokens.

- Attack Scenario:

- Recommendation: Verify the sender’s Jetton wallet address before accepting tokens.

Final Thoughts

By following these best practices, developers can enhance the security of their smart contracts and mitigate potential risks. In the rapidly evolving blockchain space, security remains paramount. We hope these practices will help developers create safe and reliable smart contracts, contributing to the healthy development of blockchain technology.

References:

1. https://dev.to/dvlkv/drawing-conclusions-from-ton-hack-challenge-1aep

2. https://docs.ton.org/develop/smart-contracts/security/ton-hack-challenge-1

3. https://docs.ton.org/learn/tvm-instructions/tvm-overview

4. https://docs.ton.org/develop/smart-contracts/messages

5. https://docs.ton.org/develop/smart-contracts/security/secure-programming

6. https://docs.ton.org/develop/smart-contracts/security/things-to-focus

About SlowMist

At SlowMist, we pride ourselves on being a frontrunner in blockchain security, dedicating years to mastering threat intelligence. Our expertise is grounded in providing comprehensive security audits and advanced anti-money laundering tracking to a diverse clientele. We’ve established a robust network for threat intelligence collaboration, positioning ourselves as a key player in the global blockchain security landscape. We offer tailor-made security solutions that span from identifying threats to implementing effective defense mechanisms. This holistic approach has garnered the trust of numerous leading and recognized projects worldwide, including names like Huobi, OKX, Binance, imToken, Crypto.com, Amber Group, Klaytn, EOS, 1inch, PancakeSwap, TUSD, Alpaca Finance, MultiChain, and Cheers UP. Our mission is to ensure the blockchain ecosystem is not only innovative but also secure and reliable.

We offers a variety of services that include but are not limited to security audits, threat intelligence, defense deployment, security consultants, and other security-related services. We also offer AML (Anti-money laundering) solutions, Vulpush (Vulnerability monitoring) , SlowMist Hacked (Crypto hack archives), FireWall.x (Smart contract firewall) , Safe Staking and other SaaS products. We have partnerships with domestic and international firms such as Akamai, BitDefender, FireEye, RC², TianJi Partners, IPIP, etc.

By delivering a comprehensive security solution customized to individual projects, we can identify risks and prevent them from occurring. Our team was able to find and publish several high-risk blockchain security flaws. By doing so, we wish to help spread awareness and raise the security standards in the blockchain ecosystem.

💬Website 🐦Twitter ⌨️GitHub

--

--

SlowMist

SlowMist is a Blockchain security firm established in 2018, providing services such as security audits, security consultants, red teaming, and more.