Sending modes
By default, message sending process has the following properties:
- the forward fees are paid from the indicated message value, so it is decreased by the amount of forward fees before sending;
- if sending fails, the transaction is rolled back and a bounce message is not sent.
The purpose of send modes is to modify the above logic by specifying:
- what exactly value should be in the outgoing message (will it be increased by something or even reset to some value);
- whether to pay forward fees from the account balance or from the message value;
- whether to rollback the transaction and send a bounce message if sending fails, etc.
The send modes are specified via an 8-bit bitmask mode parameter of the SENDRAWMSG or the SENDMSG instructions. The resulting mode value can have the following base modes:
| Mode value | Tolk constant | Description |
|---|---|---|
0 | SEND_MODE_REGULAR | Default mode. |
64 | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE | Complex logic. Will be described below. |
128 | SEND_MODE_CARRY_ALL_BALANCE | Send all remaining balance of the account. |
1024 | SEND_MODE_ESTIMATE_FEE_ONLY | Only available for the SENDMSG instruction. Does not send the message, only estimates the forward fees. |
Additionally, the resulting mode can have the following optional flags added:
| Flag value | Tolk constant | Description |
|---|---|---|
+1 | SEND_MODE_PAY_FEES_SEPARATELY | Pay forward fees separately from the message value. |
+2 | SEND_MODE_IGNORE_ERRORS | Ignore errors during sending. No bounce message will be sent on failure. |
+16 | SEND_MODE_BOUNCE_ON_ACTION_FAIL | Bounce the transaction in case of any errors during the action phase. |
+32 | SEND_MODE_DESTROY | The current account (contract) will be destroyed if its resulting balance is zero. This flag has effect only if mode 128, SEND_MODE_CARRY_ALL_BALANCE, is used. |
Behavior
Notation:
value– the amount of Toncoin indicated in the outgoing message.mode– the bitmask passed to theSENDRAWMSGor theSENDMSGinstructions.msg_balance_remaining– the remaining value of the incoming message. At the start of the action phase it equals either the incoming message value or account's balance before compute phase if it was less than the value of incoming message with bounce flag set tofalse. At the start of sending message process, it is zero if there was the previous sending message action with modesSEND_MODE_CARRY_ALL_BALANCEorSEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE, otherwise it equals the value described above.remaining_balance– the remaining balance of the account at the start of the action.fwd_fees– the amount of forward fees for sending the message.gas_fees– the fees paid for gas used during the computation phase.action_fine– the accumulated fine for the previous failed and skipped send message actions.final_value– the final value of the outgoing message.req– value that will be deducted from the account balance.
The algorithm for the resulting value of outgoing internal message and amount of nanotoncoins that will be deducted from account's balance is as follows:
- Check that
modehas flagSEND_MODE_BOUNCE_ON_ACTION_FAIL:- if so, then in case of any failure the action phase will be interrupted, the bounce phase will be initiated;
- if not, then in case of any failure the action phase will be interrupted but no bounce message will be sent.
- Check that
modehas flagSEND_MODE_IGNORE_ERRORS:- if so, then in case of almost all failure (errors on which this mode is not work are described in Errors subsection.) during sending the message an error will be ignored and the action phase will continue;
- Set
final_valueto thevalue. - Check that
modehas base modeSEND_MODE_CARRY_ALL_BALANCE:- if so, then set
final_valuetoremaining_balanceand remove+1flag frommodeif it is presented.
- if so, then set
- Otherwise, check that
modehas base modeSEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE:- Check that
modehas flagSEND_MODE_PAY_FEES_SEPARATELY:- if so, then increase
final_valuebymsg_balance_remaining; - otherwise, increase
final_valuebymsg_balance_remaining - gas_fees - action_fine.
- if so, then increase
- Check that
- Set
reqtofinal_value. - Check that
modehas flagSEND_MODE_PAY_FEES_SEPARATELY:- if so, then increase
reqbyfwd_fees. - otherwise, decrease
final_valuebyfwd_fees.
- if so, then increase
- Set
msg_balance_remainingto zero ifmodehas base modesSEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUEorSEND_MODE_CARRY_ALL_BALANCE. - Decrease
remaining_balancebyreq. - Check that
modehas flagSEND_MODE_DESTROYand base modeSEND_MODE_CARRY_ALL_BALANCE:- if so, then destroy the current account (contract) if
remaining_balanceis zero.
- if so, then destroy the current account (contract) if
Example
Assume that
value = 0.1 TON;mode = 80 = 00001010000(that is,SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE + SEND_MODE_BOUNCE_ON_ACTION_FAIL);msg_balance_remaining = 0 TON(for instance, there was previous sending message action with modeSEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);remaining_balance = 2 TON;fwd_fees = 0.01 TON;gas_fees = 0.005 TON;action_fine = 0 TON.
Then the sending proceeds as follows:
modehas flagSEND_MODE_BOUNCE_ON_ACTION_FAIL? Yes.modehas flagSEND_MODE_IGNORE_ERRORS? No.- Set
final_value = 0.1 TON. modehas base modeSEND_MODE_CARRY_ALL_BALANCE? No.modehas base modeSEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE? Yes.modehas flagSEND_MODE_PAY_FEES_SEPARATELY? No.- Increase
final_valuebymsg_balance_remaining - gas_fees - action_fine = 0 TON - 0.005 TON - 0 TON = -0.005 TON. - Now,
final_value = 0.1 TON - 0.005 TON = 0.095 TON.
- Set
req = final_value = 0.095 TON. modehas flagSEND_MODE_PAY_FEES_SEPARATELY? No.- Decrease
final_valuebyfwd_fees = 0.01 TON. - Now,
final_value = 0.095 TON - 0.01 TON = 0.085 TON.
- Decrease
- Set
msg_balance_remainingto zero (it is already zero). - Decrease
remaining_balancebyreq = 0.095 TON.- Now,
remaining_balance = 2 TON - 0.095 TON = 1.905 TON.
- Now,
Outgoing external messages
The algorithm above describes the sending process only for outgoing internal messages. However, outgoing external message can have only the following three modes: SEND_MODE_BOUNCE_ON_ACTION_FAIL, SEND_MODE_IGNORE_ERRORS, and SEND_MODE_PAY_FEES_SEPARATELY (use of any other leads to an error). SEND_MODE_PAY_FEES_SEPARATELY can be used, but have no effect. For outgoing external messages, SEND_MODE_BOUNCE_ON_ACTION_FAIL and SEND_MODE_IGNORE_ERRORS have the same behavior, i.e., to ignore almost all errors during the action phase processing.
There is no value field in external messages, so the forward fees are always deducted from account's balance.
Errors
The following errors can occur during the sending message flow:
- Simultaneous use of modes
SEND_MODE_CARRY_ALL_BALANCEandSEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE,34exit code. - Modes except
SEND_MODE_IGNORE_ERRORS,SEND_MODE_BOUNCE_ON_ACTION_FAIL, andSEND_MODE_PAY_FEES_SEPARATELYused for outbound external messages,34exit code. - Source address in the outbound message is not equal to
addr_noneor the contract address,35exit code. - Some problems with repacking the message body and
StateInitinto references if the message body orStateInitis too big to be located in place,34exit code. - Malformed message structure,
34exit code. - Invalid destination address in the outbound message,
36exit code. - Not enough value to transfer with the message: all the inbound message value has been consumed,
37exit code. - Not enough funds for processing all message references,
40exit code. - The number of bits or references in
StateInitand message body is too large,40exit code. - Message has Merkle depth more than two,
40exit code. - If a message has only one
SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUEbase mode andfinal_valueafter the step5is negative, then an error with37exit code is thrown. - If
final_valueafter step7is negative, then an error with37exit code is thrown. - If
remaining_balanceafter step9is negative, then an error with37exit code is thrown. - If
remaining_balanceafter pay forward fees step is negative in a case of outgoing external message, then an error with37exit code is thrown. - Problems related to extra-currency, exit codes
37,44,38.
The SEND_MODE_IGNORE_ERRORS mode ignore all the above errors except the four first ones (simultaneous use of modes, invalid modes for external messages, source address problems, and problems with repacking).