Beginner’s Guide to TON: Accounts, Tokens, and Security

Background

TON (The Open Network) is a decentralized blockchain platform initially designed and developed by the Telegram team. TON aims to provide a high-performance and scalable blockchain platform to support large-scale decentralized applications (DApps) and smart contracts.

TON is unique in that it is easy to use, deeply integrated with Telegram, allowing ordinary people to easily use tokens. At the same time, it is complex, with an architecture that is distinct from other blockchains, and it uses a non-mainstream smart contract language called FunC.

Today, we will discuss the characteristics of TON and the security of user assets from the perspectives of accounts, tokens, and transactions.

Characteristics of TON

Account Generation

The method of generating an account address on TON is different from most blockchains; it is a smart contract address. First, everything starts with a private key. TON primarily uses the Ed25519 algorithm to generate a public key, with the process as follows:

There are two forms of the public key: one is the raw public key calculated from the private key, which looks like:

E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D

The other is a “beautified” public key, which includes some information and check bits, and it looks like:

Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2

If you think that just getting the public key will allow you to obtain the account address like in Ethereum, you’re mistaken. Merely having the user’s public key is not enough to calculate the user’s account address.

As mentioned, the user’s account address is a smart contract address, but how can you deploy a smart contract without having an account?

The correct sequence is to first calculate the address, receive some initial amount of tokens, and then deploy the contract. The process of calculating the account address is shown in the following diagram:

A user’s address also comes in multiple forms. First, there is the raw form, which looks like:

0:b4c1b2ede12aa76f4a44353944258bcc8f99e9c7c474711a152c78b43218e296

Then there is a user-friendly form, which looks like:

Mainnet:

  • Bounceable: EQC0wbLt4Sqnb0pENTlEJYvMj5npx8R0cRoVLHi0MhjilkPX
  • Non-bounceable: UQC0wbLt4Sqnb0pENTlEJYvMj5npx8R0cRoVLHi0Mhjilh4S

Testnet:

  • Bounceable: kQC0wbLt4Sqnb0pENTlEJYvMj5npx8R0cRoVLHi0Mhjilvhd
  • Non-bounceable: 0QC0wbLt4Sqnb0pENTlEJYvMj5npx8R0cRoVLHi0MhjilqWY

By carefully observing these addresses, you can see that they differ only in the first and last few characters, with the middle account_id being the same.

However, we still can’t see the relationship between the public key and the account address.

The secret lies in the initial data at the beginning, which contains a user’s public key, allowing the user to control the wallet contract. The workchainId is easy to understand; TON is not just a single chain but consists of many shards.

Each shard is a part of the entire network, handling specific accounts and transactions. To locate and manage smart contracts, it is necessary to specify which shard they are in. What’s the difference between Bounceable and Non-bounceable?

This relates to the way smart contracts work, but let’s continue to look further.

Wallet Contract

Below is a snippet of a user wallet contract’s source code. It shows that when receiving a message from the user, it reads four parameters: stored_seqno, stored_subwallet, public_key, and plugins:

wallet-v4-code.fc



() recv_external(slice in_msg) impure {

var signature = in_msg~load_bits(512);

var cs = in_msg;

var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));

throw_if(36, valid_until <= now());

var ds = get_data().begin_parse();

var (stored_seqno, stored_subwallet, public_key, plugins) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256), ds~load_dict()); ;;##The Initial Data

ds.end_parse();

throw_unless(33, msg_seqno == stored_seqno);

throw_unless(34, subwallet_id == stored_subwallet);

throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));

//...

}

Indeed, when this user wallet contract is deployed, it requires some initial parameters, including a 256-bit public_key. This ensures that every user has a unique contract address even when using the same contract code.

Every transaction initiated by the user must be signed with in_msg, then verified by the wallet contract (check_signature), after which the contract will perform operations on the blockchain. From this, we can deduce that a user’s public key can correspond to numerous wallet addresses.

Deploying different wallet contracts or using different initialization data will result in entirely different contract addresses.

Jetton Token

A token represents an asset on the blockchain, making it a fundamental element we need to understand. Jetton is the standard form of TON tokens and is composed of two contracts: Jetton-minter and Jetton-wallet.

When a token is issued, a Jetton-minter contract is created. This contract initialization records information such as the total supply of tokens, the administrator, wallet code, and other details.

When tokens are distributed to users, the Minter contract deploys a wallet contract for each user. During contract initialization, it records the user’s balance, ownership, the token Minter contract address, user wallet code, and other relevant information. Each user has an individually deployed contract.

It’s important to note that the contract created here is a wallet contract for managing specific Jetton tokens, which is different from the user’s account wallet contract. The owner_address recorded here is the address of the user’s account wallet.

When User Alice transfers tokens to User Bob, the invocation relationship is as follows:

Alice signs the transaction through an off-chain app and sends an operational command via her wallet contract. These commands will further invoke her token wallet to execute the transfer. When Bob’s token wallet receives the tokens, it notifies Bob’s wallet contract (the owner address of Bob’s Jetton-wallet).

