Message Modes Cookbook
Understanding the different modes and flags available for sending messages is crucial to ensure that your smart contracts behave as intended. While message modes section provided detailed descriptions of these modes and flags, in this section we 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 owned by a contract are reflected in the contract balance. Some of these tokens are also attributed to the currently processed incoming message - a mechanism that works effectively 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
value
. For instance, computation fees are paid in this way, unless contract calls accept_message. This ensures that malicious actors cannot spend contract's balance on handling their data. - From the contract
balance
(will not touch amount of TON designated as incoming this transaction). Storage fees in workchains 0 and -1, as well as most actions, are currently examples of this.
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 fees and gas_fees if the message value
is above certain amount.
According to the transaction flow there are 5 phases:
- Storage, consisting of account storage and in_msg import
- Credit, where in_msg
value
is added to thebalance
- Compute, where the actual smart contract code is executed in TVM
- Action, where actions like
SENDRAWMSG
are performed - Bounce, where everything about bouncing is handled
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 |
total_fwd_fees | 0,001 | fwd_fee + action_fee + ihr_fee |
gas_fees | 0,0011976 | compute phase, gas used |
storage_fees | 0,000000003 | storage phase, account only |
total_action_fees | 0,000133331 | action phase, cost per action |
import_fee (hidden) | 0,0006512 | cost of import of ext_msg |
fwd_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 are for illustrative purposes only. Any fees other than message forwarding are out of scope of this article. Funds included with an ignored message will still be credited to the receiving address.
1. Send a regular 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 transaction: Account A has 0.9 TON, Account B has 1.096 TON
Mode and Flags | Code |
---|---|
mode = 0, no flag | send_raw_message(msg, 0) |
2. Send a regular message, no bounce the message on error and ignore it
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
.
In case of an error during action phase, the message will be skipped instead of throwing an exit code.
State after 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
.
Mode and Flags | Code |
---|---|
mode = 0, flag = 2 | send_raw_message(msg, 2) |
3. Send a regular message, and bounce the message in case of an action error
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
.
In case of an error during action phase, the message will bounce and total_fee
+ fwd_fee
will be deducted from value
.
State after 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
.
Mode and Flags | Code |
---|---|
mode = 0, flag = 16 | send_raw_message(msg, 16) |
4. Send a regular message with separate fees
State before the 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.1 TON, fwd_fee
and action_fee
are deducted from balance
.
State after the transaction: Account A has 0.896 TON, Account B has 1.1 TON
Mode and Flags | Code |
---|---|
mode = 0, flag = 1 | send_raw_message(msg, 1) |
5. Send a regular message with separate fees and bounce the message on error
State before the 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.1 TON, fwd_fee
and action_fee
are deducted from balance
.
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 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
.
Mode and Flags | Code |
---|---|
mode = 0, flag = 1 + 16 = 17 | send_raw_message(msg, 17) |
6. Carry remaining value with new message
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 it is always paid from contract balance
.
Please note that SENDRAWMSG
doesn't update balance.
If you try to send multiple messages (i.e. mode 0 and mode 64) you'll get exit code 37.
Mode and Flags | Code |
---|---|
mode = 64, no flag | send_raw_message(msg, 64) |
7. Carry remaining value with a new message 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 it is always paid from contract balance
.
Mode and Flags | Code |
---|---|
mode = 64, flag = 1 | send_raw_message(msg, 65) |
8. Carry remaining value and bounce the message on error
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
.
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, Account C has 1 TON
If no errors occur the result is the same as mode = 64
. This mode is widely used in TON for jetton transfers. You can check it in C5 action list of the jetton wallet.
Mode and Flags | Code |
---|---|
mode = 64, flag = 16 | send_raw_message(msg, 80) |
9. Carry the remaining value with a new message with separate fees and bounce the message on error
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
.
In case of an error during the action phase, the message will bounce and total_fee
+ fwd_fee
will be are deducted from value
.
State after 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
.
Mode and Flags | Code |
---|---|
mode = 64, flag = 16 + 1 | send_raw_message(msg, 81) |
10. Send all received tokens along with the contract 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, 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
Mode and Flags | Code |
---|---|
mode = 128, no flag | send_raw_message(msg, 128) |
11. Send all received tokens along with the contract balance and bounce the message on error
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, 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 C5 action list of the jetton wallet.
Mode and Flags | Code |
---|---|
mode = 128, flag = 16 | send_raw_message(msg, 144) |
12. Send all received tokens along with the contract balance and destroy the smart 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 after that B sent 0.5 TON to C with mode
= 160, msg_fwd_fees
are 0.004 TON, actual received value will be 1.1 - total_fee TON, 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.
Mode and Flags | Code |
---|---|
mode = 128, flag = 32 | send_raw_message(msg, 160) |