diff --git a/pages/book/cells.en.mdx b/pages/book/cells.en.mdx index 1db35995..cc04bfec 100644 --- a/pages/book/cells.en.mdx +++ b/pages/book/cells.en.mdx @@ -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 in TL-B + bRem: Builder as remaining; // remainder in TL-B + sRem: Slice as remaining; // remainder 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. - 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. @@ -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 diff --git a/pages/book/integers.en.mdx b/pages/book/integers.en.mdx index b37191a2..793e35ee 100644 --- a/pages/book/integers.en.mdx +++ b/pages/book/integers.en.mdx @@ -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. -[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 diff --git a/pages/book/maps.en.mdx b/pages/book/maps.en.mdx index c7f48038..67a5350f 100644 --- a/pages/book/maps.en.mdx +++ b/pages/book/maps.en.mdx @@ -80,14 +80,14 @@ let fizz: map = 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... } @@ -304,11 +304,11 @@ contract Example { const MaxMapSize: Int = 42; // Persistent state variables - arr: map; // "array" of String values as a map - arrLength: Int = 0; // length of the "array", defaults to 0 + arr: map; // "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 { diff --git a/pages/book/statements.en.mdx b/pages/book/statements.en.mdx index 18b908a7..1b62db13 100644 --- a/pages/book/statements.en.mdx +++ b/pages/book/statements.en.mdx @@ -289,7 +289,7 @@ do { The `foreach{:tact}` loop operates on key-value pairs (entries) of [`map{: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`. diff --git a/pages/ecosystem/tools/misti.mdx b/pages/ecosystem/tools/misti.mdx new file mode 100644 index 00000000..761ceeff --- /dev/null +++ b/pages/ecosystem/tools/misti.mdx @@ -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) diff --git a/pages/ecosystem/tools/overview.en.mdx b/pages/ecosystem/tools/overview.en.mdx index 57038105..3e386dc3 100644 --- a/pages/ecosystem/tools/overview.en.mdx +++ b/pages/ecosystem/tools/overview.en.mdx @@ -10,6 +10,11 @@ This sub-section contains a list of official and community-made tools made speci title="Typescript" href="/ecosystem/tools/typescript" /> + - \ No newline at end of file +