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

Commit

Permalink
Merge branch 'main' into full-zh-example
Browse files Browse the repository at this point in the history
  • Loading branch information
sansx committed Aug 28, 2024
2 parents ca7512a + aa77a64 commit f30c4ca
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 17 deletions.
78 changes: 72 additions & 6 deletions pages/book/cells.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,86 @@ While you may use them for [manual parsing](#cnp-manually) of the cells, it's st

Similar to serialization options of [`Int{:tact}`](/book/integers) type, `Cell{:tact}`, `Builder{:tact}` and `Slice{:tact}` also have various representations for encoding their values in the following cases:

* as fields of [contracts](/book/contracts) and [traits](/book/types#traits),
* as fields of [Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages),
* and as key/value types of [maps](/book/maps).
* as [storage variables](/book/contracts#variables) of [contracts](/book/contracts) and [traits](/book/types#traits),
* and as fields of [Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages).

```tact
```tact {2-3}
contract SerializationExample {
someCell: Cell as remaining;
someSlice: Slice as bytes32;
// Constructor function,
// necessary for this example contract to compile
init() {
self.someCell = emptyCell();
self.someSlice = beginCell().storeUint(42, 256).asSlice();
}
}
```

### `remaining` [#serialization-remaining]

The `remaining{:tact}` serialization option can be applied to values of [`Cell{:tact}`](#cells), [`Builder{:tact}`](#builders) and [`Slice{:tact}`](#slices) types.

It affects the process of constructing and parsing cell values by causing them to be stored and loaded directly rather than as a reference. To draw parallels with [cell manipulation instructions](#cells-immutability), specifying `remaining{:tact}` is like using [`Builder.storeSlice(){:tact}`][b-5] and [`Slice.loadSlice(){:tact}`][s-5] instead of [`Builder.storeRef(){:tact}`][b-8] and [`Slice.loadRef(){:tact}`][s-8], which are to be used by default.

In addition, the [TL-B][tlb] representation produced by Tact changes too:

```tact {3-5, 8-10}
contract SerializationExample {
// By default
cRef: Cell; // ^cell in TL-B
bRef: Builder; // ^builder in TL-B
sRef: Slice; // ^slice in TL-B
// With `remaining`
cRem: Cell as remaining; // remainder<cell> in TL-B
bRem: Builder as remaining; // remainder<builder> in TL-B
sRem: Slice as remaining; // remainder<slice> in TL-B
// Constructor function,
// necessary for this example contract to compile
init() {
self.cRef = emptyCell();
self.bRef = beginCell();
self.sRef = emptySlice();
self.cRem = emptyCell();
self.bRem = beginCell();
self.sRem = emptySlice();
}
}
```

There, `^cell`, `^builder` and `^slice` in [TL-B][tlb] syntax mean the reference to [`Cell{:tact}`](#cells), [`Builder{:tact}`](#builders) and [`Slice{:tact}`](#slices) values respectively, while the `remainder<…>` of `cell`, `builder` or `slice` tells that the given value would be stored as a `Slice{:tact}` directly and not as a reference.

Now, to give a real-world example, imagine that you need to notice and react to inbound [jetton][jetton] transfers in your smart contract. The appropriate [Message][message] structure for doing so would look something like this:

```tact /remaining/
message(0x7362d09c) JettonTransferNotification {
queryId: Int as uint64; // arbitrary request number to prevent replay attacks
amount: Int as coins; // amount of jettons transferred
sender: Address; // address of the sender of the jettons
forwardPayload: Slice as remaining; // optional custom payload
}
```

### `remaining` [#serialization-bytes64]
And the [receiver][recv] in the contract would look like this:

```tact
receive(msg: JettonTransferNotification) {
// ... you do you ...
}
```

Upon receiving a [jetton][jetton] transfer notification message, its cell body is converted into a [`Slice{:tact}`](#slices) and then parsed as a `JettonTransferNotification{:tact}` [Message][message]. At the end of this process, the `forwardPayload` will have all the remaining data of the original message cell.

Here, it's not possible to violate the [jetton][jetton] standard by placing the `forwardPayload: Slice as remaining` field in any other position in the `JettonTransferNotification{:tact}` [Message][message]. That's because Tact prohibits usage of `as remaining{:tact}` for any but the last field of the [Structs][struct] and [Messages][message] to prevent misuse of the contract storage and reduce gas consumption.

<Callout>

To be resolved by [#26](https://github.com/tact-lang/tact-docs/issues/26).
Note, that the cell serialized via `as remaining{:tact}` cannot be [optional](/book/optional). That is, specifying something like `Cell? as remaining{:tact}`, `Builder? as remaining{:tact}` or `Slice? as remaining{:tact}` would cause a compilation error.

Also note, that specifying `remaining{:tact}` for the `Cell{:tact}` as the [map](/book/maps) value type is considered an error and it won't compile.

</Callout>

Expand Down Expand Up @@ -373,9 +437,11 @@ let areSlicesNotEqual = aSlice.hash() != bSlice.hash(); // false
[p]: /book/types#primitive-types
[struct]: /book/structs-and-messages#structs
[message]: /book/structs-and-messages#messages
[recv]: /book/contracts#receiver-functions

[tvm]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
[tlb]: https://docs.ton.org/develop/data-formats/tl-b-language
[jetton]: https://docs.ton.org/develop/dapps/asset-processing/jettons
[sha-2]: https://en.wikipedia.org/wiki/SHA-2#Hash_standard

[quadtree]: https://en.wikipedia.org/wiki/Quadtree
Expand Down
2 changes: 1 addition & 1 deletion pages/book/integers.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,6 @@ Here, `oneByte` is serialized as a [`uint8`](#serialization-types), which occupi
Therefore, be **very** careful with numbers and always double-check calculations when using serialization.
</Callout>

[tlb]: https://docs.ton.org/develop/data-formats/tl-b-languagehttps://docs.ton.org/develop/data-formats/tl-b-language
[tlb]: https://docs.ton.org/develop/data-formats/tl-b-language
[tlb-builtin]: https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types
[varuint]: https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n
16 changes: 8 additions & 8 deletions pages/book/maps.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ let fizz: map<Int, Int> = emptyMap();
fizz.set(68, 0);
// Getting the value by its key
let gotButUnsure: String? = fizz.get(68); // returns String or null, therefore the type is String?
let mustHaveGotOrErrored: String = fizz.get(68)!!; // explicitly asserting that the value must not be null,
// which may crush at runtime if the value is, in fact, null
let gotButUnsure: Int? = fizz.get(68); // returns Int or null, therefore the type is Int?
let mustHaveGotOrErrored: Int = fizz.get(68)!!; // explicitly asserting that the value must not be null,
// which may crush at runtime if the value is, in fact, null
// Alternatively, we can check for the key in the if statement
if (gotButUnsure != null) {
// Hooray, let's use !! without fear now and cast String? to String
let definitelyGotIt: String = fizz.get(68)!!;
// Hooray, let's use !! without fear now and cast Int? to Int
let definitelyGotIt: Int = fizz.get(68)!!;
} else {
// Do something else...
}
Expand Down Expand Up @@ -304,11 +304,11 @@ contract Example {
const MaxMapSize: Int = 42;
// Persistent state variables
arr: map<Int, Int>; // "array" of String values as a map
arrLength: Int = 0; // length of the "array", defaults to 0
arr: map<Int, Int>; // "array" of Int values as a map
arrLength: Int = 0; // length of the "array", defaults to 0
// Internal function for pushing an item to the end of the "array"
fun arrPush(item: String) {
fun arrPush(item: Int) {
if (self.arrLength >= self.MaxMapSize) {
// Do something, stop the operation, for example
} else {
Expand Down
2 changes: 1 addition & 1 deletion pages/book/statements.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ do {

The `foreach{:tact}` loop operates on key-value pairs (entries) of [`map<K, V>{:tact}`](/book/maps) type in sequential order: from the smallest keys of the map to the biggest ones.

This loop executes a block of code for each entry in the given map, capturing the key and value on each iteration. This is handy when you don't know in advance how many items there is in the map or don't want to explicitly look for each of the entry using [`.set(){:tact}`](/book/maps#set) [method](/book/functions#extension-function) of maps.
This loop executes a block of code for each entry in the given map, capturing the key and value on each iteration. This is handy when you don't know in advance how many items there is in the map or don't want to explicitly look for each of the entry using [`.get(){:tact}`](/book/maps#get) [method](/book/functions#extension-function) of maps.

Note, that the names of captured key and value pair on each iteration are arbitrary and can be any valid Tact identifier, provided that they're new to the current scope. The most common options are: `k` and `v`, or `key` and `value`.

Expand Down
16 changes: 16 additions & 0 deletions pages/ecosystem/tools/misti.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Misti

[Misti](https://nowarp.github.io/tools/misti/) is a static program analysis tool that supports Tact.

## What is Misti?

* **Static Program Analysis**: Misti analyzes code without executing it, scanning for [bugs and security flaws](https://nowarp.github.io/tools/misti/docs/detectors) by examining the structure and syntax. This approach catches issues early, preventing them from reaching production.
* **Custom Detectors**: Customize Misti to your specific needs by creating [custom detectors](https://nowarp.github.io/tools/misti/docs/hacking/custom-detector). This helps identify vulnerabilities that generic tools might miss, ensuring a thorough review of your code.
* **CI/CD Integration**: [Integrate](https://nowarp.github.io/tools/misti/docs/tutorial/ci-cd) Misti into your CI/CD pipeline to ensure continuous code quality checks, catching issues before they make it to production.

## Resources

* [Github](https://github.com/nowarp/misti)
* [Telegram Community](https://t.me/misti_dev)
* [Misti Documentation](https://nowarp.github.io/docs/misti/)
* [Misti API Reference](https://nowarp.github.io/docs/misti/api)
7 changes: 6 additions & 1 deletion pages/ecosystem/tools/overview.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ This sub-section contains a list of official and community-made tools made speci
title="Typescript"
href="/ecosystem/tools/typescript"
/>
<Cards.Card
arrow
title="Misti Static Analyzer"
href="/ecosystem/tools/misti"
/>
<Cards.Card
arrow
title="VS Code Extension"
Expand All @@ -20,4 +25,4 @@ This sub-section contains a list of official and community-made tools made speci
title="JetBrains IDEs Plugin"
href="/ecosystem/tools/jetbrains"
/>
</Cards>
</Cards>

0 comments on commit f30c4ca

Please sign in to comment.