Processing Global Overview
This page contains an overview and specific details that explain how to process (send and accept) digital assets on the TON blockchain.
TON transactions are irreversible after just one confirmation. For the best user experience, it is suggested to avoid waiting on additional blocks once transactions are finalized on the TON Blockchain. Read more in the Catchain.pdf.
Best Practices
Toncoin
Toncoin Deposits
It is suggested to set several MEMO deposit wallets for better performance.
Toncoin Withdrawals
Jetton
Made by TON Community
GO
- Gobicycle - service is focused on replenishing user balances and sending payments to blockchain accounts. Both TONs and Jettons are supported. The service is written with numerous pitfalls in mind that a developer might encounter (all checks for jettons, correct operations status check, resending messages, performance during high load when blockchain is splitted by shards). Provide simple HTTP API, rabbit and webhook notifications about new payments.
- GO examples
JavaScript
Using ton.js SDK (supported by TON Community):
- Create a key pair, a wallet and get a wallet address
- Create a wallet, get its balance, make a transfer
Python
Using tonsdk library (similar to tonweb):
Global Overview
Embodying a fully asynchronous approach, TON Blockchain involves a few concepts which are uncommon to traditional blockchains. Particularly, each interaction of any actor with the blockchain consists of a graph of asynchronously transferred messages between smart contracts and/or the external world. The common path of any interaction starts with an external message sent to a wallet
smart contract, which authenticates the message sender using public-key cryptography, takes charge of fee payment, and sends inner blockchain messages. That way, transactions on the TON network are not synonymous with user interaction with the blockchain but merely nodes of the message graph: the result of accepting and processing a message by a smart contract, which may or may not lead to the emergence of new messages. The interaction may consist of an arbitrary number of messages and transactions and span a prolonged period of time. Technically, transactions with queues of messages are aggregated into blocks processed by validators. The asynchronous nature of the TON Blockchain does not allow to predict the hash and lt (logical time) of a transaction at the stage of sending a message. The transaction accepted to the block is final and cannot be modified.
Each inner blockchain message is a message from one smart contract to another, which bears some amount of digital assets, as well as an arbitrary portion of data.
Smart contract guidelines recommend treating the data payload, which begins with 32 binary zeros, as a human-readable text message. Most software, such as wallets and libraries, support this specification and allow to send text comments along with Toncoin as well as display comments in other messages.
Smart contracts pay fees for transactions (usually from the balance of an incoming message) as well as a storage fee for the contract's stored code and data. Fees depend on workchain configs with maximal fees on masterchain
and substantially lower fees on basechain
.
external message
is the input message forwallet A v4
contract with empty soure (a message from nowhere, such as Tonkeeper).outgoing message
is the output message forwallet A v4
contract and input message forwallet B v4
contract withwallet A v4
source andwallet B v4
destination.
As a result there are 2 transactions with their set of input and output messages.
Digital assets on TON
TON has three types of digital assets.
- Toncoin, the main token of the network. It is used for all basic operations on the blockchain, for example, paying gas fees or staking for validation.
- Native tokens, which are special kinds of assets that can be attached to any message on the network. These assets are currently not in use since the functionality for issuing new native tokens is closed.
- Contract assets, such as tokens and NFTs, which are analogous to the ERC-20/ERC-721 standards and are managed by arbitrary contracts and thus can require custom rules for processing. You can find more info on it's processin in process NFTs and process Jettons articles.
Simple Toncoin transfer
To send Toncoin, the user needs to send a request via an external message, that is, a message from the outside world to the blockchain, to a special wallet
smart contract (see below). Upon receiving this request, wallet
will send an inner message with the desired amount of assets and optional data payload, for instance a text comment.
Wallet smart contract
Wallet smart contracts are contracts on the TON Network which serve the task of allowing actors outside the blockchain to interact with blockchain entities. Generally, it solves three challenges:
- authenticates owner: Rejects to process and pay fees for non-owners' requests.
- replays protection: Prohibits the repetitive execution of one request, for instance sending assets to some other smart contract.
- initiates arbitrary interaction with other smart contracts.
Standard solution for the first challenge is public-key cryptography: wallet
stores the public key and checks that an incoming message with a request is signed by the corresponding private key which is known only by the owner. The solution to the third challenge is common as well; generally, a request contains a fully formed inner message wallet
sends to the network. However, for replay protection, there are a few different approaches.
Seqno-based wallets
Seqno-based wallets follow the most simple approach to sequencing messages. Each message has a special seqno
integer that must coincide with the counter stored in the wallet
smart contract. wallet
updates its counter on each request, thus ensuring that one request will not be processed twice. There are a few wallet
versions that differ in publicly available methods: the ability to limit requests by expiration time, and the ability to have multiple wallets with the same public key. However, an inherent requirement of that approach is to send requests one by one, since any gap in seqno
sequence will result in the inability to process all subsequent requests.
High-load wallets
This wallet
type follows an approach based on storing the identifier of the non-expired processed requests in smart-contract storage. In this approach, any request is checked for being a duplicate of an already processed request and, if a replay is detected, dropped. Due to expiration, the contract may not store all requests forever, but it will remove those that cannot be processed due to the expiration limit. Requests to this wallet
may be sent in parallel without interfering with each other; however, this approach requires more sophisticated monitoring of request processing.
Interaction with blockchain
Basic operations on TON Blockchain can be carried out via TonLib. It is a shared library which can be compiled along with a TON node and expose APIs for interaction with the blockchain via so-called lite servers (servers for lite clients). TonLib follows a trustless approach by checking proofs for all incoming data; thus, there is no necessity for a trusted data provider. Methods available to TonLib are listed in the TL scheme. They can be used either as a shared library via wrappers like pyTON or tonlib-go (technically those are the wrappers for tonlibjson
) or through tonlib-cli
.
Wallet deployment
To deploy a wallet via TonLib one needs to:
- Generate a private/public key pair via createNewKey or its wrapper functions (example in tonlib-go). Note that the private key is generated locally and does not leave the host machine.
- Form InitialAccountWallet structure corresponding to one of the enabled
wallets
. Currentlywallet.v3
,wallet.highload.v1
,wallet.highload.v2
are available. - Calculate the address of a new
wallet
smart contract via the getAccountAddress method. We recommend using a default revision0
and also deploying wallets in the basechainworkchain=0
for lower processing and storage fees. - Send some Toncoin to the calculated address. Note that you need to send them in
non-bounce
mode since this address has no code yet and thus cannot process incoming messages.non-bounce
flag indicates that even if processing fails, money should not be returned with a bounce message. We do not recommend using thenon-bounce
flag for other transactions, especially when carrying large sums, since the bounce mechanism provides some degree of protection against mistakes. - Form the desired action, for instance
actionNoop
for deploy only. Then use createQuery and sendQuery to initiate interactions with the blockchain. - Check the contract in a few seconds with getAccountState method.
Read more in the Wallet Tutorial
Incoming message value
To calculate the incoming value that the message brings to the contract, one needs to parse the transaction. It happens when the message hits the contract. A transaction can be obtained using getTransactions. For an incoming wallet transaction, the correct data consists of one incoming message and zero outgoing messages. Otherwise, either an external message is sent to the wallet, in which case the owner spends Toncoin, or the wallet is not deployed and the incoming transaction bounces back.
Anyway, in general, the amount that a message brings to the contract can be calculated as the value of the incoming message minus the sum of the values of the outgoing messages minus the fee: value_{in_msg} - SUM(value_{out_msg}) - fee
. Technically, transaction representation contains three different fields with fee
in name: fee
, storage_fee
, and other_fee
, that is, a total fee, a part of the fee related to storage costs, and a part of the fee related to transaction processing. Only the first one should be used.
Checking contract's transactions
A contract's transactions can be obtained using getTransactions. This method allows to get 10 transactions from some transactionId
and earlier. To process all incoming transactions, the following steps should be followed:
- The latest
last_transaction_id
can be obtained using getAccountState - List of 10 transactions should be loaded via the
getTransactions
method. - Unseen transactions from this list should be processed.
- Incoming payments are transactions in which the incoming message has a source address; outgoing payments are transactions in which the incoming message has no source address and also presents the outgoing messages. These transactions should be processed accordingly.
- If all of those 10 transactions are unseen, the next 10 transactions should be loaded and steps 2,3,4,5 should be repeated.
Checking transactions' flow
It's possible to track messages flow during transaction processing. Since the message flow is a DAG it's enough to get the input in_msg
or output out_msgs
messages of current transaction using getTransactions method to find incoming transaction with tryLocateResultTx or outgoing transactions with tryLocateSourceTx.
Accepting payments
There are a few approaches to accepting payments that differ in their method of distinguishing users.
Invoice-based approach
To accept payments based on attached comments, the service should
- Deploy the
wallet
contract. - Generate a unique
invoice
for each user. String representation of uuid32 will be enough. - Users should be instructed to send Toncoin to the service's
wallet
contract with an attachedinvoice
as a comment. - Service should regularly poll the getTransactions method for the
wallet
contract. - For new transactions, the incoming message should be extracted,
comment
matched against the database, and the value (see Incoming message value paragraph) deposited to the user's account.
Invoices
Invoices with ton:// link
If you need an easy integration for a simple user flow, it is suitable to use the ton:// link. Best suited for one-time payments and invoices with Toncoin.
ton://transfer/<destination-address>?
[amount=<toncoin-in-nanocoins>&]
[text=<url-encoded-utf8-comment>]
Example of ton:// link generation:
const tonLink = `ton://transfer/${address.toString({
urlSafe: true,
})}?amount=${amount}${text ? `&text=${encodeURIComponent(text)}` : ''}`;
✅ Easy integration
✅ No need to connect a wallet
❌ Users need to scan a new QR code for each payment
❌ It's not possible to track whether the user has signed the transaction or not
❌ No information about the user's address
❌ Workarounds are needed on platforms where such links are not clickable (e.g. messages from bots for Telegram desktop clients )
Learn More
Invoices with TON Connect
Best suited for dApps that need to sign multiple payments/transactions within a session or need to maintain a connection to the wallet for some time.
✅ There's a permanent communication channel with the wallet, information about the user's address
✅ Users only need to scan a QR code once
✅ It's possible to find out whether the user confirmed the transaction in the wallet, track the transaction by the returned BOC
✅ Ready-made SDKs and UI kits are available for different platforms
❌ If you only need to send one payment, the user needs to take two actions: connect the wallet and confirm the transaction
❌ Integration is more complex than the ton:// link
Learn More
Sending payments
- Service should deploy a
wallet
and keep it funded to prevent contract destruction due to storage fees. Note that storage fees are generally less than 1 Toncoin per year. - Service should get from the user
destination_address
and optionalcomment
. Note that for the meantime, we recommend either prohibiting unfinished outgoing payments with the same (destination_address
,value
,comment
) set or proper scheduling of those payments; that way, the next payment is initiated only after the previous one is confirmed. - Form msg.dataText with
comment
as text. - Form msg.message which contains
destination_address
, emptypublic_key
,amount
andmsg.dataText
. - Form Action which contains a set of outgoing messages.
- Use createQuery and sendQuery queries to send outgoing payments.
- Service should regularly poll the getTransactions method for the
wallet
contract. Matching confirmed transactions with the outgoing payments by (destination_address
,value
,comment
) allows to mark payments as finished; detect and show the user the corresponding transaction hash and lt (logical time). - Requests to
v3
ofhigh-load
wallets have an expiration time equal to 60 seconds by default. After that time unprocessed requests can be safely resent to the network (see steps 3-6).
Explorers
The blockchain explorer is https://tonscan.org.
To generate a transaction link in the explorer, the service needs to get the lt (logic time), transaction hash, and account address (account address for which lt and txhash were retrieved via the getTransactions method). https://tonscan.org and https://explorer.toncoin.org/ may then show the page for that tx in the following format:
https://tonviewer.com/transaction/{txhash as base64url}
https://tonscan.org/tx/{lt as int}:{txhash as base64url}:{account address}
https://explorer.toncoin.org/transaction?account={account address}<={lt as int}&hash={txhash as base64url}