You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -52,11 +52,11 @@ This folder contains your smart contract source code written in one of the avail
52
52
53
53
### `/wrappers`
54
54
55
-
While `@ton/ton SDK` provides us interfaces of serializing and sending messages for standard smart-contracts such as `wallets`, if we develop our own smart-contract that will deserialize received messages by its own custom protocol we need to provide some wrapper object that will serialize messages sent to smart-contract, deserialize responses from `get method`s and serialize contract itself for deployment.
55
+
To interact with your smart-contract off-chain you need to serialize and desirialize messages sended to it. `Wrapper` classes developed to mirror your smart-contract implementation making it simple to use it's functionality.
56
56
57
57
### `/tests`
58
58
59
-
This directory contains test files for your smart contracts. Testing contracts directly in TON network is not the best option because it requires some amount of time and may lead to losing funds. This testing playground tool allow you to execute multiple smart-contracts and even send messages between them in your "local network". Tests are crucial for ensuring your smart contracts behave as expected before deployment to the network.
59
+
This directory contains test files for your smart contracts. Testing contracts directly in TON network is not the best option because it requires some amount of time and may lead to losing funds. This testing playground tool allow you to execute multiple smart-contracts and even send messages between them in your **"local network"**. Tests are crucial for ensuring your smart contracts behave as expected before deployment to the network.
Copy file name to clipboardExpand all lines: docs/v3/guidelines/quick-start/developing-smart-contracts/deploying-to-network.mdx
+8-11Lines changed: 8 additions & 11 deletions
Original file line number
Diff line number
Diff line change
@@ -6,17 +6,17 @@ In this part of the guide we will proceed to deployment of previously developed
6
6
7
7
## Address and initial state
8
8
9
-
We already know that [address](/v3/documentation/smart-contracts/addresses/) is unique identifier of `smart-contract`, i.e `actor`, `account`in network which is used to send transactions and verify their sender upon receive but we still didn't discussed how it's created. The common formula of smart-contract address looks like that:
9
+
We already know that [address](/v3/documentation/smart-contracts/addresses/) is unique identifier of `smart-contract`in network which is used to send transactions and verify their sender upon receive, but we still didn't discussed how it's created. The common formula of smart-contract address looks like that:
10
10
11
11
***address=hash(state_init(code, data))***
12
12
13
13
Address of smart-contract is a hash of aggregated initial code and data of smart-contracts upon deployment. This simple mechanism have few important consequences:
14
14
15
15
### You already know the address
16
16
17
-
In TON any address that didn't accept any transaction and, as a consequnce, dont have any data is considered in `nonexzist` state, nethertheless when we created a wallet using wallet app in [Getting started](/v3/guidelines/quick-start/getting-started) section we still was able to get address of our **future** wallet smart-contract from wallet app before it's deployment and examine it in explorer.
17
+
In TON any address that don't have any data is considered in `nonexistent` state, nevertheless when we created a wallet using wallet app in [Getting started](/v3/guidelines/quick-start/getting-started) section we still was able to get address of our **future** wallet smart-contract from wallet app before it's deployment and examine it in explorer.
18
18
19
-
The reason behind that is because creating your private and public key pair through **mnemonic phrase**, where second key is part of initial data of smart-contract makes `state_init` of our contract fully determent:
19
+
The reason behind that is because creating your **private** and **public** key pair through **mnemonic phrase**, where second key is part of initial data of smart-contract makes `state_init` of our contract fully determent:
20
20
-**code** is one of the standard wallet implementation, like `v5r1`.
21
21
-**data** is `public_key` with other default initialized fields.
22
22
@@ -40,7 +40,7 @@ init(id: Int, owner: Address) {
40
40
}
41
41
```
42
42
43
-
If we remove `id` field from its initial storage we can ensure that **only one**`CounterInternal` smart-cotnract could exzist for a particular owner, moreover, if we consider owner as wallet smart-contract, by knowing its public_key and version we could calculate wallet address and, as a consequnce, address of its `CounterInternal` contract.
43
+
If we remove `id` field from its initial storage we can ensure that **only one**`CounterInternal` smart-cotnract could exzist for a particular owner.
44
44
45
45
:::info Tokens
46
46
This mechanism plays cruicial role in [Jetton Processing](v3/guidelines/dapps/asset-processing/jettons), each non-native(jetton) token requires it's own `Jetton Wallet` for a particular owner and therefore provides a calculatable address from it, creating a **star scheme** with basic wallet in center.
@@ -50,23 +50,19 @@ This mechanism plays cruicial role in [Jetton Processing](v3/guidelines/dapps/as
50
50
51
51
Now, when our smart-contracts is fully tested, we are ready to deploy them into the TON. In `Blueprint SDK` this process is the same for both `mainnet` and `testnet` and any of the presented languages in guide: `FunC`, `Tact`, `Tolk`. Deploy scripts relays on the same wrappers that you have used in testing scripts:
Copy file name to clipboardExpand all lines: docs/v3/guidelines/quick-start/developing-smart-contracts/processing-messages.mdx
+85-84Lines changed: 85 additions & 84 deletions
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ import TabItem from '@theme/TabItem';
5
5
6
6
> **Summary:** In previous steps we modified our smart-contract interaction with `storage, `get methods` and learned basic smart-contract development flow.
7
7
8
-
Now that we have learned basic examples of modifying smart-contract code and using development tools, we are ready to move on to the main functionality of smart contracts - sending and receiving messages. In TON messages not only used for sending currency, but also as data-exchange mechanism between smart-contracts.
8
+
Now we are ready to move on to the main functionality of smart contracts - **sending and receiving messages**. In TON messages not only used for sending currency, but also as data-exchange mechanism between smart-contracts.
9
9
10
10
11
11
:::tip
@@ -18,81 +18,14 @@ If you are stuck on some of the examples you can find original template project
18
18
19
19
Before we proceed to implementation let's briefly describe main ways and patterns that we can use to process internal messages.
20
20
21
-
### Operations
22
-
23
-
Common pattern in TON contracts is to include a **32-bit operation code** in message bodies which tells your contract what action to perform:
24
-
25
-
<TabsgroupId="language">
26
-
<TabItemvalue="FunC"label="FunC">
27
-
```func
28
-
;; This is NOT a part of the project, just an example!
//This is NOT a part of the project, just an example!
59
-
const op::increment : int = 1;
60
-
const op::decrement : int = 2;
61
-
62
-
fun onInternalMessage(myBalance: int, msgValue: int, msgFull: cell, msgBody: slice) {
63
-
// Step 1: Check if the message is empty
64
-
if (slice.isEndOfSlice()) {
65
-
return; // Nothing to do with empty messages
66
-
}
67
-
68
-
// Step 2: Extract the operation code
69
-
var op = in_msg_body~load_uint(32);
70
-
71
-
// Step 3-7: Handle the requested operation
72
-
if (op == op::increment) {
73
-
increment(); //call to specific operation handler
74
-
return;
75
-
} else if (op == op::decrement) {
76
-
decrement();
77
-
// Just accept the money
78
-
return;
79
-
}
80
-
81
-
// Unknown operation
82
-
throw(0xffff);
83
-
}
84
-
```
85
-
</TabItem>
86
-
</Tabs>
87
-
88
21
### Actors and roles
89
22
90
23
Since TON implements [actor](/v3/concepts/dive-into-ton/ton-blockchain/blockchain-of-blockchains/#single-actor) model it's natural to think about smart-contracts relations in terms of `roles`, determining who can access smart-contract functionality or not. The most common examples of roles are:
91
24
92
25
-`anyone`: any contract that don't have distinct role.
93
26
-`owner`: contract that has exclusive access to some crucial parts of functionality.
94
27
95
-
Let's examine `recv_internal` function signature to understdand how we could use that:
28
+
Let's examine `recv_internal` function signature to understand how we could use that:
//This is NOT a part of the project, just an example!
150
+
const op::increment : int = 1;
151
+
const op::decrement : int = 2;
152
+
153
+
fun onInternalMessage(myBalance: int, msgValue: int, msgFull: cell, msgBody: slice) {
154
+
// Step 1: Check if the message is empty
155
+
if (slice.isEndOfSlice()) {
156
+
return; // Nothing to do with empty messages
157
+
}
158
+
159
+
// Step 2: Extract the operation code
160
+
var op = in_msg_body~load_uint(32);
161
+
162
+
// Step 3-7: Handle the requested operation
163
+
if (op == op::increment) {
164
+
increment(); //call to specific operation handler
165
+
return;
166
+
} else if (op == op::decrement) {
167
+
decrement();
168
+
// Just accept the money
169
+
return;
170
+
}
171
+
172
+
// Unknown operation
173
+
throw(0xffff);
174
+
}
175
+
```
176
+
</TabItem>
177
+
</Tabs>
178
+
179
+
178
180
By combining both of these patterns you can achieve a comprehensive description of your smart-contract's systems ensuring secure interaction between them and unleash full potential of TON actors model.
179
181
180
182
## Implementation in Tact
@@ -244,7 +246,7 @@ Example/
244
246
245
247
At the top of the generated contract file: `counter_internal.tact`, you may see a [message](https://docs.tact-lang.org/book/structs-and-messages/) definition:
246
248
247
-
```tact title="counter_internal.tact"
249
+
```tact title="/contracts/counter_internal.tact"
248
250
message Add {
249
251
queryId: Int as uint64;
250
252
amount: Int as uint32;
@@ -253,7 +255,7 @@ message Add {
253
255
254
256
A message is a basic structure for communication between contracts. Tact automatically serializes and deserializes messages into cells. To ensure that opcodes will be the same during message structure changes, it may be added like below:
255
257
256
-
```tact title="counter_internal.tact"
258
+
```tact title="/contracts/counter_internal.tact"
257
259
message(0x7e8764ef) Add {
258
260
queryId: Int as uint64;
259
261
amount: Int as uint32;
@@ -293,7 +295,7 @@ counter: Int as uint32;
293
295
294
296
To ensure that only the contract owner can interact with specific functions, add an `owner` field:
295
297
296
-
```tact title="counter_internal.tact"
298
+
```tact title="/contracts/counter_internal.tact"
297
299
id: Int as uint32;
298
300
counter: Int as uint32;
299
301
owner: Address;
@@ -305,7 +307,7 @@ These fields are serialized similarly to structures and stored in the contract's
305
307
306
308
If you compile the contract at this stage, you will encounter the error: `Field "owner" is not set`. This is because the contract needs to initialize its fields upon deployment. Define an [`init()`](https://docs.tact-lang.org/book/contracts/#init-function) function to do this:
To accept messages from other contracts, use a [receiver](https://docs.tact-lang.org/book/functions/#receiver-functions) function. Receiver functions automatically match the message's opcode and invoke the corresponding function:
319
321
320
-
```tact title="counter_internal.tact"
322
+
```tact title="/contracts/counter_internal.tact"
321
323
receive(msg: Add) {
322
324
self.counter += msg.amount;
323
325
self.notify("Cashback".asComment());
@@ -328,7 +330,7 @@ receive(msg: Add) {
328
330
329
331
To ensure that only the contract owner can send messages, use the `require` function:
330
332
331
-
```tact title="counter_internal.tact"
333
+
```tact title="/contracts/counter_internal.tact"
332
334
receive(msg: Add) {
333
335
// `sender()` function is used to retrieve message sender address
334
336
require(sender() == self.owner, "Not owner!");
@@ -343,7 +345,7 @@ receive(msg: Add) {
343
345
344
346
Tact also provides handy ways to share same logic through [traits](https://docs.tact-lang.org/book/types/#traits). Use the `Ownable` trait, which provides built-in ownership checks:
Get function cannot be called from another contract.
371
373
:::
372
374
373
-
```tact title="counter_internal.tact"
375
+
```tact title="/contracts/counter_internal.tact"
374
376
get fun counter(): Int {
375
377
return self.counter;
376
378
}
@@ -380,7 +382,7 @@ Note, that the `owner` getter is automatically defined via the `Ownable` trait.
380
382
381
383
#### Complete contract
382
384
383
-
```tact title="counter_internal.tact"
385
+
```tact title="/contracts/counter_internal.tact"
384
386
import "@stdlib/deploy";
385
387
import "@stdlib/ownable";
386
388
@@ -436,15 +438,15 @@ npm blueprint build
436
438
437
439
[Wrappers](https://docs.tact-lang.org/book/compile/#wrap-ts) facilitate contract interaction from TypeScript. Unlike in FunC or Tolk, they are generated automatically during the build process:
@@ -540,7 +542,7 @@ Let's modify our smart-contract to recieve external messages and send increase c
540
542
541
543
Add `recv_external` function to `HelloWorld` smart-contract:
542
544
543
-
```func title="HelloWorld.fc"
545
+
```func title="/contracts/HelloWorld.fc"
544
546
() recv_external(slice in_msg) impure {
545
547
accept_message();
546
548
@@ -578,7 +580,7 @@ npm blueprint build
578
580
579
581
And add wrapper method to call it through our wrapper class for sending external message:
580
582
581
-
```typescript
583
+
```typescript title="/wrappers/HelloWorld.ts"
582
584
asyncsendExternalIncrease(
583
585
provider: ContractProvider,
584
586
opts: {
@@ -603,7 +605,7 @@ async sendExternalIncrease(
603
605
604
606
Update test to esnure that `HelloWorld` contract recieved internal message, sended internal message to `CounterInternal` contract and both updated their counters:
@@ -693,4 +695,3 @@ Verify that all examples is correct by running test script:
693
695
npm blueprint test
694
696
```
695
697
696
-
Congratulations! You have successfully created a **multi-contract** system and learned how to handle **internal** and **external** messages. This example illustrates the typical flow of any message chain: sending an `external message`, triggering the `internal messages` flow based on your system model, and so on. Now that our contracts have been fully tested, we are ready to deploy them and interact with them on-chain.
0 commit comments