Skip to content
This repository was archived by the owner on Dec 12, 2024. It is now read-only.

Commit d285e25

Browse files
feat: add jetton cookbook (#380)
* feat: add jetton cookbook * fix: fix typos * fix: fix after review * fix: fixes after review * fix: add rawSlice --------- Co-authored-by: Aliaksandr Bahdanau <[email protected]>
1 parent 61c0386 commit d285e25

File tree

1 file changed

+154
-3
lines changed

1 file changed

+154
-3
lines changed

pages/cookbook/jettons.mdx

+154-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,160 @@
11
# Fungible Tokens (Jettons)
22

3-
import { Callout } from 'nextra/components'
3+
import { Callout } from 'nextra-theme-docs';
44

5-
<Callout emoji="🚨">
5+
This page lists common examples of working with [jettons](https://docs.ton.org/develop/dapps/asset-processing/jettons).
66

7-
This page is a stub. [Contributions are welcome!](https://github.com/tact-lang/tact-docs/issues)
7+
## Accepting jetton transfer
8+
9+
Transfer notification message have the following structure.
10+
11+
```tact
12+
message(0x7362d09c) JettonTransferNotification {
13+
queryId: Int as uint64;
14+
amount: Int as coins;
15+
sender: Address;
16+
forwardPayload: Slice as remaining;
17+
}
18+
```
19+
20+
Use [receiver](/book/receive) function to accept token notification message.
21+
22+
<Callout type="warning" emoji="⚠️">
23+
24+
Sender of transfer notification must be validated!
25+
26+
</Callout>
27+
28+
Validation can be done using jetton wallet state init and calculating jetton address.
29+
Note, that notifications are coming from YOUR contract's jetton wallet, so [`myAddress()`](/ref/core-common#myaddress) should be used in owner address field.
30+
Wallet initial data layout is shown below, but sometimes it can differ.
31+
Note that `myJettonWalletAddress` may also be stored in contract storage to use less gas in every transaction.
32+
33+
```tact
34+
struct JettonWalletData {
35+
balance: Int as coins;
36+
ownerAddress: Address;
37+
jettonMasterAddress: Address;
38+
jettonWalletCode: Cell;
39+
}
40+
41+
fun calculateJettonWalletAddress(ownerAddress: Address, jettonMasterAddress: Address, jettonWalletCode: Cell): Address {
42+
let initData = JettonWalletData{
43+
balance: 0,
44+
ownerAddress,
45+
jettonMasterAddress,
46+
jettonWalletCode,
47+
};
48+
49+
return contractAddress(StateInit{code: jettonWalletCode, data: initData.toCell()});
50+
}
51+
52+
contract Sample {
53+
jettonWalletCode: Cell;
54+
jettonMasterAddress: Address;
55+
56+
init(jettonWalletCode: Cell, jettonMasterAddress: Address) {
57+
self.jettonWalletCode = jettonWalletCode;
58+
self.jettonMasterAddress = jettonMasterAddress;
59+
}
60+
61+
receive(msg: JettonTransferNotification) {
62+
let myJettonWalletAddress = calculateJettonWalletAddress(myAddress(), self.jettonMasterAddress, self.jettonWalletCode);
63+
require(sender() == myJettonWalletAddress, "Notification not from your jetton wallet!");
64+
65+
// your logic of processing token notification
66+
}
67+
}
68+
```
69+
70+
## Sending jetton transfer
71+
72+
To send jetton transfer use [`send(){:tact}`](/book/send) function.
73+
Note that `myJettonWalletAddress` may also be stored in contract storage to use less gas in every transaction.
74+
75+
```tact
76+
message(0xf8a7ea5) JettonTransfer {
77+
queryId: Int as uint64;
78+
amount: Int as coins;
79+
destination: Address;
80+
responseDestination: Address?;
81+
customPayload: Cell? = null;
82+
forwardTonAmount: Int as coins;
83+
forwardPayload: Slice as remaining;
84+
}
85+
86+
receive("send") {
87+
let myJettonWalletAddress = calculateJettonWalletAddress(myAddress(), self.jettonMasterAddress, self.jettonWalletCode);
88+
send(SendParameters{
89+
to: myJettonWalletAddress,
90+
value: ton("0.05"),
91+
body: JettonTransfer{
92+
queryId: 42,
93+
amount: jettonAmount, // jetton amount you want to transfer
94+
destination: msg.userAddress, // address you want to transfer jettons. Note that this is address of jetton wallet owner, not jetton wallet itself
95+
responseDestination: msg.userAddress, // address where to send a response with confirmation of a successful transfer and the rest of the incoming message Toncoins
96+
customPayload: null, // in most cases will be null and can be omitted. Needed for custom logic on Jetton Wallets itself
97+
forwardTonAmount: 1, // amount that will be transferred with JettonTransferNotification. Needed for custom logic execution like in example below. If the amount is 0 notification won't be sent
98+
forwardPayload: rawSlice("F") // precomputed beginCell().storeUint(0xF, 4).endCell().beginParse(). This works for simple transfer, if needed any struct can be used as `forwardPayload`
99+
}.toCell(),
100+
});
101+
}
102+
```
103+
104+
## Burning jetton
105+
106+
```tact
107+
message(0x595f07bc) JettonBurn {
108+
queryId: Int as uint64;
109+
amount: Int as coins;
110+
responseDestination: Address?;
111+
customPayload: Cell? = null;
112+
}
113+
114+
receive("burn") {
115+
let myJettonWalletAddress = calculateJettonWalletAddress(myAddress(), self.jettonMasterAddress, self.jettonWalletCode);
116+
send(SendParameters{
117+
to: myJettonWalletAddress,
118+
body: JettonBurn{
119+
queryId: 42,
120+
amount: jettonAmount, // jetton amount you want to burn
121+
responseDestination: someAddress, // address where to send a response with confirmation of a successful burn and the rest of the incoming message coins
122+
customPayload: null, // in most cases will be null and can be omitted. Needed for custom logic on jettons itself
123+
}.toCell(),
124+
});
125+
}
126+
```
127+
128+
## USDT jetton operations
129+
130+
Operations with USDT (on TON) remain the same, except that the `JettonWalletData` will have the following structure:
131+
132+
```tact
133+
struct JettonWalletData {
134+
status: Ins as uint4;
135+
balance: Int as coins;
136+
ownerAddress: Address;
137+
jettonMasterAddress: Address;
138+
}
139+
```
140+
141+
Function to calculate wallet address will look like this:
142+
143+
```tact
144+
fun calculateJettonWalletAddress(ownerAddress: Address, jettonMasterAddress: Address, jettonWalletCode: Cell): Address {
145+
let initData = JettonWalletData{
146+
status: 0,
147+
balance: 0,
148+
ownerAddress,
149+
jettonMasterAddress,
150+
};
151+
152+
return contractAddress(StateInit{code: jettonWalletCode, data: initData.toCell()});
153+
}
154+
```
155+
156+
<Callout type="info" emoji="🤔">
157+
158+
Didn't find your favorite example of a jettons communication? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact-docs/issues)
8159

9160
</Callout>

0 commit comments

Comments
 (0)