Message modes cookbook
Understanding the modes and flags available for sending messages is crucial to ensure your smart contracts behave as intended. This section will illustrate their practical application through specific examples.
You can check this example as a real‐world validation.
Message value and account balance
Please check how get_balance works to better understand balance
inside TVM.
All TON tokens held by a contract are reflected in the contract balance
. Some of these tokens are also assigned to the currently processed incoming message
. This mechanism is effective because any TON transaction involving a non‐system contract processes exactly one incoming message at a time.
Therefore, any blockchain payment may come either:
- From the incoming message's
value
. Contracts pay computation fees this way unless they call accept_message, which prevents malicious actors from spending the contract's balance to process their data - From the contract's
balance
, which leaves the incoming TON amount untouched during the transaction This approach currently applies to storage fees in workchains 0 and -1, along with most common actions
Fees
Actual transaction fees will vary depending on the blockchain configuration, the smart contract code, and other factors. When a message is received, part of the contract balance
will be consumed by storage and gas fees if the message value
is above a certain amount.
According to the transaction flow, there are five distinct phases:
- Storage: This phase includes both account storage and in_msg import.
- Credit: In this phase, the
value
ofin_msg
is added to thebalance
. - Compute: The TVM executes the smart contract code.
- Action: This phase involves performing actions such as
SENDRAWMSG
. - Bounce: This phase manages everything related to bouncing.
The order is: storage_fee -> import_fee -> gas_fee -> action_fee + fwd_fee
The table is populated based on this example. You can check the live calculator.
Fee in Explorer | Value | How it's obtained |
---|---|---|
Total fee | 0,001982134 | gas + storage + action + import |
Fwd. fee | 0,001 | fwd_fee + action_fee + ihr_fee |
Gas fee | 0,0011976 | compute phase, gas used |
Storage fee | 0,000000003 | storage phase, account only |
Action fee | 0,000133331 | action phase, cost per action |
Import fee (hidden) | 0,0006512 | cost of import of ext_msg |
Forward fee (each msg) | 0,000266669 | cost of fwd of in_msg |
IHR fee (each msg) | 0.0006 | cost of ihr fwd of in_msg |
The transaction fees used in these examples are hypothetical and for illustrative purposes only. Any fees other than message forwarding are outside the scope of this article. Funds included with an ignored message will still be credited to the receiving address.
1. (Mode 0, Flag 0) Basic message
State before transaction: Account A has 1 TON, Account B has 1 TON
A sent 0.1 TON to B, msg_fwd_fees are 0.004 TON, actual received value will be 0.096 TON, fwd_fee
and action_fee
are deducted from value
.
State after the transaction: Account A has 0.9 TON, Account B has 1.096 TON


2. (Mode 0, Flag 2) Error‐silent message
State before transaction: Account A has 1 TON, Account B has 1 TON
A sent 0.1 TON to B. The msg_fwd_fees
are 0.004 TON, and the actual received value will be 0.096 TON. The fwd_fee
and action_fee
are deducted from value
.
In case of an error during action phase, the message will be skipped instead of throwing an exit code.
State after the transaction: Account A has 0.9 TON, Account B has 1.096 TON
If no errors occur, the result is the same as mode = 0.


3. (Mode 0, Flag 16) Bounce on action error
State before transaction: Account A has 1 TON, Account B has 1 TON
A sent 0.1 TON to B. The msg_fwd_fees
are 0.004 TON, and the actual received value will be 0.096 TON. The fwd_fee
and action_fee
are deducted from value
.
In case of an error during action phase, the message will bounce and total_fee
+ fwd_fee
will be deducted from value
.
State after the transaction with error: Account A has 1 - (total_fee + fwd_fee
) TON, Account B has 1 TON


If no errors occur, the result is the same as mode = 0.
The key difference is that flag 16
creates bounces for action phase errors. In contrast, the message's built‐in bounce flag handles protocol‐level failures like:
- The destination contract does not exist.
- The destination contract throws an unhandled exception.


4. (Mode 0, Flag 1) Separate fees
State before the transaction: Account A has 1 TON, Account B has 1 TON
A sent 0.1 TON to B. The msg_fwd_fees
are 0.004 TON, and the actual received value will be 0.1 TON. The fwd_fee
and action_fee
are deducted from the balance
.
State after the transaction: Account A has 0.896 TON, Account B has 1.1 TON


