Interaction of Smart Contract Addresses on TON

Repost-by www.gate.io
The address of a smart contract running on TON typically consists of two main components:

  1. (workchain_id): Represents the Workchain ID (a signed 32-bit integer)

  2. (account_id): Represents the account address (ranging from 64 to 512 bits depending on the workchain)

In the original address overview section of this document, we will discuss how the (workchain_id, account_id) is represented.

Workchain ID and Account ID

Workchain ID

As previously noted, up to 2^32 workchains can be created on the TON blockchain. We also observed that a 32-bit prefix in smart contract addresses is used to identify and link smart contracts across different workchains. This allows smart contracts to send and receive messages between different workchains on the TON blockchain.

Currently, only the mainchain (workchain_id=-1) and occasionally the base workchain (workchain_id=0) are active on the TON blockchain.

Both have 256-bit addresses, so we assume that if the workchain_id is 0 or -1, the address within the workchain is exactly 256 bits.

Account ID

All account IDs in TON use a 256-bit address on the mainchain and base chain (or base workchain).

In practice, the account ID (account_id) is defined as the hash of the smart contract object (specifically SHA-256). Each smart contract running on the TON blockchain stores two main components. These include:

  • Compiled Code: The logic of the smart contract compiled into bytecode.

  • Initial State: The values at the time of the contract’s deployment on the chain.

To accurately derive the contract’s address, it is necessary to compute the hash corresponding to the (initial code, initial state) object. We won’t delve into the workings of TVM here, but it’s important to understand that the account ID on TON is determined using this formula: account_id = hash(initial code, initial state).

As this document progresses, we will delve deeper into technical specifications and provide an overview of TVM and TL-B schemes. Having understood how account IDs are generated and their interaction with smart contract addresses on TON, let’s explain what raw addresses and user-friendly addresses are.

Raw Addresses and User-Friendly Addresses

After briefly outlining how smart contract addresses on TON use workchain IDs and account IDs (especially for the mainchain and base chain), it’s important to understand these addresses are represented in two main formats:

  • Raw Address: The raw, complete representation of a smart contract address.

  • User-Friendly Address: An enhanced format of the raw address with better security and usability.

Below, we will explain in more detail the differences between these two address types and explore why user-friendly addresses are used on TON.

Raw Address

The raw smart contract address consists of the workchain ID and account ID (workchain_id, account_id) and is displayed in the following format:

[decimal workchain_id]:[64 hexadecimal digits account_id]

Here is an example of a raw smart contract address using workchain ID and account ID (represented as workchain_id and account_id):

-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260

Note that the address string starts with -1, indicating that it belongs to the mainchain workchain_id.

Note

The address string can use uppercase letters (such as ‘A’, ‘B’, ‘C’, ‘D’, etc.) instead of their lowercase counterparts (such as ‘a’, ‘b’, ‘c’, ‘d’, etc.).

Issues with Raw Addresses

There are two main issues with using raw addresses:

  1. It is impossible to validate the address before sending a transaction in the raw address format to eliminate errors. This means that if you accidentally add or remove a character in the address string before sending the transaction, your transaction will be sent to the wrong destination, resulting in loss of funds.

  2. The raw address format does not support adding special flags used when sending transactions with user-friendly addresses. To help you better understand this concept, we will explain the flags that can be used below.

User-Friendly Address

User-friendly addresses were developed to protect and simplify the experience of TON users sharing addresses on the internet (e.g., on public messaging platforms or through email service providers) and in the real world.

User-Friendly Address Structure

