Skip to content

Commit d467d00

Browse files
authored
feat(docs): add headers with various receiver kinds (#3397)
1 parent e3132d5 commit d467d00

File tree

1 file changed

+74
-9
lines changed

1 file changed

+74
-9
lines changed

docs/src/content/docs/book/receive.mdx

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,84 @@ prev:
66
label: Functions
77
---
88

9-
TON is a distributed blockchain, which means that communication between contracts is performed by sending and receiving messages. The most common type of message is the internal message - a message sent from one contract (or a wallet) to another.
9+
import { Badge } from '@astrojs/starlight/components';
10+
11+
TON is a distributed blockchain, which means that communication between contracts is performed by sending and receiving messages. The most common type of message is the _internal message_ — a message sent from one contract (or a wallet) to another.
1012

1113
## Receive internal messages
1214

1315
To receive a message of the required type, you need to declare a receiver function. For example, `receive("increment"){:tact}`. This notation means the declaration of a receiver function that will be called when a text with the value `"increment"{:tact}` is sent to the contract. The function body can modify the state of the contract and send messages to other contracts. It is impossible to call a receiver directly. If you need to reuse some logic, you can declare a function and call it from the receiver.
1416

15-
There are several receiver functions. All receiver functions are processed in the order they are listed below. The first receiver that matches the message type processes the message:
17+
### Empty receiver
18+
19+
This receiver specifically handles internal messages with no contents, i.e., the `null{:tact}` body. Note that as a function, it's own body doesn't have to be empty.
20+
21+
```tact
22+
contract Emptiness() {
23+
// This receiver handles `null` (empty) message bodies of internal messages.
24+
receive() {
25+
// Although you can use this receiver for anything,
26+
// it's most common to utilize it for deployments and forward excess funds
27+
// from the incoming message back to the sender's address.
28+
cashback(sender());
29+
}
30+
}
31+
```
32+
33+
### Text receivers
34+
35+
<Badge text="500+ gas" title="Uses 500 gas units or more" variant="danger" size="medium"/><p/>
36+
37+
There are two kinds of text receivers:
38+
39+
* `receive("..."){:tact}` — the exact text receiver that handles specific string comments with the maximum length of 123 bytes
40+
* `receive(str: String){:tact}` — the catch-all string receiver that handles arbitrary string comments
41+
42+
Processing and distinguishing text receivers, e.g., the comment receiver `receive("..."){:tact}` and the string receiver `receive(str: String){:tact}`, costs significantly more gas than [processing binary ones](#binary-receivers), such as `receive(){:tact}` or `receive(msg: MyMessage){:tact}`. Thus, it is recommended to [prefer binary receivers to text receivers](/book/gas-best-practices#prefer-binary-receivers-to-text-receivers).
43+
44+
```tact
45+
contract CertainMD() {
46+
receive("time changes everything") {
47+
message(MessageParameters {
48+
to: sender(),
49+
value: 0,
50+
mode: SendRemainingValue,
51+
body: "Doing things changes things. Not doing things leaves things exactly as they were".asComment(),
52+
});
53+
}
54+
55+
receive(str: String) {
56+
message(MessageParameters {
57+
to: sender(),
58+
value: 0,
59+
mode: SendRemainingValue,
60+
body: "Do I get bonus points if I act like I care?".asComment(),
61+
});
62+
}
63+
}
64+
```
65+
66+
### Binary receivers
67+
68+
If the message body starts with a recognized [opcode](/book/structs-and-messages#message-opcodes) of 4 non-zero bytes, that internal message will be handled with a corresponding binary receiver `receive(msg: MessageStruct){:tact}` or the catch-all slice receiver `receive(msg: Slice){:tact}`, if there is no binary receiver for that opcode.
69+
70+
```tact
71+
// This message struct overrides its unique id (opcode) with 411,
72+
// which allows message bodies that start with such opcodes
73+
// to be recognized and handled by the respective binary receiver function.
74+
message(411) HandleMe {}
75+
76+
contract Handler() {
77+
receive(msg: HandleMe) {
78+
let body = inMsg();
79+
body.preloadUint(32) == HandleMe.opcode(); // true
80+
}
81+
}
82+
```
83+
84+
## Processing order
85+
86+
All receiver functions are processed in the order they are listed below. The first receiver that matches the message type processes the message:
1687

1788
* `receive(){:tact}` - called when an empty message is sent to the contract
1889
* `receive("message"){:tact}` - called when a text message with a specific comment is sent to the contract (maximum `"message"{:tact}` length is 123 bytes)
@@ -50,13 +121,7 @@ In a contract, the order of declaration of receivers has no effect on how receiv
50121

51122
Contracts are not required to declare receivers for all possible message types. If a contract does not have a receiver for a specific message type, the message will be processed by the next receiver that matches the message type in the receiver execution order list. For example, if we remove the receiver `receive("message"){:tact}` in the above contract, then when a message with the comment `"message"{:tact}` arrives, it will be processed by `receive(str: String){:tact}`. yet, the message with an empty comment `""{:tact}` will be processed by the empty body receiver, `receive(){:tact}`.
52123

53-
Processing and distinguishing the text receivers, like the comment receiver `receive("..."){:tact}` and the string receiver `receive(str: String){:tact}`, costs significantly more gas than processing binary ones, such as `receive(){:tact}` or `receive(msg: MyMessage){:tact}`. Thus, it is recommended to [prefer binary receivers to text receivers](/book/gas-best-practices#prefer-binary-receivers-to-text-receivers).
54-
55-
Note that the receiver `receive(msg: Slice){:tact}` acts as a fallback that catches all messages that did not match previous receivers in the execution order list.
56-
57-
If there is no receiver to process a message type and the fallback receiver `receive(msg: Slice){:tact}` is not declared, the transaction will fail with exit code [130](/book/exit-codes/#130).
58-
59-
Receivers accept all incoming funds by default. That is, without explicitly sending a message that will refund spare Toncoin with the [`cashback(){:tact}`](/ref/core-send#cashback) function, all the incoming message value will be kept by the contract.
124+
Note that the receiver `receive(msg: Slice){:tact}` acts as a fallback that catches all messages that did not match previous receivers in the execution order list. If there is no receiver to process a message type and the fallback receiver `receive(msg: Slice){:tact}` is not declared, the transaction will fail with exit code [130](/book/exit-codes/#130).
60125

61126
Receivers accept all incoming funds by default. That is, without explicitly sending a message that will refund spare Toncoin with the [`cashback(){:tact}`](/ref/core-send#cashback) function, the contract will keep all the incoming message value.
62127

0 commit comments

Comments
 (0)