Smart Contract Addresses
This section will detail the specifics of smart contract addresses on TON Blockchain. It will also explain how actors are synonymous with smart contracts on TON.
Everything is a Smart Contract
On TON, smart contracts are built using the Actor model. In fact, actors in TON are technically represented as smart contracts. This means that even your wallet is a simple actor (and smart contract).
Typically, actors process incoming messages, change their internal state, and generate outbound messages as a result. That's why every actor (i.e., smart contract) on TON Blockchain must have an address so it is able to receive messages from other actors.
On the Ethereum Virtual Machine (EVM), addresses are completely separate from smart contracts. Feel free to learn more about the differences by reading our article "Six unique aspects of TON Blockchain that will surprise Solidity developers" by Tal Kol.
Address of Smart Contract
Smart contract addresses operating on TON typically consist of two main components:
(workchain_id): denotes the workchain ID (a signed 32-bit integer)
(account_id) denotes the address of the account (64-512 bits, depending on the workchain)
In the raw address overview section of this documentation, we'll discuss how (workchain_id, account_id) pairs present themselves.
Workchain ID and Account ID
As we've seen before, it is possible to create as many as
2^32 workchains operating on TON Blockchain. We also noted how 32-bit prefix smart contract addresses identify and are linked to smart contract addresses within different workchains. This allows smart contracts to send and receive messages to and from different workchains on TON Blockchain.
Nowadays, only the Masterchain (workchain_id=-1) and occasionally the basic workchain (workchain_id=0) are running in the TON Blockchain.
Both of them have 256-bit addresses, so we henceforth assume that workchain_id is either 0 or -1 and that the address inside the workchain is exactly 256-bit.
All account IDs on TON make use of 256-bit addresses on the MasterChain and BaseChain (or basic workchain).
In fact, Account ID’s (account_id) defined as hash functions for smart contract objects (particular, the SHA256). Every smart contract operating on the TON blockchain stores two main components. These include:
- Compiled code. Logic of smart contract compiled in byte code.
- Initial state. Contract’s values in its initial moment deploying on-chain.
Finally, to correctly receive the address account it is necessary to calculate the hash corresponding to the pair (Initial code, Initial state) object. At this time, we won't take a deep dive into how the TVM works, but it's important to understand that account ID’s on TON are determined using this formula: : account_id = hash(initial code, initial state)
In time, throughout this documentation, we'll dive deeper into the technical specifications and overview of the TVM and TL-B scheme. Now that we are familiar with the formation of account_id and their interaction with smart contract addresses on TON, let’s explain Raw and User-Friendly addresses.
Raw and User-Friendly Addresses
After providing a brief overview of how smart contract addresses on TON leverage workchains and account ID’s (for the MasterChain and BaseChain specifically), it's important to understand that these addresses are expressed in two main formats:
- Raw addresses: Original full representation of smart contract addresses.
- User-friendly addresses: User-friendly addresses are an enhanced format of raw address that employ better security and ease of use.
Below, we’ll explain more about the differences between these two address types and dive deeper into why user-friendly addresses are used on TON.
Raw smart contract addresses consist of a workchain ID and account ID (workchain_id, account_id) and are displayed in the following format:
- [decimal workchain_id]:[64 hexadecimal digits with account_id]
Provided below, is an example of a raw smart contract address using a workchain ID and account ID together (expressed as workchain_id and account_id):
-1 at the start of the address string, this denotes a workchain_id that belongs to the MasterChain.
Uppercase letters (such as 'A', ‘B’, ‘C’, ‘D’ etc.) may be used in address strings instead of their lower-case counterparts (such as 'a', ‘b’, ’c’ 'd' etc.).
Issues With Raw Addresses
Using the Raw Address form presents two main issues:
- When using the raw address format, it's not possible to verify addresses to eliminate errors prior to sending a transaction. This means that if you accidentally add or remove characters in the address string prior to sending the transaction, your transaction will be sent to the wrong destination, resulting in loss of funds.
- When using the raw address format, it's impossible to add special flags like those used when sending transactions that employ user-friendly addresses. To help you better understand this concept, we’ll explain which flags can be used below.
User-friendly addresses were developed to secure and simplify the experience for TON users who share addresses on the internet (for example, on public messaging platforms and via their email service providers) and in the real world.
User-Friendly Address Structure
User-friendly addresses are made up of 36 bytes in total and are obtained by generating the following components in order:
[flags - 1 byte] — Flags that are pinned to addresses change the way smart contracts react to the received message. Flags types that employ the user-friendly address format include:
- isBounceable. Denotes a bounceable or non-bounceable address type. (0x11 for "bounceable", 0x51 for "non-bounceable")
- isTestnetOnly. Denotes an address type used for testnet purposes only. Addresses beginning with 0x80 should not be accepted by software running on the production network
- isUrlSafe. Denotes a deprecated flag that is defined as url safe for an address. All addresses are then considered url safe.
[workchain_id - 1 byte] — The workchain ID (workchain_id) is defined by a signed 8-bit integer workchain_id.
(0x00 for the BaseChain, 0xff for the MasterChain)
[account_id - 32 byte] — The account ID is made up of a (big-endian) 256-bit address inside the workchain.
[address verification - 2 bytes] — In user-friendly addresses, address verification is composed of a CRC16-CCITT signature from the previous 34 bytes. (for example) In fact, the idea pertaining to verification for user-friendly addresses is quite similar to the Luhn algorithm used in all bank cards to prevent the user from writing non-existing card numbers by mistake.
The addition of these 4 main components means that:
1 + 1 + 32 + 2 = 36 bytes in total (per user-friendly address).
To generate a user-friendly address, the developer must encode all 36 bytes using either:
- base64 (i.e., with digits, upper and lowercase Latin letters, '/' and '+')
- base64url (with '_' and '-' instead of '/' and '+')
After this process is complete, the generation of a user-friendly address with a length of 48 non-spaced characters is finalized.
On TON, DNS addresses such as mywallet.ton are sometimes used instead of raw and user-friendly addresses. In fact, DNS addresses are made up of user-friendly addresses and include all required flags that allow developers to access all flags from the DNS record within the TON domain.
User-Friendly Address Encoding Examples
For example, a "test giver" smart contract (a special smart contract residing in the testnet masterchain that sends 2 test tokens to anyone who requests them) makes use of the following raw address:
The above "test giver" raw address must be converted into the user-friendly address form. This is obtained using either the base64 or base64url forms (that we introduced previously) as follows:
Notice that both forms (base64 and base64url) are valid and must be accepted!
Bounceable vs Non-Bounceable Addresses
The core idea behind the bounceable address flag is sender security.
For example, if the destination smart contract does not exist, or if retrieval issues become apparent while processing the transaction, the message will be "bounced" back to the sender and constitute the remainder of the original value of the transaction (minus all transfer and gas fees). This ensures the sender doesn't lose their funds that were sent to an address that cannot accept the transaction.
In relation to bounceable addresses specifically:
- The bounceable=false flag generally means the receiver is a wallet.
- The bounceable=true flag typically denotes a custom smart contract with its own application logic (for example, a DEX). In this example, non-bounceable messages should not be sent because of security reasons.
Feel free to read more on this topic in our documentation to gain a better understanding of non-bounceable messages.
Armored base64 Representations
Additional binary data related to the TON blockchain employs similar “armored” base64 user-friendly address representations. These differentiate from one another depending on the first 4 characters of their byte tag. For example, 256-bit Ed25519 public keys are represented by first creating a 36-byte sequence using the below process in order:
- A single byte tag using the 0x3E format denotes a public key
- A single byte tag using the 0xE6 format denotes a Ed25519 public key
- 32 bytes containing the standard binary representation of the Ed25519 public key
- 2 bytes containing the big-endian representation of CRC16-CCITT of the previous 34 bytes
The resulting 36-byte sequence is converted into a 48-character base64 or base64url string in the standard fashion. For example, the Ed25519 public key
E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D (usually represented by a sequence of 32 bytes such as:
0xE3, 0x9E, ..., 0x7D) presents itself through the "armored" representation as follows:
Converting User-Friendly Addresses and Raw Addresses
The simplest way to convert user-friendly and raw addresses is realized through the use of several TON APIs and other tools, including:
- Convert address from/to user-friendly or raw form using ton.js
- Convert address from/to user-friendly or raw form using tonweb
It's also possible to make use of similar mechanisms using SDKs.