If there is any leftover gas during the transaction, it will be returned to the appropriate address, usually Alice’s account contract.

Below is an example of a Jetton token transfer parsed by the Tonviewer browser:

While an ERC20 transfer requires only a single contract invocation, a Jetton token transfer requires at least four contract invocations. This method is designed to enable on-chain concurrency, improving transaction efficiency.

Transactions

When a certain event occurs in a TON account, it triggers a transaction. The most common event is “receiving a message.” A transaction includes the following elements:

  • The incoming message that initially triggers the contract (with special trigger methods available).
  • Contract actions resulting from the incoming message, such as updating the contract’s storage (optional).
  • Outgoing messages sent to other participants (optional).

There are several key features to be aware of regarding transactions:

  1. Asynchronous: TON transactions are not completed in a single call; they may require message passing to multiple different smart contracts to execute a series of calls. Due to different routing in the sharded chains, TON cannot guarantee the order of message delivery between multiple smart contracts.
  2. Fees: The asynchronous nature of transactions introduces a challenge in estimating the consumed fees. Therefore, wallets often send a little extra token as a fee when initiating a transaction. If the called contract has a good fee-handling mechanism, the remaining fees will be returned to the user’s wallet. Users might notice their wallet tokens suddenly decreasing and then increasing again after a few minutes, which is due to this mechanism.
  3. Bounce: Bounce is an error-handling mechanism in contracts. If the called contract does not exist or throws an error, and the transaction is set as bounceable, a bounced message will be returned to the calling contract. For example, if a user initiates a transfer and an error occurs during the process, a bounce message is necessary so that the user’s wallet contract can restore its balance. Almost all internal messages sent between smart contracts should be bounceable, meaning they should have their “bounce” bit set.

Asset Security

TON has many features that can lead to security issues, so users need to be aware of some common pitfalls.

Fee Withholding Attack

As mentioned, wallets often need to send a little extra fee to prevent transaction failure, which provides an opportunity for attackers. If you are a TON wallet user, you may have encountered a situation where your wallet frequently receives various NFTs or tokens.

Initially, these may seem like garbage token airdrops, but upon checking the transaction details, you find that they can be sold for a significant amount of money. However, when you attempt to initiate a transaction, you notice that the required fee is extremely high (1 TON). At this point, you should be cautious, as this could be a fee scam.

Attackers create a carefully crafted token contract that causes the wallet to estimate an excessively high transfer fee, but in reality, only the fee is withheld, and no transfer message is sent.

First and Last Digit Phishing

First and last digit phishing is not unique to TON; this phishing attack exists on many major blockchains. Attackers generate a counterfeit account for every user address on the network with the same first and last digits.

When a user initiates a transfer, the attacker also sends a small transfer, following the user’s transaction, to leave a record in the user’s transaction history. When the recipient user wants to send tokens back, they might copy the address from their transaction history, which could be the attacker’s address, leading to a transfer to the wrong address. The attacker has accurately exploited the user’s behavior.

Comment Phishing

When transferring tokens on TON, users can add a comment to annotate the transaction. This feature is often used when making deposits on exchanges, where exchanges usually require users to include their user ID in the deposit comment. However, this feature is frequently exploited by malicious actors, who write fraudulent information in the comments to steal users’ assets. For example:

Users should be especially cautious about the “Anonymous Telegram Number” NFT. If a user activates their Telegram account with an Anonymous Telegram Number but does not enable Two-Step Verification, and this NFT is phished, the hacker can directly log into the target Telegram account and proceed with subsequent asset theft and fraudulent activities.

Smart Contract Vulnerabilities

Security vulnerabilities in smart contracts can lead to the loss of funds stored in the contract. Users should choose projects that have undergone thorough auditing. TON’s smart contracts are primarily programmed using the FunC language, although some use the more advanced Tact or the lower-level Fift.

All of these languages are highly original. New programming languages bring new security risks, particularly for developers, who need to practice safe coding habits, master best security practices, and undergo rigorous security audits before deploying to the production environment. Due to space constraints, this article will not discuss contract security in detail.

Fake Deposit Attack

Wallet or exchange users should be aware of fake deposit attacks, which usually come in two forms:

  1. Fake Tokens: An attacker issues a token with metadata identical to the target token. If the automated deposit program does not check whether the token is from the correct minter contract, it can lead to incorrect deposits.
  2. Bounce: TON’s transfer process requires an invocation relationship between the wallet contracts of two users. If the recipient’s wallet contract does not exist and the transaction is set as bounceable, the message will bounce back, and the original funds, minus the fee, will be returned to the sender. Those interested in the details can refer to our previous article on fake deposits.

Conclusion

This article introduced some fundamental technical principles of TON from the perspectives of key and wallet creation, token forms, and transaction characteristics. It also explored potential security issues when using TON, hoping to inspire your learning journey.