Paying for processing queries and sending responses
In general, if a smart contract wants to send a query to another smart contract, it should pay for sending the internal message to the destination smart contract (message forwarding fees), processing this message at the destination (gas fees), and sending back the answer if required (message forwarding fees).
In most cases, the sender will attach a small amount of Toncoin (e.g., one Toncoin) to the internal message (sufficient to pay for the processing of this message) and set its "bounce" flag (i.e., send a bounceable internal message); the receiver will return the unused portion of the received value with the answer (deducting message forwarding fees from it). This is normally accomplished by invoking
mode = 64 (cf. Appendix A of the TON VM documentation).
If the receiver is unable to parse the received message and terminates with a non-zero exit code (for example, because of an unhandled cell deserialization exception), the message will be automatically "bounced" back to its sender, with the "bounce" flag cleared and the "bounced" flag set. The body of the bounced message will contain 32 bit
0xffffffff followed by 256 bit from original message. It is important to check the "bounced" flag of incoming internal messages before parsing the
op field in the smart contract and processing the corresponding query (otherwise there is a risk that the query contained in a bounced message will be processed by its original sender as a new separate query). If the "bounced" flag is set, special code could find out which query has failed (e.g., by deserializing
query_id from the bounced message) and take appropriate action. A simpler smart contract might simply ignore all bounced messages (terminate with zero exit code if "bounced" flag is set). Note, that "bounced" flag is rewritten during sending so it can not be forged and it is safe to assume that if message came with "bounced" flag it is result of bouncing of some message sent from receiver.
On the other hand, the receiver might parse the incoming query successfully and find out that the requested method
op is not supported, or that another error condition is met. Then a response with
op equal to
0xffffffff or another appropriate value should be sent back, using
mode = 64 as mentioned above.
In some situations, the sender wants both to transfer some value to the sender and to receive either a confirmation or an error message. For instance, the validator elections smart contract receives an election participation request along with the stake as the attached value. In such cases, it makes sense to attach, say, one extra Toncoin to the intended value. If there is an error (e.g., the stake may not be accepted for any reason), the full amount received (minus the processing fees) should be returned to the sender along with an error message (e.g., by using
mode = 64 as explained before). In the case of success, the confirmation message is created and exactly one Toncoin is sent back (with the message transferring fees deducted from this value; this is
mode = 1 of