A user-friendly address consists of 36 bytes, generated in the following order:

  1. [Flag - 1 byte]: Flags attached to the address that change the smart contract’s response to received messages. Flag types for user-friendly addresses include:
  • isBounceable: Indicates whether the address type is bounceable or non-bounceable. (0x11 means “bounceable,” 0x51 means “non-bounceable”)

  • isTestnetOnly: Indicates addresses only for testnet use. Addresses starting with 0x80 should not be accepted by software running on the production network.

  • isUrlSafe: Indicates addresses that have been defined as URL-safe, deprecated. All addresses are considered URL-safe.

  1. [workchain_id - 1 byte]: The workchain ID (workchain_id) is defined by a signed 8-bit integer. (0x00 means the base chain, 0xff means the mainchain)

  2. [account_id - 32 bytes]: The account ID is a 256-bit (big-endian) address in the workchain.

  3. [Address Verification - 2 bytes]: In user-friendly addresses, address verification is done using a CRC16-CCITT signature of the first 34 bytes. (Example) The verification concept of user-friendly addresses is similar to the Luhn algorithm used on all credit cards to prevent user input errors for non-existent card numbers.

These 4 main components total 1 + 1 + 32 + 2 = 36 bytes (for each user-friendly address).

To generate a user-friendly address, developers must encode all 36 bytes as follows:

  • base64 (i.e., numbers, uppercase and lowercase Latin letters, ‘/’ and ‘+’)

  • base64url (replacing ‘/’ and ‘+’ with ‘_’ and ‘-’)

After this process, a user-friendly address of 48 non-space characters is generated.

DNS Address Flags

On TON, DNS addresses such as mywallet.ton are sometimes used instead of raw and user-friendly addresses. In fact, DNS addresses consist of user-friendly addresses and include all required flags, allowing developers to access all flags from DNS records in the TON domain.

User-Friendly Address Encoding Example

For example, a “Test Giver” smart contract (a special smart contract located on the testnet mainchain that sends 2 test tokens to any requester) uses the following raw address:

-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260

This raw address of the “Test Giver” must be converted to a user-friendly address format. This can be done using the previously introduced base64 or base64url formats, as shown below:

  • kf/8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15+KsQHFLbKSMiYIny (base64)

  • kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny (base64url)

Note: Both base64 and base64url formats are valid and accepted!

Bounceable vs. Non-Bounceable Addresses

The core idea behind the bounceable address flag is the safety of the sender’s funds.

For example, if the target smart contract does not exist or if there is an issue during the transaction, the message will be “bounced” back to the sender, including the remaining portion of the original transaction value (minus all transfers and fuel fees). This ensures that the sender does not lose funds due to accidentally sending to an address that cannot accept transactions.

Special Note on Bounceable Addresses:

  • bounceable=false typically means the recipient is a wallet.

  • bounceable=true usually indicates a custom smart contract with its own application logic (e.g., a DEX). In this case, non-bounce messages should not be sent for security reasons.

Please refer to our documentation for more information on non-bounceable messages.

Base64 Hardened Representation

Additional binary data related to the TON blockchain is represented in a similar “hardened” base64 user-friendly address format. They are distinguished based on the first 4 characters of the byte tag. For example, a 256-bit Ed25519 public key is represented by a 36-byte sequence created as follows:

  • Single-byte tag for public key in format 0x3E

  • Single-byte tag for Ed25519 public key in format 0xE6

  • 32-byte tag with the standard binary representation of the Ed25519 public key

  • 2-byte tag with the CRC16-CCITT of the first 34 bytes in big-endian format

The resulting 36-byte sequence is converted to a standard 48-character base64 or base64url string. For example, the Ed25519 public key E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D (usually represented

by a 32-byte sequence such as: 0xE3, 0x9E, …, 0x7D) is represented in a “hardened” form as:

Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2

Conversion Between User-Friendly and Raw Addresses

The easiest ways to convert between user-friendly and raw addresses are using various TON APIs and other tools, including:

  • TON Address

  • TON Center mainnet API methods

  • TON Center testnet API methods

Additionally, JavaScript provides two ways to convert user-friendly and raw addresses:

  • Using ton.js for conversion between user-friendly and raw formats

  • Using tonweb for conversion between user-friendly and raw formats

SDKs can also be used for similar conversions.