5. (Mode 0, Flag 17) Separate fees and bounce on action error
State before the transaction: Account A has 1 TON, Account B has 1 TON
A sent 0.1 TON to B. The msg_fwd_fees
are 0.004 TON, and the actual received value will be 0.1 TON. The fwd_fee
and action_fee
are deducted from the balance
.
In case of an error during the action phase, the message will bounce and total_fee
+ fwd_fee
will be deducted from value
.
State after the transaction with an error: Account A has 1 - (total_fee + fwd_fee
) TON, Account B has 1 TON


If no errors occur, the result is the same as mode = 1.


6. (Mode 64, Flag 0) Carry forward the remaining value
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B after that B sent 0.5 TON to C with mode
= 64, msg_fwd_fees
are 0.004 TON, actual received value
will be 0.6 TON, total_fee + fwd_fee
are deducted from value
.
State after the transaction: Account A has 0.896 TON, Account B has 0.5 TON, Account C has 1.6 - (total_fee + fwd_fee
) TON
You might check this example.
Please note that storage_fee
is included in total_fee
but is always paid from the contract balance
.
Please note that SENDRAWMSG
doesn't update the balance.
If you try to send multiple messages (e.g., mode 0 and mode 64), you'll get exit code 37.


7. (Mode 64, Flag 1) Carry forward with separate fees
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B after that B sent 0.5 TON to C with mode
= 65, msg_fwd_fees
are 0.004 TON, actual received value will be 0.6 TON, total_fee + fwd_fee
are deducted from balance
.
State after the transaction: Account A has 0.896 TON, Account B has 0.5 - (total_fee + fwd_fee
) TON, Account C has 1.6 TON
You might check this example.
Please note that storage_fee
is included in total_fee
but is always paid from the contract balance
.


8. (Mode 64, Flag 16) Bounce‐protected carry forward
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B after that B sent 0.5 TON to C with mode
= 80, msg_fwd_fees
are 0.004 TON, actual received value will be 0.6 TON, total_fee + fwd_fee
are deducted from value
.
If an error occurs during the action phase, the message will bounce, and total_fee
+ fwd_fee
will be deducted from the value
.
State after the transaction with an error: Account A has 1 - (total_fee + fwd_fee
) TON, Account B has 1 TON, Account C has 1 TON


If no errors occur, the result is the same as mode = 64, flag 0. This mode is widely used in TON for jetton transfers. You can check it in the C5 action list of the jetton wallet.


9. (Mode 64, Flag 17) Bounce‐protected carry forward with separate fees
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B after that B sent 0.5 TON to C with mode
= 81, msg_fwd_fees
are 0.004 TON, actual received value will be 0.6 TON, total_fee + fwd_fee
are deducted from balance
.
If an error occurs during the action phase, the message will bounce, and total_fee
+ fwd_fee
will be deducted from the value
.
State after the transaction with an error: Account A has 1 - (total_fee + fwd_fee
) TON, Account B has 1 TON, Account C has 1 TON


If no errors occur, the result is the same as mode = 65.


10. (Mode 128, Flag 0) Send whole balance
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B after that B sent 0.5 TON to C with mode
= 128, msg_fwd_fees
are 0.004 TON, the actual received value will be 1.1 - total_fee TON, total_fee is deducted from value
.
State after the transaction: Account A has 0.896 TON, Account B has 0 TON, Account C has 2.1 - (total_fee + fwd_fee
) TON


11. (Mode 128, Flag 16) Send the whole balance bounce‐protected
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B after that B sent 0.5 TON to C with mode
= 144, msg_fwd_fees
are 0.004 TON, the actual received value will be 1.1 - total_fee TON, total_fee is deducted from value
.
State after the transaction with an error: Account A has 1 - (total_fee + fwd_fee
) TON, Account B has 1 TON, Account C has 1 TON


If no errors occur, the result is the same as mode = 128. This mode is widely used in TON for jetton transfers. You can check it in the C5 action list of the jetton wallet.


12. (Mode 128, Flag 32) Send the whole balance and destroy the contract
State before the transaction: Account A has 1 TON, Account B has 1 TON, Account C has 1 TON
A sent 0.1 TON to B, and after that, B sent 0.5 TON to C with mode
= 160. The msg_fwd_fees
are 0.004 TON. The actual received value will be 1.1 - total_fee TON, with total_fee deducted from value
.
State after the transaction: Account A has 0.896 TON, Account B has 0 TON and nonexist
, Account C has 2.1 - (total_fee + fwd_fee
) TON
When the balance reaches 0 TON, destroy the contract.

