This is the full developer documentation for ⚡ Tact Documentation
---
# Learn all about programming in Tact
> Tact is a powerful programming language for TON Blockchain focused on efficiency and simplicity. It is designed to be easy to learn and use, and to be a good fit for smart contracts. Tact is a statically typed language with a simple syntax and a powerful type system.
## 🚀 Let’s start\
ㅤ
1. #### Ensure that the supported version of Node.js is installed and available[](#start-1)
To check it, run `node --version` — it should show you the version 22.0.0 or later.
2. #### Run the following command[](#start-2)
It will create a new project with a simple counter contract:
* yarn
```shell
# recommended
yarn create ton simple-counter --type tact-counter --contractName SimpleCounter
```
* npm
```shell
npm create ton@latest -- simple-counter --type tact-counter --contractName SimpleCounter
```
* pnpm
```shell
pnpm create ton@latest simple-counter --type tact-counter --contractName SimpleCounter
```
* bun
```shell
bun create ton@latest simple-counter --type tact-counter --contractName SimpleCounter
```
3. #### That’s it\
Your first contract project has already been written and compiled!
Check it out by moving into the relevant directory — `cd simple-counter/contracts`. Here’s what it would look like:
```tact
message Add {
queryId: Int as uint64;
amount: Int as uint32;
}
contract SimpleCounter(
id: Int as uint32,
counter: Int as uint32,
) {
// Empty receiver for the deployment
receive() {
// Forward the remaining value in the
// incoming message back to the sender
cashback(sender());
}
receive(msg: Add) {
self.counter += msg.amount;
// Forward the remaining value in the
// incoming message back to the sender
cashback(sender());
}
get fun counter(): Int {
return self.counter;
}
get fun id(): Int {
return self.id;
}
}
```
To re-compile or deploy, refer to the commands in the scripts section of `package.json` in the root of this newly created project and to the documentation of [Blueprint](https://github.com/ton-org/blueprint) — this is the tool we’ve used to create and compile your first simple counter contract in Tact. Blueprint can do much more than that: including tests, customizations, and more.
## 🤔 Where to go next?[](#next)
ㅤ
1. #### Have some blockchain knowledge already?[](#next-1)
See the [Tact Cookbook](/cookbook), which is a handy collection of everyday tasks (and solutions) every Tact developer faces during smart contract development. Use it to avoid reinventing the wheel.
Alternatively, check the following scenic tours and cheat sheets to get started right away:
[⚡ Learn Tact in Y minutes ](/book/learn-tact-in-y-minutes)
2. #### Want to know more?[](#next-2)
For further guidance on compilation, testing, and deployment see the respective pages:
* [Testing and debugging](/book/debug) page tells you everything about debugging Tact contracts
* [Deployment](/book/deploy) page shows what deployment looks like and helps you harness the powers of [Blueprint](https://github.com/ton-org/blueprint) for it.
For custom plugins for your favorite editor and other tooling see the [Ecosystem](/ecosystem) section.
Alternatively, take a look at the following broader sections:
* [Book](/book) helps you learn the language step-by-step
* [Cookbook](/cookbook) gives you ready-made recipes of Tact code
* [Reference](/ref) provides a complete glossary of the standard library, grammar and evolution process
* Finally, [Ecosystem](/ecosystem) describes “what’s out there” in the Tact’s and TON’s ecosystems
[📚 Read the Book of Tact ](/book)
[🍲 Grind the Cookbook ](/cookbook)
[🔬 Skim the Reference ](/ref)
[🗺️ Embrace the Ecosystem ](/ecosystem)
3. #### Feeling a bit uncomfortable?[](#next-3)
If you ever get stuck, try searching — the search box is at the top of the documentation. There is also a handy `Ctrl` + `K` shortcut to focus and start the search as you type.
If you can’t find the answer in the docs, or you’ve tried to do some local testing and it still didn’t help — don’t hesitate to reach out to Tact’s flourishing community:
[✈️ Telegram Group ](https://t.me/tactlang)
[🐦 X/Twitter ](https://twitter.com/tact_language)
Good luck on your coding adventure with ⚡ Tact!
---
# Assembly functions
> Advanced module-level functions that allow writing TVM instructions directly in the Tact assembly
Available since Tact 1.5
Danger
Current assembly functions are highly experimental and may change in future releases. Please be sure to follow our updates in the [Tact Kitchen](https://t.me/tact_kitchen) or monitor the release changelogs to see when we update this feature.
The change is necessary because the current assembly described and used is a remnant of the current FunC backend of Tact. To further improve compilation speed, reduce gas usage, and provide better type safety, we need to eventually prepare and present our own assembly for composing [Bags of Cells (BoC)](/book/cells#cells-boc) of compiled contracts.
When that happens, almost all the [TVM instructions](#tvm) *inside* the `asm` function bodies on this page will be rewritten.
However, virtually everything else will stay as it is now, including the general syntax of the `asm` function declarations and arrangements, stack calling conventions, and many limitations of assembly functions. After all, the fundamental principles of how TON Blockchain works won’t be changed by internal improvements of Tact, so you should read about both.
Caution
These are very advanced functions that require experience and vigilance in both definitions and usage. Logical errors in them are extremely hard to spot, error messages are abysmal, and type checking isn’t currently provided by Tact.
That said, if you know what you’re doing, they can offer you the smallest possible gas usage, the best performance, and the most control over [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) execution. Remember — with great power comes great responsibility.
Assembly functions (or asm functions for short) are module-level functions that allow you to write Tact assembly. Unlike all other functions, their bodies consist only of [TVM instructions](#tvm) and some other primitives, and don’t use any Tact [statements](/book/statements) or [expressions](/book/expressions).
```tact
// all assembly functions must start with the "asm" keyword
// ↓
asm fun answer(): Int { 42 INT }
// ------
// Notice that the body contains only
// TVM instructions and some primitives,
// like numbers or bitstrings, which serve
// as arguments to the instructions
```
## TVM instructions[](#tvm)
In Tact, the term *TVM instruction* refers to a command that is executed by the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) during its runtime — the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase). Where possible, Tact will try to optimize their use for you, but it won’t define new ones or introduce extraneous syntax for their [pre-processing](https://docs.ton.org/v3/documentation/smart-contracts/fift/fift-and-tvm-assembly). Instead, it is recommended to combine the best of Tact and TVM instructions, as shown in the [`onchainSha256()` example](#onchainsha256) near the end of this page.
Each [TVM instruction](https://docs.ton.org/v3/documentation/tvm/instructions), when converted to its binary representation, is an opcode (operation code) to be executed by the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview), plus some optional arguments written immediately after it. However, when writing instructions in `asm` functions, the arguments, if any, are written before the instruction and are separated by spaces. This [reverse Polish notation (RPN)](https://en.wikipedia.org/wiki/Reverse_Polish_notation) syntax is intended to show the stack-based nature of the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview).
For example, the [`DROP2`](https://docs.ton.org/v3/documentation/tvm/instructions#5B) or its alias [`2DROP`](https://docs.ton.org/v3/documentation/tvm/instructions#5B), which drop (discard) two top values from the stack, have the same opcode prefix — `0x5B`, or `1011011` in binary.
```tact
/// Pushes `a` and `b` onto the stack, then immediately drops them from it
asm fun discardTwo(a: Int, b: Int) { DROP2 }
```
The arguments to [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions) in Tact are called primitives—they don’t manipulate the stack themselves and aren’t pushed onto it by themselves. Attempts to specify a primitive without the instruction that immediately consumes it will result in compilation errors.
```tact
/// COMPILATION ERROR!
/// The 43 was meant to be an argument to some subsequent TVM instruction,
/// but none was found.
asm fun bad(): Int { 43 }
```
For some instructions, the resulting opcode depends on the specified primitive. For example, [`PUSHINT`](https://docs.ton.org/v3/documentation/tvm/instructions#7i), or its shorter alias [`INT`](https://docs.ton.org/v3/documentation/tvm/instructions#7i), has the same opcode `0x7` if the specified numerical argument is in the inclusive range from −5 to 10. However, if the number is outside that range, the opcode changes accordingly: [`0x80`](https://docs.ton.org/v3/documentation/tvm/instructions#80xx) for arguments in the inclusive range from −128 to 127, [`0x81`](https://docs.ton.org/v3/documentation/tvm/instructions#81xxxx) for arguments in the inclusive range from −215 to 215, and so on. For your convenience, all these variations of opcodes are described using the same instruction name; in this case, `PUSHINT`.
```tact
asm fun push42(): Int {
// The following will be converted to 0x80 followed by 0x2A
// in its binary representation for execution by the TVM
42 PUSHINT
}
```
Useful links:
[List of TVM instructions in TON Docs](https://docs.ton.org/v3/documentation/tvm/instructions)
## Stack calling conventions[](#conventions)
The syntax for parameters and returns is the same as for other function kinds, but there is one caveat — argument values are pushed onto the stack before the function body is executed, and the return type is what is captured from the stack afterward.
### Parameters[](#conventions-parameters)
The first parameter is pushed onto the stack first, the second one second, and so on, so that the first parameter is at the bottom of the stack and the last one at the top.
```tact
asm extends fun storeCoins(self: Builder, value: Int): Builder {
// ↑ ↑
// | Pushed last, sits on top of the stack
// Pushed first, sits at the bottom of the stack
// Stores the value of type `Int as coins` into the Builder,
// taking the Builder from the bottom of the stack
// and Int from the top of the stack,
// producing a new Builder back
STVARUINT16
}
```
Since the bodies of `asm` functions do not contain Tact statements, any direct references to parameters in function bodies will be recognized as [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) instructions, which can easily lead to very obscure error messages.
```tact
/// Simply returns the value of `x`
asm fun identity(x: Int): Int { }
/// COMPILATION ERROR!
/// The `BOC` is not recognized as a parameter,
/// but instead is interpreted as a non-existent TVM instruction
asm fun bocchiThe(BOC: Cell): Cell { BOC }
```
The parameters of arbitrary [struct](/book/structs-and-messages#structs) types are distributed over their fields, recursively flattened as the arguments are pushed onto the stack. In particular, the value of the first field of the struct is pushed first, the second is pushed second, and so on, so that the value of the first field is at the bottom of the stack and the value of the last is at the top. If there are nested structures inside those structs, they’re flattened in the same manner.
Note
This behavior of [structs](/book/structs-and-messages#structs) is experimental and may change in future releases of Tact. When in doubt, prefer specifying multiple parameters over a single struct with many fields.
```tact
// Struct with two fields of type Int
struct AB { a: Int; b: Int }
// This will produce the sum of two fields in the `AB` struct
asm fun sum(two: AB): Int { ADD }
// Struct with two nested `AB` structs as its fields
struct Nested { ab1: AB; ab2: AB }
// This will multiply the sums of fields of nested `AB` structs
asm fun mulOfSums(n: Nested): Int { ADD -ROT ADD MUL }
// Action!
fun showcase() {
sum(AB { a: 27, b: 50 }); // 77
// ↑ ↑
// | Pushed last, sits on top of the stack
// Pushed first, sits at the bottom of the stack
mulOfSums(Nested { ab1: AB { a: 1, b: 2 }, ab2: AB { a: 3, b: 4 } }); // 21
// ↑ ↑ ↑ ↑
// | | | Pushed last,
// | | | sits on top of the stack
// | | Pushed second-to-last,
// | | sits below the top of the stack
// | Pushed second,
// | sits just above the bottom of the stack
// Pushed first, sits at the bottom of the stack
}
```
### Returns[](#conventions-returns)
When present, the return type of an assembly function attempts to capture relevant values from the resulting stack after the function execution and possible stack [arrangements](#arrangements). When not present, however, the assembly function does not take any values from the stack.
When present, an assembly function’s return type attempts to grab relevant values from the resulting stack after the function execution and any [result arrangements](#arrangements). If the return type is not present, however, the assembly function does not take any values from the stack.
```tact
// Pushes `x` onto the stack, increments it there,
// but does not capture the result, leaving it on the stack
asm fun push(x: Int) { INC }
```
Specifying a [primitive type](/book/types#primitive-types), such as an [`Int`](/book/integers) or a [`Cell`](/book/cells#cells), will make the assembly function capture the top value from the stack. If the run-time type of the captured value doesn’t match the specified return type, an exception with [exit code 7](/book/exit-codes#7) will be thrown: `Type check error`.
```tact
// CAUSES RUN-TIME ERROR WHEN CALLED!
// Pushes `x` onto the stack, does nothing else with it,
// then tries to capture it as a Cell, causing an exit code 7: Type check error
asm fun push(x: Int): Cell { }
```
Just like in [parameters](#conventions-parameters), arbitrary [struct](/book/structs-and-messages#structs) return types are distributed across their fields and recursively flattened in exactly the same order. The only differences are that they now capture values from the stack and do so in a right-to-left fashion — the last field of the struct grabs the topmost value from the stack, the second-to-last grabs the second from the top, and so on, so that the last field contains the value from the top of the stack and the first field contains the value from the bottom.
```tact
// Struct with two fields of type Int
struct MinMax { minVal: Int; maxVal: Int }
// Pushes `a` and `b` onto the stack,
// then captures two values back via the `MinMax` Struct
asm fun minmax(a: Int, b: Int): MinMax { MINMAX }
```
If the run-time type of some captured value doesn’t match a specified field type of the [struct](/book/structs-and-messages#structs) or the nested structs, if any, an exception with [exit code 7](/book/exit-codes#7) will be thrown: `Type check error`. Moreover, attempts to capture more values than there were on the stack throw an exception with [exit code 2](/book/exit-codes#2): `Stack underflow`.
```tact
// Struct with way too many fields for the initial stack to handle
struct Handler { f1: Int; f2: Int; f3: Int; f4: Int; f5: Int; f6: Int; f7: Int }
// CAUSES RUN-TIME ERROR WHEN CALLED!
// Tries to capture 7 values from the stack and map them onto the fields of `Handler`,
// but there just aren't that many values on the initial stack after TVM initialization,
// which causes an exit code 2 to be thrown: Stack underflow
asm fun overHandler(): Handler { }
```
As parameters and return values of assembly functions, [structs](/book/structs-and-messages#structs) can only have up to 16 fields. Each of these fields can in turn be declared as another struct, where each of these nested structures can also only have up to 16 fields. This process can be repeated until there are a total of 256 fields of [primitive types](/book/types#primitive-types) due to the [assembly function limitations](#limitations). This restriction also applies to the parameter list of assembly functions — you can only declare up to 16 parameters.
```tact
// Seventeen fields
struct S17 { f1:Int; f2:Int; f3:Int; f4:Int; f5:Int; f6:Int; f7:Int; f8:Int; f9:Int; f10:Int; f11:Int; f12:Int; f13:Int; f14:Int; f15:Int; f16:Int; f17:Int }
// COMPILATION ERROR!
asm fun chuckles(imInDanger: S17) { }
```
## Stack registers[](#stack-registers)
The so-called *stack registers* are a way of referring to the values at the top of the stack. In total, there are 256 stack registers, i.e., values held on the stack at any given time. You can specify any of them using `s0`, `s1`, …, `s255`, but only if a particular [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) instruction expects it as an argument. Otherwise, their concept is meant for succinct descriptions of the effects of a particular [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) instruction in text or comments to the code, not in the code itself.
Register `s0` is the value at the top of the stack, register `s1` is the value immediately after it, and so on, until we reach the bottom of the stack, represented by `s255`, i.e., the 256th stack register. When a value `x` is pushed onto the stack, it becomes the new `s0`. At the same time, the old `s0` becomes the new `s1`, the old `s1` becomes the new `s2`, and so on.
```tact
asm fun takeSecond(a: Int, b: Int): Int {
// ↑ ↑
// | Pushed last, sits on top of the stack
// Pushed first, sits second from the top of the stack
// Now, let's swap s0 (top of the stack) with s1 (second-to-top)
// Before │ After
// ───────┼───────
// s0 = b │ s0 = a
// s1 = a │ s1 = b
SWAP
// Then, let's drop the value from the top of the stack
// Before │ After
// ───────┼───────
// s0 = a │ s0 = b
// s1 = b │ s1 is now either some value deeper or just blank
DROP
// At the end, we have only one value on the stack, which is b
// Thus, it is captured by our return type `Int`
}
fun showcase() {
takeSecond(5, 10); // 10, i.e., b
}
```
Caution
Attempts to access an empty stack register, i.e., one with no value at the time of access, throw an exception with [exit code 2](/book/exit-codes#2): `Stack underflow`.
For more about stack limits, see: [Limitations](#limitations).
## Arrangements[](#arrangements)
Often, it’s useful to change the order of arguments pushed onto the stack or the order of return values without referring to stack registers in the body. You can do this with `asm` arrangements.
Considering arrangements, the evaluation flow of the assembly function can be thought of in these 5 steps:
1. The function takes arguments in the order specified by the parameters.
2. If an argument arrangement is present, arguments are reordered before being pushed onto the stack.
3. The function body, consisting of [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions) and primitives, is executed.
4. If a result arrangement is present, resulting values are reordered on the stack.
5. The resulting values are captured (partially or fully) by the return type of the function.
The argument arrangement has the syntax `asm(arg2 arg1)`, where `arg1` and `arg2` are some arguments of the function arranged in the order we want to push them onto the stack: `arg1` will be pushed first and placed at the bottom of the stack, while `arg2` will be pushed last and placed at the top of the stack. Arrangements are not limited to two arguments and operate on all parameters of the function. If there are any parameters of arbitrary [struct](/book/structs-and-messages#structs) types, their arrangement is done prior to their flattening.
```tact
// Changing the order of arguments to match the STDICT signature:
// `c` will be pushed first and placed at the bottom of the stack,
// while `self` will be pushed last and placed at the top of the stack
asm(c self) extends fun asmStoreDict(self: Builder, c: Cell?): Builder { STDICT }
```
The return arrangement has the syntax `asm(-> 1 0)`, where 1 and 0 represent a left-to-right reordering of [stack registers](#stack-registers) `s1` and `s0`, respectively. The contents of `s1` will be at the top of the stack, followed by the contents of `s0`. Arrangements are not limited to two return values and operate on captured values.
If an arbitrary [struct](/book/structs-and-messages#structs) is specified as the return type, the arrangement is made concerning its fields, mapping values on the stack to the recursively flattened [struct](/book/structs-and-messages#structs).
```tact
// Changing the order of return values of LDVARUINT16 instruction,
// since originally it would place the modified Slice on top of the stack
asm(-> 1 0) extends fun asmLoadCoins(self: Slice): SliceInt { LDVARUINT16 }
// ↑ ↑
// | Value of the stack register 0,
// | which is the topmost value on the stack
// Value of the stack register 1,
// which is the second-to-top value on the stack
// And the return type `SliceInt`, which is the following struct:
struct SliceInt { s: Slice; val: Int }
```
Both argument and return arrangement can be combined together and written as follows: `asm(arg2 arg1 -> 1 0)`.
```tact
// Changing the order of return values compared to the stack
// and switching the order of arguments as well
asm(s len -> 1 0) fun asmLoadInt(len: Int, s: Slice): SliceInt { LDIX }
// ↑ ↑
// | Value of the stack register 0,
// | which is the topmost value on the stack
// Value of the stack register 1,
// which is the second-to-top value on the stack
// And the return type `SliceInt`, which is the following struct:
struct SliceInt { s: Slice; val: Int }
```
Using all those rearranged functions together, we get:
```tact
asm(c self) extends fun asmStoreDict(self: Builder, c: Cell?): Builder { STDICT }
asm(-> 1 0) extends fun asmLoadCoins(self: Slice): SliceInt { LDVARUINT16 }
asm(s len -> 1 0) fun asmLoadInt(len: Int, s: Slice): SliceInt { LDIX }
struct SliceInt { s: Slice; val: Int }
fun showcase() {
let b = beginCell()
.storeCoins(42)
.storeInt(27, 10)
.asmStoreDict(emptyMap());
let s = b.asSlice();
let si: SliceInt = s.asmLoadCoins(); // Slice remainder and 42
s = si.s; // assigning the modified Slice
let coins = si.val; // 42
let si2: SliceInt = asmLoadInt(10, s); // Slice remainder and 27
}
```
Arrangements do not drop or discard any values — they only manipulate the order of arguments and return values as declared. This means, for example, that an arrangement cannot access values from the stack that are not captured by the return type of the assembly function.
That said, there’s a [caveat to the `mutates` attribute and `asm` arrangements](#caveats-mutates).
## Limitations[](#limitations)
Attempts to drop the number of stack values below 0 throw an exception with [exit code 2](/book/exit-codes#2): `Stack underflow`.
```tact
asm fun drop() { DROP }
fun exitCode2() {
// Drops far more elements from the stack
// than there are, causing an underflow
repeat (100) { drop() }
}
```
The [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) stack itself has **no** limit on the total number of values, so you can theoretically push new values onto it until you run out of gas. However, various [continuations](https://docs.ton.org/v3/documentation/tvm/tvm-overview#tvm-is-a-stack-machine) may have a maximum number of values defined for their inner stacks, exceeding which will throw an exception with [exit code 3](/book/exit-codes#3): `Stack overflow`.
```tact
asm fun stackOverflow() {
x{} SLICE // s
BLESS // c
0 SETNUMARGS // c'
2 PUSHINT // c' 2
SWAP // 2 c'
1 -1 SETCONTARGS // ← this blows up
}
fun exitCode3() {
// Overflows the inner stack of a continuation
stackOverflow();
}
```
Although there are only 256 [stack registers](#stack-registers), the stack itself can have more than 256 values in total. The deeper values won’t be immediately accessible by any [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions), but they will be on the stack nonetheless.
## Caveats[](#caveats)
### Case sensitivity[](#caveats-case)
[TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions) are case-sensitive and are always written in upper case (capital letters).
```tact
/// ERROR!
asm fun bad1(): Cell { mycode }
/// ERROR!
asm fun bad2(): Cell { MyCoDe }
/// 👍
asm fun good(): Cell { MYCODE }
```
### No double quotes needed[](#caveats-quotes)
It is not necessary to enclose [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions) in double quotes. On the contrary, they will then be interpreted as strings, which is probably *not* what you want:
```tact
// Pushes the string "MYCODE" onto the compile-time stack,
// where it gets discarded even before the compute phase starts
asm fun wrongMyCode() { "MYCODE" }
// Invokes the TVM instruction MYCODE during the compute phase,
// which returns the contract code as a Cell
asm fun myCode(): Cell { MYCODE }
```
### `mutates` consumes an extra value[](#caveats-mutates)
Specifying the [`mutates`](/book/functions#mutates) attribute, i.e. defining a mutation function, makes the assembly function consume one additional value deeper in the stack than the declared return values. Consider the following example:
```tact
asm(-> 1 0) extends mutates fun loadRef(self: Slice): Cell { LDREF }
```
Here, the `LDREF` instruction produces two stack entries: a [`Cell`](/book/cells#cells) and a modified [`Slice`](/book/cells#slices), in that order, with the [`Slice`](/book/cells#slices) pushed on top of the stack. Then, the arrangement `-> 1 0` inverts those values, making the [`Cell`](/book/cells#cells) sit on top of the stack.
Finally, the [`mutates`](/book/functions#mutates) attribute makes the function consume the deepest value on the stack, i.e. [`Slice`](/book/cells#slices), and assigns it to `self`, while returning the [`Cell`](/book/cells#cells) value to the caller.
Overall, the [`mutates`](/book/functions#mutates) attribute can be useful in some cases, but you must remain vigilant when using it with assembly functions.
Caution
If the type of the deepest value on the stack does not match the type of `self`, then an exception with [exit code 7](/book/exit-codes#7) will be thrown: `Type check error`.
### Don’t rely on initial stack values[](#caveats-initial)
The [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) places a couple of values onto its stack upon initialization, and those values are based on the [event that caused the transaction](https://docs.ton.org/v3/documentation/tvm/tvm-initialization#stack). In other languages, you might need to rely on their order and types, while in Tact the parsing is done for you. Thus, in Tact, these initial stack values are different from [what’s described in TON Docs](https://docs.ton.org/v3/documentation/tvm/tvm-initialization#stack).
Caution
The initial elements placed on the stack during the [TVM initialization](https://docs.ton.org/v3/documentation/tvm/tvm-initialization#stack) and altered by Tact **must** remain on the stack until the end of the function body and must be the only values present there. If they aren’t, an exception with [exit code 7](/book/exit-codes#7) is thrown: `Type check error`.
Therefore, to access details such as the amount of [nanoToncoins](/book/integers#nanotoncoin) in a message or the [`Address`](/book/types#primitive-types) of the sender, it’s strongly recommended to call the [`context()`](/ref/core-contextstate#context) or [`sender()`](/ref/core-contextstate#sender) functions instead of attempting to look for those values on the stack.
### Don’t rely on the order of fields in structures in the standard library[](#caveats-stdlib-structures)
To reduce the number of stack-manipulating statements and to save gas, the order of the fields of structures in the standard library may change between releases. Such changes do not affect any kinds of functions other than `asm` functions.
That’s because assembly functions, unlike all others, require a certain order of values on the stack before and after their execution. If this order is disrupted, the entire logic of such functions can be broken immediately.
Hence, when writing assembly functions, make sure you are not using the built-in [structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) from Tact’s library. If you want to target a specific structure, make a copy of it in your code, and then use that copy so that it won’t be affected by future Tact updates.
## Debugging[](#debugging)
The number of values the stack has at any given time is called the *depth*, and it is accessible via the [`DEPTH`](https://docs.ton.org/v3/documentation/tvm/instructions#68) instruction. It’s quite handy for seeing the number of values before and after calling the assembly functions you’re debugging, and it can be used within asm logic.
```tact
asm fun depth(): Int { DEPTH }
```
To see both the stack depth and the values on it, there is a function in the Core library of Tact: [`dumpStack()`](/ref/core-debug#dumpstack). It’s useful for keeping track of the stack while debugging, although it is computationally expensive and only prints values instead of returning them. Therefore, use it sparingly and only during testing.
Read more about debugging Tact contracts on the dedicated page: [Debugging](/book/debug).
## Attributes[](#attributes)
The following attributes can be specified:
* `inline` — does nothing, since assembly functions are always inlined.
* [`extends`](/book/functions#extensions) — makes it an [extension function](/book/functions#extensions).
* [`mutates`](/book/functions#mutates), along with [`extends`](/book/functions#extensions) — makes it an [extension mutation function](/book/functions#mutates).
These attributes *cannot* be specified:
* `abstract` — assembly functions must have a defined body.
* `virtual` and `override` — assembly functions cannot be defined within a contract or a trait.
* [`get`](/book/functions#get) — assembly functions cannot be [getters](/book/functions#get).
```tact
/// `Builder.storeCoins()` extension function
asm extends fun storeCoins(self: Builder, value: Int): Builder {
STVARUINT16
}
/// `Slice.skipBits()` extension mutation function
asm extends mutates fun skipBits(self: Slice, l: Int) {
SDSKIPFIRST
}
```
## Interesting examples[](#examples)
On the [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions) page, you may have noticed that the “signatures” of instructions are written in a special form called *stack notation*, which describes the state of the stack before and after a given instruction is executed.
For example, `x y - z` describes an instruction that grabs two values `x` and `y` from the stack, with `y` at the top of the stack and `x` second to the top, and then pushes the result `z` onto the stack. Notice that other values deeper down the stack are not accessed.
This notation omits type information and only implicitly describes the state of stack registers, so for the following examples we’ll use a different one, combining the notions of parameters and return values with the stack notation like this:
```tact
// The types of parameters
// | | and types of return values are shown
// ↓ ↓ ↓
// x:Int, y:Int → z:Int — all comma-separated
// ————————————————————
// s1 s0 → s0
// ↑ ↑ ↑
// And the stack registers are shown too,
// which helps visually map them onto parameters and return values
```
When literals are involved, they’ll be shown as is. Additionally, when values on the stack do not represent parameters or [struct](/book/structs-and-messages#structs) fields of the return type, only their type is given.
### keccak256[](#keccak256)
```tact
// Computes and returns the Keccak-256 hash as a 256-bit unsigned `Int`
// from a passed `Slice` `s`. Uses an Ethereum-compatible* implementation.
asm fun keccak256(s: Slice): Int {
// s:Slice → s:Slice, 1
// —————————————————————
// s0 → s1 s0
ONE
// s:Slice, 1 → h:Int
// ———————————————————
// s1 s0 → s0
HASHEXT_KECCAK256
}
```
The [`HASHEXT_SHA256`](https://docs.ton.org/v3/documentation/tvm/instructions#F90400) and [`HASHEXT_BLAKE2B`](https://docs.ton.org/v3/documentation/tvm/instructions#F90402) instructions can be used in a similar manner with respect to a different number of return values. In addition, all of those can also work with values of type [`Builder`](/book/cells#builders).
The [`HASHEXT_KECCAK512`](https://docs.ton.org/v3/documentation/tvm/instructions#F90404) and [`HASHEXT_SHA512`](https://docs.ton.org/v3/documentation/tvm/instructions#F90401), however, put a tuple of two integers on the stack instead of putting two separate integers there. Because of that, you need to also add the `UNPAIR` instruction right after them.
```tact
// Computes and returns the Keccak-512 hash in two 256-bit unsigned `Int`
// values from a passed `Slice` `s`. Uses an Ethereum-compatible* implementation.
asm fun keccak512(s: Slice): Hash512 {
// s:Slice → s:Slice, 1
// —————————————————————
// s0 → s1 s0
ONE
// s:Slice, 1 → Tuple(h1:Int, h2:Int)
// ———————————————————————————————————
// s1 s0 → s0
HASHEXT_KECCAK512
// Tuple(h1:Int, h2:Int) → h1:Int, h2:Int
// —————————————————————————————————————
// s0 → s1 s2
UNPAIR // could've used UNTUPLE in a more general case too
}
// Helper struct
struct Hash512 { h1: Int; h2: Int }
```
While it is said that these sample `keccak256()` and `keccak512()` functions use an Ethereum-compatible implementation, note that the underlying `HASHEXT` family of [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) instructions has its own drawbacks.
These drawbacks stem from the limitations of the [`Slice`](/book/cells#slices) type itself — `HASHEXT_KECCAK256` and other hashing instructions of the `HASHEXT` family ignore any references present in the passed slice(s). That is, only up to 1023 bits of their data are used.
To work around this, you can recursively load all the refs from the given [`Slice`](/book/cells#slices) and then hash them all at once by specifying their exact number instead of the `ONE` [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) instruction used earlier. See an example below: [`onchainSha256`](#onchainsha256).
Useful links:
[`HASHEXT_KECCAK256`](https://docs.ton.org/v3/documentation/tvm/instructions#F90403)\
[`HASHEXT_KECCAK512`](https://docs.ton.org/v3/documentation/tvm/instructions#F90404)\
[Reference Keccak-256 implementation](https://keccak.team/index.html)\
[`keccak256()` in the Core library](/ref/core-crypto#keccak256)
### isUint8[](#isuint8)
Mapping onto a single instruction by itself is inefficient if the values it places onto the stack can vary depending on certain conditions. That is because one cannot map them to Tact types directly and often needs additional stack manipulations before or after their execution.
Since this is often the case for the “quiet” versions of instructions, the recommendation is to prefer their non-quiet alternatives. Usually, non-quiet versions throw exceptions and are consistent in their return values, while quiet ones push −1 or other values onto the stack, thus varying the number or the type of their result values.
For simpler cases such as this example, it is convenient to do all the stack manipulations within the same function.
```tact
// Checks if the given `Int` `val` is in
// the inclusive range from 0 to 255
asm fun isUint8(val: Int): Bool {
// val:Int → val:Int or NaN
// ————————————————————————
// s0 → s0
8 QUFITS
// val:Int or NaN → Bool
// —————————————————————
// s0 → s0
ISNAN
// Since ISNAN gives true when the `val` is NaN,
// i.e., when the `val` did not fit into the uint8 range,
// we need to flip it
// Bool → Bool
// ———————————
// s0 → s0
NOT // could've used 0 EQINT too
}
fun showcase() {
isUint8(55); // true
isUint8(-55); // false
isUint8(pow(2, 8)); // false
isUint8(pow(2, 8) - 1); // true
}
```
### ecrecover[](#ecrecover)
This example shows one possible way to work with partially captured results from the stack, obtaining the omitted ones later.
```tact
// Recovers a public key from the signature as done in Bitcoin or Ethereum.
//
// Takes the 256-bit unsigned integer `hash` and the 65-byte signature consisting of:
// * 8-bit unsigned integer `v`
// * 256-bit unsigned integers `r` and `s`
//
// Returns `null` on failure or an `EcrecoverKey` structure on success.
fun ecrecover(hash: Int, v: Int, r: Int, s: Int): EcrecoverKey? {
let successful = _ecrecoverExecute(hash, v, r, s);
if (successful) {
return _ecrecoverSuccess();
} else {
return null;
}
}
// The 65-byte public key returned by `ecrecover()` in case of success,
// which consists of the 8-bit unsigned integer `h`
// and 256-bit unsigned integers `x1` and `x2`.
struct EcrecoverKey {
h: Int as uint8;
x1: Int as uint256;
x2: Int as uint256;
}
// Underlying assembly function that does the work
// and only captures the topmost value from the stack.
//
// Since the `ECRECOVER` instruction places 0 on top of the stack
// in case of failure and -1 in case of success,
// this maps nicely onto the Bool type.
asm fun _ecrecoverExecute(hash: Int, v: Int, r: Int, s: Int): Bool { ECRECOVER }
// Simply captures the values from the stack
// if the call to `_ecrecoverExecute()` was successful.
asm fun _ecrecoverSuccess(): EcrecoverKey { }
```
### onchainSha256[](#onchainsha256)
This example extends the [`ecrecover()`](#ecrecover) example and adds more complex stack management and interaction with Tact statements, such as loops.
```tact
// Calculates and returns the SHA-256 hash
// as a 256-bit unsigned `Int` of the given `data`.
//
// Unlike the `sha256()` function from the Core library,
// this one works purely on-chain (at runtime).
fun onchainSha256(data: String): Int {
_onchainShaPush(data);
while (_onchainShaShouldProceed()) {
_onchainShaOperate();
}
return _onchainShaHashExt();
}
// Helper assembly functions,
// each manipulating the stack in its own way
// in different parts of the `onchainSha256()` function.
asm fun _onchainShaPush(data: String) { ONE }
asm fun _onchainShaShouldProceed(): Bool { OVER SREFS 0 NEQINT }
asm fun _onchainShaOperate() { OVER LDREF s0 POP CTOS s0 s1 XCHG INC }
asm fun _onchainShaHashExt(): Int { HASHEXT_SHA256 }
```
Useful links:
[TVM overview in TON Docs](https://docs.ton.org/learn/tvm-instructions/tvm-overview)\
[List of TVM instructions in TON Docs](https://docs.ton.org/v3/documentation/tvm/instructions)
---
# Bounced messages
> When a contract sends a message with the flag bounce set to true, then if the message isn't processed properly, it will bounce back to the sender.
When a contract sends a message with the flag `bounce` set to `true`, and if the message isn’t processed properly, it will bounce back to the sender. This is useful when you want to ensure that the message has been processed properly and, if not, revert the changes.
## Caveats[](#caveats)
Currently, bounced messages in TON can have at most 256 bits of payload and no references, but the amount of useful data bits when handling messages in `bounced` receivers is at most 224, since the first 32 bits are occupied by the message opcode. This means that you can’t recover much of the data from the bounced message, for instance you cannot fit an address into a bounced message, since regular internal addresses need 267 bits to be represented.
Tact helps you to check if your message fits the limit, and if it doesn’t, suggests using a special type constructor `bounced` for the bounced message receiver, which constructs a partial representation of the message that fits within the required limits.
Note that the inner [message struct](/book/structs-and-messages#messages) of the `bounced` type constructor cannot be [optional](/book/optionals).
```tact
contract Bounce() {
// COMPILATION ERROR! Only named type can be bounced<>
bounced(msg: bounced) {}
// ~~~~~~~~~~~~
}
message BB {}
```
Only the first message fields that fit into the 224 bits will be available to use in bounced message receivers. Sometimes you need to rearrange the order of the fields in your message so the relevant ones would fit into the limit.
```tact
contract Bounce() {
bounced(msg: bounced) {
// COMPILATION ERROR! Maximum size of the bounced message is 224 bits...
msg.f2;
// ~~
}
}
message TwoFields {
f1: Int as uint224; // only this field will fit in a bounced message body
f2: Int;
}
```
## Bounced message receiver[](#bounced-message-receiver)
Caution
Bounced text messages are not supported yet.
To receive a bounced message, define a `bounced()` [receiver function](/book/contracts#receiver-functions) in your [contract](/book/contracts) or a [trait](/book/types#traits):
```tact
contract MyContract {
bounced(msg: bounced) {
// ...
}
}
```
To process bounced messages manually, you can use a fallback definition that handles a raw [`Slice`](/book/cells#slices) directly. Note that such a receiver will get **all** the bounced messages produced by your contract:
```tact
contract MyContract {
bounced(rawMsg: Slice) {
// ...
}
}
```
---
# Cells, Builders, and Slices
> Cells, Builders, and Slices are low-level primitives of TON Blockchain
[Cells](#cells), [Builders](#builders), and [Slices](#slices) are low-level [primitives](/book/types#primitive-types) of TON Blockchain. The virtual machine of TON Blockchain, [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview), uses cells to represent all data structures in persistent storage and most in memory.
## Cells[](#cells)
`Cell` is a [primitive](/book/types#primitive-types) and a data structure, which [ordinarily](#cells-kinds) consists of up to 1023 continuously laid out bits and up to 4 references (refs) to other cells. Circular references are forbidden and cannot be created by means of [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview), which means cells can be viewed as [quadtrees](https://en.wikipedia.org/wiki/Quadtree) or [directed acyclic graphs (DAGs)](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of themselves. Contract code itself is represented by a tree of cells.
Cells and [cell primitives](#cells-immutability) are bit-oriented, not byte-oriented: [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) regards data kept in cells as sequences (strings or streams) of up to 1023 bits, not bytes. If necessary, contracts are free to use, for example, 21-bit integer fields serialized into [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) cells, thus using fewer persistent storage bytes to represent the same data.
### Kinds[](#cells-kinds)
While the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) type [`Cell`](#cells) refers to all cells, there are different kinds of cells with various memory layouts. The one described [earlier](#cells) is commonly referred to as an *ordinary* (or simple) cell—that is the simplest and most commonly used flavor of cells, which can only contain data. The vast majority of descriptions, guides, and [references](/ref/core-cells) to cells and their usage assume ordinary ones.
Other kinds of cells are collectively called *exotic* (or special) cells. They sometimes appear in actual representations of blocks and other data structures on TON Blockchain. Their memory layouts and purposes differ significantly from ordinary cells.
Kinds (or subtypes) of all cells are encoded by an integer between −1 and 255. Ordinary cells are encoded by −1, while exotic ones can be encoded by any other integer in that range. The subtype of an exotic cell is stored in the first 8 bits of its data, which means valid exotic cells always have at least 8 data bits.
[TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) currently supports the following exotic cell subtypes:
* [Pruned branch cell](https://docs.ton.org/develop/data-formats/exotic-cells#pruned-branch), with subtype encoded as 1 — they represent deleted subtrees of cells.
* [Library reference cell](https://docs.ton.org/develop/data-formats/library-cells), with subtype encoded as 2 — they are used for storing libraries, usually in [masterchain](https://docs.ton.org/v3/documentation/smart-contracts/shards/shards-intro#masterchain) contexts.
* [Merkle proof cell](https://docs.ton.org/develop/data-formats/exotic-cells#merkle-proof), with subtype encoded as 3 — they are used for verifying that certain portions of another cell’s tree data belong to the full tree.
* [Merkle update cell](https://docs.ton.org/develop/data-formats/exotic-cells#merkle-update), with subtype encoded as 4 — they always have two references and behave like a [Merkle proof](https://docs.ton.org/develop/data-formats/exotic-cells#simple-proof-verifying-example) for both of them.
Useful links:
[Pruned branch cells in TON Docs](https://docs.ton.org/develop/data-formats/exotic-cells#pruned-branch)\
[Library reference cells in TON Docs](https://docs.ton.org/develop/data-formats/library-cells)\
[Merkle proof cells in TON Docs](https://docs.ton.org/develop/data-formats/exotic-cells#merkle-proof)\
[Merkle update cells in TON Docs](https://docs.ton.org/develop/data-formats/exotic-cells#merkle-update)\
[Simple proof-verifying example in TON Docs](https://docs.ton.org/develop/data-formats/exotic-cells#simple-proof-verifying-example)
### Levels[](#cells-levels)
Every cell, being a [quadtree](https://en.wikipedia.org/wiki/Quadtree), has an attribute called *level*, which is represented by an integer between 0 and 3. The level of an [ordinary](#cells-kinds) cell is always equal to the maximum of the levels of all its references. That is, the level of an ordinary cell without references is equal to 0.
[Exotic](#cells-kinds) cells have different rules for determining their level, which are described [on this page in TON Docs](https://docs.ton.org/develop/data-formats/exotic-cells).
### Serialization[](#cells-serialization)
Before a cell can be transferred over the network or stored on disk, it must be serialized. There are several common formats, such as the [standard `Cell` representation](#cells-representation) and [BoC](#cells-boc).
#### Standard representation[](#cells-representation)
The standard [`Cell`](#cells) representation is a common serialization format for cells, first described in [tvm.pdf](https://docs.ton.org/tvm.pdf). Its algorithm serializing cells into octet (byte) sequences begins by serializing the first 2 bytes, called descriptors:
* The *Refs descriptor* is calculated according to the formula: r+8×k+32×l, where r is the number of references contained in the cell (between 0 and 4), k is a flag indicating the cell kind (0 for [ordinary](#cells-kinds) and 1 for [exotic](#cells-kinds)), and l is the [level](#cells-levels) of the cell (between 0 and 3).
* The *Bits descriptor* is calculated according to the formula: ⌊8b⌋+⌈8b⌉, where b is the number of bits in the cell (between 0 and 1023).
Then, the data bits of the cell themselves are serialized as ⌈8b⌉ 8-bit octets (bytes). If b is not a multiple of eight, a binary `1` followed by up to six binary `0`s is appended to the data bits.
Next, 2 bytes store the depth of the refs, i.e., the number of cells between the root of the cell tree (the current cell) and the deepest reference, including it. For example, a cell containing only one reference and no further references would have a depth of 1, while the referenced cell would have a depth of 0.
Finally, for every referenced cell, the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of its standard representation is stored, occupying 32 bytes per referenced cell, recursively repeating the said algorithm. Note that cyclic cell references are not allowed, so this recursion always terminates in a well-defined manner.
If we were to compute the hash of the standard representation of this cell, all bytes from the above steps would be concatenated together and then hashed using the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash function. This is the algorithm behind the [`HASHCU` and `HASHSU` instructions](https://docs.ton.org/learn/tvm-instructions/instructions) of [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) and the respective [`Cell.hash()`](/ref/core-cells#cellhash) and [`Slice.hash()`](/ref/core-cells#slicehash) functions of Tact.
#### Bag of Cells[](#cells-boc)
Bag of Cells, or *BoC* for short, is a format for serializing and deserializing cells into byte arrays as described in [boc.tlb](https://github.com/ton-blockchain/ton/blob/24dc184a2ea67f9c47042b4104bbb4d82289fac1/crypto/tl/boc.tlb#L25) [TL-B schema](https://docs.ton.org/develop/data-formats/tl-b-language).
Read more about BoC in TON Docs: [Bag of Cells](https://docs.ton.org/develop/data-formats/cell-boc#bag-of-cells).
Note
Advanced information on [`Cell`](#cells) serialization: [Canonical `Cell` Serialization](https://docs.ton.org/develop/research-and-development/boc).
### Immutability[](#cells-immutability)
Cells are read-only and immutable, but there are two major sets of [ordinary](#cells-kinds) cell manipulation instructions in [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview):
* Cell creation (or serialization) instructions, which are used to construct new cells from previously stored values and cells.
* Cell parsing (or deserialization) instructions, which are used to extract or load data previously stored into cells via serialization instructions.
In addition, there are instructions specific to [exotic](#cells-kinds) cells to create them and inspect their values. However, [ordinary](#cells-kinds) cell parsing instructions can still be used on [exotic](#cells-kinds) cells, in which case they are automatically replaced by [ordinary](#cells-kinds) cells during such deserialization attempts.
All cell manipulation instructions require transforming values of [`Cell`](#cells) type into either [`Builder`](#builders) or [`Slice`](#slices) types before such cells can be modified or inspected.
## Builders[](#builders)
`Builder` is a cell manipulation [primitive](/book/types#primitive-types) used for cell creation instructions. They are immutable just like cells and allow constructing new cells from previously stored values and cells. Unlike cells, values of type `Builder` appear only on the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) stack and cannot be stored in persistent storage. This means, for example, that persistent storage fields with type `Builder` are actually stored as cells under the hood.
The `Builder` type represents partially composed cells, for which fast operations to append integers, other cells, references to other cells, and many other operations are defined:
* [`Builder.storeUint()` in Core library](/ref/core-cells#builderstoreuint)
* [`Builder.storeInt()` in Core library](/ref/core-cells#builderstoreint)
* [`Builder.storeBool()` in Core library](/ref/core-cells#builderstorebool)
* [`Builder.storeSlice()` in Core library](/ref/core-cells#builderstoreslice)
* [`Builder.storeCoins()` in Core library](/ref/core-cells#builderstorecoins)
* [`Builder.storeAddress()` in Core library](/ref/core-cells#builderstoreaddress)
* [`Builder.storeRef()` in Core library](/ref/core-cells#builderstoreref)
While you may use them for [manual construction](#cnp-manually) of cells, it’s strongly recommended to use [structs](/book/structs-and-messages#structs) instead: [Construction of cells with structures](#cnp-structs).
## Slices[](#slices)
`Slice` is a cell manipulation [primitive](/book/types#primitive-types) used for cell parsing instructions. Unlike cells, slices are mutable and allow extraction or loading of data previously stored in cells via serialization instructions. Also unlike cells, values of type `Slice` appear only on the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) stack and cannot be stored in persistent storage. This means, for example, that persistent storage fields with type `Slice` would actually be stored as cells under the hood.
The `Slice` type represents either the remainder of a partially parsed cell or a value (subcell) residing inside such a cell, extracted from it by a parsing instruction:
* [`Slice.loadUint()` in Core library](/ref/core-cells#sliceloaduint)
* [`Slice.loadInt()` in Core library](/ref/core-cells#sliceloadint)
* [`Slice.loadBool()` in Core library](/ref/core-cells#sliceloadbool)
* [`Slice.loadBits()` in Core library](/ref/core-cells#sliceloadbits)
* [`Slice.loadCoins()` in Core library](/ref/core-cells#sliceloadcoins)
* [`Slice.loadAddress()` in Core library](/ref/core-cells#sliceloadaddress)
* [`Slice.loadRef()` in Core library](/ref/core-cells#sliceloadref)
While you may use slices for [manual parsing](#cnp-manually) of cells, it is strongly recommended to use [structs](/book/structs-and-messages#structs) instead: [Parsing cells with structures](#cnp-structs).
## Serialization types[](#serialization-types)
Similar to serialization options of the [`Int`](/book/integers) type, `Cell`, `Builder`, and `Slice` also have various representations for encoding their values in the following cases:
* as [storage variables](/book/contracts#variables) 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)
```tact
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` serialization option can be applied to values of [`Cell`](#cells), [`Builder`](#builders), and [`Slice`](#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` is like using [`Builder.storeSlice()`](/ref/core-cells#builderstoreslice) and [`Slice.loadBits()`](/ref/core-cells#sliceloadbits) instead of the default [`Builder.storeRef()`](/ref/core-cells#builderstoreref) and [`Slice.loadRef()`](/ref/core-cells#sliceloadref).
In addition, the [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) representation produced by Tact changes too:
```tact
struct TwoCell {
cRef: Cell; // ^cell in TL-B
cRem: Cell as remaining; // cell in TL-B
}
struct TwoBuilder {
bRef: Builder; // ^builder in TL-B
bRem: Builder as remaining; // builder in TL-B
}
struct TwoSlice {
sRef: Slice; // ^slice in TL-B
sRem: Slice as remaining; // slice in TL-B
}
contract SerializationExample {
cell2: TwoCell;
builder2: TwoBuilder;
slice2: TwoSlice;
// Constructor function,
// necessary for this example contract to compile
init() {
self.cell2 = TwoCell {
cRef: emptyCell(),
cRem: emptyCell(),
};
self.builder2 = TwoBuilder {
bRef: beginCell(),
bRem: beginCell(),
};
self.slice2 = TwoSlice {
sRef: emptySlice(),
sRem: emptySlice(),
};
}
}
```
Here, `^cell`, `^builder`, and `^slice` in [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) syntax mean a reference to [`Cell`](#cells), [`Builder`](#builders), and [`Slice`](#slices) values respectively, whereas `cell`, `builder`, or `slice` indicate that the given value will be stored directly as a `Cell`, `Builder`, or `Slice` rather than as a reference.
To give a real-world example, imagine that you need to notice and react to inbound [Jetton](/cookbook/jettons) transfers in your smart contract. The appropriate [Message](/book/structs-and-messages#messages) structure for doing so would look like this:
```tact
message(0x7362d09c) JettonTransferNotification {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means we don't mark messages to trace their chains
queryId: Int as uint64 = 0;
// Amount of Jettons transferred
amount: Int as coins;
// Address of the sender of the Jettons
sender: Address;
// Optional custom payload
forwardPayload: Slice as remaining;
}
```
And the [receiver](/book/contracts#receiver-functions) in the contract would look like this:
```tact
receive(msg: JettonTransferNotification) {
// ... you do you ...
}
```
Upon receiving a [Jetton](/cookbook/jettons) transfer notification message, its cell body is converted into a [`Slice`](#slices) and then parsed as a `JettonTransferNotification` [Message](/book/structs-and-messages#messages). At the end of this process, the `forwardPayload` will contain all the remaining data of the original message cell.
In this context, it’s not possible to violate the [Jetton](/cookbook/jettons) standard by placing the `forwardPayload: Slice as remaining` field in any other position within the `JettonTransferNotification` [Message](/book/structs-and-messages#messages). That’s because Tact prohibits the usage of `as remaining` for any field other than the last one in [structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages), preventing misuse of contract storage and reducing gas consumption.
Note
Note that a cell serialized via `as remaining` cannot be [optional](/book/optionals). Specifying something like `Cell? as remaining`, `Builder? as remaining`, or `Slice? as remaining` would cause a compilation error.
Also, note that specifying `remaining` for a `Cell` type used as a [map](/book/maps) value type is considered an error and will not compile.
### `bytes32`[](#serialization-bytes32)
The `as bytes32` serialization annotation can only be applied to slices and is used to read 32 bytes (256 bits) of data from a cell. The `as uint256` annotation achieves a similar result, but it can only be applied to integers.
### `bytes64`[](#serialization-bytes64)
The `as bytes64` serialization annotation can only be applied to slices and is used to read 64 bytes (512 bits) of data from a cell. It can be useful for serializing and deserializing cryptographic signatures.
For a usage example, see the [`SignedBundle`](/ref/core-crypto#signedbundle) [struct](/book/structs-and-messages#structs).
## Operations[](#operations)
### Construct and parse[](#operations-cnp)
In Tact, there are at least two ways to construct and parse cells:
* [Manually](#cnp-manually), which involves actively using [`Builder`](#builders), [`Slice`](#slices), and [relevant methods](/ref/core-cells).
* [Using structures](#cnp-structs), which is the recommended and much more convenient approach.
#### Manually[](#cnp-manually)
| Construction via `Builder` | Parsing via `Slice` |
| :-------------------------------------------------------------- | :-------------------------------------------------------- |
| [`beginCell()`](/ref/core-cells#begincell) | [`Cell.beginParse()`](/ref/core-cells#cellbeginparse) |
| [`.storeUint(42, 7)`](/ref/core-cells#builderstoreuint) | [`Slice.loadUint(7)`](/ref/core-cells#sliceloaduint) |
| [`.storeInt(42, 7)`](/ref/core-cells#builderstoreint) | [`Slice.loadInt(7)`](/ref/core-cells#sliceloadint) |
| [`.storeBool(true)`](/ref/core-cells#builderstorebool) | [`Slice.loadBool(true)`](/ref/core-cells#sliceloadbool) |
| [`.storeSlice(slice)`](/ref/core-cells#builderstoreslice) | [`Slice.loadBits(slice)`](/ref/core-cells#sliceloadbits) |
| [`.storeCoins(42)`](/ref/core-cells#builderstorecoins) | [`Slice.loadCoins(42)`](/ref/core-cells#sliceloadcoins) |
| [`.storeAddress(address)`](/ref/core-cells#builderstoreaddress) | [`Slice.loadAddress()`](/ref/core-cells#sliceloadaddress) |
| [`.storeRef(cell)`](/ref/core-cells#builderstoreref) | [`Slice.loadRef()`](/ref/core-cells#sliceloadref) |
| [`.endCell()`](/ref/core-cells#builderendcell) | [`Slice.endParse()`](/ref/core-cells#sliceendparse) |
#### Using structures (recommended)[](#cnp-structs)
[Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) are almost like living [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language), meaning they are essentially [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language) expressed in maintainable, verifiable, and user-friendly Tact code.
It is strongly recommended to use them and their [methods](/book/functions#extensions), such as [`Struct.toCell()`](/ref/core-cells#structtocell) and [`Struct.fromCell()`](/ref/core-cells#structfromcell), instead of manually constructing and parsing cells, as this allows for much more declarative and self-explanatory contracts.
The examples of manual parsing [above](#cnp-manually) can be rewritten using structs, with descriptive names for fields if desired:
```tact
// First struct
struct Showcase {
id: Int as uint8;
someImportantNumber: Int as int8;
isThatCool: Bool;
payload: Slice;
nanoToncoins: Int as coins;
wackyTacky: Address;
jojoRef: Adventure; // another struct
}
// Here it is
struct Adventure {
bizarre: Bool = true;
time: Bool = false;
}
fun example() {
// Basics
let s = Showcase.fromCell(
Showcase {
id: 7,
someImportantNumber: 42,
isThatCool: true,
payload: emptySlice(),
nanoToncoins: 1330 + 7,
wackyTacky: myAddress(),
jojoRef: Adventure { bizarre: true, time: false },
}.toCell());
s.isThatCool; // true
}
```
Note that Tact’s auto-layout algorithm is greedy. For example, `struct Adventure` occupies very little space and will not be stored as a reference [`Cell`](#cells). Instead, it will be provided directly as a [`Slice`](#slices).
By using structures instead of manual [`Cell`](#cells) composition and parsing, those details will be simplified away and will not cause any hassle when the optimized layout changes.
Useful links:
[Convert serialization](/book/func#convert-serialization)\
[`Struct.toCell()` in Core library](/ref/core-cells#structtocell)\
[`Struct.fromCell()` in Core library](/ref/core-cells#structfromcell)\
[`Struct.fromSlice()` in Core library](/ref/core-cells#structfromslice)\
[`Message.toCell()` in Core library](/ref/core-cells#messagetocell)\
[`Message.fromCell()` in Core library](/ref/core-cells#messagefromcell)\
[`Message.fromSlice()` in Core library](/ref/core-cells#messagefromslice)\
[`Contract.toCell()` in Core library](/ref/core-cells#contracttocell)\
[`Contract.toSlice()` in Core library](/ref/core-cells#contracttoslice)
### Check if empty[](#operations-empty)
Neither [`Cell`](#cells) nor [`Builder`](#builders) can be checked for emptiness directly — one needs to convert them to [`Slice`](#slices) first.
To check if there are any bits, use [`Slice.dataEmpty()`](/ref/core-cells#slicedataempty). To check if there are any references, use [`Slice.refsEmpty()`](/ref/core-cells#slicerefsempty). To check both at the same time, use [`Slice.empty()`](/ref/core-cells#sliceempty).
To also throw an [exit code 9](/book/exit-codes#9) whenever the [`Slice`](#slices) isn’t completely empty, use [`Slice.endParse()`](/ref/core-cells#sliceendparse).
```tact
// Preparations
let someCell = beginCell().storeUint(42, 7).endCell();
let someBuilder = beginCell().storeRef(someCell);
// Obtaining our Slices
let slice1 = someCell.asSlice();
let slice2 = someBuilder.asSlice();
// .dataEmpty()
slice1.dataEmpty(); // false
slice2.dataEmpty(); // true
// .refsEmpty()
slice1.refsEmpty(); // true
slice2.refsEmpty(); // false
// .empty()
slice1.empty(); // false
slice2.empty(); // false
// .endParse()
try {
slice1.endParse();
slice2.endParse();
} catch (e) {
e; // 9
}
```
Useful links:
[`Cell.asSlice()` in Core library](/ref/core-cells#cellasslice)\
[`Builder.asSlice()` in Core library](/ref/core-cells#builderasslice)\
[`Slice.dataEmpty()` in Core library](/ref/core-cells#slicedataempty)\
[`Slice.refsEmpty()` in Core library](/ref/core-cells#slicerefsempty)\
[`Slice.empty()` in Core library](/ref/core-cells#sliceempty)\
[`Slice.endParse()` in Core library](/ref/core-cells#sliceendparse)
### Check if equal[](#operations-equal)
Values of type [`Builder`](#builders) cannot be compared directly using the binary equality [`==`](/book/operators#binary-equality) or inequality [`!=`](/book/operators#binary-equality) operators. However, values of type [`Cell`](#cells) and [`Slice`](#slices) can.
Direct comparisons:
```tact
let a = beginCell().storeUint(123, 8).endCell();
let aSlice = a.asSlice();
let b = beginCell().storeUint(123, 8).endCell();
let bSlice = b.asSlice();
let areCellsEqual = a == b; // true
let areCellsNotEqual = a != b; // false
let areSlicesEqual = aSlice == bSlice; // true
let areSlicesNotEqual = aSlice != bSlice; // false
```
Note that direct comparison via the `==` or `!=` operators implicitly uses [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hashes of the [standard `Cell` representation](#cells-representation) under the hood.
Explicit comparisons using `.hash()` are also available:
```tact
let a = beginCell().storeUint(123, 8).endCell();
let aSlice = a.asSlice();
let b = beginCell().storeUint(123, 8).endCell();
let bSlice = b.asSlice();
let areCellsEqual = a.hash() == b.hash(); // true
let areCellsNotEqual = a.hash() != b.hash(); // false
let areSlicesEqual = aSlice.hash() == bSlice.hash(); // true
let areSlicesNotEqual = aSlice.hash() != bSlice.hash(); // false
```
Useful links:
[`Cell.hash()` in Core library](/ref/core-cells#cellhash)\
[`Slice.hash()` in Core library](/ref/core-cells#slicehash)\
[`==` and `!=`](/book/operators#binary-equality)
---
# Compilation
> How to compile Tact smart contracts, as well as details on the build artifacts that are provided.
The Tact compiler can produce various outputs, ranging from the [BoC](/book/cells#cells-boc) of the [compiled contract](#boc) to various supplementary files, such as the [compilation report](#report) or the [contract package](#pkg).
With the proper [configuration settings](/book/config), you can customize the behavior of the compiler to skip the generation of some or all [build artifacts](#artifacts), and even control the addition or exclusion of [getters for supported interfaces](/book/contracts#interfaces).
Since the Tact compiler is a command-line program, some of the configuration settings can be set directly. When inside a folder with a Tact-based project, such as one created using the [Blueprint](https://github.com/ton-org/blueprint) or from the [tact-template](https://github.com/tact-lang/tact-template), refer to the command `npx tact --help` for further instructions.
## Compiler upgrades[](#upgrades)
Work on the compiler is active and extensive, so be sure to check out [NPM](https://www.npmjs.com/package/@tact-lang/compiler) whenever we push new releases. To follow updates, see the [Tact Kitchen in Telegram](https://t.me/tact_kitchen) for the short scoop, or our [GitHub organization](https://github.com/tact-lang) for the full picture in all its details.
To upgrade the Tact compiler to its latest version in a [Blueprint](https://github.com/ton-org/blueprint)-based project or a project created from the [tact-template](https://github.com/tact-lang/tact-template), run:
* yarn v1
```shell
# recommended
yarn upgrade @tact-lang/compiler
```
* yarn v4+
```shell
yarn up @tact-lang/compiler
```
* npm
```shell
npm update --save @tact-lang/compiler
```
* pnpm
```shell
pnpm upgrade @tact-lang/compiler
```
* bun
```shell
bun update --latest @tact-lang/compiler
```
Sometimes, bug fixes require us to change existing behavior, introducing small breaking changes. To be prepared for these, make sure to read the [CHANGELOG.md](https://github.com/tact-lang/tact/blob/main/dev-docs/CHANGELOG.md) and act accordingly. Except for bug fixes, Tact tries its best not to introduce breaking changes in minor or patch versions according to [semantic versioning](https://semver.org/#summary).
If you want to pin down a specific version of the compiler, run the following command. Here, `X.Y.Z` is the target version you want to install:
* yarn
```shell
# X.Y.Z must be replaced by the actual version number
yarn add --exact @tact-lang/compiler@X.Y.Z
```
* npm
```shell
# X.Y.Z must be replaced by the actual version number
npm i --save-exact @tact-lang/compiler@X.Y.Z
```
* pnpm
```shell
# X.Y.Z must be replaced by the actual version number
pnpm add --save-exact @tact-lang/compiler@X.Y.Z
```
* bun
```shell
# X.Y.Z must be replaced by the actual version number
bun add --exact @tact-lang/compiler@X.Y.Z
```
Caution
Do not mix different Node.js package managers in your projects. If you created the [Blueprint](https://github.com/ton-org/blueprint) project with `npm`, stick to using `npm` for the rest of the commands — this will ensure that you don’t get “File not found” errors or lock-file conflicts between different package managers.
For example, using the `npm` package manager to install dependencies and then switching to `yarn` to build the contracts can lead to the following error message:
```shell
File not found: tact_Task1.headers.fc
#include "tact_Task1.headers.fc";
💥 Compilation failed. Skipping packaging
Error: Could not compile tact
error Command failed with exit code 1.
```
## Build artifacts[](#artifacts)
A number of build artifacts can be produced per compilation of each contract. Some artifacts can be omitted using [configuration settings](/book/config).
The location of the artifacts depends on the compilation method:
* For projects using `tact.config.json`, use the [`output`](/book/config#projects-output) field in the config file.
* For single contract compilation, you can specify the output directory using the `-o` or `--output` flag:
```shell
tact contract.tact --output ./custom-output
```
If not specified, the files will be generated in the same directory as the input file.
In [Blueprint](https://github.com/ton-org/blueprint)-based projects, the `output` field is not used, and all generated files are always placed in `build/ProjectName/`.
### Compilation report, `.md`[](#report)
Every markdown compilation report first features the name of the contract for which it was prepared, followed by the byte size of the contract compiled into [BoC](/book/cells#cells-boc).
The following subheadings describe the respective sections of the `.md` report.
#### Structures[](#structures)
Written as '# Types' prior to Tact 1.6
The first section introduces the present structures, i.e., some of the [composite types](/book/types#composite-types), [structs and Messages](/book/structs-and-messages) declared or imported directly in the contract code, as well as those exposed from the Core standard library.
Along with the number of structures present, each of the [structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) is described with its respective signature and [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language), which include the [message opcodes](/book/structs-and-messages#message-opcodes).
For example:
```md
Total structures: 10
### StateInit
TL-B: `_ code:^cell data:^cell = StateInit`
Signature: `StateInit{code:^cell,data:^cell}`
### Deploy
TL-B: `deploy#946a98b6 queryId:uint64 = Deploy`
Signature: `Deploy{queryId:uint64}`
...etc.
```
The [TL-B schema](https://docs.ton.org/develop/data-formats/tl-b-language) of each [Message](/book/structs-and-messages#messages) contains its opcode, which is handy for looking up the auto-generated opcodes as well as confirming the [manually provided ones](/book/structs-and-messages#message-opcodes). For example, the following [Message](/book/structs-and-messages#messages) declarations:
```tact
message GeneratedOpcode { }
message(0x12345678) ManuallySpecifiedOpcode { }
```
translate to their respective [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language):
```md
### GeneratedOpcode
TL-B: `generated_opcode#6dfea180 = GeneratedOpcode`
Signature: `GeneratedOpcode{}`
### ManuallySpecifiedOpcode
TL-B: `manually_specified_opcode#12345678 = ManuallySpecifiedOpcode`
Signature: `ManuallySpecifiedOpcode{}`
```
Here, `6dfea180` and `12345678`, specified after the `#` in the [constructor definitions](https://docs.ton.org/v3/documentation/data-formats/tlb/tl-b-language#constructors), are opcodes written in hexadecimal notation representing 32-bit unsigned integers. Thus, the automatically generated `6dfea180` opcode of the `GeneratedOpcode` [Message](/book/structs-and-messages#messages) represents the decimal value 1845404032, and the manually provided `12345678` opcode of the `ManuallySpecifiedOpcode` [Message](/book/structs-and-messages#messages) represents the decimal value 305419896, and **not** 12345678 as it might appear.
#### Get methods[](#getters)
This section specifies the number of available get methods or [getter functions](/book/functions#get) and outlines them with their argument names, if any.
For example:
```md
Total get methods: 2
## lshift
Argument: x
## gas
```
Here, the `lshift()` getter has a single argument `x`, whereas the `gas()` getter has no arguments.
#### Exit codes[](#exit-codes)
This section lists all default [exit codes](/book/exit-codes), as well as those generated from the error messages of the [`require()`](/ref/core-debug#require), along with those messages for your convenience.
For example:
```md
* 2: Stack underflow
* 3: Stack overflow
...etc.
* 135: Code of a contract was not found
* 42933: Hey, I'm the error message of require()
```
Here, the [exit codes](/book/exit-codes) in the range from 0 to 255 are those reserved by TON Blockchain or the Tact compiler, while the exit code of 42933 is produced by the respective call to the [`require()`](/ref/core-debug#require) function.
#### Trait inheritance diagram[](#trait-diagram)
This section shows a [Mermaid](https://mermaid.js.org/) diagram of [inherited traits](/book/contracts#traits), including the [`BaseTrait`](/ref/core-base).
For example:

Here, [`JettonWallet`](https://github.com/tact-lang/jetton/blob/70f6c9c51755fcab4b451da0cd2f2016476271cc/sources/jetton_wallet.tact) inherits the `WalletExitcodes` and `GasConstant` traits, and all inherit the [`BaseTrait`](/ref/core-base).
#### Contract dependency diagram[](#contract-diagram)
This section shows a [Mermaid](https://mermaid.js.org/) diagram of [contract](/book/contracts) dependencies, i.e., any calls to [`initOf`](/book/expressions#initof) to compute the initial state of other contracts and [`codeOf`](/book/expressions#codeof) to compute the code of other contracts.
If the contract has no dependencies, only its name is displayed:

However, if the contract, for example `FirstOne`, somewhere in its code computes the [initial state](/book/expressions#initof) of another contract, for example `SecondOne`, such a relationship is shown in the diagram:

A real-world example of this would be the [`JettonMinter`](https://github.com/tact-lang/jetton/blob/70f6c9c51755fcab4b451da0cd2f2016476271cc/sources/jetton_minter_discoverable.tact) contract, commonly referred to as the [Jetton Master](/cookbook/jettons#jetton-master-contract). Often, `JettonMinter` needs the [initial state](/book/expressions#initof) of the [`JettonWallet`](https://github.com/tact-lang/jetton/blob/70f6c9c51755fcab4b451da0cd2f2016476271cc/sources/jetton_wallet.tact), which is why `JettonMinter` defines the following [internal function](/book/contracts#internal-functions):
```tact
inline fun getJettonWalletInit(address: Address): StateInit {
return initOf JettonWallet(address, myAddress());
}
```
Thus, the following dependency diagram is produced:

### Compiled contract, `.boc`[](#boc)
The end result of compiling each contract is obtaining its code in the [BoC](/book/cells#cells-boc) format, which is placed in a binary file with the `.boc` extension.
By combining the initial code with the initial data for the contract, you can locally and deterministically obtain the blockchain [`Address`](/book/types#primitive-types) for the given contract.
From there, you only need to send the message containing the initial code and data, usually referred to as the initial state or [`StateInit`](/book/expressions#initof), to the computed address and provide enough Toncoin for the deployment.
However, instead of doing this manually, prefer using the provided [TypeScript wrappers](#wrap-ts) and other [deployment facilities](/book/deploy).
Note
When compiling with the [`fullWithDecompilation`](/book/config#projects-mode) mode set in the [Tact config](/book/config), the resulting `.boc` is then decompiled into intermediate assembly sources.
The `.boc` file and decompiled assembly sources are intended to be used by advanced users and are not required for regular [deployment](/book/deploy) and [debugging](/book/debug). For example, the `.boc` would be very handy when working with a language that doesn’t yet have an officially supported [wrapper generation setup](#wrap).
### Contract package, `.pkg`[](#pkg)
The contract package is a way to bundle a compiled contract, its dependencies, and all related metadata into a single file. It is a JSON file with the `.pkg` extension that one can use to [verify the smart contract’s origin](https://verifier.ton.org).
Additionally, the [contract ABI](#abi) is included in the package as a string.
Read more: [OTP-006: Contract Package](/ref/evolution/otp-006).
### Contract ABI, `.abi`[](#abi)
A contract’s ABI is a JSON file with the `.abi` extension, which describes the contract’s data structures, receivers, getters, possible [exit codes](/book/exit-codes) (errors), and [interfaces](/book/contracts#interfaces).
Essentially, it’s a [compilation report](#report) provided in a machine-readable format, though without the diagrams.
Note that the contract ABI is included in the [contract package](#pkg) as a string.
Read more: [OTP-002: Contract ABI](/ref/evolution/otp-002).
### Bindings and wrappers[](#wrap)
Using the [compiled `.boc`](#boc) directly is inconvenient and error-prone, which is why Tact also provides a number of contract wrappers in different general-purpose languages.
Note
Currently, only [TypeScript wrappers](#wrap-ts) are provided. This [may change in the future](https://github.com/tact-lang/tact/issues/255).
#### TypeScript wrappers, `.ts`[](#wrap-ts)
To aid in [deployment](/book/deploy) and further interactions with the contract, after each successful compilation, a `.ts` file containing all necessary wrappers is produced. The entities added there all use the [@ton/core](https://github.com/ton-org/ton-core) library.
All the [structs](/book/structs-and-messages#structs) and [message structs](/book/structs-and-messages#messages) observable in the [compilation report](#structures) are provided as new `type` definitions.
```typescript
export type StateInit = {
$$type: 'StateInit';
code: Cell;
data: Cell;
}
```
For each such definition, there are corresponding `storeStructureName()` and `loadStructureName()` functions to help compose and parse cells from these structures.
```typescript
export function storeStateInit(src: StateInit) {
return (builder: Builder) => {
const b_0 = builder;
b_0.storeRef(src.code);
b_0.storeRef(src.data);
};
}
export function loadStateInit(slice: Slice) {
const sc_0 = slice;
const _code = sc_0.loadRef();
const _data = sc_0.loadRef();
return { $$type: 'StateInit' as const, code: _code, data: _data };
}
```
All global constants are exported as well.
```typescript
// Global constant
export const CUSTOM_CONSTANT_NAME = 42n;
```
Finally, the [ABI declarations](#abi) are defined and a contract wrapper is provided. The latter is designed specifically to allow you to easily [deploy](/book/deploy) and interact with the deployed contract.
```typescript
export class Playground implements Contract {
// Constants declared in the contract or its inherited traits
public static readonly storageReserve = 0n;
// Named constructor from the initial package
// for deployments and further interactions
static async fromInit() {
const init = await Playground_init(); // init code and data
const address = contractAddress(0, init);
return new Playground(address, init);
}
// Named constructor from the address
// for interacting with deployed contracts
static fromAddress(address: Address) {
return new Playground(address);
}
// A helper function to send messages to the contract
async send(
provider: ContractProvider,
via: Sender,
args: { value: bigint, bounce?: boolean| null | undefined },
message: null | "plays",
) { /* ... */ }
// Getters
async getLshift(provider: ContractProvider, x: bigint): bigint { /* ... */ }
async getGas(provider: ContractProvider): bigint { /* ... */ }
}
```
Available since Tact 1.6.1
Now, you can also access two records that mirror each other: a `ContractName_errors` record, which maps [exit code](/book/exit-codes) numbers to their error message strings, and a `ContractName_errors_backward` record, which does the opposite — maps the error message strings to the exit code numbers. Organized this way, they provide convenient bidirectional access to exit codes.
Both records only feature the standard exit codes reserved by TON Blockchain and Tact compiler and those generated by [`require()`](/ref/core-debug#require) function. If you define some custom exit codes as global or contract constants, those will be exported separately.
```typescript
export const Playground_errors = {
2: { message: `Stack underflow` },
3: { message: `Stack overflow` },
// ...
47499: { message: `The expected exit code didn't match the actual one!` },
} as const
export const Playground_errors_backward = {
"Stack underflow": 2,
"Stack overflow": 3,
// ...
"The expected exit code didn't match the actual one!": 47499,
} as const
// Global constant
export const CUSTOM_CONSTANT_NAME = 42n;
export class Playground implements Contract {
// Constants declared in the contract or its inherited traits
public static readonly storageReserve = 0n;
// ...
}
```
The `ContractName_errors_backward` record is also accessible through a `ContractName.errors` static field on each exported contract class.
```typescript
export class Playground implements Contract {
// ...
// Same record from error message names to their exit code numbers,
// but exposed as a public static class field and accessible through
// instances of this contract in your tests or scripts
public static readonly errors = Playground_errors_backward;
// ...
}
```
To help you access [opcodes](/book/structs-and-messages#message-opcodes) of all [message structs](/book/structs-and-messages#messages) that are declared or imported directly in the contract code and those exposed from the Core standard library, there’s a `ContractName.opcodes` static field.
```typescript
export class Playground implements Contract {
// ...
// A record from message struct names to their opcodes (32-bit integer headers)
public static readonly opcodes = Playground_opcodes;
// ...
}
```
Note
See how to apply TypeScript wrappers in scripts and tests of your [Blueprint](https://github.com/ton-org/blueprint) projects:
* [Parsing body of the emitted message](/book/debug#logging-parsing).
* [Interacting with TypeScript wrappers](/book/debug#tests-wrappers).
---
# Configuration
> The behavior of the Tact compiler can be customized using its configuration file
The behavior of the Tact compiler can be customized using its configuration file, `tact.config.json` — a JSON file that contains a list of settings according to the specific [schema](#schema).
This page lists all the configuration options as they’re structured in the [schema](#schema). Look for the table of contents on the right to easily navigate them.
Note
The only requirement for that file is to be valid JSON with [proper fields](#schema), so it can be named arbitrarily. However, naming your config file as `tact.config.json` is a common convention encouraged and supported by all tools working with Tact.
## `$schema`[](#schema)
A [JSON schema](https://json-schema.org/) file is available for editors to provide autocompletion and hover hints: [configSchema.json](http://raw.githubusercontent.com/tact-lang/tact/main/src/config/configSchema.json).
Simply add the `$schema` field at the top of your configuration file:
```json
{
"$schema": "http://raw.githubusercontent.com/tact-lang/tact/main/src/config/configSchema.json",
"projects": []
}
```
## `projects`[](#projects)
A list of Tact projects with respective compilation options. Each `.tact` file represents its own Tact project.
```json
{
"projects": [
{ },
{ }
]
}
```
### `name`[](#projects-name)
The name of the project. All generated files are prefixed with it.
In [Blueprint](https://github.com/ton-org/blueprint), `name` refers to the name of the contract itself.
```json
{
"projects": [
{
"name": "some_prefix"
},
{
"name": "ContractUnderBlueprint"
}
]
}
```
### `path`[](#projects-path)
Path to the project’s Tact file. You can specify only one Tact file per project.
In [Blueprint](https://github.com/ton-org/blueprint), the `path` field is superseded by the `target` field in `wrappers/ContractName.compile.ts` by default, or in `compilables/ContractName.compile.ts` if you have the `separateCompilables` option set in [`blueprint.config.ts`](https://github.com/ton-org/blueprint/tree/main?tab=readme-ov-file#configuration).
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact"
}
]
}
```
### `output`[](#projects-output)
Path to the directory where all generated files will be placed.
In [Blueprint](https://github.com/ton-org/blueprint), the `output` field is not used, and all generated files are always placed in `build/ProjectName/`.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output"
}
]
}
```
### `options`[](#projects-options)
Compilation options for the project.
In [Blueprint](https://github.com/ton-org/blueprint), these options act as defaults unless modified in `wrappers/ContractName.compile.ts` by default, or in `compilables/ContractName.compile.ts` if you have the `separateCompilables` option set in [`blueprint.config.ts`](https://github.com/ton-org/blueprint/tree/main?tab=readme-ov-file#configuration).
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {}
},
{
"name": "ContractUnderBlueprint",
"options": {}
}
]
}
```
#### `debug`[](#options-debug)
`false` by default.
If set to `true`, enables debug output for a contract and allows the usage of the [`dump()`](/ref/core-debug#dump) function, which is useful for [debugging purposes](/book/debug). With this option enabled, the contract will report that it was compiled in debug mode using the `supported_interfaces` method.
The `debug` mode implies the activation of the [`nullChecks`](#safety-nullchecks) safety option.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {
"debug": true
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"debug": true
}
}
]
}
```
Note
Read more on the dedicated page: [Debugging](/book/debug).
#### `external`[](#options-external)
`false` by default.
If set to `true`, enables support for [external](/book/external) message receivers.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {
"external": true
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"external": true
}
}
]
}
```
Note
Read more on the dedicated page: [External messages](/book/external).
#### `ipfsAbiGetter`[](#options-ipfsabigetter)
`false` by default.
If set to `true`, enables the generation of a [getter](/book/contracts#getter-functions) with IPFS links describing the contract’s ABI.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {
"ipfsAbiGetter": true
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"ipfsAbiGetter": true
}
}
]
}
```
Note
Read more on the dedicated page: [OTP-003: Self-ABI reporting](/ref/evolution/otp-003).
#### `interfacesGetter`[](#options-interfacesgetter)
`false` by default.
If set to `true`, enables the generation of a [getter](/book/contracts#getter-functions) with a list of interfaces provided by the contract.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {
"interfacesGetter": true
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"interfacesGetter": true
}
}
]
}
```
Note
Read more: [Supported interfaces](/book/contracts#interfaces).
#### `experimental`[](#options-experimental)
Experimental options that might be removed in the future. Use with caution!
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {
"experimental": {}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"experimental": {}
}
}
]
}
```
##### `inline`[](#experimental-inline)
`false` by default.
If set to `true`, enables inlining of all functions in contracts. This can reduce gas usage at the cost of larger contracts.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"options": {
"experimental": {
"inline": true
}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"experimental": {
"inline": true
}
}
}
]
}
```
#### `safety`[](#options-safety)
Available since Tact 1.6
Options that affect the safety of contracts.
```json
{
"projects": [
{
"name": "contract",
"path": "./contract.tact",
"output": "./output",
"options": {
"safety": {}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"safety": {}
}
}
]
}
```
##### `nullChecks`[](#safety-nullchecks)
Available since Tact 1.6
`true` by default.
If set to `true`, enables runtime null checks on the arguments of the unwrapping [non-null assertion `!!`](/book/operators/#unary-non-null-assert) operator. Setting the option to `false` disables these checks and decreases gas consumption.
Null checks are always enabled in [`debug`](#options-debug) mode.
```json
{
"projects": [
{
"name": "contract",
"path": "./contract.tact",
"output": "./output",
"options": {
"safety": {
"nullChecks": false
}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"safety": {
"nullChecks": false
}
}
}
]
}
```
#### `optimizations`[](#options-optimizations)
Available since Tact 1.6
Options that affect the optimization of contracts.
```json
{
"projects": [
{
"name": "contract",
"path": "./contract.tact",
"output": "./output",
"options": {
"optimizations": {}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"optimizations": {}
}
}
]
}
```
##### `alwaysSaveContractData`[](#optimizations-alwayssavecontractdata)
Available since Tact 1.6
`false` by default.
If set to `false`, saves the contract state at the end of a receiver execution only if the contract state was modified. Otherwise, the contract data cell is not overwritten. Setting the option to `true` results in each receiver updating the contract data cell regardless of contract state modifications, thus increasing gas consumption.
This option can be used to provide an extra safety level or for debugging.
```json
{
"projects": [
{
"name": "contract",
"path": "./contract.tact",
"output": "./output",
"options": {
"optimizations": {
"alwaysSaveContractData": true
}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"optimizations": {
"alwaysSaveContractData": true
}
}
}
]
}
```
##### `internalExternalReceiversOutsideMethodsMap`[](#optimizations-internalexternalreceiversoutsidemethodsmap)
Available since Tact 1.6.3
`true` by default.
If set to `true`, stores internal and external receivers outside the methods map.
When enabled, it saves gas but can cause the contract to be incorrectly recognized and misparsed by some explorers and user wallets.
```json
{
"projects": [
{
"name": "contract",
"path": "./contract.tact",
"output": "./output",
"options": {
"optimizations": {
"internalExternalReceiversOutsideMethodsMap": false
}
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"optimizations": {
"internalExternalReceiversOutsideMethodsMap": false
}
}
}
]
}
```
#### `enableLazyDeploymentCompletedGetter`[](#options-enablelazydeploymentcompletedgetter)
Available since Tact 1.6
`false` by default.
If set to `true`, enables the generation of the `lazy_deployment_completed()` getter. This option has no effect if [contract parameters](/book/contracts#parameters) are declared.
```json
{
"projects": [
{
"name": "contract",
"path": "./contract.tact",
"output": "./output",
"options": {
"enableLazyDeploymentCompletedGetter": true
}
},
{
"name": "ContractUnderBlueprint",
"options": {
"enableLazyDeploymentCompletedGetter": true
}
}
]
}
```
### `verbose`[](#projects-verbose)
Available since Tact 1.6
`1` by default.
Sets the verbosity level — higher values produce more output.
```json
{
"projects": [
{
"name": "func_only",
"path": "./contract.tact",
"output": "./contract_output",
"verbose": 2
}
]
}
```
### `mode`[](#projects-mode)
Compilation mode of the project. Valid values are:
| Value | Description |
| :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------- |
| `"full"` | (default) Runs the entire compilation pipeline and emits FunC code, BoC, and various utility files, including wrappers for TypeScript. |
| `"fullWithDecompilation"` | Runs the entire compilation pipeline like `"full"` and also decompiles the produced binary code in BoC format. |
| `"funcOnly"` | Outputs only intermediate FunC code, preventing further compilation. |
| `"checkOnly"` | Performs only syntax and type checking, preventing further compilation. |
In [Blueprint](https://github.com/ton-org/blueprint), `mode` is always set to `"full"` and cannot be overridden.
```json
{
"projects": [
{
"name": "some_prefix",
"path": "./contract.tact",
"output": "./contract_output",
"mode": "full"
},
{
"name": "func_only",
"path": "./contract.tact",
"output": "./contract_output",
"mode": "funcOnly"
}
]
}
```
## Full example[](#full-example)
```json
{
"$schema": "http://raw.githubusercontent.com/tact-lang/tact/main/src/config/configSchema.json",
"projects": [
{
"name": "basic",
"path": "./basic.tact",
"output": "./basic_output",
"mode": "full"
},
{
"name": "func_only",
"path": "./basic.tact",
"output": "./basic_output",
"mode": "funcOnly"
},
{
"name": "debugPrefix",
"path": "./contracts/contract.tact",
"output": "./contracts/output",
"options": {
"debug": true
},
"verbose": 2
},
{
"name": "ContractUnderBlueprint",
"options": {
"debug": false,
"external": false,
"ipfsAbiGetter": true,
"interfacesGetter": true,
"experimental": {
"inline": false
},
"safety": {
"nullChecks": false
},
"optimizations": {
"alwaysSaveContractData": true,
"internalExternalReceiversOutsideMethodsMap": true
},
"enableLazyDeploymentCompletedGetter": true
}
}
]
}
```
---
# Constants
> Immutable values that cannot be changed through reassignment
Constants in Tact can be slightly more advanced than in popular languages: they can be virtual and abstract. Smart contracts often need to implement multiple traits, and sometimes you need to configure some of them at compile time. Constructors in traits are prohibited due to their unpredictable behavior. Therefore, we have to use constants and fields instead to pass values to them. It is the job of the main contract to implement values and constants for all traits.
## Simple constant[](#simple-constant)
Let’s start with a simple constant. It is a value that is defined at compile time and cannot be changed. You can define a constant at the top level or inside a contract/trait. Let’s define a constant at the top level:
```tact
const MY_CONSTANT: Int = 42;
```
Similarly for traits and contracts:
```tact
trait MyTrait {
const MY_CONSTANT: Int = 42;
}
contract MyContract {
const MY_CONSTANT: Int = 42;
}
```
## Virtual and abstract constants[](#virtual-and-abstract-constants)
Virtual constants are constants that can be defined in a trait but changed in a contract. This is useful when you need to configure some traits at compile time. Let’s define a virtual constant and an abstract one:
```tact
trait MyTrait {
virtual const MY_FEE: Int = ton("1.0");
}
trait MyAbstractTrait {
abstract const MY_DEV_FEE: Int;
}
```
Now you can override the defaults in the contract:
```tact
contract MyContract with
MyTrait,
MyAbstractTrait, // trailing comma is allowed
{
override const MY_FEE: Int = ton("0.5");
override const MY_DEV_FEE: Int = ton("1000");
}
```
This can be very useful for helping the compiler determine certain values at compile time. For example, you can enable and disable features without needing to change the code and without wasting gas:
```tact
trait Treasure {
virtual const ENABLE_TIMELOCK: Bool = true;
receive("Execute") {
if (self.ENABLE_TIMELOCK) {
//
// This branch would be removed at compile time if ENABLE_TIMELOCK is false
//
}
}
}
contract MyContract with Treasure {
override const ENABLE_TIMELOCK: Bool = false;
}
```
---
# Contracts
> Contracts in Tact are similar to classes in popular object-oriented languages, except that their instances are deployed on the blockchain and they can't be passed around like structs and Messages.
Contracts in Tact are similar to classes in popular object-oriented languages, except that their instances are deployed on the blockchain and they can’t be passed around like [structs and Messages](/book/structs-and-messages).
## Self-references[](#self)
Contracts and [traits](/book/types#traits) have a built-in [identifier](/book/expressions#identifiers) `self`, which is used to refer to their fields (persistent state [variables](#variables) and [constants](#variables)) and methods ([internal functions](#internal-functions)):
```tact
contract Example {
// persistent state variables
foo: Int;
init() {
self.foo = 42; // <- referencing variable foo through self.
}
}
contract ExampleParams(
// persistent state variables
foo: Int,
) {
receive() {
self.foo = 42; // <- referencing variable foo through self.
}
}
```
## Structure[](#structure)
Each contract can be defined with or contain:
* [Inherited traits](#traits)
* [Supported interfaces](#interfaces)
* [Contract parameters](#parameters)
* [Persistent state variables](#variables)
* [Constructor function `init()`](#init-function)
* [Contract constants](#constants)
* [Getter functions](#getter-functions)
* [Receiver functions](#receiver-functions)
* [Internal functions](#internal-functions)
### Inherited traits, `with`[](#traits)
Contracts can inherit all declarations and definitions from [traits](/book/types#traits) and override some of their default behaviors. In addition to that, every contract and trait implicitly inherits the special [`BaseTrait` trait](/ref/core-base).
To inherit a [trait](/book/types#traits), specify its name after the keyword `with` in the contract’s declaration. To inherit multiple traits at once, specify their names in a comma-separated list with an optional trailing comma.
```tact
trait InheritMe {}
trait InheritMeToo {}
// A contract inheriting a single trait
contract Single with InheritMe {}
// A contract inheriting multiple traits
contract Plural with
InheritMe,
InheritMeToo, // trailing comma is allowed
{}
```
As [traits](/book/types#traits) are not allowed to have an [`init()` function](#init-function), a contract inheriting a trait with any [persistent state variables](#variables) declared must either provide its own [`init()` function](#init-function) or declare [contract parameters](#parameters).
```tact
trait Supe { omelander: Bool }
// This contract will perform lazy initialization,
// setting its data on-chain after the initial deployment
contract LazyVot with Supe {
init() { self.omelander = false }
}
// This contract will directly set its values with the
// initial data received from the deployment message
contract Vot(
omelander: Bool,
) with Supe {}
```
If declared or defined in a trait, internal functions and constants can be marked as [virtual or abstract](/book/functions#inheritance) and overridden in contracts inheriting from the trait.
### Supported interfaces, `@interface(…)`[](#interfaces)
It’s hard to determine what a contract does and which [receivers](#receiver-functions) and [getters](#getter-functions) it has without examining its source code. Sometimes the source is unavailable or inaccessible, leaving one to try to disassemble and introspect the contract, which is a very messy and error-prone approach with diminishing returns and no real reproducibility.
To resolve this issue, an [OTP-001: Supported Interfaces](/ref/evolution/otp-001) was created. According to it, Tact contracts [can report](/book/config#options-interfacesgetter) the list of supported interfaces through a special `supported_interfaces` [getter](#getter-functions). That getter is accessible off-chain using any TON Blockchain explorer — one simply needs to specify `supported_interfaces` as a method to execute and obtain a list of hexadecimal values.
These hexadecimal values are truncated to the first 128 bits of [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hashes of the original [`String`](/book/types#primitive-types) values of the supported interfaces. The first value in this list **must** equal 0x5cec3d5d2cae7b1e84ec39d64a851b66 in [hexadecimal notation](/book/integers#hexadecimal), which is the first half of the SHA-256 hash for `"org.ton.introspection.v0"`. If the first value is incorrect, you must stop trying to introspect the contract, as it does not conform to the [Supported Interfaces](/ref/evolution/otp-001) proposal.
To declare support for a certain interface, add one or more `@interface("…")` attributes directly before contract and [trait](/book/types#traits) declarations:
```tact
@interface("His name is")
@interface("John")
contract SeeNah with Misc {
// ...
}
@interface("name_of_your_org - miscellaneous")
trait Misc {
// ...
}
```
Tact provides a small set of interfaces under specific conditions:
* `"org.ton.abi.ipfs.v0"`, according to [OTP-003: Self-ABI Reporting](/ref/evolution/otp-003) — opt-in via [`ipfsAbiGetter`](/book/config#options-ipfsabigetter) config property
* `"org.ton.deploy.lazy.v0"`, according to [OTP-005: Argument-addressable contracts](/ref/evolution/otp-005)
* `"org.ton.debug.v0"`, but only if [debug mode](/book/debug#debug-mode) is enabled
Some [traits](/book/types#traits) in [standard libraries](/ref/standard-libraries) define their interfaces as well:
* [`Ownable`](/ref/stdlib-ownable#ownable) trait specifies `"org.ton.ownable"`
* [`OwnableTransferable`](/ref/stdlib-ownable#ownabletransferable) trait specifies `"org.ton.ownable.transferable.v2"`
* [`Stoppable`](/ref/stdlib-stoppable#stoppable) trait specifies `"org.ton.stoppable"`
* [`Resumable`](/ref/stdlib-stoppable#resumable) trait specifies `"org.ton.resumable"`
To enable the generation of the `supported_interfaces` [getter](#getter-functions) and use the `@interface()` attribute in your Tact contracts, modify the [`tact.config.json`](/book/config) file in the root of your project (or create it if it does not yet exist), and [set the `interfacesGetter` property to `true`](/book/config#options-interfacesgetter).
If you are working on a [Blueprint](https://github.com/ton-org/blueprint)-based project, you can enable `supported_interfaces` in the compilation configs of your contracts, which are located in a directory named `wrappers/`:
wrappers/YourContractName.compile.ts
```typescript
import { CompilerConfig } from '@ton/blueprint';
export const compile: CompilerConfig = {
lang: 'tact',
target: 'contracts/your_contract_name.tact',
options: {
interfacesGetter: true, // ← that's the stuff!
}
};
```
Additionally, [`tact.config.json`](/book/config) may still be used in [Blueprint](https://github.com/ton-org/blueprint) projects. In such cases, values specified in [`tact.config.json`](/book/config) act as defaults unless modified in the `wrappers/`.
Note
If you have the `separateCompilables` option set to `true` in the [`blueprint.config.ts`](https://github.com/ton-org/blueprint/tree/main?tab=readme-ov-file#configuration), then the `.compile.ts` files will be located in the `compilables/` directory, and **not** in `wrappers/`.
Caution
Be aware that adding an interface does not guarantee that the contract actually implements any particular functionality or that it implements it in any particular way. It is simply an off-chain, verifiable promise indicating that a contract *might* contain some specific code. It is your responsibility to trust, but verify, such claims.
In addition, there is no guarantee that there will not be name clashes between different interfaces, although they are unlikely because even the first 128 bits of SHA-256 provide sufficient [collision resistance](https://en.wikipedia.org/wiki/Collision_resistance).
### Contract parameters[](#parameters)
Available since Tact 1.6
Most contracts do not require any on-chain deployment logic that runs just once after the contract’s deployment is completed. As such, the costly lazy deployment strategy provided by the [`init()`](#init-function) function is generally discouraged in favor of simple, direct deployments with [initial code and initial data](/book/expressions#initof).
To declare [persistent state variables](#variables) and set their values during such deployments, use the following *contract parameters* syntax:
```tact
contract ContractParameters(
// persistent state variables declared via the contract parameters syntax
val: Int, // Int, implicitly serialized to a 257-bit signed
val32: Int as uint32, // Int, serialized to a 32-bit unsigned
mapVal: map, // Int keys to Int values
optVal: Int?, // Int or null
) {
// ...
}
```
State variables declared in this way have **no** default value. Instead, they get their initial data only when the contract is deployed, which is much cheaper compared to deployments with an extra initialization step in the [`init()`](#init-function) function.
The use of contract parameters syntax conflicts with using an `init()` function or declaring persistent state variables via the [contract fields syntax](#variables). Whenever possible, prefer using contract parameters unless you need specific on-chain deployment logic that must be run exactly once, i.e. via the `init()` function.
```tact
contract ParamParamParam(
param1: Int,
param2: Int,
) {
// COMPILATION ERROR! init() cannot be used along with contract parameters
init(param1: Int, param2: Int) {}
}
```
An empty parameter list is still a parameter list, meaning that the contract won’t have an implicit or explicit `init()` function and will enjoy storage write optimizations. Removing the empty list makes a contract use the delayed initialization with an implicit `init()` function.
```tact
contract StillParam() {
// COMPILATION ERROR! init() cannot be used along with contract parameters
init() {}
}
contract LazyInit {
// Everything's ok, and the following init() is redundant because there
// would be an implicit empty init() anyway in the absence of contract parameters.
init() {}
}
```
Note
To obtain the initial state of the target contract in [internal functions](#internal-functions), [receivers](#receiver-functions), or [getters](#getter-functions), use the [`initOf`](/book/expressions#initof) expression.
To obtain only the contract’s code, use the [`codeOf`](/book/expressions#codeof) expression.
### Persistent state variables[](#variables)
Contracts can define state variables that persist between contract calls, thus commonly referred to as *storage* variables. Contracts in TON [pay rent](https://docs.ton.org/develop/smart-contracts/fees#storage-fee) in proportion to the amount of persistent space they consume, so [compact representations via serialization](/book/integers#serialization) are encouraged.
The storage variables can be defined by using [contract parameters](#parameters) or by using the following *contract fields* syntax:
```tact
contract ContractFields {
// persistent state variables declared via the contract fields syntax
val: Int; // Int, implicitly serialized to a 257-bit signed
val32: Int as uint32; // Int, serialized to a 32-bit unsigned
mapVal: map; // Int keys to Int values
optVal: Int?; // Int or null
}
```
State variables defined via the contract fields syntax must have a default value or be initialized in the [`init()`](#init-function) function, which runs once on deployment of the contract. The only exception is for persistent state variables of type [`map`](/book/maps), since they are initialized empty by default.
The default value of state variables is assigned before any values can be assigned in the [`init()`](#init-function) function.
```tact
contract Example {
// persistent state variables
var1: Int = 0; // initialized with default value 0
// constructor function
init() {
self.var1 = 42; // overrides the default to 42
}
}
```
As the contract state is updated at the very end of the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) of the transaction, intermediate assignments of [`Int`](/book/integers) values exceeding the limits specified by [serialization formats](/book/integers#serialization) won’t fail immediately. Instead, such assignments would cause an [exit code 5](/book/exit-codes#5) only after all statements have been executed.
This is to be expected because the integers in the temporary [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) memory, which is used to process the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase), always have 257 bits and are capable of holding values in the inclusive range from −2256 to 2256−1.
```tact
contract DeRanged {
// Persistent state variables
var: Int as uint8; // cannot store values outside the 0-255 range
init() {
self.var = -1; // this won't fail immediately
self.var = 500; // and this won't fail right away either
} // only here, at the end of the compute phase,
// would an error be thrown with exit code 5:
// Integer out of expected range
}
```
In the end, this means that you cannot rely on intermediate out-of-bounds checks because there are none at [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) runtime, and only the last assignment of each state variable is used to update its persistent state value.
```tact
contract Zero {
// Persistent state variables
var: Int as uint8; // cannot store values outside the 0-255 range
var2: Int as uint4; // cannot store values outside the 0-15 range
init() {
self.var = -1; // this won't fail
self.var = 0; // this is in the range of `uint8`
self.var2 = -1; // this won't fail
self.var2 = 15; // this is in the range of `uint4`
} // no errors, and now `self.var` is 0 and `self.var2` is 15
}
```
The above contract fields syntax for declaring persistent state variables conflicts with the use of [contract parameters](#parameters). Use one or the other, but not both.
```tact
contract ParamParamParam(
param1: Int,
param2: Int,
) {
// COMPILATION ERROR! Cannot use contract fields along with contract parameters.
field1: Int;
field2: Int;
}
```
Note
Tact supports local, non-persistent state variables too. See: [Variable definition with `let` statement](/book/statements#let).
### Contract constants[](#constants)
Unlike [variables](#variables), constants cannot change. Their values are calculated at *compile-time* and cannot change during execution.
There isn’t much difference between constants defined outside of a contract (global constants) and those inside the contract (contract constants). Those defined outside can be used by other contracts in your project.
Constant initialization must be relatively simple and only rely on values known during compilation. If you add two numbers, for example, the compiler will calculate the result during the build and put the result in your compiled code.
You can read constants both in [receivers](#receiver-functions) and in [getters](#getter-functions).
Unlike [contract variables](#variables), **contract constants don’t consume space in persistent state**. Their values are stored directly in the code [`Cell`](/book/cells#cells) of the contract.
```tact
// global constants are calculated at compile-time and cannot change
const GlobalConst1: Int = 1000 + ton("42") + pow(10, 9);
contract Example {
// contract constants are also calculated at compile-time and cannot change
const ContractConst1: Int = 2000 + ton("43") + pow(10, 9);
// contract constants can be an easy alternative to enums
const StateUnpaid: Int = 0;
const StatePaid: Int = 1;
const StateDelivered: Int = 2;
const StateDisputed: Int = 3;
get fun sum(): Int {
// access constants from anywhere
return GlobalConst1 + self.ContractConst1 + self.StatePaid;
}
}
```
Read more about constants on their dedicated page: [Constants](/book/constants).
### Constructor function `init()`[](#init-function)
On deployment of the contract, the constructor function `init()` is run. Unlike [contract parameters](#parameters), it performs a delayed initialization of the contract data, setting the values of persistent state variables on-chain.
If a contract has any [persistent state variables](#variables) without default values specified, it must initialize them in this function.
```tact
contract Example {
// persistent state variables
var1: Int = 0; // initialized with default value 0
var2: Int; // must be initialized in the init() function
var3: Int = 7; // initialized with default value 7
// constructor function
init() {
self.var2 = 42;
self.var3 = 32; // overrides the default to 32
}
}
```
If a contract doesn’t have any persistent state variables, or if they all have their default values specified, it may omit the `init()` function declaration altogether. That is because unless explicitly declared, the empty `init()` function is present by default in all contracts that do not declare [contract parameters](#parameters).
The following is an example of a valid empty contract:
```tact
contract IamEmptyAndIKnowIt {}
```
For your convenience, the parameter list of `init()` can have a trailing comma:
```tact
contract TheySeeMeTrailing {
init(
param1: Int,
param2: Int, // trailing comma is allowed
) {
// ...
}
}
```
Available since Tact 1.6.7 The parameters of the `init()` function can specify [serialization formats](/book/integers#serialization) using the `as` keyword, just like you can with contract fields:
```tact
contract Example {
param: Int as uint32;
init(param: Int as uint32) {
self.param = param;
}
}
```
Tip
Always specify serialization formats for initialization parameters with same types as for contract fields that you want to initialize.
Usage of the `init()` function conflicts with the use of [contract parameters](#parameters). Use one or the other, but not both.
```tact
contract ParamParamParam(
param1: Int,
param2: Int,
) {
// COMPILATION ERROR! init() cannot be used along with contract parameters
init(param1: Int, param2: Int) {}
}
```
Note that even an empty contract parameter list counts as using [contract parameters syntax](#parameters) and means that the contract won’t have any variables in its persistent state. Removing the empty list makes a contract use the delayed initialization with an implicit `init()` function.
```tact
contract StillParam() {
// COMPILATION ERROR! init() cannot be used along with contract parameters
init() {}
}
contract LazyInit {
// Everything's ok, and the following init() is redundant because there
// would be an implicit empty init() anyway in the absence of contract parameters.
init() {}
}
```
Note
To obtain the initial state of the target contract in [internal functions](#internal-functions), [receivers](#receiver-functions), or [getters](#getter-functions), use the [`initOf`](/book/expressions#initof) expression.
To obtain only the contract’s code, use the [`codeOf`](/book/expressions#codeof) expression.
### Getter functions[](#getter-functions)
[Getter functions](/book/functions#get) are **not accessible** from other contracts and are exported only to the off-chain world.
```tact
contract HelloWorld(foo: Int) {
// Getter function with return type Int
get fun foo(): Int {
return self.foo + 42;
}
}
```
Read more about them in their dedicated section: [Getter functions](/book/functions#get).
### Receiver functions[](#receiver-functions)
[Receiver functions](/book/functions#receivers) in Tact can be one of the following three kinds:
* [`receive()`](/book/receive), which receives internal messages (from other contracts).
* [`bounced()`](/book/bounced), which is called when an outgoing message from this contract bounces back.
* [`external()`](/book/external), which doesn’t have a sender and can be sent by anyone in the world.
```tact
message CanBounce {
counter: Int;
}
contract HelloWorld {
counter: Int;
init() {
self.counter = 0;
}
get fun counter(): Int {
return self.counter;
}
// internal message receiver, which responds to a string message "increment"
receive("increment") {
self.counter += 1;
// sending the message back to the sender
send(SendParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
body: CanBounce { counter: self.counter }.toCell(),
});
}
// bounced message receiver, which is called when the message bounces back to this contract
bounced(src: bounced) {
self.counter = 0; // reset the counter in case the message bounces
}
// external message receiver, which responds to off-chain message "hello, it's me"
external("hello, it's me") {
// can't be replied to as there's no sender!
self.counter = 0;
}
}
```
Naming a parameter of the receiver function with an underscore `_` indicates that its value is unused and discarded. This is useful when you don’t need to inspect the received message and only want it to convey a specific opcode:
```tact
message(42) UniverseCalls {}
contract Example {
receive(_: UniverseCalls) {
// Got a Message with opcode 42
}
}
```
### Internal functions[](#internal-functions)
These functions behave similarly to private methods in popular object-oriented languages — they’re internal to contracts and can be called by prefixing them with a special [identifier `self`](#self). That’s why internal functions are sometimes referred to as “contract methods.”
Internal functions can access the contract’s [persistent state variables](#variables) and [constants](#constants).
They can only be called from [receivers](#receiver-functions), [getters](#getter-functions), and other internal functions, but not from other contracts or [`init()`](#init-function).
```tact
contract Functions {
val: Int = 0;
// this contract method can only be called from within this contract and access its variables
fun onlyZeros() {
require(self.val == 0, "Only zeros are permitted!");
}
// receiver function, which calls the internal function onlyZeros
receive("only zeros") {
self.onlyZeros();
}
}
```
Read more about them in their dedicated section: [Internal functions](/book/functions#fun-internal).
Note
Tact supports other kinds of functions too. See: [Functions](/book/functions).
### Converting to Cell or Slice[](#converting-to-cell-or-slice)
Available since Tact 1.6.12
You can convert a contract instance to a [`Cell`](/book/cells#cells) or [`Slice`](/book/cells#slices) using the `toCell()` and `toSlice()` methods. These methods will build a new `Cell` or `Slice` with the contract data.
```tact
// ...
contract WalletV4(
seqno: Int as uint32,
walletId: Int as int32,
publicKey: Int as uint256,
extensions: map,
) {
// ...
external(msgSlice: Slice) {
let msg = ExtRequest.fromSlice(msgSlice);
throwIf(Expired, msg.validUntil < now());
throwUnless(SeqnoMismatch, msg.seqno == self.seqno);
throwUnless(WalletIdMismatch, msg.walletId == self.walletId);
throwUnless(SignatureMismatch, msg.bundle.verifySignature(self.publicKey));
acceptMessage();
self.seqno += 1;
setData(self.toCell()); // <- set the contract data explicitly for low level control
commit();
// ...
}
}
```
This is useful when you need to explicitly set data of your contract for low level control of the contract data.
Note
If a contract doesn’t use [contract parameters](/book/contracts#parameters), the resulting `Cell` or `Slice` will contain a leading one bit representing the [lazy initialization bit](/book/functions/#init).
Useful links:
[`Contract.toCell()` in Core library](/ref/core-cells#contracttocell)\
[`Contract.toSlice()` in Core library](/ref/core-cells#contracttoslice)
---
# Debugging and testing
> Various ways to reveal and prevent problems or bugs in Tact code
Without fail, the code we write as smart contract developers doesn’t always do what we expect it to do. Sometimes it does something completely different! When the unexpected happens, the next task is to figure out why. To do so, there are various ways to reveal problems or “bugs” in the code. Let’s get to *debugging*!
[General approach ](#approach)
[Debug mode ](#debug-mode)
[Structure of tests ](#tests-structure)
[Dump values ](#tests-dump)
[Expect certain states ](#tests-errors)
[Send messages ](#tests-send)
[Observe fees ](#tests-fees)
[Expect exit codes ](#tests-errors)
[Simulate time ](#tests-time)
[Emit and log messages ](#logging)
[Handle bounced messages ](#bounced)
[Experimental lab setup ](#lab)
## General approach[](#approach)
At the moment, Tact doesn’t have a step-through debugger. Despite that, it’s still possible to use the [“printf debugging”](https://en.wikipedia.org/wiki/Debugging#printf_debugging) approach.
This involves actively placing [`dump()`](/ref/core-debug#dump) and [`dumpStack()`](/ref/core-debug#dumpstack) function calls throughout your code and observing the states of variables at a given point in time. Note that these functions work only in [debug mode](#debug-mode) and won’t be executed otherwise.
Note
See how to use [`dump()`](/ref/core-debug#dump) for debugging: [Debug with `dump()`](#tests-dump).
In addition to dumping values, it’s often helpful to use assertive functions like [`require()`](/ref/core-debug#require), [`throwIf()`](/ref/core-debug#throwif), and [`throwUnless()`](/ref/core-debug#throwunless). They help clearly state your assumptions and are handy for setting up “trip wires” for catching issues in the future.
If you can’t find or resolve the cause of your issues, try asking the community in Tact’s [Telegram chat](https://t.me/tactlang), or if your issue or question is generally related to TON more than to Tact, hop into the [TON Dev Telegram chat](https://t.me/tondev_eng).
## Common debugging functions[](#debug-functions)
Tact provides a handful of various functions useful for debugging: [Core library → Debug](/ref/core-debug).
## Enabling debug mode in compilation options[](#debug-mode)
In order to make certain functions like [`dump()`](/ref/core-debug#dump) or [`dumpStack()`](/ref/core-debug#dumpstack) work, you need to enable debug mode.
Note
Make sure to disable debug mode in production, as the [`dump()`](/ref/core-debug#dump) and [`dumpStack()`](/ref/core-debug#dumpstack) functions are very gas-expensive and should only be used for local debugging.
The simplest and recommended approach is to modify the [`tact.config.json`](/book/config) file in the root of your project (or create it if it doesn’t exist yet) and [set the `debug` property to `true`](/book/config#options-debug).
If you’re working on a [Blueprint](https://github.com/ton-org/blueprint)-based project, you can enable debug mode in the compilation configs of your contracts, which are located in a directory named `wrappers/`:
wrappers/YourContractName.compile.ts
```typescript
import { CompilerConfig } from '@ton/blueprint';
export const compile: CompilerConfig = {
lang: 'tact',
target: 'contracts/your_contract_name.tact',
options: {
debug: true, // ← that's the stuff!
}
};
```
Note that versions of [Blueprint](https://github.com/ton-org/blueprint) starting with 0.20.0 automatically enable debug mode in `wrappers/` for new contracts.
In addition to that, [`tact.config.json`](/book/config) may still be used in [Blueprint](https://github.com/ton-org/blueprint) projects. In such cases, values specified in [`tact.config.json`](/book/config) act as defaults unless modified in the `wrappers/`.
Note
If you have the `separateCompilables` option set to `true` in the [`blueprint.config.ts`](https://github.com/ton-org/blueprint/tree/main?tab=readme-ov-file#configuration), then the `.compile.ts` files will be located in the `compilables/` directory and **not** in `wrappers/`.
Note
Read more about configuration and the [`tact.config.json`](/book/config) file: [Configuration](/book/config).\
See how to use [`dump()`](/ref/core-debug#dump) for debugging: [Debug with `dump()`](#tests-dump).
## Writing tests in Blueprint, with Sandbox and Jest[](#tests)
The [Blueprint](https://github.com/ton-org/blueprint) is a popular development framework for writing, testing, and deploying smart contracts on TON Blockchain.
For testing smart contracts, it uses the [Sandbox](https://github.com/ton-org/sandbox), a local TON Blockchain emulator, and [Jest](https://jestjs.io), a JavaScript testing framework.
Whenever you create a new [Blueprint](https://github.com/ton-org/blueprint) project or use the `blueprint create` command inside an existing project, it creates a new contract along with a test suite file for it.
Those files are placed in the `tests/` folder and executed with [Jest](https://jestjs.io). By default, all tests run unless you specify a specific group or test closure. For other options, refer to the brief documentation in the Jest CLI: `jest --help`.
### Structure of test files[](#tests-structure)
Let’s say we have a contract named `Playground`, written in the `contracts/playground.tact` file. If we’ve created that contract through [Blueprint](https://github.com/ton-org/blueprint), it also created a `tests/Playground.spec.ts` test suite file for us.
The test file contains a single `describe()` [Jest](https://jestjs.io) function call, which denotes a test group.
Inside that group, you’ll have three variables available in all tests within:
* `blockchain` — a local blockchain instance provided by [Sandbox](https://github.com/ton-org/sandbox)
* `deployer` — a TypeScript wrapper used for deploying our `Playground` contract or any other we’d like to deploy
* `playground` — a TypeScript wrapper for our `Playground` contract
Note
It is a common mistake to update `.tact` code and run tests without making a build first. That’s because tests in [Blueprint](https://github.com/ton-org/blueprint) rely on [TypeScript wrappers](#tests-wrappers) generated by the Tact compiler and work with the latest build made.
That is why every time you make a change to your Tact code, make sure to build it with `npx blueprint build` before you execute the test suite. For your convenience, you may combine builds and tests into a single command, as shown in the [experimental lab setup](#lab-4).
Then, a `beforeEach()` [Jest](https://jestjs.io) function is called — it specifies all the code to be executed before each of the subsequent test closures.
Note
It is strongly advised not to modify the contents of `beforeEach()` unless you really need specific behavior for each test closure or the parameters of your [`init()`](/book/contracts#init-function) function have changed.
Additionally, you may need to edit the contents of `beforeEach()` if you’ve changed the [contract parameters](/book/contracts#parameters).
Finally, each test closure is described with a call to the `it()` [Jest](https://jestjs.io) function—that’s where tests are actually written.
The simplest example of a test closure can look like this:
```typescript
it('should deploy', async () => {
// The check is done inside beforeEach, so this can be empty
});
```
### Debug with `dump()`[](#tests-dump)
Note
Calling [`dump()`](/ref/core-debug#dump) is computationally expensive and consumes a lot of gas. Be sure to always supply enough Toncoin in your tests to avoid [exit code -14](/book/exit-codes#-14).
To see the results of [`dump()`](/ref/core-debug#dump) function calls and use the [“printf debugging”](#approach) approach, one has to:
1. Put calls to [`dump()`](/ref/core-debug#dump) and other [common debugging functions](#debug-functions) in relevant places within the code.
2. Run [Jest](https://jestjs.io) tests, which will call the target functions and send messages to the target receivers.
Assuming you’ve created a [new counter contract project](/#start), let’s see how it works in practice.
First, let’s place a call to [`dump()`](/ref/core-debug#dump) in `contracts/simple_counter.tact`, which will output the `amount` passed in the `msg` [struct](/book/structs-and-messages#structs) to the contract’s debug console:
contracts/simple\_counter.tact
```tact
// ...
receive(msg: Add) {
dump(msg.amount);
// ...
}
// ...
```
Next, let’s comment out all existing `it()` test closures in the `tests/SimpleCounter.spec.ts` file. Then add the following one:
tests/SimpleCounter.spec.ts
```typescript
it('should dump', async () => {
await playground.send(
deployer.getSender(),
{ value: toNano('0.5') },
{ $$type: 'Add', queryId: 1n, amount: 1n },
);
});
```
It sends a message to our contract’s `receive(msg: Add)` [receiver](/book/receive) without storing the [results of such send](#tests-send).
Now, if we build our contract with `yarn build` and run our test suite with `yarn test`, we’ll see the following in the test logs:
```txt
console.log
#DEBUG#: [DEBUG] File contracts/simple_counter.tact:17:9
#DEBUG#: 1
at SmartContract.runCommon (node_modules/@ton/sandbox/dist/blockchain/SmartContract.js:221:21)
```
This output is produced by our [`dump()`](/ref/core-debug#dump) call above.
Note
Read more about sending messages to contracts in tests: [Send messages to contracts](#tests-send).
### State expectations with `expect()`[](#tests-expect)
An integral part of writing tests is ensuring that your expectations match the observed reality. For that, [Jest](https://jestjs.io) provides a function `expect()`, which is used as follows:
1. First, an observed variable is provided.
2. Then, a specific method is called to check a certain property of that variable.
Here’s a more involved example, which uses the `expect()` function to check that a counter contract properly increases the counter:
```typescript
it('should increase counter', async () => {
const increaseTimes = 3;
for (let i = 0; i < increaseTimes; i++) {
console.log(`increase ${i + 1}/${increaseTimes}`);
const increaser = await blockchain.treasury('increaser' + i);
const counterBefore = await simpleCounter.getCounter();
console.log('counter before increasing', counterBefore);
const increaseBy = BigInt(Math.floor(Math.random() * 100));
console.log('increasing by', increaseBy);
const increaseResult = await simpleCounter.send(
increaser.getSender(),
{ value: toNano('0.05') },
{ $$type: 'Add', queryId: 0n, amount: increaseBy }
);
expect(increaseResult.transactions).toHaveTransaction({
from: increaser.address,
to: simpleCounter.address,
success: true,
});
const counterAfter = await simpleCounter.getCounter();
console.log('counter after increasing', counterAfter);
expect(counterAfter).toBe(counterBefore + increaseBy);
}
});
```
Note
See more test examples in the [Sandbox](https://github.com/ton-org/sandbox) documentation:\
[Testing flow](https://github.com/ton-org/sandbox/blob/main/docs/testing-key-points.md)\
[Writing tests for Tact](https://github.com/ton-org/sandbox/blob/main/docs/tact-testing-examples.md)
### Utility methods[](#tests-jest-utils)
Test files generated by [Blueprint](https://github.com/ton-org/blueprint) import the `@ton/test-utils` library, which provides access to a number of additional helper methods for the result type of the `expect()` function from [Jest](https://jestjs.io). Note that regular methods like `toEqual()` are still there and ready to be used.
#### toHaveTransaction[](#tohavetransaction)
The method `expect(…).toHaveTransaction()` checks that the list of transactions contains a transaction matching certain properties you specify:
```typescript
const res = await yourContractName.send(…);
expect(res.transactions).toHaveTransaction({
// For example, let's check that a transaction to your contract was successful:
to: yourContractName.address,
success: true,
});
```
To know the full list of such properties, look at the auto-completion options provided by your editor or IDE.
#### toEqualCell[](#toequalcell)
The method `expect(…).toEqualCell()` checks the equality of two [cells](/book/cells#cells):
```typescript
expect(oneCell).toEqualCell(anotherCell);
```
#### toEqualSlice[](#toequalslice)
The method `expect(…).toEqualSlice()` checks the equality of two [slices](/book/cells#slices):
```typescript
expect(oneSlice).toEqualSlice(anotherSlice);
```
#### toEqualAddress[](#toequaladdress)
The method `expect(…).toEqualAddress()` checks the equality of two [addresses](/book/types#primitive-types):
```typescript
expect(oneAddress).toEqualAddress(anotherAddress);
```
### Interacting with TypeScript wrappers[](#tests-wrappers)
Upon successful compilation, the Tact compiler produces a `.ts` file that includes all necessary [TypeScript wrappers](/book/compile#wrap-ts) for easy interaction with a compiled contract. You can use them in tests, deployment scripts, or elsewhere.
Some of the most commonly used generated utility functions, structural types, classes, and constants are described below.
For more, see: [TypeScript wrappers on the Compilation page](/book/compile#wrap-ts).
#### Structures and corresponding (de)composition functions[](#wrappers-structs)
All the [structs](/book/structs-and-messages#structs) and [message structs](/book/structs-and-messages#messages) observable in the [compilation report](/book/compile#structures) are provided as new `type` definitions.
For each such definition, there are corresponding `storeStructureName()` and `loadStructureName()` functions to help compose and parse cells from these structures.
```typescript
// The following import path is relevant for Blueprint projects,
// but your mileage may vary — check your output/ or build/ folders for exact paths.
import { StateInit, loadStateInit, storeStateInit } from '../wrappers/MyContract';
import { beginCell } from '@ton/core';
let si1: StateInit = {
$$type: 'StateInit',
code: beginCell().endCell(),
data: beginCell().endCell(),
};
// Storing StateInit, mutating the passed Builder
let b = beginCell();
storeStateInit(si1)(b);
// Loading StateInit, mutating the passed Slice
let s = b.asSlice();
let si2 = loadStateInit(s);
// They are equal
si1.code === si2.code;
si1.data === si2.data;
```
#### Contract wrapper class[](#wrappers-contract)
The contract wrapper class provides convenient methods to send messages and call getters. It also exposes contract constants, a [record of error string messages to exit code numbers](#wrappers-exit-codes), and a [record of all message opcodes](#wrappers-opcodes).
```typescript
// MyContract is a contract class in the generated TypeScript bindings.
// The following import path is relevant for Blueprint projects,
// but your mileage may vary — check your output/ or build/ folders for exact paths.
import { MyContract } from '../wrappers/MyContract';
import { NetworkProvider } from '@ton/blueprint';
import { toNano } from '@ton/core';
// The main function of each script in Blueprint projects
export async function run(provider: NetworkProvider) {
// Creating an instance of MyContract with no initial data
const myContract = provider.open(await MyContract.fromInit());
// Deploying it via a simple message with `null` body
await myContract.send(
provider.sender(),
{ value: toNano('0.05') },
null,
);
await provider.waitForDeploy(myContract.address);
// Now, let's call some getter
await myContract.getGas();
}
```
#### Bidirectional access for exit codes[](#wrappers-exit-codes)
Available since Tact 1.6.1
You can access two records that mirror each other: a `ContractName_errors` record, which maps [exit code](/book/exit-codes) numbers to their error message strings, and a `ContractName_errors_backward` record, which does the opposite — maps the error message strings to the exit code numbers. Organized this way, they provide convenient bidirectional access to exit codes.
Both records only feature the standard exit codes reserved by TON Blockchain and Tact compiler and those generated by [`require()`](/ref/core-debug#require) function. If you define some custom exit codes as global or contract constants, those will be exported separately.
Additionally, you can access the `ContractName_errors_backward` record through the static field `ContractName.errors`.
```typescript
// MyContract is a contract class in the generated TypeScript bindings.
// The following import path is relevant for Blueprint projects,
// but your mileage may vary — check your output/ or build/ folders for exact paths.
import {
MyContract, // contract class
MyContract_errors, // record of exit code numbers to error string messages
MyContract_errors_backward, // record of error string messages to exit code numbers
} from '../wrappers/MyContract';
// ...somewhere down in the body of the `it()` test closure...
expect(MyContract_errors[37]).toBe("Not enough Toncoin");
expect(receipt.transactions).toHaveTransaction({
from: walletV5.address,
to: myContract, // instance of MyContract
actionResultCode: MyContract_errors_backward['Not enough Toncoin'], // 37
});
// Similar to the previous `toHaveTransaction()` check,
// but now uses the static field instead of the global record
expect(receipt.transactions).toHaveTransaction({
from: walletV5.address,
to: myContract, // instance of MyContract
actionResultCode: myContract.errors['Not enough Toncoin'], // 37
});
```
Only the standard [exit codes](/book/exit-codes) reserved by TON Blockchain and Tact compiler and those generated by [`require()`](/ref/core-debug#require) are present in those records. If you define some custom exit codes as global or contract constants, those will be exported separately.
tact\_MyContract.ts
```typescript
// Global constant
export const CUSTOM_CONSTANT_NAME = 42n;
export class MyContract implements Contract {
// Constants declared in the contract or its inherited traits
public static readonly storageReserve = 0n;
// ...
}
```
#### Message opcodes[](#wrappers-opcodes)
Available since Tact 1.6.1
Through the static field `ContractName.opcodes` you can access opcodes of [message structs](/book/structs-and-messages#messages) that are declared or imported directly in the contract code and those exposed from the Core standard library.
```typescript
// MyContract is a contract class in the generated TypeScript bindings.
// The following import path is relevant for Blueprint projects,
// but your mileage may vary — check your output/ or build/ folders for exact paths.
import { MyContract } from '../wrappers/MyContract';
// ...somewhere down in the body of the `it()` test closure...
expect(receipt.transactions).toHaveTransaction({
from: walletV5.address,
to: escrowContract, // instance of MyContract
op: escrowContract.opcodes.Funding, // 2488396969 (or 0x9451eca9 in hex)
});
```
## Send messages to contracts[](#tests-send)
To send messages to contracts, use the `.send()` method on their [TypeScript wrappers](/book/compile#wrap-ts) like so:
```typescript
// It accepts 3 arguments:
await yourContractName.send(
// 1. sender of the message
deployer.getSender(), // this is a default treasury, can be replaced
// 2. value and (optional) bounce, which is true by default
{ value: toNano('0.5'), bounce: false },
// 3. a message body, if any
'Look at me!',
);
```
The message body can be a simple string or an object specifying fields of the [Message](/book/structs-and-messages#messages) type:
```typescript
await yourContractName.send(
deployer.getSender(),
{ value: toNano('0.5') },
{
$$type: 'NameOfYourMessageType',
field1: 0n, // bigint zero
field2: 'yay',
},
);
```
More often than not, it’s important to store the results of such sends because they contain events that occurred, transactions made, and external messages sent:
```typescript
const res = await yourContractName.send(…);
// res.events — array of events occurred
// res.externals — array of external-out messages
// res.transactions — array of transactions made
```
With that, we can easily filter or check certain transactions:
```typescript
expect(res.transactions).toHaveTransaction(…);
```
### Observe the fees and values[](#tests-fees)
[Sandbox](https://github.com/ton-org/sandbox) provides a helper function `printTransactionFees()`, which pretty-prints all the values and fees used in the provided transactions. It is quite handy for observing the flow of [nanoToncoins](/book/integers#nanotoncoin).
To use it, modify the imports from `@ton/sandbox` at the top of the test file:
```typescript
import { Blockchain, SandboxContract, TreasuryContract, printTransactionFees } from '@ton/sandbox';
// ^^^^^^^^^^^^^^^^^^^^
```
Then, provide an array of transactions as an argument, like so:
```typescript
printTransactionFees(res.transactions);
```
To work with individual values of total fees or fees from the compute and action [phases](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases), inspect each transaction individually:
```typescript
// Storing the transaction handled by the receiver in a separate constant
const receiverHandledTx = res.transactions[1];
expect(receiverHandledTx.description.type).toEqual('generic');
// Needed to please TypeScript
if (receiverHandledTx.description.type !== 'generic') {
throw new Error('Generic transaction expected');
}
// Total fees
console.log('Total fees: ', receiverHandledTx.totalFees);
// Compute fee
const computeFee = receiverHandledTx.description.computePhase.type === 'vm'
? receiverHandledTx.description.computePhase.gasFees
: undefined;
console.log('Compute fee: ', computeFee);
// Action fee
const actionFee = receiverHandledTx.description.actionPhase?.totalActionFees;
console.log('Action fee: ', actionFee);
// Now we can do some involved checks, like limiting the fees to 1 Toncoin
expect(
(computeFee ?? 0n)
+ (actionFee ?? 0n)
).toBeLessThanOrEqual(toNano('1'));
```
Note
[Sandbox](https://github.com/ton-org/sandbox) has many more utility functions that are often handy. For example, it provides `prettyLogTransaction()` and `prettyLogTransactions()`, which operate on a single or multiple transactions respectively, and pretty-print the flow of values between addresses.
### Transactions with intentional errors[](#tests-errors)
Sometimes it’s useful to perform negative tests featuring intentional errors and throwing specific [exit codes](/book/exit-codes).
An example of such a [Jest](https://jestjs.io) test closure in [Blueprint](https://github.com/ton-org/blueprint):
tests/YourTestFileHere.spec.ts
```typescript
it('throws specific exit code', async () => {
// Send a specific message to our contract and store the result
const res = await your_contract_name.send(
deployer.getSender(),
{
value: toNano('0.5'), // value in nanoToncoins sent
bounce: true, // (default) bounceable message
},
'the message your receiver expects', // ← change it to yours
);
// Expect the transaction to our contract to fail with a certain exit code
expect(res.transactions).toHaveTransaction({
to: your_contract_name.address,
exitCode: 5, // ← change it to yours
});
});
```
Note that to track down transactions with a certain exit code, you only need to specify the `exitCode` field in the object argument to the `toHaveTransaction()` method of `expect()`.
However, it’s useful to narrow the scope by specifying the recipient address `to`, so that Jest looks only at the transaction caused by our message to the contract.
### Simulate passage of time[](#tests-time)
The Unix time in local blockchain instances provided by [Sandbox](https://github.com/ton-org/blueprint) starts at the moment of their creation in the `beforeEach()` block.
```typescript
beforeEach(async () => {
blockchain = await Blockchain.create(); // ← here
// ...
});
```
Previously, we’ve been warned not to modify the `beforeEach()` block unless we really need to. Now, we must override the time and travel a little forward.
Let’s add the following line at the end of it, explicitly setting `blockchain.now` to the time when the deployment message was handled:
```typescript
beforeEach(async () => {
// ...
blockchain.now = deployResult.transactions[1].now;
});
```
Now, we can manipulate time in our test clauses. For example, let’s make a transaction one minute after deployment and another one after two minutes:
```typescript
it('your test clause title', async () => {
blockchain.now += 60; // 60 seconds later
const res1 = await yourContractName.send(…);
blockchain.now += 60; // another 60 seconds later
const res2 = await yourContractName.send(…);
});
```
## Logging via `emit`[](#logging)
A [global function](/book/functions#fun-global) [`emit()`](/ref/core-send#emit) sends a message to the outer world — it doesn’t have a specific recipient.
This function is very handy for logging and analyzing data off-chain — one just has to look at [external messages](/book/external) produced by the contract.
### Logs in local Sandbox tests[](#logging-local)
When deploying in the [Sandbox](https://github.com/ton-org/sandbox), you may call [`emit()`](/ref/core-send#emit) from a [receiver function](/book/contracts#receiver-functions) and then observe the list of sent [external messages](/book/external):
```typescript
it('emits', async () => {
const res = await simpleCounter.send(
deployer.getSender(),
{ value: toNano('0.05') },
'emit_receiver', // ← change to the message your receiver handles
);
console.log("Address of our contract: " + simpleCounter.address);
console.log(res.externals); // ← here you would see results of emit() calls,
// and all external messages in general
});
```
### Logs of a deployed contract[](#logging-deployed)
Every transaction on TON Blockchain [contains `out_msgs`](https://docs.ton.org/develop/data-formats/transaction-layout#transaction) — a dictionary that holds the list of outgoing messages created during the transaction execution.
To see logs from [`emit()`](/ref/core-send#emit) in that dictionary, look for external messages without a recipient. In various TON Blockchain explorers, such transactions will be marked as `external-out` with the destination specified as `-` or `empty`.
Note that some explorers deserialize the message body sent for you, while others don’t. However, you can always [parse it yourself](#logging-parsing) locally.
### Parsing the body of the emitted message[](#logging-parsing)
Consider the following example:
```tact
// We have a struct
struct Ballroom {
meme: Bool;
in: Int;
theory: String;
}
// And a simple contract,
contract Bonanza {
// which can receive a String message,
receive("time to emit") {
// emit a String
emit("But to the Supes? Absolutely diabolical.".asComment());
// and a struct
emit(Ballroom { meme: true, in: 42, theory: "Duh" }.toCell());
}
}
```
Now, let’s make a simple [test clause](#tests-structure) for the `Bonanza` contract:
```typescript
it('emits', async () => {
const res = await bonanza.send(
deployer.getSender(),
{ value: toNano('0.05') },
'time to emit',
);
});
```
Here, the `res` object would contain the list of sent [external messages](/book/external) as its `externals` field. Let’s access it to parse the first message sent via a call to [`emit()`](/ref/core-send#emit) in Tact code (or *emitted* for short):
```typescript
it('emits', async () => {
// ... prior code ...
// We'll need only the body of the observed message:
const firstMsgBody = res.externals[0].body;
// Now, let's parse it, knowing it's a text message.
// NOTE: In a real-world scenario,
// you'd want to check that first or wrap this in a try...catch
const firstMsgText = firstMsgBody.asSlice().loadStringTail();
// "But to the Supes? Absolutely diabolical."
console.log(firstMsgText);
});
```
To parse the second emitted message, we could manually use several `.loadSomething()` functions, but that’s overly brittle — if the fields of the `Ballroom` [struct](/book/structs-and-messages#structs) ever change, you’d need to start all over. That could significantly backfire when you have numerous tests written in that manner.
Fortunately, the Tact compiler auto-generates [TypeScript bindings (or wrappers)](/book/compile#wrap-ts) for contracts, making it easy to reuse them in your test suite. Not only do they provide wrappers for the contract you’re testing, but they also export helper functions to store or load structs and [Messages](/book/structs-and-messages#messages) defined in the contract. These helper functions have names similar to their corresponding structures, prefixed with `load`.
For example, in our case, we’ll need a function called `loadBallroom()`, to parse a [`Slice`](/book/cells#slices) into the `Ballroom` struct in TypeScript. To import it, either type the name and let your IDE suggest auto-importing it for you, or look at the top of your test suite file — there should be a similar line:
```typescript
import { Bonanza } from '../wrappers/Bonanza';
// ^ here you could import loadBallroom
```
With that, let’s parse the second emitted message:
```typescript
it('emits', async () => {
// ... prior code ...
// We'll need only the body of the observed message:
const secondMsgBody = res.externals[1].body;
// Now, let's parse it, knowing it's the Ballroom struct.
// NOTE: In a real-world scenario,
// you'd want to check that first or wrap this in a try...catch
const secondMsgStruct = loadBallroom(secondMsgBody.asSlice());
// { '$$type': 'Ballroom', meme: true, in: 42n, theory: 'Duh' }
console.log(secondMsgStruct);
});
```
Note that it’s also possible to parse emitted messages of deployed contracts outside of our test suite. You would simply need to obtain the emitted message bodies and use the auto-generated TypeScript bindings from Tact alongside the `@ton/core` library, just like we’ve done in the examples above.
## Handling bounced messages[](#bounced)
When [sent](/book/send) with `bounce: true`, messages can bounce back in case of errors. Make sure to write the relevant [`bounced()`](/book/bounced) message [receivers](/book/contracts#receiver-functions) and handle bounced messages gracefully:
```tact
bounced(msg: YourMessage) {
// ...alright squad, let's bounce!...
}
```
Keep in mind that bounced messages in TON have only 224 usable data bits in their message body and do not have any references, so one cannot recover much data from them. However, you still get to see whether the message has bounced or not, allowing you to create more robust contracts.
Read more about bounced messages and receivers: [Bounced messages](/book/bounced).
## Experimental lab setup[](#lab)
If you’re overwhelmed by the testing setup of [Blueprint](https://github.com/ton-org/blueprint) or just want to test some things quickly, worry not — there is a way to set up a simple playground as an experimental lab to test your ideas and hypotheses.
1. #### Create a new Blueprint project[](#lab-1)
This will prevent pollution of your existing project with arbitrary code and tests.
The new project can be named anything, but we’ll name it `Playground` to convey its intended purpose.
To create it, run the following command:
* yarn
```shell
# recommended
yarn create ton tact-playground --type tact-empty --contractName Playground
```
* npm
```shell
npm create ton@latest -- tact-playground --type tact-empty --contractName Playground
```
* pnpm
```shell
pnpm create ton@latest tact-playground --type tact-empty --contractName Playground
```
* bun
```shell
bun create ton@latest tact-playground --type tact-empty --contractName Playground
```
Versions of [Blueprint](https://github.com/ton-org/blueprint) starting with 0.20.0 automatically enable debug mode in `wrappers/` for new contracts, so we only have to adjust the testing suite and prepare our `Playground` contract for testing.
2. #### Update the test suite[](#lab-2)
Move into the newly created `tact-playground/` project, and in the file `tests/Playground.spec.ts`, change the `"should deploy"` test closure to the following:
tests/Playground.spec.ts
```typescript
it('plays', async () => {
const res = await playground.send(
deployer.getSender(),
{ value: toNano('0.5') }, // ← here you may increase the value in nanoToncoins sent
'plays',
);
console.log("Address of our contract: " + playground.address);
console.log(res.externals); // ← here one would see results of emit() calls
});
```
3. #### Modify the contract[](#lab-3)
Replace the code in `contracts/playground.tact` with the following:
contracts/playground.tact
```tact
contract Playground {
// Empty receiver for the deployment
receive() {
// Forward the remaining value in the
// incoming message back to the sender
cashback(sender());
}
receive("plays") {
// NOTE: write your test logic here!
}
}
```
The basic idea of this setup is to place the code you want to test into the [receiver function](/book/contracts#receiver-functions) responding to the [string](/book/types#primitive-types) message `"plays"`.
Note that you can still write any valid Tact code outside of that [receiver](/book/contracts#receiver-functions), but in order to test it, you’ll need to write related test logic inside it.
4. #### Let’s test\
With that, our experimental lab setup is complete. To execute that single test we’ve prepared for our `Playground` contract, run the following:
```shell
yarn test -t plays
```
From now on, to test something, you only need to modify the contents of the tested [receiver function](/book/contracts#receiver-functions) of your Tact contract file and re-run the command above. Rinse and repeat that process until you’ve tested what you intended to test.
For simplicity and cleaner output, you may add a new field to `scripts` in your `package.json`, enabling execution of `yarn lab` to build and test in one step.
On Linux or macOS, it would look like:
```json
{
"scripts": {
"lab": "blueprint build --all 1>/dev/null && yarn test -t plays"
}
}
```
And here’s how it may look on Windows:
```json
{
"scripts": {
"build": "blueprint build --all | out-null",
"lab": "yarn build && yarn test -t plays"
}
}
```
To run:
```shell
yarn lab
```
---
# Deployment
> Common ways to deploy Tact contracts to the testnet or mainnet of TON Blockchain
Note
This page is being rewritten as per [#890](https://github.com/tact-lang/tact/issues/890).
Tact Deployer is a small library that integrates with [TON Verifier](https://verifier.ton.org), allowing you to safely deploy your contracts using your favorite wallet without needing to manage keys or deploy contracts manually. Tact Deployer also automatically verifies your contract’s source code, ensuring that your compiler is not compromised.
## Requirements[](#requirements)
Your contract MUST have the `Deployer` trait from the `@stdlib/deploy` package to be able to use Tact Deployer.
## Installation[](#installation)
To add Tact Deployer to your project, just use `yarn`:
```bash
yarn add @tact-lang/deployer
```
## How to use[](#how-to-use)
When you build your smart contracts using Tact, it produces a package (\*.pkg) file that contains all the required information about the built smart contract. To deploy your smart contract, you need to create a deployer instance, pass your package file to it, and provide initial data for your contract.
```typescript
import * as fs from 'fs';
import * as path from 'path';
import { Address, contractAddress } from "ton";
import { SampleTactContract } from "./output/sample_SampleTactContract";
import { prepareTactDeployment } from "@tact-lang/deployer";
// Parameters
let testnet = true; // Flag for testnet or mainnet
let packageName = 'sample_SampleTactContract.pkg'; // Name of your package to deploy
let outputPath = path.resolve(__dirname, 'output'); // Path to output directory
let owner = Address.parse(''); // Our sample contract has an owner
let init = await SampleTactContract.init(owner); // Create initial data for our contract
// Calculations
let address = contractAddress(0, init); // Calculate contract address. MUST match the address in the verifier
let data = init.data.toBoc(); // Create init data
let pkg = fs.readFileSync( // Read package file
path.resolve(outputPath, packageName)
);
// Prepare deployment
let link = await prepareTactDeployment({ pkg, data, testnet });
// Present a deployment link and contract address
console.log('Address: ' + address.toString({ testOnly: testnet }));
console.log('Deploy link: ' + link);
```
After following this link, you will be able to deploy and verify your smart contract.
---
# Exit codes
> An exit code is a 32-bit signed integer, which indicates whether the compute or action phase of the transaction was successful, and if not — holds the code of the exception that occurred.
Each transaction on TON Blockchain consists of [multiple phases](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases). An *exit code* is a 32-bit signed integer that indicates whether the [compute](#compute) or [action](#action) phase of the transaction was successful, and if not — holds the code of the exception that occurred. Each exit code represents its own exception or resulting state of the transaction.
Exit codes 0 and 1 indicate normal (successful) execution of the [compute phase](#compute). Exit (or [result](#action)) code 0 indicates normal (successful) execution of the [action phase](#action). Any other exit code indicates that a certain exception has occurred and that the transaction was not successful in one way or another, i.e. the transaction was reverted or the inbound message has bounced back.
TON Blockchain reserves exit code values from 0 to 127, while Tact utilizes exit codes from 128 to 255. Note that exit codes used by Tact indicate contract errors, which can occur when using Tact-generated code, and are therefore thrown in the transaction’s [compute phase](#compute) and not during compilation.
The range from 256 to 65535 is free for developer-defined exit codes.
Note
While an exit (or [result](#action)) code is a 32-bit signed integer on TON Blockchain, an attempt to [throw](/ref/core-debug) an exit code outside the bounds of a 16-bit unsigned integer (0−65535) will cause an error with [exit code 5](#5). This is done intentionally to prevent some exit codes from being produced artificially, such as [exit code -14](#-14).
## Table of exit codes[](#table)
The following table lists exit codes with their origin (where they can occur) and a short description for each. The table does not list the exit code of the [`require()`](/ref/core-debug#require), as it generates it depending on the concrete `error` message [String](/book/types#primitive-types). To see such exit codes, refer to the [Exit codes section of the compilation report](/book/compile#exit-codes).
| Exit code | Origin | Brief description |
| :-------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| [0](#0) | [Compute](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) and [action](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) phases | Standard successful execution exit code. |
| [1](#1) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Alternative successful execution exit code. Reserved, but does not occur. |
| [2](#2) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Stack underflow. |
| [3](#3) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Stack overflow. |
| [4](#4) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Integer overflow. |
| [5](#5) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Range check error — an integer is out of its expected range. |
| [6](#6) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Invalid [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) opcode. |
| [7](#7) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Type check error. |
| [8](#8) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Cell overflow. |
| [9](#9) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Cell underflow. |
| [10](#10) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Dictionary error. |
| [11](#11) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Described in [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) docs as “Unknown error, may be thrown by user programs.” |
| [12](#12) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Fatal error. Thrown by [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) in situations deemed impossible. |
| [13](#13) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Out of gas error. |
| [−14](#-14) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | Same as 13. Negative, so that it [cannot be faked](#13). |
| [14](#14) | [Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) | VM virtualization error. Reserved, but never thrown. |
| [32](#32) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Action list is invalid. |
| [33](#33) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Action list is too long. |
| [34](#34) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Action is invalid or not supported. |
| [35](#35) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Invalid source address in outbound message. |
| [36](#36) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Invalid destination address in outbound message. |
| [37](#37) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Not enough Toncoin. |
| [38](#38) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Not enough extra currencies. |
| [39](#39) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Outbound message does not fit into a cell after rewriting. |
| [40](#40) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Cannot process a message — not enough funds, the message is too large, or its Merkle depth is too big. |
| [41](#41) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Library reference is null during library change action. |
| [42](#42) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Library change action error. |
| [43](#43) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Exceeded the maximum number of cells in the library or the maximum depth of the Merkle tree. |
| [50](#50) | [Action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) | Account state size exceeded limits. |
| [128](#128) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Null reference exception. Configurable since Tact 1.6. |
| [129](#129) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Invalid serialization prefix. |
| [130](#130) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Invalid incoming message — there is no receiver for the opcode of the received message. |
| [131](#131) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Constraints error. Reserved, but never thrown. |
| [132](#132) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Access denied — someone other than the owner sent a message to the contract. |
| [133](#133) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Contract stopped. |
| [134](#134) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Invalid argument. |
| [135](#135) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Code of a contract was not found. |
| [136](#136) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Invalid standard address. |
| ~~[137](#137)~~ | ~~Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase))~~ | ~~Masterchain support is not enabled for this contract.~~ Removed since Tact 1.6. |
| [138](#138) | Tact compiler ([Compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase)) | Not a basechain address. Available since Tact 1.6.3. |
Note
Often enough, you might encounter the exit code 65535 (or `0xffff`), which usually means the same as the [exit code 130](#130) — the received opcode is unknown to the contract, as there were no receivers expecting it. When writing contracts, the exit code 65535 is set by the developers and not by [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) or the Tact compiler.
## Exit codes in Blueprint projects[](#blueprint)
In [Blueprint](https://github.com/ton-org/blueprint) tests, exit codes from the [compute phase](#compute) are specified in the `exitCode` field of the object argument for the `toHaveTransaction()` method of the `expect()` matcher. The field for the [result](#action) codes (exit codes from the [action phase](#action)) in the same `toHaveTransaction()` method is called `actionResultCode`.
Note
Read more about expecting specific exit codes: [Transactions with intentional errors](/book/debug#tests-errors).
Additionally, one can examine the result of [sending a message to a contract](/book/debug#tests-send) and discover the phases of each transaction and their values, including exit (or result) codes for the [compute phase](#compute) (or [action phase](#action)).
Note that to do so, you’ll have to perform a couple of type checks first:
```typescript
it('tests something, you name it', async () => {
// Send a specific message to our contract and store the results
const res = await your_contract_name.send(…);
// Now, we have access to an array of executed transactions,
// with the second one (index 1) being the one we look for
const tx = res.transactions[1]!;
// To do something useful with it, let's ensure that its type is 'generic'
// and that the compute phase in it wasn't skipped
if (tx.description.type === "generic"
&& tx.description.computePhase.type === "vm") {
// Finally, we're able to freely peek into the transaction for general details,
// such as printing out the exit code of the compute phase if we so desire
console.log(tx.description.computePhase.exitCode);
}
// ...
});
```
## Compute and action phases[](#compute-and-action-phases)
### 0: Normal termination[](#0)
This exit (or [result](#action)) code indicates the successful completion of the [compute phase](#compute) (or [action phase](#action)) of the transaction.
## Compute phase[](#compute)
[TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) initialization and all computations occur in the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase).
If the compute phase fails (the resulting exit code is neither [0](#0) nor [1](#1)), the transaction skips the [action phase](#action) and proceeds to the bounce phase. In this phase, a bounce message is formed for transactions initiated by the inbound message.
### 1: Alternative termination[](#1)
This is an alternative exit code for the successful execution of the [compute phase](#compute). It is reserved but never occurs.
### 2: Stack underflow[](#2)
If an operation consumes more elements than exist on the stack, an error with exit code 2 is thrown: `Stack underflow`.
```tact
asm fun drop() { DROP }
contract Loot {
receive("I solemnly swear that I'm up to no good") {
try {
// Removes 100 elements from the stack, causing an underflow
repeat (100) { drop() }
} catch (exitCode) {
// exitCode is 2
}
}
}
```
Useful links:
[TVM is a stack machine](https://docs.ton.org/learn/tvm-instructions/tvm-overview#tvm-is-a-stack-machine) in TON Docs.
### 3: Stack overflow[](#3)
If there are too many elements copied into a closure continuation, an error with exit code 3 is thrown: `Stack overflow`. This occurs rarely unless you’re deep in the [Fift and TVM assembly](https://docs.ton.org/develop/fift/fift-and-tvm-assembly) trenches:
```tact
// Remember kids, don't try to overflow the stack at home!
asm fun stackOverflow() {
x{} SLICE // s
BLESS // c
0 SETNUMARGS // c'
2 PUSHINT // c' 2
SWAP // 2 c'
1 -1 SETCONTARGS // ← this blows up
}
contract ItsSoOver {
receive("I solemnly swear that I'm up to no good") {
try {
stackOverflow();
} catch (exitCode) {
// exitCode is 3
}
}
}
```
Useful links:
[TVM is a stack machine](https://docs.ton.org/learn/tvm-instructions/tvm-overview#tvm-is-a-stack-machine) in TON Docs.
### 4: Integer overflow[](#4)
If the [value in a calculation](/book/integers#operations) goes beyond the range from −2256 to 2256−1 inclusive, or there’s an attempt to [divide](/book/operators#binary-divide) or perform [modulo](/book/operators#binary-modulo) by zero, an error with exit code 4 is thrown: `Integer overflow`.
```tact
let x = -pow(2, 255) - pow(2, 255); // -2^{256}
try {
-x; // integer overflow by negation
// since the max positive value is 2^{256} - 1
} catch (exitCode) {
// exitCode is 4
}
try {
x / 0; // division by zero!
} catch (exitCode) {
// exitCode is 4
}
try {
x * x * x; // integer overflow!
} catch (exitCode) {
// exitCode is 4
}
// There can also be an integer overflow when performing:
// addition (+),
// subtraction (-),
// division (/) by a negative number or modulo (%) by zero
```
### 5: Integer out of expected range[](#5)
A range check error occurs when [some integer](/book/integers#operations) is out of its expected range. Any attempt to store an unexpected amount of data or specify an out-of-bounds value throws an error with exit code 5: `Integer out of expected range`.
Examples of specifying an out-of-bounds value:
```tact
try {
// Repeat only operates on an inclusive range from 1 to 2^{31} - 1
// Any valid integer value greater than that causes an error with exit code 5
repeat (pow(2, 55)) {
dump("smash. logs. I. must.");
}
} catch (exitCode) {
// exitCode is 5
}
try {
// Builder.storeUint() function can only use up to 256 bits, thus 512 is too much:
let s: Slice = beginCell().storeUint(-1, 512).asSlice();
} catch (exitCode) {
// exitCode is 5
}
```
### 6: Invalid opcode[](#6)
If you specify an instruction that is not defined in the current [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) version or attempt to set an unsupported [code page](https://docs.ton.org/v3/documentation/tvm/tvm-overview#tvm-state), an error with exit code 6 is thrown: `Invalid opcode`.
```tact
// There's no such code page, and an attempt to set it fails
asm fun invalidOpcode() { 42 SETCP }
contract OpOp {
receive("I solemnly swear that I'm up to no good") {
try {
invalidOpcode();
} catch (exitCode) {
// exitCode is 6
}
}
}
```
### 7: Type check error[](#7)
If an argument to a primitive is of an incorrect value type or there is any other mismatch in types during the [compute phase](#compute), an error with exit code 7 is thrown: `Type check error`.
```tact
// The actual returned value type doesn't match the declared one
asm fun typeCheckError(): map { 42 PUSHINT }
contract VibeCheck {
receive("I solemnly swear that I'm up to no good") {
try {
// The 0th index doesn't exist
typeCheckError().get(0)!!;
} catch (exitCode) {
// exitCode is 7
}
}
}
```
### 8: Cell overflow[](#8)
From the [Cells, Builders and Slices page](/book/cells#cells) of the Book:
> [`Cell`](/book/cells) is a [primitive](/book/types#primitive-types) and a data structure, which [ordinarily](/book/cells#cells-kinds) consists of up to 1023 continuously laid out bits and up to 4 references (refs) to other cells.
To construct a [`Cell`](/book/cells), a [`Builder`](/book/cells#builders) is used. If you try to store more than 1023 bits of data or more than 4 references to other cells, an error with exit code 8 is thrown: `Cell overflow`.
This error can be triggered by [manual construction](/book/cells#cnp-manually) of the cells via [relevant `.storeSomething()` methods](/ref/core-cells#builder) or when [using structs and Messages and their convenience methods](/book/cells#cnp-structs).
```tact
// Too many bits
try {
let data = beginCell()
.storeInt(0, 250)
.storeInt(0, 250)
.storeInt(0, 250)
.storeInt(0, 250)
.storeInt(0, 24) // 1024 bits!
.endCell();
} catch (exitCode) {
// exitCode is 8
}
// Too many refs
try {
let data = beginCell()
.storeRef(emptyCell())
.storeRef(emptyCell())
.storeRef(emptyCell())
.storeRef(emptyCell())
.storeRef(emptyCell()) // 5 refs!
.endCell();
} catch (exitCode) {
// exitCode is 8
}
```
### 9: Cell underflow[](#9)
From the [Cells, Builders and Slices page](/book/cells#cells) of the Book:
> `Cell` is a [primitive](/book/types#primitive-types) and a data structure, which [ordinarily](/book/cells#cells-kinds) consists of up to 1023 continuously laid-out bits and up to 4 references (refs) to other cells.
To parse a [`Cell`](/book/cells), a [`Slice`](/book/cells#slices) is used. If you try to load more data or references than a `Slice` contains, an error with exit code 9 is thrown: `Cell underflow`.
The most common cause of this error is a mismatch between the expected and actual memory layouts of the cells, so it’s recommended to [use structs and Messages for parsing](/book/cells#cnp-structs) the cells instead of [manual parsing](/book/cells#cnp-manually) via [relevant `.loadSomething()` methods](/ref/core-cells#slice).
```tact
// Too few bits
try {
emptySlice().loadInt(1); // 0 bits!
} catch (exitCode) {
// exitCode is 9
}
// Too few refs
try {
emptySlice().loadRef(); // 0 refs!
} catch (exitCode) {
// exitCode is 9
}
```
### 10: Dictionary error[](#10)
In Tact, the [`map`](/book/maps) type is an abstraction over the [“hash” map dictionaries of TVM](/book/maps#low-level-representation).
If there is incorrect manipulation of dictionaries, such as improper assumptions about their memory layout, an error with exit code 10 is thrown: `Dictionary error`. Note that Tact prevents you from getting this error unless you perform [TVM assembly](https://docs.ton.org/develop/fift/fift-and-tvm-assembly) work yourself:
```tact
/// Pre-computed Int to Int dictionary with two entries — 0: 0 and 1: 1
const cellWithDictIntInt: Cell = cell("te6cckEBBAEAUAABAcABAgPQCAIDAEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLMbT1U=");
/// Tries to preload a dictionary from a Slice as a map
asm fun toMapIntCell(x: Slice): map { PLDDICT }
contract DictPic {
receive("I solemnly swear that I'm up to no good") {
try {
// The Int to Int dictionary is being misinterpreted as a map
let m: map = toMapIntCell(cellWithDictIntInt.beginParse());
// And the error happens only when we touch it
m.get(0)!!;
} catch (exitCode) {
// exitCode is 10
}
}
}
```
### 11: “Unknown” error[](#11)
Described in the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) docs as “Unknown error, may be thrown by user programs,” although most commonly used for problems with queuing a message send or problems with [get-methods](https://docs.ton.org/develop/smart-contracts/guidelines/get-methods).
```tact
try {
// Unlike sendRawMessage which uses SENDRAWMSG, this one uses SENDMSG,
// and therefore fails in Compute phase when the message is ill-formed
sendRawMessageReturnForwardFee(emptyCell(), 0);
} catch (exitCode) {
// exitCode is 11
}
```
### 12: Fatal error[](#12)
Fatal error. Thrown by TVM in situations deemed impossible.
### 13: Out of gas error[](#13)
If there isn’t enough gas to complete computations in the [compute phase](#compute), an error with exit code 13 is thrown: `Out of gas error`.
However, this code isn’t immediately shown as is — instead, the bitwise NOT operation is applied, changing the value from 13 to −14. Only then is the code displayed.
This is done to prevent the resulting code (−14) from being produced artificially in user contracts, as all functions that can [throw an exit code](/ref/core-debug) can only specify integers in the range from 0 to 65535 inclusive.
```tact
try {
repeat (pow(2, 31) - 1) {}
} catch (exitCode) {
// exitCode is -14
}
```
### -14: Out of gas error[](#-14)
See [exit code 13](#13).
### 14: Virtualization error[](#14)
Virtualization error related to [pruned branch cells](/book/cells#cells-kinds). Reserved but never thrown.
## Action phase[](#action)
The [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) is processed after the successful execution of the [compute phase](#compute). It attempts to perform the actions stored in the action list by [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) during the compute phase.
Some actions may fail during processing, in which case those actions may be skipped or the whole transaction may revert depending on the mode of actions. The code indicating the resulting state of the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) is called a *result code*. Since it is also a 32-bit signed integer that essentially serves the same purpose as the *exit code* of the [compute phase](#compute), it is common to call the result code an exit code as well.
### 32: Action list is invalid[](#32)
If the list of actions contains [exotic cells](/book/cells#cells-kinds), an action entry cell does not have references, or some action entry cell cannot be parsed, an error with exit code 32 is thrown: `Action list is invalid`.
Note
Aside from this exit code, there is a boolean flag `valid`, which you can find under `description.actionPhase.valid` in the transaction results when working with [Sandbox and Blueprint](#blueprint). A transaction can set this flag to `false` even when there is some other exit code thrown from the action phase.
### 33: Action list is too long[](#33)
If there are more than 255 actions queued for execution, the [action phase](#action) will throw an error with an exit code 33: `Action list is too long`.
```tact
// For example, let's attempt to queue reservation of a specific amount of nanoToncoins
// This won't fail in the compute phase, but will result in exit code 33 in the action phase
repeat (256) {
nativeReserve(ton("0.001"), ReserveAtMost);
}
```
### 34: Invalid or unsupported action[](#34)
There are only four supported actions at the moment: changing the contract code, sending a message, reserving a specific amount of [nanoToncoins](/book/integers#nanotoncoin), and changing the library cell. If there is any issue with the specified action (invalid message, unsupported action, etc.), an error with exit code 34 is thrown: `Invalid or unsupported action`.
```tact
// For example, let's try to send an ill-formed message:
sendRawMessage(emptyCell(), 0); // won't fail in the compute phase,
// but will result in exit code 34 in the Action phase
```
### 35: Invalid source address in outbound message[](#35)
If the source address in the outbound message is not equal to [`addr_none`](https://docs.ton.org/develop/data-formats/msg-tlb#addr_none00) or to the address of the contract that initiated this message, an error with exit code 35 is thrown: `Invalid source address in outbound message`.
### 36: Invalid destination address in outbound message[](#36)
If the destination address in the outbound message is invalid, e.g., it does not conform to the relevant [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) schemas, contains an unknown workchain ID, or has an invalid length for the given workchain, an error with exit code 36 is thrown: `Invalid destination address in outbound message`.
Note
If the [optional flag +2](/book/message-mode#optional-flags) is set, this error won’t be thrown, and the given message won’t be sent.
### 37: Not enough Toncoin[](#37)
If all funds of the inbound message with [base mode 64](/book/message-mode#base-modes) set have already been consumed and there are not enough funds to pay for the failed action, or the [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) layout of the provided value ([`CurrencyCollection`](https://docs.ton.org/develop/data-formats/msg-tlb#currencycollection)) is invalid, or there are not enough funds to pay [forward fees](https://docs.ton.org/develop/smart-contracts/guidelines/processing) or not enough funds after deducting fees, an error with exit code 37 is thrown: `Not enough Toncoin`.
Note
If the [optional flag +2](/book/message-mode#optional-flags) is set, this error won’t be thrown and the given message won’t be sent.
### 38: Not enough extra currencies[](#38)
Besides the native currency, Toncoin, TON Blockchain supports up to 232 extra currencies. They differ from creating new [Jettons](/cookbook/jettons) because extra currencies are natively supported — one can potentially just specify an extra [`HashmapE`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap) of extra currency amounts in addition to the Toncoin amount in the internal message to another contract. Unlike Jettons, extra currencies can only be stored and transferred and do not have any other functionality.
At the moment, **there are no extra currencies** on TON Blockchain, but the exit code 38 for cases when there is not enough extra currency to send the specified amount is already reserved: `Not enough extra currencies`.
Useful links:
[Extra currencies](https://docs.ton.org/develop/dapps/defi/coins) in TON Docs.\
[Extra currency mining](https://docs.ton.org/develop/research-and-development/minter-flow) in TON Docs.
### 39: Outbound message doesn’t fit into a cell[](#39)
When processing the message, TON Blockchain tries to pack it according to the [relevant TL-B schemas](https://docs.ton.org/develop/data-formats/msg-tlb), and if it cannot, an error with exit code 39 is thrown: `Outbound message doesn't fit into a cell`.
Note
If attempts at sending the message fail multiple times and the [optional flag +2](/book/message-mode#optional-flags) is set, this error won’t be thrown and the given message won’t be sent.
### 40: Cannot process a message[](#40)
If there are not enough funds to process all the cells in a message, the message is too large, or its Merkle depth is too big, an error with exit code 40 is thrown: `Cannot process a message`.
Note
If the [optional flag +2](/book/message-mode#optional-flags) is set, this error won’t be thrown and the given message won’t be sent.
### 41: Library reference is null[](#41)
If a library reference is required during a library change action but is null, an error with exit code 41 is thrown: `Library reference is null`.
### 42: Library change action error[](#42)
If there’s an error during an attempt at a library change action, an error with exit code 42 is thrown: `Library change action error`.
### 43: Library limits exceeded[](#43)
If the maximum number of cells in the library is exceeded or the maximum depth of the Merkle tree is exceeded, an error with exit code 43 is thrown: `Library limits exceeded`.
### 50: Account state size exceeded limits[](#50)
If the account state (contract storage, essentially) exceeds any of the limits specified in [config param 43 of TON Blockchain](https://docs.ton.org/develop/howto/blockchain-configs#param-43) by the end of the [action phase](#action), an error with exit code 50 is thrown: `Account state size exceeded limits`.
If the configuration is absent, the default values are:
* `max_msg_bits` is equal to 221 — maximum message size in bits.
* `max_msg_cells` is equal to 213 — maximum number of [cells](/book/cells) a message can occupy.
* `max_library_cells` is equal to 1000 — maximum number of [cells](/book/cells) that can be used as [library reference cells](/book/cells#cells-kinds).
* `max_vm_data_depth` is equal to 29 — maximum [cells](/book/cells) [depth](/book/cells#cells-representation) in messages and account state.
* `ext_msg_limits.max_size` is equal to 65535 — maximum external message size in bits.
* `ext_msg_limits.max_depth` is equal to 29 — maximum external message [depth](/book/cells#cells-representation).
* `max_acc_state_cells` is equal to 216 — maximum number of [cells](/book/cells) that an account state can occupy.
* `max_acc_state_bits` is equal to 216×1023 — maximum account state size in bits.
* `max_acc_public_libraries` is equal to 28 — maximum number of [library reference cells](/book/cells#cells-kinds) that an account state can use on the masterchain.
* `defer_out_queue_size_limit` is equal to 28 — maximum number of outbound messages to be queued (regarding validators and collators).
## Tact compiler[](#tact-compiler)
Tact utilizes exit codes from 128 to 255. Note that exit codes used by Tact indicate contract errors, which can occur when using Tact-generated code and are therefore thrown in the transaction’s [compute phase](#compute), not during compilation.
### 128: Null reference exception[](#128)
If there is a non-null assertion, such as the [`!!`](/book/operators#unary-non-null-assert) operator, and the checked value is [`null`](/book/optionals), an error with exit code 128 is thrown: `Null reference exception`.
This behavior can be modified by setting the [`nullChecks`](/book/config#safety-nullchecks) option to `false`, which will disable runtime null checks and would allow to save some gas. However, it is recommended to use it only for well-tested contracts, as it can lead to less recognizable type errors reported by TVM.
```tact
let gotcha: String? = null;
try {
// Asserting that the value isn't null, which isn't the case!
dump(gotcha!!);
} catch (exitCode) {
// exitCode is 128
}
```
Available since Tact 1.6.6 Access this exit code value 128 with the `TactExitCodeNullReferenceException` [constant](/book/constants).
### 129: Invalid serialization prefix[](#129)
If there is an attempt to parse (deserialize) a [`Cell`](/book/cells) or [`Slice`](/book/cells#slices) into a [message struct](/book/structs-and-messages#messages) and the parsed opcode prefix doesn’t match the expected target one, an error with exit code 129 is thrown: `Invalid serialization prefix`.
Thus, this error can occur whenever there is an opcode mismatch when using either of the following functions:
1. [`Message.fromCell`](/ref/core-cells#messagefromcell)
2. [`Message.fromSlice()`](/ref/core-cells#messagefromslice)
```tact
fun example() {
// This cell contains a 32-bit opcode prefix (0x00000001)
let cellOne = MsgOne {}.toCell();
try {
// This is a failed attempt to parse one message that has an opcode of 1 (0x00000001)
// from a Cell with another message that has an opcode of 2 (0x00000002)
let msgTwo = MsgTwo.fromCell(cellOne);
dump(msgTwo.toCell());
} catch (exitCode) {
// exitCode is 129
}
}
// An empty message struct with an opcode of 1 (0x00000001)
message(1) MsgOne {}
// An empty message struct with an opcode of 2 (0x00000002)
message(2) MsgTwo {}
```
Additionally, this error can happen if one hijacks the contract code before deployment and changes the opcodes of the [message structs](/book/structs-and-messages#messages) expected to be received in the contract.
Available since Tact 1.6.6 Access this exit code value 129 with the `TactExitCodeInvalidSerializationPrefix` [constant](/book/constants).
### 130: Invalid incoming message[](#130)
If the received internal or external message is not handled by the contract, an error with exit code 130 is thrown: `Invalid incoming message`. It usually happens when the contract does not have a receiver for the particular message and its opcode prefix: a 32-bit integer header.
Consider the following contract:
```tact
import "@stdlib/deploy";
contract Dummy with Deployable {}
```
If you try to send any message except for [`Deploy`](/ref/stdlib-deploy#deploy), provided by [`@stdlib/deploy`](/ref/stdlib-deploy), the contract will not have a receiver for it and thus will throw an error with exit code 130.
Available since Tact 1.6.6 Access this exit code value 130 with the `TactExitCodeInvalidIncomingMessage` [constant](/book/constants).
### 131: Constraints error[](#131)
Constraints error. Reserved, but never thrown.
Available since Tact 1.6.6 Access this exit code value 131 with the `TactExitCodeConstraintsError` [constant](/book/constants).
### 132: Access denied[](#132)
If you use the [`Ownable`](/ref/stdlib-ownable#ownable) [trait](/book/types/#traits) from the [`@stdlib/ownable`](/ref/stdlib-ownable) library, the helper function `requireOwner()` provided by it will throw an error with exit code 132 if the sender of the inbound message does not match the specified owner: `Access denied`.
```tact
import "@stdlib/ownable";
contract Hal9k with Ownable {
owner: Address;
init(owner: Address) {
self.owner = owner; // set the owner address upon deployment
}
receive("I'm sorry Dave, I'm afraid I can't do that.") {
// Checks that the message sender's address equals the owner address,
// and if not — throws an error with exit code 132.
self.requireOwner();
// ... you do you ...
}
}
```
Available since Tact 1.6.6 Access this exit code value 132 with the `TactExitCodeAccessDenied` [constant](/book/constants).
### 133: Contract stopped[](#133)
A message has been sent to a “stopped” contract: a contract that inherits the [`Stoppable`](/ref/stdlib-stoppable#stoppable) trait and has the `self.stopped` flag set to `true`.
Available since Tact 1.6.6 Access this exit code value 133 with the `ContractStopped` [constant](/book/constants).
### 134: Invalid argument[](#134)
If there is an invalid or unexpected argument value, an error with exit code 134 is thrown: `Invalid argument`.
Here are some of the functions in Tact which can throw an error with this exit code:
1. [`Int.toFloatString(digits)`](/ref/core-strings#inttofloatstring): if `digits` is not in the interval 0\ This page lists all the expressions in Tact
Every operator in Tact forms an expression, but there’s much more to uncover, as Tact offers a wide range of expressive options to choose from.
Note
The current maximum allowed nesting level of expressions is 83. An attempt to write a deeper expression will result in a compilation error:
```tact
fun elegantWeaponsForCivilizedAge(): Int {
return
((((((((((((((((((((((((((((((((
((((((((((((((((((((((((((((((((
(((((((((((((((((((( // 84 parens, compilation error!
42
))))))))))))))))))))
))))))))))))))))))))))))))))))))
))))))))))))))))))))))))))))))));
}
```
## Literals[](#literals)
Literals represent values in Tact. These are fixed values—not variables—that you *literally* provide in your code. All literals in Tact are expressions themselves.
You can also call [extension functions](/book/functions#extensions) defined on certain [primitive types](/book/types#primitive-types) directly on their corresponding literal values:
```tact
// Calling toString() defined for Int on an integer literal:
42.toString();
// Calling asComment() defined for String on a string literal:
"Tact is awesome!".asComment();
```
### Integer literals[](#integer-literals)
Integer literals can be written in [decimal](/book/integers#decimal) (base 10), [hexadecimal](/book/integers#hexadecimal) (base 16), [octal](/book/integers#octal) (base 8), and [binary](/book/integers#binary) (base 2) notations:
* A [*decimal* integer](/book/integers#decimal) literal is a sequence of digits (0−9).
* A leading 0x (or 0X) indicates a [hexadecimal integer](/book/integers#hexadecimal) literal. They can include digits (0−9) and the letters a−f and A−F. Note that the case of a character does not change its value. Therefore, 0xa = 0xA = 10 and 0xf = 0xF = 15.
* A leading 0o (or 0O) indicates an [octal integer](/book/integers#octal) literal. They can include only the digits 0−7.
* A leading 0b (or 0B) indicates a [binary integer](/book/integers#binary) literal. They can include only the digits 0 and 1.
Caution
Be wary that in Tact, integer literals with a leading 0 are still considered decimals, unlike in JavaScript/TypeScript, where a leading 0 indicates an octal!
Some examples of integer literals:
```tact
// decimal, base 10:
0, 42, 1_000, 020
// hexadecimal, base 16:
0xABC, 0xF, 0x0011
// octal, base 8:
0o777, 0o001
// binary, base 2:
0b01111001_01101111_01110101_00100000_01100001_01110010_01100101_00100000_01100001_01110111_01100101_01110011_01101111_01101101_01100101
```
Read more about integers and the [`Int`](/book/integers) type on the dedicated page: [Integers](/book/integers).
### Boolean literals[](#boolean-literals)
The [`Bool`](/book/types#booleans) type has only two literal values: `true` and `false`.
```tact
true == true;
true != false;
```
Read more about booleans and the [`Bool`](/book/types#booleans) type in the dedicated chapter: [Booleans](/book/types#booleans).
### String literals[](#string-literals)
A string literal is zero or more characters enclosed in double (`"`) quotation marks. All string literals are objects of the [`String`](/book/types#primitive-types) type.
```tact
"foo";
"1234";
```
Tact strings support a range of [escape sequences](https://en.wikipedia.org/wiki/Escape_sequence) starting with a backslash `\\` character:
* `\\` — literal backslash
* `\"` — double quote
* `\n` — newline
* `\r` — carriage return
* `\t` — tab
* `\v` — vertical tab
* `\b` — backspace
* `\f` — form feed
* `\x00` through `\xFF` — [code point](https://en.wikipedia.org/wiki/Code_point), must be exactly two hex digits long
* `\u0000` through `\uFFFF` — [Unicode code point](https://en.wikipedia.org/wiki/Unicode#Codespace_and_code_points), must be exactly four hex digits long
* `\u{0}` through `\u{10FFFF}` — [Unicode code point](https://en.wikipedia.org/wiki/Unicode#Codespace_and_code_points), can be from 1 to 6 hex digits long
```tact
// \\
"escape \\ if \\ you \\ can \\";
// \"
"this \"literally\" works";
// \n
"line \n another line";
// \r
"Shutters \r Like \r This \r One";
// \t
"spacing \t granted!";
// \v
"those \v words \v are \v aligned";
// \b
"rm\b\bcreate!";
// \f
"form \f feed";
// \x00 - \xFF
"this \x22literally\x22 works"; // \x22 represents a double quote
// \u0000 - \uFFFF
"danger, \u26A1 high voltage \u26A1"; // \u26A1 represents the ⚡ emoji
// \u{0} - \u{10FFFF}
"\u{1F602} LOL \u{1F602}"; // \u{1F602} represents the 😂 emoji
// This Unicode code point is outside of valid range 000000–10FFFF
"\u{FFFFFF}"; // COMPILATION ERROR!
```
Note
Read more about strings and the [`String`](/book/types#primitive-types) type:\
[Primitive types in the Book](/book/types#primitive-types)\
[Strings and StringBuilders in the Reference](/ref/core-strings)
### `null` literal[](#null-literal)
The `null` value is written with a `null` literal. It is **not** an [identifier](#identifiers) and does not refer to any object. It is also **not** an instance of a [primitive type](/book/types#primitive-types). Instead, `null` represents a lack of identification and the intentional absence of any value.
```tact
let var: Int? = null; // variable which can hold a null value
var = 42;
if (var != null) {
var!! + var!!;
}
```
Read more about working with `null` on the dedicated page: [Optionals](/book/optionals).
### Map literals[](#map-literals)
Available since Tact 1.6.7
Map literals create maps by enclosing a comma-delimited list of zero or more predefined key-value pairs in curly braces.
```tact
// A compile-time map literal
let myMap: map = map {
// Key expression: Value expression
1 + 2: 10 * pow2(3), // key 3, value 80
1 + 3: 20 * pow2(4), // key 4, value 320
};
myMap.get(3)!!; // 80
myMap.get(4)!!; // 320
```
Read more: [Initialize a map with a literal](/book/maps#initialize).
Note
Support for runtime initialization values that are not resolved at [compile-time](/ref/core-comptime) is planned for future Tact releases.
## Identifiers[](#identifiers)
An identifier is a sequence of characters in the code that *identifies* a [variable](/book/statements#let), [constant](/book/constants), [map](/book/maps), a [function](/book/functions), as well as a [Struct](/book/structs-and-messages#structs), [Message](/book/structs-and-messages#messages), [contract](/book/contracts), [trait](/book/types#traits), or their fields and methods. Identifiers are case-sensitive and not quoted.
In Tact, identifiers may contain Latin lowercase letters `a-z`, Latin uppercase letters `A-Z`, underscores `_`, and digits 0−9, but may not start with a digit. No other symbols are allowed, and Unicode identifiers are prohibited.
Note that identifiers for [primitive types](/book/types#primitive-types) start with an uppercase letter. User-defined [composite types](/book/types#composite-types), such as [Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages), must also be capitalized.
Caution
All identifiers starting with `__gen` and `__tact` are not allowed and are instead reserved for internal use by the compiler.
## Instantiation[](#instantiation)
You can create instances of the following types:
* [Structs](/book/structs-and-messages#structs)
* [Messages](/book/structs-and-messages#messages)
```tact
struct StExample {
fieldInit: Int = 1;
fieldUninit: Int;
}
fun example() {
// Instance with default value of fieldInit
StExample { fieldUninit: 2 };
// Instance with both fields set
StExample {
fieldInit: 0,
fieldUninit: 2, // trailing comma is allowed
};
}
```
## Field access[](#field-access)
You can directly access fields of the following types:
* [Structs](/book/structs-and-messages#structs)
* [Messages](/book/structs-and-messages#messages)
```tact
struct StExample {
fieldInit: Int = 1;
fieldUninit: Int;
}
fun example(): Int {
let struct: StExample = StExample { fieldUninit: 2 }; // instantiation
struct.fieldInit; // access a field
return struct.fieldUninit; // return field value from the function
}
```
## Extension function call[](#extension-function-call)
[Extension functions](/book/functions#extensions) are defined only on specific types. They can be called similarly to method calls in many other languages:
```tact
42.toString(); // toString() is a stdlib function that is defined on Int type
```
## Static function call[](#static-function-call)
A [global function](/book/functions#fun-global) or a [internal function](/book/functions#fun-internal) of a [contract](/book/contracts) can be called from anywhere in the function body:
```tact
contract ExampleContract {
receive() {
now(); // now() is a static function of stdlib
let expiration: Int = now() + 1000; // operation and variable definition
expiration = self.answerQuestion(); // internal function
}
fun answerQuestion(): Int {
return 42;
}
}
```
## `initOf`[](#initof)
500+ gas
The expression `initOf` computes the initial state, i.e., `StateInit`, of a [contract](/book/contracts):
```tact
// argument values of contract or init() parameters
// ↓ ↓
initOf ExampleContract(42, 100); // returns a Struct StateInit{}
// ---------------
// ↑
// name of the contract
// ↓
// ---------------
initOf ExampleContract(
42, // first argument
100, // second argument; a trailing comma is allowed
);
```
The `StateInit` is a [struct](/book/structs-and-messages#structs) consisting of the following fields:
| Field | Type | Description |
| :----- | :-------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `code` | [`Cell`](/book/cells#cells) | The initial code of the [contract](/book/contracts) (compiled bitcode) |
| `data` | [`Cell`](/book/cells#cells) | The initial data of the [contract](/book/contracts) (parameters of the [`init()`](/book/contracts#init-function) function or [contract parameters](/book/contracts#parameters)) |
Note
For workchain 0, the [`Address`](/book/types#primitive-types) of the current contract obtained by calling the [`myAddress()`](/ref/core-contextstate#myaddress) function is identical to the one that can be obtained by calling the [`contractAddress()`](/ref/core-addresses#contractaddress) function with the initial state of the current contract computed via `initOf`:
```tact
contract TheKingPrawn {
receive("keeping the address") {
let myAddr1 = myAddress();
let myAddr2 = contractAddress(initOf TheKingPrawn());
myAddr1 == myAddr2; // true
}
}
```
However, if you only need the address of the current contract at runtime and not its `StateInit`, use the [`myAddress()`](/ref/core-contextstate#myaddress) function, as it consumes **significantly** less gas.
## `codeOf`[](#codeof)
500+ gas Available since Tact 1.6
The expression `codeOf` returns a [`Cell`](/book/cells#cells) containing the code of a [contract](/book/contracts):
```tact
codeOf ExampleContract; // a Cell with ExampleContract code
// ---------------
// ↑
// name of the contract
```
If `codeOf` is used for the current contract, its result is equivalent to calling [`myCode()`](/ref/core-contextstate#mycode).
```tact
contract ExampleContract() {
receive() {
myCode() == codeOf ExampleContract; // true
}
}
```
If you only need the code of a given contract and not its [`StateInit`](#initof), prefer using `codeOf ContractName` over [`initOf ContractName(param1, param2, ...)`](#initof) to **significantly** reduce gas usage.
---
# External Messages
> External messages don't have a sender and can be sent by anyone from off-chain.
Caution
This page is under reconstruction as per [#384](https://github.com/tact-lang/tact-docs/issues/384). All anchor links (`#`) may change in the future!
Caution
External message support must be explicitly enabled in the project configuration. Without enabling it, compilation will fail.
External messages are messages that don’t have a sender and can be sent by anyone in the world. External messages are useful tools for integrating with off-chain systems or for general contract maintenance. Handling external messages differs from handling internal messages. In this section, we will cover how to handle external messages.
## How External Messages are Different[](#how-external-messages-are-different)
External messages differ from internal messages in the following ways:
### Contracts Pay for Gas Usage Themselves[](#contracts-pay-for-gas-usage-themselves)
When processing internal messages, the sender usually pays for gas usage. When processing external messages, the contract pays for gas usage. This means that you need to be careful with gas usage in external messages. You should always test your contracts’ gas usage and verify that everything is working as intended.
### Messages Have to Be Accepted Manually[](#messages-have-to-be-accepted-manually)
External messages are not accepted automatically. You need to accept them manually. This is done by calling the `acceptMessage` function. If you don’t call the `acceptMessage` function, the message will be rejected. This mechanism prevents the spamming of external messages.
### 10k Gas Limit Before Message Acceptance[](#10k-gas-limit-before-message-acceptance)
The 10k gas amount is a very small limit, and Tact itself can consume a sizable amount of gas before it even reaches your code. You should always test the gas usage of your contracts and verify that everything is working as intended.
Hey there!
The 10k gas limit for external messages is based on the parameter set by the validator for the entire blockchain in the `gas_limit` field. You can refer to:
*
*
### Unbounded Gas Usage After Message Acceptance[](#unbounded-gas-usage-after-message-acceptance)
After accepting a message, the contract can use as much gas as it wants. This is allowed to let the contract carry out any kind of processing. You should always test the gas usage of your contracts, verify everything is working as intended, and avoid possible vulnerabilities that could drain the contract balance.
### No Context Available[](#no-context-available)
When processing an external message, the `context` and `sender` functions are not available. This is because there is no context available for external messages. Therefore, you cannot use the `context` and `sender` functions in external messages. You need to carefully test your contract to ensure that it does not use the `context` and `sender` functions.
## Enable External Messages Support[](#enable-external-messages-support)
To enable external message support, please enable it in the project configuration file:
```json
{
"options": {
"external": true
}
}
```
## External receivers[](#external-receivers)
External receivers are defined in the same way as internal ones, but using the `external` keyword instead of `receive`:
```tact
contract SampleContract {
external("Check Timeout") {
// Check for contract timeout
require(self.timeout > now(), "Not timed out");
// Accept message
acceptMessage();
// Timeout processing
self.onTimeout();
}
}
```
External receivers follow the same execution order conventions as [internal receivers](/book/receive).
---
# Compatibility with FunC
> Tact compiles to FunC and maps all its entities directly to various FunC and TL-B types.
Tact itself compiles to FunC and maps all its entities directly to various FunC and TL-B types.
## Convert types[](#convert-types)
[Primitive types](/book/types#primitive-types) in Tact are directly mapped to FunC ones.
All rules about copying variables are the same. One of the main differences is that there are no visible mutation operators in Tact, and most [`Slice`](/book/cells#slices) operations mutate variables in place.
## Convert serialization[](#convert-serialization)
Serialization of [structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) in Tact is automatic, unlike FunC, where you need to define serialization logic manually.
Tact’s auto-layout algorithm is greedy. This means that it takes the next variable, calculates its size, and tries to fit it into the current cell. If it doesn’t fit, it creates a new cell and continues. All inner structs for auto-layout are flattened before allocation.
All optional types are serialized as `Maybe` in TL-B, except for [`Address`](/book/types#primitive-types).
There is no support for `Either` since it does not define which variant to pick during serialization in some cases.
### Examples[](#examples)
```tact
// _ value1:int257 = SomeValue;
struct SomeValue {
value1: Int; // Default is 257 bits
}
```
```tact
// _ value1:int256 value2:uint32 = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as uint32;
}
```
```tact
// _ value1:bool value2:Maybe bool = SomeValue;
struct SomeValue {
value1: Bool;
value2: Bool?;
}
```
```tact
// _ cell:^cell = SomeValue;
struct SomeValue {
cell: Cell; // Always stored as a reference
}
```
```tact
// _ cell:^slice = SomeValue;
struct SomeValue {
cell: Slice; // Always stored as a reference
}
```
```tact
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as int256;
value3: Int as int256;
value4: Int as int256;
}
```
```tact
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256] flag:bool = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as int256;
value3: Int as int256;
flag: Bool; // Flag is written before value4 to prevent auto-layout from allocating it to the next cell
value4: Int as int256;
}
```
```tact
// _ value1:int256 value2:int256 value3:int256 ^[value4:int256 flag:bool] = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: Int as int256;
value3: Int as int256;
value4: Int as int256;
flag: Bool;
}
```
```tact
// _ value1:int256 value2:^TailString value3:int256 = SomeValue;
struct SomeValue {
value1: Int as int256;
value2: String;
value3: Int as int256;
}
```
## Convert received messages to `op` operations[](#convert-received-messages-to-op-operations)
Tact generates a unique `op` for every received typed message, but it can be overridden.
The following code in FunC:
```func
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
;; incoming message code...
;; Receive MessageWithGeneratedOp message
if (op == 1180414602) {
;; code...
}
;; Receive MessageWithOverwrittenOp message
if (op == 291) {
;; code...
}
}
```
Becomes this in Tact:
```tact
message MessageWithGeneratedOp {
amount: Int as uint32;
}
message(0x123) MessageWithOverwrittenOp {
amount: Int as uint32;
}
contract Contract {
// Contract Body...
receive(msg: MessageWithGeneratedOp) {
// code...
}
receive(msg: MessageWithOverwrittenOp) {
// code...
}
}
```
## Convert `get`-methods[](#convert-get-methods)
You can express everything except `list-style-lists` in Tact that would be compatible with FunC’s `get`-methods.
### Primitive return type[](#primitive-return-type)
If a `get`-method returns a primitive in FunC, you can implement it the same way in Tact.
The following code in FunC:
```func
int seqno() method_id {
return 0;
}
```
Becomes this in Tact:
```tact
get fun seqno(): Int {
return 0;
}
```
### Tensor return types[](#tensor-return-types)
In FunC, there is a difference between the tensor types `(int, int)` and `(int, (int))`, but for TVM there is no difference; they both represent a stack of two integers.
To convert the tensor returned from a FunC `get`-method, you need to define a [struct](/book/structs-and-messages#structs) that has the same field types as the tensor and in the same order.
The following code in FunC:
```func
(int, slice, slice, cell) get_wallet_data() method_id {
return ...;
}
```
Becomes this in Tact:
```tact
struct JettonWalletData {
balance: Int;
owner: Address;
master: Address;
walletCode: Cell;
}
contract JettonWallet {
get fun get_wallet_data(): JettonWalletData {
return ...;
}
}
```
### Tuple return type[](#tuple-return-type)
In FunC, if you are returning a tuple instead of a tensor, you need to follow the same process used for a tensor type but define the return type of a `get`-method as optional.
The following code in FunC:
```func
[int, int] get_contract_state() method_id {
return ...;
}
```
Becomes this in Tact:
```tact
struct ContractState {
valueA: Int;
valueB: Int;
}
contract StatefulContract {
get fun get_contract_state(): ContractState? {
return ...;
}
}
```
### Mixed tuple and tensor return types[](#mixed-tuple-and-tensor-return-types)
When some of the returned values are tuples within a tensor, you need to define a struct as in the previous steps, and the tuple itself must be defined as a separate [struct](/book/structs-and-messages#structs).
The following code in FunC:
```func
(int, [int, int]) get_contract_state() method_id {
return ...;
}
```
Becomes this in Tact:
```tact
struct ContractStateInner {
valueA: Int;
valueB: Int;
}
struct ContractState {
valueA: Int;
valueB: ContractStateInner;
}
contract StatefulContract {
get fun get_contract_state(): ContractState {
return ...;
}
}
```
### Arguments mapping[](#arguments-mapping)
Conversion of arguments for `get` methods is straightforward. Each argument is mapped *as-is* to a FunC argument, and each tuple is mapped to a [struct](/book/structs-and-messages#structs).
The following FunC code:
```func
(int, [int, int]) get_contract_state(int arg1, [int,int] arg2) method_id {
return ...;
}
```
becomes this in Tact:
```tact
struct ContractStateArg2 {
valueA: Int;
valueB: Int;
}
struct ContractStateInner {
valueA: Int;
valueB: Int;
}
struct ContractState {
valueA: Int;
valueB: ContractStateInner;
}
contract StatefulContract {
get fun get_contract_state(arg1: Int, arg2: ContractStateArg2): ContractState {
return ContractState {
valueA: arg1,
valueB: ContractStateInner {
valueA: arg2.valueA,
valueB: arg2.valueB, // trailing comma is allowed
}, // trailing comma is allowed
};
}
}
```
---
# Functions
> Global, asm, native functions, as well as receivers, getters, and internal functions, plus the many attributes that allow for great flexibility and expressivity in the Tact language
Tact offers a diverse set of function kinds and attributes that provide great flexibility and expressivity. While some functions stand out, many of their [parts and behaviors are common](#commonalities).
[Receiver functions ](#receivers)
[Regular functions ](#fun)
[Extension functions ](#extends)
[Extension mutation functions ](#mutates)
[Getter functions ](#get)
[Init function ](#init)
[Native functions ](#native)
[Assembly functions ](#asm)
[Inheritance ](#inheritance)
[Inlining ](#inline)
[Commonalities ](#commonalities)
[Low-level representation ](#low-level-representation)
## Receiver functions[](#receivers)
Receiver functions are special functions responsible for [receiving messages](/book/receive) in contracts and can be defined only within a contract or trait.
```tact
contract Counter(counter: Int) {
// This means that this contract can receive the Increment message body,
// and this function would be called to handle such messages.
receive(msg: Increment) {
self.counter += 1;
}
}
message Increment {}
```
There are three kinds of receiver functions in Tact:
* [`receive()`](#receive), which receives internal messages from other contracts.
* [`bounced()`](#bounced), which is processed when an outgoing message from this contract bounces back.
* [`external()`](#external), which doesn’t have a sender and can be sent by anyone in the world.
### `receive` — internal message receivers[](#receive)
Contract scope
The most common receiver functions, `receive()`, handle incoming messages from other contracts.
```tact
// This contract defines various kinds of receivers in their
// order of handling the corresponding incoming messages.
contract OrderOfReceivers() {
// Empty receiver
receive() {
inMsg().bits; // 0
}
// Text receiver
receive("yeehaw!") {
inMsg().asString(); // "yeehaw!"
}
// Catch-all String receiver
receive(str: String) {
// ...
}
// Binary message receiver
receive(msg: FancyMessage) {
// ...
}
// Catch-all Slice receiver
receive(rawMsg: Slice) {
// ...
}
}
message FancyMessage {}
```
Read more about them on their dedicated page: [Receive messages](/book/receive).
### `bounced` — bounced internal message receivers[](#bounced)
Contract scope
The `bounced()` is a special kind of receivers which handle outgoing messages that were sent from this contract and bounced back to it.
```tact
contract Bouncy() {
// Handles empty message bodies
receive() {
// Sending a message...
message(MessageParameters{
to: sender(),
value: ton("0.1"),
body: BB {}.toCell(), // ...with a BB message body
});
}
// If the BB message body wasn't successfully processed by the recipient,
// it can bounce back to our contract, in which case the following receiver
// will handle it.
bounced(msg: bounced) {
// ...
}
}
message BB {}
```
Read more about them on their dedicated page: [Bounced messages](/book/bounced).
### `external` — external message receivers[](#external)
Contract scope
The `external()` is a special kind of receivers which handle external messages — they are sent from the off-chain world and do not have a sender address on the blockchain. Such messages are often sent to wallet contracts to process specific messages or simply to send funds to another wallet contract.
```tact
contract FeaturelessWallet(publicKey: Int as uint256) {
external(msg: MessageWithSignedData) {
// Can't be replied to as there's no sender!
// Thus, many checks are required.
throwUnless(35, msg.bundle.verifySignature(self.publicKey));
}
}
message MessageWithSignedData {
bundle: SignedBundle;
walletId: Int as int32;
seqno: Int as uint32;
}
```
Read more about them on their dedicated page: [External messages](/book/external).
## `fun` — regular functions[](#fun)
Any scope
Regular functions are defined using the `fun` keyword.
```tact
fun add(a: Int, b: Int): Int {
return a + b;
}
```
Read about common aspects of functions: [Commonalities](#commonalities).
### Global functions[](#fun-global)
Global scope
Regular functions that can be defined only at the top (module) level are called global. They differ from [internal functions](#fun-internal) not only in the scope, but also in available [attributes](#commonalities-attributes).
```tact
fun reply(msgBody: Cell) {
message(MessageParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
body: msgBody,
});
}
```
The following attributes can be specified for global functions:
* [`inline`](#inline) — embeds the function contents at the call site.
* [`extends`](#extends) — makes it an [extension function](#extends).
* [`mutates`](#mutates), along with [`extends`](#extends) — makes it an [extension mutation function](#mutates).
These attributes *cannot* be specified:
* [`abstract`](#abstract), [`virtual`](#virtual) and [`override`](#override) — global functions cannot be defined within a contract or a trait.
* [`get`](#get) — global functions cannot be [getters](#get).
### Internal functions[](#fun-internal)
Contract scope
These functions behave similarly to private methods in popular object-oriented languages — they are internal to contracts and can be called by prefixing their names with a special [identifier `self`](/book/contracts#self). That is why internal (or member) functions are sometimes referred to as “contract methods”.
Internal functions can access the contract’s [persistent state variables](/book/contracts#variables) and [constants](/book/contracts#constants).
They can only be called from [receivers](#receivers), [getters](#get), and other internal functions, but not from other contracts.
```tact
contract InternalFun(stopped: Bool) {
// Let's define an internal function to ensure that the contract was not stopped.
fun requireNotStopped() {
throwUnless(TactExitCodeContractStopped, !self.stopped);
}
// And use that internal function within a getter.
get fun veryImportantComputation(): Int {
// Internal function calls are prefixed with `self`
self.requireNotStopped();
return 2 + 2;
}
}
```
The following attributes can be specified for internal functions with no prior attributes:
* [`inline`](#inline) — embeds the function contents at the call site.
* [`abstract`](#abstract), [`virtual`](#virtual) and [`override`](#override) — function [inheritance](#inheritance).
* [`get`](#get) — internal functions can become [getters](#get).
These attributes *cannot* be specified:
* [`extends`](#extends) — internal function cannot become an [extension function](#extends).
* [`mutates`](#mutates) — internal function cannot become an [extension mutation function](#mutates).
## Extensions[](#extensions)
Global scope
[Extension functions](#extends) provide a clean way to organize and extend code by allowing you to add new behaviors to existing types. The [extension *mutation* functions](#mutates) also allow you to modify the value they operate on. Both kinds of extension functions can be called methods and both use special attributes: [`extends`](#extends) and [`mutates`](#mutates), respectively.
### `extends` — extension functions[](#extends)
Global scope
The `extends` attribute can be applied to all top level functions, transforming them into statically dispatched methods on the extended type. These methods are called *extension functions*.
To define an extension function, add an `extends` attribute to any [global function](#fun-global) and name its first parameter as `self`. The type of `self` is the type that is being extended.
```tact
// Extension function that compares two instances of the `StdAddress` type.
extends fun equals(self: StdAddress, other: StdAddress): Bool {
if (self.workchain == other.workchain && self.address == other.address) {
return true;
}
return false;
}
```
The special `self` identifier inside an extension function is a copy of the value of the extended type. In other words, it is the argument value passed to the `self` parameter.
```tact
// Let's define a variable to call the `equals()` extension function on.
let addr = parseStdAddress(
address("EQAFmjUoZUqKFEBGYFEMbv-m61sFStgAfUR8J6hJDwUU09iT").asSlice(),
);
// You can call extension functions on instances of the extended type,
// such as variables...
addr.equals(addr); // true
// ...literals and structure instances...
StdAddress {
workchain: addr.workchain,
address: addr.address,
}.equals(addr); // true
// ...or any other values of that type.
parseStdAddress(
address("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N").asSlice()
).equals(addr); // false
```
Most of the standard library functions that work with values of the [`Builder`](/book/cells#builders) type are extension functions on that type. As such, they do not modify the original value they are applied to.
To preserve newly created values with extension functions, use intermediary assignments or make a long chained call in a single assignment.
```tact
let builder = beginCell();
let cell = builder
.storeUint(42, 7)
.storeInt(42, 7)
.storeBool(true)
.storeSlice(slice)
.storeCoins(42)
.storeAddress(address)
.storeRef(cell)
.endCell();
// Notice that the chained extension function call did not change
// the `builder` variable itself, which is still holding an empty Builder.
builder.refs(); // 0
builder.bits(); // 0
```
The first parameter of extension functions must be named `self`. Failure to do so leads to a compilation error.
Additionally, naming the first parameter of any non-extension function as `self` leads to a compilation error too.
```tact
// COMPILATION ERROR! Extend function must have first parameter named "self"
extends fun add(this: Int, other: Int): Int {
// ~~~~~~~~~
return this + other;
}
// COMPILATION ERROR! Parameter name "self" is reserved for functions with "extends"
fun add(self: Int, other: Int): Int {
// ~~~~~~~~~
return self + other;
}
```
The following additional attributes can be specified:
* [`inline`](#inline) — embeds the function contents at the call site.
* [`mutates`](#mutates) — makes it into an [extension mutation function](#mutates).
These attributes *cannot* be specified:
* [`abstract`](#abstract), [`virtual`](#virtual) and [`override`](#override) — extension functions cannot be defined within a contract or a trait.
* [`get`](#get) — extension functions cannot become [getters](#get).
### `mutates` — extension mutation functions[](#mutates)
Global scope
The `mutates` attribute can be applied to [extension functions](#extends) only, which enables the persistence of the modifications made to the value of the extended type through the `self` identifier. They allow mutations, and so they are called *extension mutation functions*.
The extension *mutation* functions replace the value of the extended type with the new one at the end of its execution. That value would change only upon the assignment to `self` within the function body.
To define an extension mutation function, add a `mutates` attribute to the existing [extension function](#extends).
```tact
// Like the `skipBool` extension mutation function, but usable in chain calls.
extends mutates fun chainSkipBool(self: Slice): Slice {
self.skipBool();
// Notice that returning the `self` value gives a copy of the slice,
// but not a mutable reference to it. Therefore, chaining of mutation functions
// is not very useful in most cases, and may lead to seemingly weird errors.
return self;
}
```
For extension mutation functions, the special `self` identifier refers to the value of the extended type, and changes made to it will persist after the function call.
```tact
// It is most useful to call extension mutation functions on instances
// of the extended type that can keep the change stored either temporarily, i.e.,
// within the current transaction, or permanently — in the contract's state.
contract Mut(val: Slice) {
receive() {
let valTmp = beginCell().storeBool(true).storeInt(42, 7).asSlice();
valTmp.chainSkipBool().loadInt(7); // 42
self.val.chainSkipBool().loadInt(7); // 42
// Now, `valTmp` holds a slice without one bit, i.e.,
// only the value 42 stored using 7 bits. The `self.val` holds its original
// slice but without one bit from its front.
}
}
```
Extension mutation functions cannot modify [constants](/book/constants) because they are immutable.
```tact
// Constant of the Int type
const VAL: Int = 10;
// Extension mutation function for the Int type
extends mutates fun divideInHalf(self: Int) { self /= 2 }
fun noEffect() {
VAL; // 10
VAL.divideInHalf();
VAL; // still 10
}
```
The following additional attributes can be specified:
* [`inline`](#inline) — embeds the function contents at the call site.
These attributes *cannot* be specified:
* [`abstract`](#abstract), [`virtual`](#virtual) and [`override`](#override) — extension mutation functions cannot be defined within a contract or a trait.
* [`get`](#get) — extension mutation functions cannot become [getters](#get).
### Static extension functions[](#extends-static)
There is no such attribute yet, so the special static extension functions in the standard library of Tact are introduced directly by the compiler:
* [`Message.opcode()`](/ref/core-cells#messageopcode)
* [`Message.fromCell()`](/ref/core-cells#messagefromcell)
* [`Message.fromSlice()`](/ref/core-cells#messagefromslice)
* [`Struct.fromCell()`](/ref/core-cells#structfromcell)
* [`Struct.fromSlice()`](/ref/core-cells#structfromslice)
## `get fun` — off-chain getter functions[](#get)
Contract scope
The special `get` attribute cannot be combined with any other attribute. It is applied to [internal functions](#fun-internal), transforming them into so-called *getter functions* (or getters for short). These functions are externally accessible off-chain, allowing direct reading of contract state without regular message passing.
```tact
contract StaleCounter(val: Int as uint32) {
// Getter function that simply returns the current value of the state variable
get fun value(): Int {
return self.val;
}
// Getter function that performs basic calculations
get fun valuePlus(another: Int): Int {
return self.val + another;
}
}
```
Despite the restriction on attributes, getter functions can still be considered internal or contract methods — calling them from within another contract function is possible. In those cases, their behavior would be identical to calling an internal function through `self`, including any state modifications those functions can perform.
However, most of the time, getter functions are there to be called from the off-chain world. And when they are called that way and not via `self`, their state modifications no longer persist between transactions (changes are discarded).
```tact
contract WillNotBudge(val: Int) {
get fun changeVal() {
self.val = randomInt();
self.val; // ?, it is random!
// However, after this function is done,
// the self.val will be reset to its value prior to this function call.
}
}
```
Furthermore, when **not** used as internal functions, getters do not pay the [compute fees](https://docs.ton.org/develop/howto/fees-low-level#computation-fees) and have their gas limits to prevent infinite loops or endless transactions. That is, getters can perform arbitrary computations if their internal gas limit is not surpassed in a single transaction.
Those gas limits depend on the API provider used to call a certain getter, but they are usually around 100 million gas units per getter call.
With that in mind, getters are most commonly used for fetching the current state of contract’s persistent state variables. To do so in a convenient matter, Tact allows you to view the contract itself as a [struct](/book/structs-and-messages#structs) of contract variables, i.e., to use `self` to refer to the contract itself and return all of its state variable values at once in a single getter.
```tact
contract ManyFields(
f1: Int,
f2: Int,
// ...
f42: Int,
) {
// Notice that the return type of this get function coincides
// with the name of the contract, which makes that return type
// view the contract as a struct of its variables.
get fun state(): ManyFields {
return self; // you do not have to list all fields of a contract for this
}
}
```
### Method IDs[](#method-ids)
Like other functions in TON contracts, getters have their *unique* associated function selectors, which are 19-bit signed integer identifiers commonly called [*method IDs*](#low-level-representation).
Method IDs of getters are derived from their names using the [CRC16](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) algorithm as follows: `(crc16() & 0xffff) | 0x10000`. In addition, the Tact compiler conditionally reserves some method IDs for use in [getters of supported interfaces](/book/contracts#interfaces), namely: 113617 for `supported_interfaces`, 115390 for `lazy_deployment_completed`, and 121275 for `get_abi_ipfs`.
Thus, getters and their method IDs are an important part of the contract interfaces, to the point where explorers tend to recognize contracts based not on their entire code, but on the set of getters they expose to the off-chain world.
### Explicit resolution of method ID collisions[](#explicit-resolution-of-method-id-collisions)
Available since Tact 1.6
Sometimes, getters with different names end up with the same method ID. If this happens, you can either rename some of the getters or manually specify the method ID as a [compile-time](/ref/core-comptime) expression like so:
```tact
contract ManualMethodId() {
const methodId: Int = 16384 + 42;
get(self.methodId)
fun methodId1(): Int {
return self.methodId;
}
get(crc32("crc32") + 42 & 0x3ffff | 0x4000)
fun methodId2(): Int {
return crc32("crc32") + 42 & 0x3ffff | 0x4000;
}
}
```
Unlike getters, method IDs for [internal functions](#fun-internal) and some special functions are obtained sequentially: integers in the inclusive range from -4 to 0 are given to [certain message handlers](https://docs.ton.org/v3/documentation/smart-contracts/func/docs/functions#special-function-names), while internal functions are numbered with method IDs starting at 1 and going up to 214−1 inclusive.
Since method IDs are 19-bit signed integers and some of them are reserved, only the inclusive ranges from −218 to −5 and from 214 to 218−1 are free to be used by users. It is recommended to specify method IDs only in these ranges to avoid collisions.
Furthermore, as the algorithm for generating method IDs only produces positive values and IDs -4 to 0 are reserved, by manually specifying negative IDs from −218 up to −5, you can guarantee that there would be no collisions with any other getters.
```tact
contract AntiPositive() {
// This getter's manually specified method ID
// will not collide with any autogenerated IDs
get(-42) fun negAns(): Int {
return -42;
}
get fun posAns(): Int {
return 42;
}
}
```
## `init` — constructor function[](#init)
Contract scope
The special constructor function `init()` is run upon deployment of the contract. Unlike [contract parameters](/book/contracts#parameters), it performs a delayed initialization of the contract data, overriding the values of persistent state variables on-chain.
```tact
contract Example {
// Persistent state variables
var1: Int = 0; // initialized with default value 0
var2: Int; // must be initialized in the init() function
var3: Int = 7; // initialized with default value 7
// Constructor function, which is run only once
init() {
self.var2 = 42;
self.var3 = 32; // overrides the default to 32
}
}
```
For every receiver that doesn’t alter the contract’s variables, Tact optimizes away unnecessary storage overrides. However, contracts cannot benefit from such optimizations if the `init()` function is present. That is because for contracts with `init()` every receiver has to check whether the `init()` function has run already and did that only once, and to do so, a special flag is implicitly stored in the contract’s persistent state.
Effectively, the behavior or `init()` function can be simulated when using contract parameters instead — through adding a special [`Bool`](/book/types#booleans) field and a function that would be used in place of the `init()`. That function would be called at the beginning of every receiver, while the boolean field would be used as a flag.
```tact
contract CounterBuiltinInit {
// Persistent state variables
counter: Int as uint32;
// Constructor function, which is run only once
init() {
self.counter = 0;
}
receive() {
cashback(sender());
}
receive(_: Increment) {
self.counter += 1;
}
get fun counter(): Int {
return self.counter;
}
}
contract CounterDIYInit(
// Persistent state variables
initialized: Bool, // set this field to `false` during deployment
counter: Int as uint32, // value of this field will be overridden in the `customInit()`
) {
// Internal function, which will be used in place of a pseudo-constructor function
fun customInit() {
// Stop further actions if this customInit() function was called before
if (self.initialized) {
return;
}
// Initialize
self.initialized = true;
self.counter = 0;
}
receive() {
// Don't forget to add this call at the start of every receiver
// that can be used for deployments.
self.customInit();
cashback(sender());
}
receive(_: Increment) {
// Don't forget to add this call at the start of every receiver
// that can be used for deployments.
self.customInit();
self.counter += 1;
}
get fun counter(): Int {
return self.counter;
}
}
message Increment {}
```
None of the [attributes](#commonalities-attributes) can be specified for the `init()` function.
Read more about the `init()` on its dedicated section: [Constructor function `init()`](/book/contracts#init-function).
## `native` — foreign function interfaces[](#native)
Global scope
Native functions are Tact’s [FFI](https://en.wikipedia.org/wiki/Foreign_function_interface) to FunC — they allow direct bindings to imported FunC functions. In order to declare them, you have to import a `.fc` or `.func` file first. Granted, the FunC’s [standard library file, `stdlib.fc`](https://github.com/tact-lang/tact/blob/main/src/stdlib/stdlib/std/stdlib.fc), is always imported for you.
Consider the following FunC file:
import\_me.fc
```func
;; Notice the tensor return type (int, int),
;; which means we would have to define at least one
;; Tact structure to bind to this function.
(int, int) keccak512(slice s) impure asm "ONE HASHEXT_KECCAK512 UNPAIR";
```
In Tact code, one could access that function as follows:
```tact
// 1. Import the FunC file that contains the function.
import "./import_me.fc";
// 2. Declare the native function binding.
@name(keccak512) // name of the target FunC function
native keccak512(s: Slice): HashPair;
// ^^^^^^^^^ name of the Tact function bind,
// which can be the identical to its FunC counterpart
// 3. Define the necessary structs for the bind.
// In our case, it is the HashPair structure to capture multiple return values.
struct HashPair {
h1: Int;
h2: Int;
}
// 4. Use the function whenever you would like.
// It has the same properties as regular global functions.
fun example() {
let res = keccak512(emptySlice());
res.h1; // 663...lots of digits...092
res.h2; // 868...lots of digits...990
}
```
The following attributes can be specified for `native` functions:
* [`inline`](#inline) — embeds the function contents at the call site.
* [`extends`](#extends) — makes it an [extension function](#extends).
* [`mutates`](#mutates), along with [`extends`](#extends) — makes it an [extension mutation function](#mutates).
These attributes *cannot* be specified:
* [`abstract`](#abstract), [`virtual`](#virtual) and [`override`](#override) — native functions cannot be defined within a contract or a trait.
* [`get`](#get) — native functions cannot be [getters](#get).
## `asm` — assembly functions[](#asm)
Global scope Available since Tact 1.5
Assembly functions are top-level functions that allow you to write Tact assembly. Unlike all other functions, their bodies consist only of TVM instructions and some other primitives that serve as arguments to the instructions.
Furthermore, `asm` functions are nearly devoid of all abstractions and give direct access to the underlying stack and register contents on which TVM operates.
```tact
// Simple assembly function that creates a new `Builder`.
asm fun beginCell(): Builder { NEWC }
// Like nativeReserve(), but also allows reserving extra currencies.
asm fun extraReserve(
// Toncoin amount
nativeAmount: Int,
// A map of 32-bit extra currency IDs to VarUInt32 amounts
extraAmountMap: map,
// Reservation mode
mode: Int,
) { RAWRESERVEX }
// Assembly function as an extension function for the `Builder` type.
asm(value self) extends fun storeBool(self: Builder, value: Bool): Builder { 1 STI }
```
Read more about them on their dedicated page: [Assembly functions](/book/assembly-functions).
## Inheritance[](#inheritance)
Contract scope
The `with` keyword allows a contract to inherit a [trait](/book/types#traits) with all its constants, fields, and functions, including those transitively inherited from other traits associated with the specified trait.
In particular, all functions of the trait become accessible in the contract, regardless of any inheritance-related attributes, such as `abstract`, `virtual`, or `override`.
You can allow a contract inheriting a [trait](/book/types#traits) to modify a [internal function](#fun-internal) marked with the `virtual` keyword by using `override`. A function can also be marked as `abstract`, in which case the inheriting contract must define its implementation.
```tact
trait FilterTrait with Ownable {
// Virtual functions can be overridden by users of this trait
virtual fun filterMessage(): Bool {
return sender() != self.owner;
}
abstract fun specialFilter(): Bool;
// Receivers can be inherited, but cannot be overridden
receive() { cashback(sender()) }
}
contract Filter() with FilterTrait {
// Overriding the default behavior of the FilterTrait
override fun filterMessage(): Bool {
return true;
}
override fun specialFilter(): Bool {
return true;
}
}
```
### `abstract`[](#abstract)
Contract scope
The `abstract` attribute allows declaring a [internal function](#fun-internal) with no body given at declaration. Functions with this attribute are meant to be overridden later in the inheritance hierarchy by either an intermediate trait or the contract inheriting it.
```tact
trait DelayedOwnable {
owner: Address;
abstract fun requireOwner();
abstract fun requireOwnerDelayed(bigBadName: Int);
}
contract Ownership(owner: Address) with DelayedOwnable {
// All functions marked as abstract must be defined
// in the contract that inherits them.
override fun requireOwner() {
throwUnless(TactExitCodeAccessDenied, sender() == self.owner);
}
// The signature of the overridden function must match its inherited abstract
// counterpart on everything except parameter names. Notice the rename
// of the `bigBadName` parameter to `timestamp` in the function below.
override fun requireOwnerDelayed(timestamp: Int) {
throwUnless(TactExitCodeAccessDenied, now() >= timestamp);
throwUnless(TactExitCodeAccessDenied, sender() == self.owner);
}
}
```
### `virtual`[](#virtual)
Contract scope
The `virtual` attribute allows a [internal function](#fun-internal) to be overridden later in the inheritance hierarchy by either an intermediate trait or the contract inheriting it.
This attribute is similar to the [`abstract`](#abstract) attribute, except that you do not have to override bodies of functions with the `virtual` attribute. But if you decide to override the function body, you may do it in any trait that depends on this trait and not only in the resulting contract.
```tact
import "@stdlib/ownable";
trait DeployableFilterV1 with Ownable {
// Virtual functions can be optionally overridden by users of this trait.
virtual fun filter() {
// Not an owner
throwUnless(TactExitCodeAccessDenied, sender() == self.owner);
}
// Whereas internal functions with an abstract attribute must be overridden
// by the contract that will import this trait or any of the traits that depend on this trait.
abstract fun specialFilter();
// Receivers are inherited too,
// but they cannot defined be virtual or abstract
receive() { cashback(sender()) }
}
trait DeployableFilterV2 with DeployableFilterV1 {
override fun filter() {
// Not an owner
throwUnless(TactExitCodeAccessDenied, sender() == self.owner);
// Message carries too little Toncoin for our tastes
throwUnless(TactExitCodeAccessDenied, context().value < ton("1"));
}
}
contract Auth(owner: Address) with DeployableFilterV2 {
override fun specialFilter() {
if (randomInt() < 10) {
throw(TactExitCodeAccessDenied);
}
}
receive(_: TopSecretRequest) {
self.filter();
self.specialFilter();
// ...subsequent logic...
}
}
message TopSecretRequest {}
```
### `override`[](#override)
Contract scope
The `override` attribute is used to override an inherited [internal function](#fun-internal) that has either a [`virtual`](#virtual) or [`abstract`](#abstract) attribute specified in the declaration of that function in one of the parent traits.
## Commonalities[](#commonalities)
Functions commonly share the same aspects, parts, or behavior. For example, due to the nature of TVM, Tact uses the [call by value](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value) parameter-passing and binding strategy, which applies to all function kinds. That is, the evaluated value of any variable passed in a function call or assigned in the [`let`](/book/statements#let) or [assignment](/book/statements#assignment) statement is copied.
Therefore, there are no modifications of the original values in different scopes, except for the [extension *mutation* functions](#mutates). And even so, those functions do not mutate the original value denoted by the `self` keyword — instead, they discard the old value and replace it with the new one obtained at the end of the function body.
The above applies to all functions except for [receivers](#receivers), because they cannot be called directly and are only executed upon receiving specific messages.
### Scope[](#commonalities-scope)
All kinds of functions vary in scope: some can only be defined at the top level, such as [global functions](#fun-global), while others can only be defined within contracts and traits, such as [internal functions](#fun-internal) or [receivers](#receivers).
Functions are hoisted upon declaration, such that the ones declared earlier might call those declared later and vice versa.
```tact
// Global function first() is defined prior to the second() function,
// but we can call the second() one just fine.
fun first(): Bool {
return second(true); // always true
}
// Global function second() is defined after the first() function,
// and call to the first() function works as expected.
fun second(flag: Bool): Bool {
if (flag) {
return true;
}
return first(); // always true, because of the prior condition
}
```
### Attributes[](#commonalities-attributes)
Function attributes modify a function’s behavior and typically restrict it to a specific scope.
| Attribute | Scope | Can be applied to |
| :---------------------- | :------- | :-------------------------------------------------------------------------- |
| [`extends`](#extends) | global | All global functions |
| [`mutates`](#mutates) | global | Functions with `extends` attribute |
| [`virtual`](#virtual) | contract | Internal functions |
| [`abstract`](#abstract) | contract | Internal functions |
| [`override`](#override) | contract | Internal functions that were previously marked with `virtual` or `abstract` |
| [`inline`](#inline) | any | All functions except for receivers and getters |
| [`get`](#get) | contract | Internal functions — turns them into getters |
Notice that the “contract” scope also includes the [traits](/book/types#traits).
### Naming and namespaces[](#commonalities-naming)
Function names follow the standard Tact [identifier naming conventions](/book/expressions#identifiers).
```tact
abstract fun azAZ09_();
```
[Internal functions](#fun-internal) and [getters](#get) exist in a namespace separate from the contract’s fields. For example, a persistent state variable named `value` can co-exist with a getter function named `value()`, which is very convenient in many cases.
However, identifiers of internal functions within a single contract must be distinct, as are identifiers of all top-level functions. The only exceptions are [extensions](#extensions), which can have the same identifiers, provided that the extended types of their `self` parameter differ.
```tact
// COMPILATION ERROR! Static function "globName" already exists
fun globName() {}
fun globName() {}
// ~~~~~~~~~~~~~
// No errors, because despite the same identifiers,
// the types of the `self` parameter are different
extends fun doWith(self: Int) {}
extends fun doWith(self: Slice) {}
```
### Return values[](#commonalities-return)
All functions return a value. If the function does not have an explicit return type specified, it has an implicit return type of `void` — a pseudo-value that represents “nothing” in the Tact compiler. This also applies to the functions that do not allow specifying a return type, such as [receivers](#receivers) or [`init()`](#init).
Moreover, execution of any function can be ended prematurely with the [`return` statement](/book/statements#return). This is also true for the [receiver functions](#receivers) and \[`init()`], where empty `return` statements are allowed.
```tact
contract GreedyCashier(owner: Address) {
receive() {
// Stop the execution if the message is not from an `owner`.
if (sender() != self.owner) {
return;
}
// Otherwise, forward excesses back to the sender.
cashback(sender());
}
}
```
To return multiple values in a function, aggregate the values in a [struct](/book/structs-and-messages#structs).
```tact
fun minmax(a: Int, b: Int): MinMax {
if (a < b) {
return MinMax { min: a, max: b };
}
return MinMax { min: b, max: a };
}
struct MinMax {
min: Int;
max: Int;
}
```
[Reachability](/book/statements#return) of `return` statements should always be evident to the compiler. Otherwise, a compilation error will occur.
### Recursion[](#commonalities-recursion)
Recursive functions are allowed, including the mutually recursive functions. There is no upper limit on the recursion depth or the number of calls — computations will continue until there is no more gas to spend.
```tact
fun produceOneFrom(a: Int): Int {
if (a <= 1) { return 1 }
return alsoProduceOneFrom(a - 1);
}
fun alsoProduceOneFrom(b: Int): Int {
if (b <= 1) { return 1 }
return produceOneFrom(b - 1);
}
fun example(someA: Int, someB: Int) {
// This sum will always be 2, regardless of values of `someA` and `someB`.
// The only exception is when their values are too big and there is not
// enough gas to finish the computations, in which case the transaction
// will fail with an exit code -14: Out of gas error.
produceOneFrom(someA) + alsoProduceOneFrom(someB); // 2
}
```
### Code embedding with `inline`[](#inline)
Any scope
The `inline` attribute embeds the code of the function to its call sites, which eliminates the overhead of the calls but potentially increases the code size if the function is called from multiple places.
This attribute can improve performance of large infrequently called functions or small, alias-like functions. It can be combined with any other attribute except for [`get`](#get).
```tact
inline fun add(a: Int, b: Int) {
// The following addition will be performed in-place,
// at all the `add()` call sites.
return a + b;
}
```
### Trailing comma[](#commonalities-comma)
All functions, except for [receiver functions](#receivers), can have a trailing comma in their definitions (parameter lists) and calls (argument lists):
```tact
fun foo(
a: Int, // trailing comma in parameter lists is allowed
) {}
fun bar() {
foo(
5, // trailing comma in argument lists is allowed too!
);
}
```
### Trailing semicolon[](#commonalities-colon)
The last [statement](/book/statements) inside the function body has a trailing semicolon — it can be freely omitted, which is useful for writing one-liners.
```tact
inline fun getCoinsStringOf(val: Int) { return val.toFloatString(9) }
```
When declaring an [internal function](#fun-internal) with [`abstract`](#abstract) or [`virtual`](#virtual) attributes, Tact allows you to omit a semicolon if it is the last function in the [trait’s](/book/types#traits) body.
```tact
trait CompositionVII {
abstract fun paintedWithOil(preliminary: Bool): Bool // no semicolon needed
}
contract Abstractionism() with CompositionVII {
override fun paintedWithOil(preliminary: Bool): Bool {
if (preliminary) {
return false; // perhaps, watercolors were used...
}
return true;
}
}
```
### Wildcard parameters[](#commonalities-wildcard)
Available since Tact 1.6.1
For all kinds of functions, naming a parameter with an underscore `_` causes its value to be considered unused and discarded. This is useful when you do not access the parameter but want to include it in the signature for possible overrides. Note that such a wildcard parameter name `_` cannot be accessed.
```tact
trait WildThing {
// Using wildcards for parameter names
virtual fun assure(_: Int, _: Int): Bool {
return true;
}
}
contract YouMakeMyHeartSing() with WildThing {
// And then overriding them with concrete names
override fun assure(a: Int, b: Int): Bool {
return a + b == b + a;
}
// Wildcards are also useful when you do not intend to
// use the contents of the message and only handle the proper one
receive(_: FieldsDoNotLie) {
// ...
}
}
message FieldsDoNotLie {}
```
## Low-level representation[](#low-level-representation)
On [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) level, contracts and their functions are often represented as a dictionary (or [“hashmap”](/book/maps#low-level-representation)) of methods, from their numeric method IDs to their respective bodies composed of TVM instructions. Each function then is a method that transforms the stack and TVM registers.
A function call is, essentially, a call into the dictionary using the function’s ID, after which:
1. Function arguments are pushed onto the stack
2. The function executes, manipulating the stack
3. Return values are left on top of the stack, provoking another dictionary call or resulting in the end of the transaction
When a so-called [“selector hack”](/book/config#optimizations-internalexternalreceiversoutsidemethodsmap) optimization is enabled, if the number of defined receivers is small, they are stored outside of that map as plain instruction sequences. That saves gas but can cause the contract to be incorrectly recognized and misparsed by some explorers and user wallets, which expect the root of the contract’s code (the root cell) to point at the method dictionary.
---
# Gas best practices
> Anti-patterns, suboptimal approaches that increase gas usage, and best practices of cheap runtime execution that Tact smart contract developers should be aware of.
There are several anti-patterns that unnecessarily increase gas usage or are suboptimal in most cases. Below, we discuss various trade-offs when writing gas-efficient and safe Tact smart contracts.
Suggestions are given in no particular order as a simple and quick checklist to see how your contract is doing regarding gas usage. You don’t have to check all the points, but try to follow as many as possible without neglecting the [security best practices](/book/security-best-practices).
Note
Tact compiler is continuously evolving, so some points below may become outdated and removed or replaced. Please check this page periodically for updates.
## General considerations[](#general-considerations)
### Prefer contract parameters to `init()` and contract fields[](#prefer-contract-parameters-to-init-and-contract-fields)
If you require some on-chain deployment logic that runs just once after the contract’s deployment is completed, then use the lazy initialization strategy provided by the [`init()` function](/book/contracts#init-function). It uses an extra bit in the contract’s persistent state, runs extra checks upon receiving any message, and disables storage write optimizations of Tact compiler.
However, most contracts do not require lazy initialization and define their initial data only when the contract is first deployed, with everything for it prepared off-chain. Therefore, prefer using [contract parameters syntax](/book/contracts#parameters) to define the data of the contract’s persistent storage that way.
```tact
contract ContractParams(
// Persistent state variables declared via the contract parameters syntax
val1: Int as uint64, // `as`-annotations are supported
val2: String,
) {
// For deployments
receive() { cashback(sender()) }
}
```
```ts
// TypeScript wrappers generated by Tact compiler
import { ContractParams } from '../wrappers/ContractParams';
// Various utility libraries
import { NetworkProvider } from '@ton/blueprint';
import { toNano } from '@ton/core';
// Default deployment function / script of the Blueprint
export async function run(provider: NetworkProvider) {
const contract = provider.open(await ContractParams.fromInit(
42, // `val1` in the contract
"The time has come", // `val2` in the contract
));
await playground.send(
provider.sender(),
{ value: toNano('0.05') },
null, // because there's a `null` message body
// `receive()` function in the contract
);
await provider.waitForDeploy(playground.address);
}
```
### Do not deploy contracts with `Deployable` trait[](#do-not-deploy-contracts-with-deployable-trait)
The `Deployable` trait is now deprecated and should only be used if you require the `queryId`, which serves as a unique identifier for tracing transactions across multiple contracts.
Instead of inheriting the `Deployable` trait, prefer having a simple receiver for the empty message body and deploying your contracts with it.
```tact
contract Friendly {
// This is when you DO want to send excesses back
receive() { cashback(sender()) } // expects a `null` body
}
contract Scrooge {
// This is when you don't want to send excesses back
receive() {} // expects a `null` body
}
```
### Use `BasechainAddress` struct and related functions for runtime manipulations on addresses in the base workchain[](#use-basechainaddress-struct-and-related-functions-for-runtime-manipulations-on-addresses-in-the-base-workchain)
Available since Tact 1.6.3
Almost all contracts on TON are deployed on the basechain — a [workchain with ID 0](https://docs.ton.org/learn/overviews/addresses#workchain-id). The [`BasechainAddress`](/ref/core-addresses#basechainaddress) [struct](/book/structs-and-messages#structs) and related functions were introduced to allow optimal handling of basechain addresses at runtime.
A frequent use-case for basechain addresses is checking message sender addresses for validity, i.e., if a contract needs to make sure the incoming message comes from a specific contract deployed in the basechain, it can use the [`StateInit.hasSameBasechainAddress()`](/ref/core-addresses#stateinithassamebasechainaddress) extension function.
```tact
contract Child(parentAddr: Address) {
receive() {
// Forward surplus to the parent address
cashback(self.parentAddr);
}
}
contract Parent() {
receive() {
// Ensure that the message came from the child contract
let childContract = initOf Child(myAddress());
require(
childContract.hasSameBasechainAddress(sender()),
"Message must come from the Child contract",
);
// ...subsequent logic...
}
}
```
To ensure that a certain [`Address`](/book/types#primitive-types) is in the basechain and can be represented by the `BasechainAddress`, you can use the [`forceBasechain()`](/ref/core-addresses#forcebasechain) function first.
See other functions related to the `BasechainAddress` struct:
* [`emptyBasechainAddress()`](/ref/core-addresses#emptybasechainaddress)
* [`newBasechainAddress()`](/ref/core-addresses#newbasechainaddress)
* [`contractBasechainAddress()`](/ref/core-addresses#contractbasechainaddress)
### Pay attention to “500+ gas” badge[](#pay-attention-to-500-gas-badge)
Some functions in the Tact documentation are annotated with a special badge, “500+ gas”, which marks the functions that use 500 gas units or more. It is placed right under the function name heading and looks like this: 500+ gas
If you use one of those functions, consider finding cheaper alternatives.
### Inline functions that are rarely called[](#inline-functions-that-are-rarely-called)
Some [kinds of functions](/book/functions) allow their code to be inlined by adding an `inline` annotation. If the function is used often, this might result in a significant increase in contract code size, but generally, it allows to save gas on redundant function calls.
Furthermore, you might reach for the [experimental `inline` field](/book/config#experimental-inline) in `tact.config.json`, which enables the inlining of all functions that can be inlined.
This advice needs benchmarks to decide its usefulness on a case-by-case basis.
### Prefer manipulating strings off-chain[](#prefer-manipulating-strings-off-chain)
Strings on-chain are represented as [slices](/book/cells#slices), which are expensive for handling Unicode strings and quite costly even for ASCII ones. Prefer not to manipulate strings on-chain.
### Prefer arithmetic to branching operators[](#prefer-arithmetic-to-branching-operators)
On average, branching uses many more instructions than equivalent arithmetic. Common examples of branching are the [`if...else`](/book/statements#if-else) statement and the ternary operator [`?:`](/book/operators#ternary).
Use arithmetic and standard library functions over branching or complex control flow whenever possible.
```tact
// If the forwardAmount is non-negative, this
msg.forwardAmount > 0 ? 2 : 1;
// is more expensive than doing this
1 + sign(msg.forwardAmount);
```
### Prefer specialized math functions to general ones[](#prefer-specialized-math-functions-to-general-ones)
Specialized math functions are cheaper than general ones as they require fewer stack manipulations and often use more efficient [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions).
If you only need to obtain logarithms to the base 2, use the [`log2()`](/ref/core-math#log2) function over the general [`log()`](/ref/core-math#log) function.
If you only need to obtain powers of 2, use the [`pow2()`](/ref/core-math#pow2) function over the general [`pow()`](/ref/core-math#pow) function.
```tact
let num = 42;
// Use this instead of log(num, 2)
log2(num);
// Use this instead of pow(num, 2)
pow2(num);
```
### Asm functions[](#asm-functions)
Many commonly used [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions) expect the same values but in a different order on the stack. Often, the code you write will result in instructions defined by your logic intermittent with stack-manipulation instructions, such as `SWAP` or [`ROT`](https://docs.ton.org/v3/documentation/tvm/instructions#58), which would’ve been unnecessary if the positioning of values on the stack was better planned before.
On the other hand, if you know the layout and boundaries of your data, the generic choice of underlying instructions might be suboptimal in terms of gas usage or code size.
In both cases, you can use assembly functions (or `asm` functions for short) to manually describe the logic by writing a series of [TVM instructions](https://docs.ton.org/v3/documentation/tvm/instructions). If you know what you’re doing, `asm` functions can offer you the smallest possible gas usage and the most control over [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) execution.
Read more about them on their dedicated page: [Assembly functions](/book/assembly-functions).
### Disable run-time `safety` checks for well-tested contracts[](#disable-run-time-safety-checks-for-well-tested-contracts)
Caution
Proceed only if you have a comprehensive contract test suite and are about to apply various other security measures, such as audits. The following is not guidance but is an illustration of what can be done to maximize gas efficiency when you are sure of the safety of your contracts.
When using the unwrapping [non-null assertion `!!`](/book/operators/#unary-non-null-assert) operator, you can decrease its gas consumption at the expense of its runtime `null` checks. Thus, you should only disable such checks when you are sure there will not be a runtime `null` present in the given branch of your code.
```tact
fun example() {
let val: Int? = 42;
if (val == null) {
return;
}
// At this point we know that `val` is not null,
// so we can safely disable runtime checks of the !! operator in the config
val!!; // 42
}
```
To disable runtime `null` checks of the `!!` operator, set the [`nullChecks`](/book/config#safety-nullchecks) field to `false` in your [`tact.config.json`](/book/config).
```json
{
"projects": [
{
"name": "contract",
"path": "./your-contract-file.tact",
"output": "./output",
"options": {
"safety": {
"nullChecks": false
}
}
}
]
}
```
## Receiving messages[](#receiving-messages)
### Prefer binary receivers to text receivers[](#prefer-binary-receivers-to-text-receivers)
Tact automatically handles various message body types, including binary and string (text) ones. Both message bodies start with a 32-bit integer header (or tag) called an [opcode](/book/structs-and-messages#message-opcodes), which helps distinguish their following contents.
To prevent conflicts with binary message bodies which are usually sent on the blockchain, the string (text) receivers skip the opcode and instead route based on the hash of the message body contents — an expensive operation that requires more than 500 units of gas.
While text receivers are convenient during development in testing, when preparing your contract for production you should replace all text receivers with binary ones and create relevant [message structs](/book/structs-and-messages#messages) even if they’ll be empty and only their opcodes will be used.
```tact
message(1) One {}
message(2) Two {}
contract Example() {
// Prefer this
receive(_: One) {
// ...
}
receive(_: Two) {
// ...
}
// Over this
receive("one") {
// ...
}
receive("two") {
// ...
}
}
```
### Prefer `inMsg()` to `Message.toSlice()`[](#prefer-inmsg-to-messagetoslice)
Available since Tact 1.6.7
When working with an incoming message, prefer using the [`inMsg()`](/ref/core-contextstate#inmsg) function over the [`Message.toSlice()`](/ref/core-cells#messagetoslice) extension function, because the `inMsg()` function provides direct access to the incoming message body [`Slice`](/book/types#primitive-types), while `msg.toSlice()` performs redundant operations to recreate that `Slice`.
```tact
contract Example() {
receive(msg: SomeMessage) {
// Prefer this
let body = inMsg();
// over this
let sameBody = msg.toSlice();
}
}
```
### Avoid internal contract functions[](#avoid-internal-contract-functions)
The [internal functions](/book/contracts#internal-functions) of a contract (often called contract methods) are similar to global functions, except that they can access the contract’s [storage variables](/book/contracts#variables) and [constants](/book/contracts#constants).
However, they push the contract’s variables on the stack at the start of their execution and pop them off afterward. This creates lots of unnecessary stack-manipulation instructions and consumes gas.
If your contract method does not access any of its persistent state variables, move it outside the contract and make it a global, module-level function instead.
### Use `sender()` over `context().sender`[](#use-sender-over-contextsender)
When you receive an internal message, you can obtain the address of the contract that has sent it. This can be done by calling the [`sender()`](/ref/core-contextstate#sender) function or by accessing the `.sender` field of the `Context` [struct](/book/structs-and-messages#structs) after calling the [`context()`](/ref/core-contextstate#context) function.
If you only need the sender’s address and no additional context on the incoming message that is contained in the `Context` struct, then use the [`sender()`](/ref/core-contextstate#sender) function as it is less gas-consuming.
```tact
message(MessageParameters {
to: sender(),
value: ton("0.05"),
});
```
### Use `throwUnless()` over `require()`[](#use-throwunless-over-require)
The [`require()`](/ref/core-debug#require) function is convenient for stating assumptions in code, especially in debug environments. Granted, currently, it generates [exit codes](/book/exit-codes) greater than 211, making it a bit expensive compared to alternatives.
If you’re ready for production and are willing to sacrifice some convenience for gas, use [`throwUnless()`](/ref/core-debug#throwunless) function, keep track of your exit codes by declaring them as [constants](/book/constants), and keep exit codes within the inclusive range of 256−211. It’s essential to respect the latter range because the exit code values from 0 to 255 are reserved by [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) and the Tact compiler.
```tact
const SOMETHING_BAD_1: Int = 700;
const SOMETHING_BAD_2: Int = 701; // it is convenient to increment by 1
fun example() {
throwUnless(SOMETHING_BAD_1, now() > 1000);
throwUnless(SOMETHING_BAD_2, now() > 1000000);
}
```
### Use `SignedBundle` to verify signatures in external message receivers[](#use-signedbundle-to-verify-signatures-in-external-message-receivers)
When handling [external messages](/book/external), the [`SignedBundle`](/ref/core-crypto#signedbundle) [struct](/book/structs-and-messages#structs) provides a gas-efficient way to verify message signatures. This approach is particularly useful for wallet contracts and other contracts that need secure user authorization.
The `SignedBundle` contains both the signature and the non-serialized data of the enclosing struct or message struct that is being signed, allowing for convenient verification with the [`SignedBundle.verifySignature()`](/ref/core-crypto#signedbundleverifysignature) extension function.
```tact
contract Wallet(publicKey: Int as uint256) {
external(msg: SomeWalletOperation) {
// Verifying the signature before accepting the message
require(msg.bundle.verifySignature(self.publicKey), "Invalid signature");
// Now it's safe to accept it
acceptMessage();
// ...and proceed further...
}
}
message SomeWalletOperation {
// You must set the SignedBundle as the first field
bundle: SignedBundle;
// Some data to be signed
walletId: Int as int32;
seqno: Int as uint32;
}
```
## Sending messages[](#sending-messages)
### Prefer `message()` and `cashback()` to `self.forward()`, `self.reply()`, and `self.notify()`[](#prefer-message-and-cashback-to-selfforward-selfreply-and-selfnotify)
Every [contract](/book/contracts) in Tact implicitly [inherits](/book/contracts#traits) the `BaseTrait` trait, which contains a number of [internal functions](/book/contracts#internal-functions) for any contract. Those internal functions are gas-expensive for the same reasons as stated earlier.
Calls to `self.forward()`, `self.reply()` and `self.notify()` can be replaced with respective calls to the [`send()`](/ref/core-send#send) or [`message()`](/ref/core-send#message) functions with suitable values.
Moreover, if all you want is to forward the remaining value back to the sender, it is best to use the [`cashback()`](/ref/core-send#cashback) function instead of `self.notify()` function.
```tact
// This
self.forward(sender(), null, false, initOf SomeContract());
// could be replaced with this
let initState = initOf SomeContract();
send(SendParameters {
to: sender(),
mode: SendRemainingValue | SendIgnoreErrors,
bounce: false,
value: 0,
code: initState.code,
data: initState.data,
body: null,
})
// This
self.reply(null);
// should be replaced with this
message(MessageParameters {
body: null,
to: sender(),
mode: SendRemainingValue | SendIgnoreErrors,
bounce: true,
value: 0,
});
// And this
self.notify(null);
// should be replaced with this
cashback(sender());
```
### Use `deploy()` function for on-chain deployments[](#use-deploy-function-for-on-chain-deployments)
There are many [message-sending functions](/book/send#message-sending-functions), and the [`deploy()`](/ref/core-send#deploy) function is optimized for cheaper on-chain deployments compared to the [`send()`](/ref/core-send#send) function.
```tact
deploy(DeployParameters {
init: initOf SomeContract(), // with initial code and data of SomeContract
// and with an empty message body
mode: SendIgnoreErrors, // skip the message in case of errors
value: ton("1"), // send 1 Toncoin (1_000_000_000 nanoToncoin)
});
```
### Use `message()` function for non-deployment messages[](#use-message-function-for-non-deployment-messages)
There are many [message-sending functions](/book/send#message-sending-functions), and the [`message()`](/ref/core-send#message) function is optimized for cheaper non-deployment regular messages compared to the [`send()`](/ref/core-send#send) function.
```tact
message(MessageParameters {
to: addrOfSomeInitializedContract,
value: ton("1"), // sending 1 Toncoin (1_000_000_000 nanoToncoin),
// with an empty message body
});
```
## Applied examples of best gas practices[](#applied-examples-of-best-gas-practices)
Tact has a growing set of contracts benchmarked against their reference FunC implementations. We fine-tune each Tact contract following the gas-preserving approaches discussed on this page while staying true to the original code and without doing precompilation or excessive ASM usage.
See those examples with recommendations applied:
* [Jetton Wallet contract](https://github.com/tact-lang/jetton/blob/9db75a5a828e9093be5c425605c5f5c9903f505d/src/contracts/jetton-wallet.tact)
* [Jetton Minter contract](https://github.com/tact-lang/jetton/blob/9db75a5a828e9093be5c425605c5f5c9903f505d/src/contracts/jetton-minter.tact)
* [Escrow contract](https://github.com/tact-lang/tact/blob/73fb52b2c8b4e8b2309e0aae4dcc0f8cb35117ea/src/benchmarks/contracts/escrow.tact)
---
# Importing code
> Tact allows you to import Tact and FunC code and has a versatile set of standard libraries.
Tact allows you to import Tact and [FunC](https://docs.ton.org/develop/func/overview) code. Any given `.tact` or `.fc`/`.func` file can be imported into your project using the `import` keyword.
Additionally, the Tact compiler has a versatile set of standard libraries which come bundled in but are not included right away. See [Standard libraries overview](/ref/standard-libraries).
Caution
All imported code is combined together with yours, so it’s important to avoid name collisions and always double-check the sources!
## Import Tact code[](#import-tact-code)
It’s possible to import any Tact code using the `import` statement by providing a relative path to the target `.tact` file like so:
```tact
import "./relative/path/to/the/target/tact/file.tact";
```
Specifying parent directories (`../`) is also possible:
```tact
import "../subfolder/imported/file.tact";
```
## Import FunC code[](#import-func-code)
It’s possible to import code written in FunC directly, just as it’s done with Tact code imports:
```tact
// Relative import
import "./relative/path/to/the/target/func/file.fc";
// Specifying parent directories
import "../subfolder/imported/func/file.fc";
```
However, in order to use functions from such files, one has to declare them as [`native` functions](/book/functions#native) first. For example, when the standard library [`@stdlib/dns`](/ref/stdlib-dns) uses a `dns.fc` FunC file, it maps FunC functions to Tact ones like so:
```tact
// FunC code located in a file right next to the current Tact one:
import "./dns.fc";
// Mapping function signatures from FunC to Tact:
@name(dns_string_to_internal)
native dnsStringToInternal(str: String): Slice?;
```
## Standard libraries[](#standard-libraries)
See [Standard libraries overview](/ref/standard-libraries).
---
# Book overview
> Book section — an introductory book about the Tact language
Welcome to **The Tact Book** section (or simply **The Book**) — an introductory book about the Tact language. It is a cohesive and streamlined sequence of educational materials about Tact. Whenever there’s an existing explanation of a broader TON concept in the main TON documentation, this Book tries to reference it as well.
In general, it assumes that you are reading it in sequence from front to back. Later parts build on concepts presented in earlier parts, and earlier parts might not delve into details of a particular topic but will revisit the topic in a later part.
The Book also assumes that you have written code in another programming language but does not make any assumptions about which one. We have tried to make the material broadly accessible to those from a wide variety of programming backgrounds. We do not spend a lot of time talking about what programming *is* or how to think about it. If you are entirely new to programming, you would be better served by reading a [book that specifically provides an introduction to programming](https://johnwhitington.net/ocamlfromtheverybeginning/index.html).
Here are its main contents:
1. #### Quick start[](#quick-start)
The Book begins with a few scenic tours and cheat sheets to get you started immediately. First, it briefly discusses TON Blockchain and how smart contracts work there, then gives an overview of many syntax and semantical aspects of the Tact language.
[Learn Tact in Y minutes ](/book/learn-tact-in-y-minutes)
2. #### Fundamentals of Tact[](#fundamentals-of-tact)
The subsection [Fundamentals of Tact](/book/types) describes the type system: primitive and composite types, then the structure of each Tact contract, and lists all the defined exit codes, i.e., possible error points.
[Type system overview ](/book/types)
3. #### Expressiveness[](#expressiveness)
The [Expressiveness](/book/operators) subsection starts with the list of available operators and gradually builds up, eventually reaching the description of functions and their interactions. Finally, it descends to discuss functions closest to how the TON Virtual Machine (TVM) actually operates — assembly functions.
[Operators ](/book/operators)
4. #### Communication[](#communication)
TON is a distributed blockchain based on the idea of the [actor model](https://en.wikipedia.org/wiki/Actor_model). Therefore, the means of communication is one of the most important aspects.
The [Communication](/book/receive) subsection covers everything you want and need to know about sending and receiving messages, as well as the general transaction flow.
[Receive messages ](/book/receive)
5. #### Going places[](#going-places)
Finally, to put all our Tact and TON knowledge into action, it is necessary to have auxiliary tools and concise descriptions of their use.
The subsection [Going places](/book/compile) explains how to compile, debug, and test Tact contracts locally. From there, it moves on to provide descriptions of deploying contracts to the TON Blockchain.
Lastly, it shows how to further tweak the compiler with its configuration options, interface with existing FunC code, and discusses best practices for securing your smart contracts.
[Compilation ](/book/compile)
---
# Integers
> Arithmetic in smart contracts on TON is always done with integers and never with floats
Arithmetic in smart contracts on TON is always performed with integers and never with floating-point numbers, since floats are [unpredictable](https://learn.microsoft.com/en-us/cpp/build/why-floating-point-numbers-may-lose-precision). Therefore, a strong emphasis is placed on integers and their handling.
The only primitive number type in Tact is `Int`, for 257-bit signed integers.\
It’s capable of storing integers between −2256 and 2256−1.
## Notation[](#notation)
Tact supports various ways of writing primitive values of `Int` as [integer literals](/book/expressions#integer-literals).
Most of the notations allow adding underscores (`_`) between digits, except for:
* Representations in strings, as seen in the [nano-tons](#nanotoncoin) case.
* Decimal numbers written with a leading zero 0. Their use is generally discouraged; see [below](#decimal).
Additionally, consecutive underscores, as in 4\_\_2, or trailing underscores, as in 42\_, are **not** allowed.
### Decimal[](#decimal)
The most common and widely used way of representing numbers is using the [decimal numeral system](https://en.wikipedia.org/wiki/Decimal): 123456789.\
You can use underscores (`_`) to improve readability: 123\_456\_789 is equal to 123456789.
Caution
Alternatively, you can prefix the number with one 0, which prohibits the use of underscores and only allows decimal digits: 0123=123. Note that using this notation with a leading zero is **strongly discouraged** due to possible confusion with octal integer literals in TypeScript, which is often used alongside Tact to develop and test contracts.
### Hexadecimal[](#hexadecimal)
Represent numbers using the [hexadecimal numeral system](https://en.wikipedia.org/wiki/Hexadecimal), denoted by the 0x (or 0X) prefix: 0xFFFFFFFFF. Use underscores (`_`) to improve readability: 0xFFF\_FFF\_FFF is equal to 0xFFFFFFFFF.
### Octal[](#octal)
Represent numbers using the [octal numeral system](https://en.wikipedia.org/wiki/Octal), denoted by the 0o (or 0O) prefix: 0o777777777. Use underscores (`_`) to improve readability: 0o777\_777\_777 is equal to 0o777777777.
### Binary[](#binary)
Represent numbers using the [binary numeral system](https://en.wikipedia.org/wiki/Binary_number), denoted by the 0b (or 0B) prefix: 0b111111111. Use underscores (`_`) to improve readability: 0b111\_111\_111 is equal to 0b111111111.
### NanoToncoin[](#nanotoncoin)
Arithmetic with dollars requires two decimal places after the dot — these are used for the cents value. But how would we represent the number $1.25 if we are only able to work with integers? The solution is to work with *cents* directly. In this way, $1.25 becomes 125 cents. We simply remember that the two rightmost digits represent the numbers after the decimal point.
Similarly, working with Toncoin, the main currency of TON Blockchain, requires nine decimal places instead of two. One can say that nanoToncoin is one-billionth (1091) of a Toncoin.
Therefore, the amount of 1.25 Toncoin, which can be represented in Tact as [`ton("1.25")`](/ref/core-comptime#ton), is actually the number 1250000000. We refer to such numbers as *nanoToncoin(s)* (or *nano-ton(s)*) rather than *cents*.
## Serialization[](#serialization)
When encoding `Int` values to persistent state (fields or parameters of [contracts](/book/contracts) and fields of [traits](/book/types#traits)), it is usually better to use smaller representations than 257 bits to reduce [storage costs](https://docs.ton.org/develop/smart-contracts/fees#storage-fee). The use of such representations is also called “serialization” because they represent the native [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) types on which TON Blockchain operates.
The persistent state size is specified in every declaration of a state variable after the `as` keyword:
```tact
contract SerializationExample {
// persistent state variables
oneByte: Int as int8 = 0; // ranges from -128 to 127 (takes 8 bits = 1 byte)
twoBytes: Int as int16; // ranges from -32,768 to 32,767 (takes 16 bits = 2 bytes)
init() {
// needs to be initialized in the init() because it does not have a default value
self.twoBytes = 55*55;
}
}
```
Integer serialization is also available for the fields of [structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages), as well as in the key/value types of [maps](/book/maps):
```tact
struct StSerialization {
martin: Int as int8;
}
message MsgSerialization {
seamus: Int as int8;
mcFly: map;
}
```
The motivation is very simple:
* Storing 1000 257-bit integers in the state [costs](https://docs.ton.org/develop/smart-contracts/fees#how-to-calculate-fees) about 0.184 TON per year.
* Storing 1000 32-bit integers only costs 0.023 TON per year by comparison.
Note
Serialization limits apply only to the contract state between transactions and are **not** imposed on the temporary [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) memory, which operates only on 257-bit integers.
Attempts to assign out-of-bounds values will result in [exit code 5](/book/exit-codes#5) being thrown at the very end of the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase): `Integer out of expected range`.
### Common serialization types[](#common-serialization-types)
| Name | [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) | Inclusive range | Space taken |
| :-------: | :---------------------------------------------------------------------------------: | :-------------: | :--------------------------------------------------------: |
| `uint8` | [`uint8`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 28−1 | 8 bits = 1 byte |
| `uint16` | [`uint16`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 216−1 | 16 bits = 2 bytes |
| `uint32` | [`uint32`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 232−1 | 32 bits = 4 bytes |
| `uint64` | [`uint64`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 264−1 | 64 bits = 8 bytes |
| `uint128` | [`uint128`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 2128−1 | 128 bits = 16 bytes |
| `uint256` | [`uint256`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 2256−1 | 256 bits = 32 bytes |
| `int8` | [`int8`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −27 to 27−1 | 8 bits = 1 byte |
| `int16` | [`int16`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −215 to 215−1 | 16 bits = 2 bytes |
| `int32` | [`int32`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −231 to 231−1 | 32 bits = 4 bytes |
| `int64` | [`int64`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −263 to 263−1 | 64 bits = 8 bytes |
| `int128` | [`int128`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −2127 to 2127−1 | 128 bits = 16 bytes |
| `int256` | [`int256`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −2255 to 2255−1 | 256 bits = 32 bytes |
| `int257` | [`int257`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −2256 to 2256−1 | 257 bits = 32 bytes + 1 bit |
| `coins` | [`VarUInteger 16`](https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n) | 0 to 2120−1 | Between 4 and 124 bits, [see below](#serialization-varint) |
### Arbitrary types of fixed bit-width[](#serialization-fixed)
Available since Tact 1.5
In addition to [common serialization types](#common-serialization-types), it is possible to specify arbitrary bit-width integers by using the prefix `int` or `uint`, followed by digits. For example, writing `int7` refers to a signed 7-bit integer.
The minimum allowed bit-width of an `Int` type is 1, while the maximum is 257 for the `int` prefix (signed integers) and 256 for the `uint` prefix (unsigned integers).
| Name | [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) | Inclusive range | Space taken |
| :-----: | :-------------------------------------------------------------------------------: | :-------------: | :----------------------------------: |
| `uintX` | [`uintX`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | 0 to 2X−1 | X bits, where X is between 1 and 256 |
| `intX` | [`intX`](https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types) | −2X−1 to 2X−1−1 | X bits, where X is between 1 and 257 |
### Types of variable bit-width[](#serialization-varint)
| Name | [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) | Inclusive range | Space taken |
| :-----: | :---------------------------------------------------------------------------------: | :-------------: | :--------------------- |
| `coins` | [`VarUInteger 16`](https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n) | 0 to 2120−1 | between 4 and 124 bits |
In Tact, the variable `coins` format is an alias to [`VarUInteger 16`](https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n) in [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) representation, i.e. it takes a variable bit length depending on the optimal number of bytes needed to store the given integer and is commonly used for storing [nanoToncoin](/book/integers#nanotoncoin) amounts.
This serialization format consists of two [TL-B fields](https://docs.ton.org/develop/data-formats/tl-b-language#field-definitions):
* `len`, a 4-bit unsigned big-endian integer storing the byte length of the provided value
* `value`, an 8∗len-bit unsigned big-endian representation of the provided value
That is, integers serialized as `coins` occupy between 4 and 124 bits (4 bits for `len` and 0 to 15 bytes for `value`) and have values in the inclusive range from 0 to 2120−1.
Examples:
```tact
struct Scrooge {
// len: 0000, 4 bits (always)
// value: none!
// in total: 4 bits
a: Int as coins = 0; // 0000
// len: 0001, 4 bits
// value: 00000001, 8 bits
// in total: 12 bits
b: Int as coins = 1; // 0001 00000001
// len: 0010, 4 bits
// value: 00000001 00000010, 16 bits
// in total: 20 bits
c: Int as coins = 258; // 0010 00000001 00000010
// len: 1111, 4 bits
// value: hundred twenty 1's in binary
// in total: 124 bits
d: Int as coins = pow(2, 120) - 1; // hundred twenty 1's in binary
}
```
| Name | [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) | Inclusive range | Space taken |
| :---------: | :---------------------------------------------------------------------------------: | :-------------: | :--------------------- |
| `varuint16` | [`VarUInteger 16`](https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n) | same as `coins` | same as `coins` |
| `varint16` | `VarInteger 16` | −2119 to 2119−1 | between 4 and 124 bits |
| `varuint32` | [`VarUInteger 32`](https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n) | 0 to 2248−1 | between 5 and 253 bits |
| `varint32` | `VarInteger 32` | −2247 to 2247−1 | between 5 and 253 bits |
Available since Tact 1.6
The `varuint16` format is equivalent to [`coins`](#serialization-varint). Its signed variant, `varint16`, has the same memory layout except for the signed `value` field, which allows a different range of values: from −2119 to 2119−1, including both endpoints.
To store greater values, use the `varuint32` and `varint32` formats. These are serialized almost identically to `coins` and other smaller variable integer formats but use a 5-bit `len` field for storing the byte length. This allows the `value` to use up to 248 bits for storing the actual number, meaning that both `varuint32` and `varint32` can occupy up to 253 bits in total.
Examples:
```tact
struct BradBit {
// len: 00000, 5 bits
// value: none!
// in total: 5 bits
a: Int as varuint32 = 0; // 00000
// len: 00001, 5 bits
// value: 00000001, 8 bits
// in total: 13 bits
b: Int as varuint32 = 1; // 00001 00000001
// len: 00010, 5 bits
// value: 00000001 00000010, 16 bits
// in total: 21 bits
c: Int as varuint32 = 258; // 00010 00000001 00000010
// len: 11111, 5 bits
// value: two hundred and forty-eight 1's in binary
// in total: 253 bits
d: Int as varuint32 = pow(2, 248) - 1; // two hundred and forty-eight 1's in binary
}
```
Note
Read more on serialization here: [Compatibility with FunC](/book/func#convert-serialization)
## Operations[](#operations)
All runtime calculations with numbers are performed at 257 bits, so [overflows](https://en.wikipedia.org/wiki/Integer_overflow) are quite rare. Nevertheless, if any math operation overflows, an exception will be thrown, and the transaction will fail. You could say that Tact’s math is safe by default.
Note that there is no problem with mixing variables of [different state sizes](#serialization) in the same calculation. At runtime, they are all the same type no matter what — 257-bit signed integers, so overflows won’t occur at this stage.
However, this can still lead to **errors** in the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) of the transaction. Consider the following example:
```tact
contract ComputeErrorsOhNo {
oneByte: Int as uint8; // persistent state variable, max value is 255
init() {
self.oneByte = 255; // initial value is 255, everything fits
}
// Empty receiver for the deployment
receive() {
// Forward the remaining value in the
// incoming message back to the sender
cashback(sender());
}
receive("lets break it") {
let tmp: Int = self.oneByte * 256; // no runtime overflow
self.oneByte = tmp; // whoops, tmp value is out of expected range of oneByte
}
}
```
Here, `oneByte` is serialized as a [`uint8`](#common-serialization-types), which occupies only one byte and ranges from 0 to 28−1, which is 255. When used in runtime calculations, no overflow occurs since everything is calculated as 257-bit signed integers. However, the moment we decide to store the value of `tmp` back into `oneByte`, we get an error with [exit code 5](/book/exit-codes#5), which states the following: `Integer out of expected range`.
Caution
Therefore, be **very** careful with numbers and always double-check calculations when using serialization.
---
# Learn Tact in Y minutes
> Take a whirlwind tour of the Tact smart contract programming language. A scenic voyage inspired by the famous learnXinYminutes website.
Tact is a fresh programming language for TON Blockchain that is focused on efficiency and ease of development. It is a good fit for complex smart contracts, quick onboarding, and rapid prototyping.
You can try Tact without installing anything locally using the [Web IDE](https://ide.ton.org). In addition, most examples below have an “Open in Web IDE” button for your convenience.
## Comments[](#comments)
```tact
// Single-line (//) comments for occasional and casual annotations
/// Documentation comments that support Markdown
```
Note
There are also C-like multiline comments `/* ... */`, but their use is discouraged in favor of consecutive single-line documentation comments `///`.
## ”Hello, World!”[](#hello-world)
```tact
// Defining a contract
contract HelloWorld {
// Listens to incoming Ping messages
receive(msg: Ping) {
// Sends a Pong reply message
reply(Pong {}.toCell());
}
// Listens to incoming Hello messages
receive(msg: Hello) {
// Replies with the received Hello message
reply(msg.toCell());
}
// Listens to incoming empty messages,
// which are very handy and cheap for the deployments.
receive() {
// Forward the remaining value in the
// incoming message back to the sender.
cashback(sender());
}
}
// A helper inlined function to send binary messages.
// See the "Primitive types" section below for more info about cells.
inline fun reply(msgBody: Cell) {
message(MessageParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
body: msgBody,
});
}
// Empty message structs with specified 32-bit integer prefix.
// See the "Structs and message structs" section below for more info.
message(1) Ping {}
message(2) Pong {}
message(3) Hello {}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gRGVmaW5pbmcgYSBjb250cmFjdApjb250cmFjdCBIZWxsb1dvcmxkIHsKICAgIC8vIExpc3RlbnMgdG8gaW5jb21pbmcgUGluZyBtZXNzYWdlcwogICAgcmVjZWl2ZShtc2c6IFBpbmcpIHsKICAgICAgICAvLyBTZW5kcyBhIFBvbmcgcmVwbHkgbWVzc2FnZQogICAgICAgIHJlcGx5KFBvbmcge30udG9DZWxsKCkpOwogICAgfQoKICAgIC8vIExpc3RlbnMgdG8gaW5jb21pbmcgSGVsbG8gbWVzc2FnZXMKICAgIHJlY2VpdmUobXNnOiBIZWxsbykgewogICAgICAgIC8vIFJlcGxpZXMgd2l0aCB0aGUgcmVjZWl2ZWQgSGVsbG8gbWVzc2FnZQogICAgICAgIHJlcGx5KG1zZy50b0NlbGwoKSk7CiAgICB9CgogICAgLy8gTGlzdGVucyB0byBpbmNvbWluZyBlbXB0eSBtZXNzYWdlcywKICAgIC8vIHdoaWNoIGFyZSB2ZXJ5IGhhbmR5IGFuZCBjaGVhcCBmb3IgdGhlIGRlcGxveW1lbnRzLgogICAgcmVjZWl2ZSgpIHsKICAgICAgICAvLyBGb3J3YXJkIHRoZSByZW1haW5pbmcgdmFsdWUgaW4gdGhlCiAgICAgICAgLy8gaW5jb21pbmcgbWVzc2FnZSBiYWNrIHRvIHRoZSBzZW5kZXIuCiAgICAgICAgY2FzaGJhY2soc2VuZGVyKCkpOwogICAgfQp9CgovLyBBIGhlbHBlciBpbmxpbmVkIGZ1bmN0aW9uIHRvIHNlbmQgYmluYXJ5IG1lc3NhZ2VzLgovLyBTZWUgdGhlICJQcmltaXRpdmUgdHlwZXMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mbyBhYm91dCBjZWxscy4KaW5saW5lIGZ1biByZXBseShtc2dCb2R5OiBDZWxsKSB7CiAgICBtZXNzYWdlKE1lc3NhZ2VQYXJhbWV0ZXJzIHsKICAgICAgICB0bzogc2VuZGVyKCksCiAgICAgICAgdmFsdWU6IDAsCiAgICAgICAgbW9kZTogU2VuZFJlbWFpbmluZ1ZhbHVlIHwgU2VuZElnbm9yZUVycm9ycywKICAgICAgICBib2R5OiBtc2dCb2R5LAogICAgfSk7Cn0KCi8vIEVtcHR5IG1lc3NhZ2Ugc3RydWN0cyB3aXRoIHNwZWNpZmllZCAzMi1iaXQgaW50ZWdlciBwcmVmaXguCi8vIFNlZSB0aGUgIlN0cnVjdHMgYW5kIG1lc3NhZ2Ugc3RydWN0cyIgc2VjdGlvbiBiZWxvdyBmb3IgbW9yZSBpbmZvLgptZXNzYWdlKDEpIFBpbmcge30KbWVzc2FnZSgyKSBQb25nIHt9Cm1lc3NhZ2UoMykgSGVsbG8ge30%3D)
## Primitive types[](#primitive-types)
```tact
fun showcase() {
// There are two main groups of primitive types in Tact: integers and cells.
// All other primitive types are derivatives of those two.
// ---
// Integers,
// always 257-bit signed in runtime operations,
// but may have different lengths in persistent contract's state (storage)
// ---
let one_plus_one: Int = 1 + 1; // 2
let two_by_two: Int = 2 / 2; // 1
let three_by_two: Int = 3 / 2; // 1, because the division operator rounds
// toward -∞, which is identical to // operator
// from Python
let one_billion = 1_000_000_000; // decimal
let binary_mask = 0b1_1111_1111; // binary
let permissions = 0o7_5_5; // octal
let heHex = 0xFF80_0000_0000; // hexadecimal
let nanoToncoin: Int = 1; // 1 nanoToncoin = 0.000,000,001 Toncoin
let toncoin: Int = ton("1"); // 1 Toncoin = 1,000,000,000 nanoToncoin
// ---
// Booleans: true and false.
// They take only 1 bit in persistent storage.
// ---
let factual: Bool = !!(true || false);
let fax: Bool = true && factual;
// ---
// Addresses of smart contracts,
// deterministically obtained by combining the initial code and initial data.
// ---
// Address of the current contract
let myAddr: Address = myAddress();
// You can parse the Address to view components of the standard address:
// * a workchain ID: 8-bit signed Int
// * and an account ID: 256-bit unsigned Int
let addrComponents: StdAddress = parseStdAddress(myAddr.asSlice());
addrComponents.workchain; // 0, basechain: the most commonly used workchain on TON
addrComponents.address; // ...lots of digits...
// ---
// Cells, Builders, Slices.
// ---
// Cell is an immutable data structure that can contain up to 1023 bits
// with up to 4 reference to other cells. Cyclic references are prohibited.
let emptyC: Cell = emptyCell();
// Cells are a fundamental primitive and data structure on TON Blockchain:
// contracts communicate and interact by sending and receiving cells while
// their code and data are themselves stored as cells on the blockchain
// the code and the data of each contract are cells and contracts
// communicate and interact by sending and receiving cells.
//
// Furthermore, all data layouts are also expressed in terms of cells and
// cell (de)serialization primitives. That said, Tact provides declarative means
// to express (de)serialization to and from cells conveniently —
// see the "Structs and message structs" subsection below for more info.
// Builder is an immutable primitive to construct (compose) cells.
let bb: Builder = beginCell()
.storeUint(42, 6) // storing 42 using 6 bits
.storeInt(42, 7) // storing 42 using 7 bits (signed Int)
.storeBool(true) // writing 1 as a single bit
.storeBit(true) // alias to storeBool()
.storeCoins(40) // common way of storing nanoToncoins
.storeAddress(myAddress())
.storeRef(emptyC); // storing a reference
let composed: Cell = bb.endCell();
// Slice is a mutable primitive to deconstruct (parse) cells.
let target: Slice = composed.asSlice(); // let's start parsing `composed` Cell
// The type ascription is optional for most cases except for maps
// and optional types, but we'll discuss those in the
// "Composite types" section below.
let fortyTwo = target.loadUint(6); // taking 6 bits out of the `target` Slice,
// mutating it in the process
// If you don't want the result, you can ignore it with a wildcard.
let _ = target.loadInt(7);
// Finally, there are methods to skip the value, i.e., to discard it.
target.skipBool();
// Manual composition and parsing of Cells is tedious,
// error-prone and is generally not recommended.
// Instead, prefer using structures: struct and message struct types.
// See the "Composite types" section below for more info.
// ---
// Strings are immutable sequences of characters,
// which are used mainly to send and receive text message bodies.
// ---
// String literals are wrapped in double-quotes and can contain escape sequences,
// but they intentionally cannot be concatenated via any operators.
let str: String = "I am a string literal, 👻!"; // see the "Expressions" section for more
// Strings are useful for storing text,
// so they can be converted to a Cell type to be used as message bodies.
let noComments: Cell = "yes comments".asComment(); // prefixes a string with 32 zero bits
}
// Finally, under the hood, Address and String types are a Slice,
// although with a well-defined distinct data layout for each.
//
// While implicit type conversions aren't allowed in Tact,
// there are extension functions that can be used for those purposes,
// such as String.asSlice() or Address.asSlice().
//
// Advanced users can introduce their own casts by using assembly functions.
// See the "Functions" section below for more info.
// An empty contract needed for the showcase above to work.
contract MyContract() {}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gVGhlcmUgYXJlIHR3byBtYWluIGdyb3VwcyBvZiBwcmltaXRpdmUgdHlwZXMgaW4gVGFjdDogaW50ZWdlcnMgYW5kIGNlbGxzLgogICAgLy8gQWxsIG90aGVyIHByaW1pdGl2ZSB0eXBlcyBhcmUgZGVyaXZhdGl2ZXMgb2YgdGhvc2UgdHdvLgoKICAgIC8vIC0tLQogICAgLy8gSW50ZWdlcnMsCiAgICAvLyBhbHdheXMgMjU3LWJpdCBzaWduZWQgaW4gcnVudGltZSBvcGVyYXRpb25zLAogICAgLy8gYnV0IG1heSBoYXZlIGRpZmZlcmVudCBsZW5ndGhzIGluIHBlcnNpc3RlbnQgY29udHJhY3QncyBzdGF0ZSAoc3RvcmFnZSkKICAgIC8vIC0tLQoKICAgIGxldCBvbmVfcGx1c19vbmU6IEludCA9IDEgKyAxOyAvLyAyCiAgICBsZXQgdHdvX2J5X3R3bzogSW50ID0gMiAvIDI7ICAgLy8gMQogICAgbGV0IHRocmVlX2J5X3R3bzogSW50ID0gMyAvIDI7IC8vIDEsIGJlY2F1c2UgdGhlIGRpdmlzaW9uIG9wZXJhdG9yIHJvdW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvd2FyZCAt4oieLCB3aGljaCBpcyBpZGVudGljYWwgdG8gLy8gb3BlcmF0b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBmcm9tIFB5dGhvbgoKICAgIGxldCBvbmVfYmlsbGlvbiA9IDFfMDAwXzAwMF8wMDA7IC8vIGRlY2ltYWwKICAgIGxldCBiaW5hcnlfbWFzayA9IDBiMV8xMTExXzExMTE7IC8vIGJpbmFyeQogICAgbGV0IHBlcm1pc3Npb25zID0gMG83XzVfNTsgICAgICAgLy8gb2N0YWwKICAgIGxldCBoZUhleCA9IDB4RkY4MF8wMDAwXzAwMDA7ICAgIC8vIGhleGFkZWNpbWFsCgogICAgbGV0IG5hbm9Ub25jb2luOiBJbnQgPSAxOyAgICAvLyAxIG5hbm9Ub25jb2luID0gMC4wMDAsMDAwLDAwMSBUb25jb2luCiAgICBsZXQgdG9uY29pbjogSW50ID0gdG9uKCIxIik7IC8vIDEgVG9uY29pbiA9IDEsMDAwLDAwMCwwMDAgbmFub1RvbmNvaW4KCgogICAgLy8gLS0tCiAgICAvLyBCb29sZWFuczogdHJ1ZSBhbmQgZmFsc2UuCiAgICAvLyBUaGV5IHRha2Ugb25seSAxIGJpdCBpbiBwZXJzaXN0ZW50IHN0b3JhZ2UuCiAgICAvLyAtLS0KCiAgICBsZXQgZmFjdHVhbDogQm9vbCA9ICEhKHRydWUgfHwgZmFsc2UpOwogICAgbGV0IGZheDogQm9vbCA9IHRydWUgJiYgZmFjdHVhbDsKCgogICAgLy8gLS0tCiAgICAvLyBBZGRyZXNzZXMgb2Ygc21hcnQgY29udHJhY3RzLAogICAgLy8gZGV0ZXJtaW5pc3RpY2FsbHkgb2J0YWluZWQgYnkgY29tYmluaW5nIHRoZSBpbml0aWFsIGNvZGUgYW5kIGluaXRpYWwgZGF0YS4KICAgIC8vIC0tLQoKICAgIC8vIEFkZHJlc3Mgb2YgdGhlIGN1cnJlbnQgY29udHJhY3QKICAgIGxldCBteUFkZHI6IEFkZHJlc3MgPSBteUFkZHJlc3MoKTsKCiAgICAvLyBZb3UgY2FuIHBhcnNlIHRoZSBBZGRyZXNzIHRvIHZpZXcgY29tcG9uZW50cyBvZiB0aGUgc3RhbmRhcmQgYWRkcmVzczoKICAgIC8vICogYSB3b3JrY2hhaW4gSUQ6IDgtYml0IHNpZ25lZCBJbnQKICAgIC8vICogYW5kIGFuIGFjY291bnQgSUQ6IDI1Ni1iaXQgdW5zaWduZWQgSW50CiAgICBsZXQgYWRkckNvbXBvbmVudHM6IFN0ZEFkZHJlc3MgPSBwYXJzZVN0ZEFkZHJlc3MobXlBZGRyLmFzU2xpY2UoKSk7CiAgICBhZGRyQ29tcG9uZW50cy53b3JrY2hhaW47IC8vIDAsIGJhc2VjaGFpbjogdGhlIG1vc3QgY29tbW9ubHkgdXNlZCB3b3JrY2hhaW4gb24gVE9OCiAgICBhZGRyQ29tcG9uZW50cy5hZGRyZXNzOyAgIC8vIC4uLmxvdHMgb2YgZGlnaXRzLi4uCgoKICAgIC8vIC0tLQogICAgLy8gQ2VsbHMsIEJ1aWxkZXJzLCBTbGljZXMuCiAgICAvLyAtLS0KCiAgICAvLyBDZWxsIGlzIGFuIGltbXV0YWJsZSBkYXRhIHN0cnVjdHVyZSB0aGF0IGNhbiBjb250YWluIHVwIHRvIDEwMjMgYml0cwogICAgLy8gd2l0aCB1cCB0byA0IHJlZmVyZW5jZSB0byBvdGhlciBjZWxscy4gQ3ljbGljIHJlZmVyZW5jZXMgYXJlIHByb2hpYml0ZWQuCiAgICBsZXQgZW1wdHlDOiBDZWxsID0gZW1wdHlDZWxsKCk7CgogICAgLy8gQ2VsbHMgYXJlIGEgZnVuZGFtZW50YWwgcHJpbWl0aXZlIGFuZCBkYXRhIHN0cnVjdHVyZSBvbiBUT04gQmxvY2tjaGFpbjoKICAgIC8vIGNvbnRyYWN0cyBjb21tdW5pY2F0ZSBhbmQgaW50ZXJhY3QgYnkgc2VuZGluZyBhbmQgcmVjZWl2aW5nIGNlbGxzIHdoaWxlCiAgICAvLyB0aGVpciBjb2RlIGFuZCBkYXRhIGFyZSB0aGVtc2VsdmVzIHN0b3JlZCBhcyBjZWxscyBvbiB0aGUgYmxvY2tjaGFpbgogICAgLy8gdGhlIGNvZGUgYW5kIHRoZSBkYXRhIG9mIGVhY2ggY29udHJhY3QgYXJlIGNlbGxzIGFuZCBjb250cmFjdHMKICAgIC8vIGNvbW11bmljYXRlIGFuZCBpbnRlcmFjdCBieSBzZW5kaW5nIGFuZCByZWNlaXZpbmcgY2VsbHMuCiAgICAvLwogICAgLy8gRnVydGhlcm1vcmUsIGFsbCBkYXRhIGxheW91dHMgYXJlIGFsc28gZXhwcmVzc2VkIGluIHRlcm1zIG9mIGNlbGxzIGFuZAogICAgLy8gY2VsbCAoZGUpc2VyaWFsaXphdGlvbiBwcmltaXRpdmVzLiBUaGF0IHNhaWQsIFRhY3QgcHJvdmlkZXMgZGVjbGFyYXRpdmUgbWVhbnMKICAgIC8vIHRvIGV4cHJlc3MgKGRlKXNlcmlhbGl6YXRpb24gdG8gYW5kIGZyb20gY2VsbHMgY29udmVuaWVudGx5IOKAlAogICAgLy8gc2VlIHRoZSAiU3RydWN0cyBhbmQgbWVzc2FnZSBzdHJ1Y3RzIiBzdWJzZWN0aW9uIGJlbG93IGZvciBtb3JlIGluZm8uCgogICAgLy8gQnVpbGRlciBpcyBhbiBpbW11dGFibGUgcHJpbWl0aXZlIHRvIGNvbnN0cnVjdCAoY29tcG9zZSkgY2VsbHMuCiAgICBsZXQgYmI6IEJ1aWxkZXIgPSBiZWdpbkNlbGwoKQogICAgICAgIC5zdG9yZVVpbnQoNDIsIDYpICAvLyBzdG9yaW5nIDQyIHVzaW5nIDYgYml0cwogICAgICAgIC5zdG9yZUludCg0MiwgNykgICAvLyBzdG9yaW5nIDQyIHVzaW5nIDcgYml0cyAoc2lnbmVkIEludCkKICAgICAgICAuc3RvcmVCb29sKHRydWUpICAgLy8gd3JpdGluZyAxIGFzIGEgc2luZ2xlIGJpdAogICAgICAgIC5zdG9yZUJpdCh0cnVlKSAgICAvLyBhbGlhcyB0byBzdG9yZUJvb2woKQogICAgICAgIC5zdG9yZUNvaW5zKDQwKSAgICAvLyBjb21tb24gd2F5IG9mIHN0b3JpbmcgbmFub1RvbmNvaW5zCiAgICAgICAgLnN0b3JlQWRkcmVzcyhteUFkZHJlc3MoKSkKICAgICAgICAuc3RvcmVSZWYoZW1wdHlDKTsgLy8gc3RvcmluZyBhIHJlZmVyZW5jZQogICAgbGV0IGNvbXBvc2VkOiBDZWxsID0gYmIuZW5kQ2VsbCgpOwoKICAgIC8vIFNsaWNlIGlzIGEgbXV0YWJsZSBwcmltaXRpdmUgdG8gZGVjb25zdHJ1Y3QgKHBhcnNlKSBjZWxscy4KICAgIGxldCB0YXJnZXQ6IFNsaWNlID0gY29tcG9zZWQuYXNTbGljZSgpOyAvLyBsZXQncyBzdGFydCBwYXJzaW5nIGBjb21wb3NlZGAgQ2VsbAoKICAgIC8vIFRoZSB0eXBlIGFzY3JpcHRpb24gaXMgb3B0aW9uYWwgZm9yIG1vc3QgY2FzZXMgZXhjZXB0IGZvciBtYXBzCiAgICAvLyBhbmQgb3B0aW9uYWwgdHlwZXMsIGJ1dCB3ZSdsbCBkaXNjdXNzIHRob3NlIGluIHRoZQogICAgLy8gIkNvbXBvc2l0ZSB0eXBlcyIgc2VjdGlvbiBiZWxvdy4KICAgIGxldCBmb3J0eVR3byA9IHRhcmdldC5sb2FkVWludCg2KTsgLy8gdGFraW5nIDYgYml0cyBvdXQgb2YgdGhlIGB0YXJnZXRgIFNsaWNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtdXRhdGluZyBpdCBpbiB0aGUgcHJvY2VzcwoKICAgIC8vIElmIHlvdSBkb24ndCB3YW50IHRoZSByZXN1bHQsIHlvdSBjYW4gaWdub3JlIGl0IHdpdGggYSB3aWxkY2FyZC4KICAgIGxldCBfID0gdGFyZ2V0LmxvYWRJbnQoNyk7CgogICAgLy8gRmluYWxseSwgdGhlcmUgYXJlIG1ldGhvZHMgdG8gc2tpcCB0aGUgdmFsdWUsIGkuZS4sIHRvIGRpc2NhcmQgaXQuCiAgICB0YXJnZXQuc2tpcEJvb2woKTsKCiAgICAvLyBNYW51YWwgY29tcG9zaXRpb24gYW5kIHBhcnNpbmcgb2YgQ2VsbHMgaXMgdGVkaW91cywKICAgIC8vIGVycm9yLXByb25lIGFuZCBpcyBnZW5lcmFsbHkgbm90IHJlY29tbWVuZGVkLgogICAgLy8gSW5zdGVhZCwgcHJlZmVyIHVzaW5nIHN0cnVjdHVyZXM6IHN0cnVjdCBhbmQgbWVzc2FnZSBzdHJ1Y3QgdHlwZXMuCiAgICAvLyBTZWUgdGhlICJDb21wb3NpdGUgdHlwZXMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mby4KCgogICAgLy8gLS0tCiAgICAvLyBTdHJpbmdzIGFyZSBpbW11dGFibGUgc2VxdWVuY2VzIG9mIGNoYXJhY3RlcnMsCiAgICAvLyB3aGljaCBhcmUgdXNlZCBtYWlubHkgdG8gc2VuZCBhbmQgcmVjZWl2ZSB0ZXh0IG1lc3NhZ2UgYm9kaWVzLgogICAgLy8gLS0tCgogICAgLy8gU3RyaW5nIGxpdGVyYWxzIGFyZSB3cmFwcGVkIGluIGRvdWJsZS1xdW90ZXMgYW5kIGNhbiBjb250YWluIGVzY2FwZSBzZXF1ZW5jZXMsCiAgICAvLyBidXQgdGhleSBpbnRlbnRpb25hbGx5IGNhbm5vdCBiZSBjb25jYXRlbmF0ZWQgdmlhIGFueSBvcGVyYXRvcnMuCiAgICBsZXQgc3RyOiBTdHJpbmcgPSAiSSBhbSBhIHN0cmluZyBsaXRlcmFsLCDwn5G7ISI7IC8vIHNlZSB0aGUgIkV4cHJlc3Npb25zIiBzZWN0aW9uIGZvciBtb3JlCgogICAgLy8gU3RyaW5ncyBhcmUgdXNlZnVsIGZvciBzdG9yaW5nIHRleHQsCiAgICAvLyBzbyB0aGV5IGNhbiBiZSBjb252ZXJ0ZWQgdG8gYSBDZWxsIHR5cGUgdG8gYmUgdXNlZCBhcyBtZXNzYWdlIGJvZGllcy4KICAgIGxldCBub0NvbW1lbnRzOiBDZWxsID0gInllcyBjb21tZW50cyIuYXNDb21tZW50KCk7IC8vIHByZWZpeGVzIGEgc3RyaW5nIHdpdGggMzIgemVybyBiaXRzCn0KCi8vIEZpbmFsbHksIHVuZGVyIHRoZSBob29kLCBBZGRyZXNzIGFuZCBTdHJpbmcgdHlwZXMgYXJlIGEgU2xpY2UsCi8vIGFsdGhvdWdoIHdpdGggYSB3ZWxsLWRlZmluZWQgZGlzdGluY3QgZGF0YSBsYXlvdXQgZm9yIGVhY2guCi8vCi8vIFdoaWxlIGltcGxpY2l0IHR5cGUgY29udmVyc2lvbnMgYXJlbid0IGFsbG93ZWQgaW4gVGFjdCwKLy8gdGhlcmUgYXJlIGV4dGVuc2lvbiBmdW5jdGlvbnMgdGhhdCBjYW4gYmUgdXNlZCBmb3IgdGhvc2UgcHVycG9zZXMsCi8vIHN1Y2ggYXMgU3RyaW5nLmFzU2xpY2UoKSBvciBBZGRyZXNzLmFzU2xpY2UoKS4KLy8KLy8gQWR2YW5jZWQgdXNlcnMgY2FuIGludHJvZHVjZSB0aGVpciBvd24gY2FzdHMgYnkgdXNpbmcgYXNzZW1ibHkgZnVuY3Rpb25zLgovLyBTZWUgdGhlICJGdW5jdGlvbnMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mby4KCi8vIEFuIGVtcHR5IGNvbnRyYWN0IG5lZWRlZCBmb3IgdGhlIHNob3djYXNlIGFib3ZlIHRvIHdvcmsuCmNvbnRyYWN0IE15Q29udHJhY3QoKSB7fQ%3D%3D)
Read more: [Primitive types](/book/types#primitive-types).
## Composite types[](#composite-types)
### Optionals[](#composite-optionals)
```tact
fun showcase() {
// An optional is a value than can be of any type or null.
// Null is a special value that represents the intentional
// absence of any other value.
// Int keys to Int values.
// Type ascription of optionals is mandatory.
let optionalVal: Int? = null;
optionalVal = 255;
// If you're certain that the value isn't null at a given moment,
// use the non-null assertion operator !! to access it.
dump(optionalVal!!);
// If you are not certain, then it is better to explicitly compare
// the value to null to avoid errors at runtime.
if (optionalVal != null) {
// here we go!
} else {
// not happening right now
}
}
// You can make almost any variable or field optional by adding
// a question mark (?) after its type name.
// The only exceptions are map and bounced,
// in which you cannot make the inner key/value type (in the case of a map)
// or the inner message struct (in the case of a bounced) optional.
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gQW4gb3B0aW9uYWwgaXMgYSB2YWx1ZSB0aGFuIGNhbiBiZSBvZiBhbnkgdHlwZSBvciBudWxsLgogICAgLy8gTnVsbCBpcyBhIHNwZWNpYWwgdmFsdWUgdGhhdCByZXByZXNlbnRzIHRoZSBpbnRlbnRpb25hbAogICAgLy8gYWJzZW5jZSBvZiBhbnkgb3RoZXIgdmFsdWUuCgogICAgLy8gSW50IGtleXMgdG8gSW50IHZhbHVlcy4KICAgIC8vIFR5cGUgYXNjcmlwdGlvbiBvZiBvcHRpb25hbHMgaXMgbWFuZGF0b3J5LgogICAgbGV0IG9wdGlvbmFsVmFsOiBJbnQ%2FID0gbnVsbDsKICAgIG9wdGlvbmFsVmFsID0gMjU1OwoKICAgIC8vIElmIHlvdSdyZSBjZXJ0YWluIHRoYXQgdGhlIHZhbHVlIGlzbid0IG51bGwgYXQgYSBnaXZlbiBtb21lbnQsCiAgICAvLyB1c2UgdGhlIG5vbi1udWxsIGFzc2VydGlvbiBvcGVyYXRvciAhISB0byBhY2Nlc3MgaXQuCiAgICBkdW1wKG9wdGlvbmFsVmFsISEpOwoKICAgIC8vIElmIHlvdSBhcmUgbm90IGNlcnRhaW4sIHRoZW4gaXQgaXMgYmV0dGVyIHRvIGV4cGxpY2l0bHkgY29tcGFyZQogICAgLy8gdGhlIHZhbHVlIHRvIG51bGwgdG8gYXZvaWQgZXJyb3JzIGF0IHJ1bnRpbWUuCiAgICBpZiAob3B0aW9uYWxWYWwgIT0gbnVsbCkgewogICAgICAgIC8vIGhlcmUgd2UgZ28hCiAgICB9IGVsc2UgewogICAgICAgIC8vIG5vdCBoYXBwZW5pbmcgcmlnaHQgbm93CiAgICB9Cn0KCi8vIFlvdSBjYW4gbWFrZSBhbG1vc3QgYW55IHZhcmlhYmxlIG9yIGZpZWxkIG9wdGlvbmFsIGJ5IGFkZGluZwovLyBhIHF1ZXN0aW9uIG1hcmsgKD8pIGFmdGVyIGl0cyB0eXBlIG5hbWUuCi8vIFRoZSBvbmx5IGV4Y2VwdGlvbnMgYXJlIG1hcDxLLCBWPiBhbmQgYm91bmNlZDxNZXNzYWdlPiwKLy8gaW4gd2hpY2ggeW91IGNhbm5vdCBtYWtlIHRoZSBpbm5lciBrZXkvdmFsdWUgdHlwZSAoaW4gdGhlIGNhc2Ugb2YgYSBtYXApCi8vIG9yIHRoZSBpbm5lciBtZXNzYWdlIHN0cnVjdCAoaW4gdGhlIGNhc2Ugb2YgYSBib3VuY2VkKSBvcHRpb25hbC4%3D)
Read more: [Optionals](/book/optionals).
### Maps[](#composite-maps)
```tact
fun showcase() {
// The composite type map is used to associate
// keys of type K with corresponding values of type V.
// A map of Int keys to Int values.
// Type ascription is mandatory.
let myMap: map = emptyMap();
// Maps have a number of built-in methods.
myMap.set(0, 10); // key 0 now points to value 10
myMap.set(0, 42); // overriding the value under key 0 with 42
myMap.get(0)!!; // 42, because get can return null if the key doesn't exist
myMap.replace(1, 55); // false, because there was no key 1 and map didn't change
myMap.replaceGet(0, 10)!!; // 42, because the key 0 exists and the old value there was 42
myMap.get(0)!!; // 10, since we've just replaced the value with .replaceGet
myMap.del(0); // true, because the map contained an entry under key 0
myMap.del(0); // false and not an error, because deletion is idempotent
myMap.exists(0); // false, there is no entry under key 0
myMap.isEmpty(); // true, there is no other entries
// Statically known `.set`s can be replaced by map literals.
// That way, map entries will be defined at compile-time and consume much less gas.
let myMap2: map = map {
// Key expression: Value expression
1 + 2: 10 * pow2(3), // key 3, value 80
1 + 3: 20 * pow2(4), // key 4, value 320
};
// In most cases, to compare two maps it's sufficient to use the shallow
// comparison via the equality == and inequality != operators.
myMap == emptyMap(); // true
// To traverse maps, the foreach statement is used.
// See the "Statements" section below for more info.
foreach (k, v in myMap) {
// ...do something for each entry, if any
}
// There are many other allowed kinds of map value types for Int keys
let _: map = emptyMap(); // Int keys to Bool values
let _: map = emptyMap(); // Ints to Cells
let _: map = emptyMap(); // Ints to Addresses
let _: map = emptyMap(); // Ints to some structs
let _: map = emptyMap(); // Ints to some message structs
// And all the same value types for maps with Address keys are also allowed.
let _: map = emptyMap(); // Address keys to Int values
let _: map = emptyMap(); // Addresses to Bools
let _: map = emptyMap(); // Addresses to Cells
let _: map = emptyMap(); // Addresses to Addresses
let _: map = emptyMap(); // Addresses to some structs
let _: map = emptyMap(); // Addresses to some message structs
// Under the hood, empty maps are nulls, which is why it's important to provide a type ascription.
let _: map = null; // like emptyMap(), but less descriptive and generally discouraged
// Furthermore, as with many other types, maps are just Cells with a distinct data layout.
// Therefore, you can type cast any map back to its underlying Cell type.
myMap.asCell();
}
// Serialization of integer keys or values is possible but only meaningful
// for maps as fields of structures and maps in the contract's persistent state.
// See the "Structs and message structs" and "Persistent state"
// sections below for more info.
// Finally, mind the limits — maps are quite gas-expensive
// and have an upper limit of around 32k entries for the whole contract.
//
// On TON, contracts are very limited in their state, and for large
// or unbounded (infinitely large) maps, it is better to use contract sharding
// and essentially make the entire blockchain part of your maps.
//
// See this approach in action for the Jetton (token)
// contract system by the end of this tour.
// The following are dummy structures needed for the showcase above to work.
struct AnyStruct { field: Int }
message AnyMessage { field: Int }
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gVGhlIGNvbXBvc2l0ZSB0eXBlIG1hcDxLLCBWPiBpcyB1c2VkIHRvIGFzc29jaWF0ZQogICAgLy8ga2V5cyBvZiB0eXBlIEsgd2l0aCBjb3JyZXNwb25kaW5nIHZhbHVlcyBvZiB0eXBlIFYuCgogICAgLy8gQSBtYXAgb2YgSW50IGtleXMgdG8gSW50IHZhbHVlcy4KICAgIC8vIFR5cGUgYXNjcmlwdGlvbiBpcyBtYW5kYXRvcnkuCiAgICBsZXQgbXlNYXA6IG1hcDxJbnQsIEludD4gPSBlbXB0eU1hcCgpOwoKICAgIC8vIE1hcHMgaGF2ZSBhIG51bWJlciBvZiBidWlsdC1pbiBtZXRob2RzLgogICAgbXlNYXAuc2V0KDAsIDEwKTsgICAgICAgICAgLy8ga2V5IDAgbm93IHBvaW50cyB0byB2YWx1ZSAxMAogICAgbXlNYXAuc2V0KDAsIDQyKTsgICAgICAgICAgLy8gb3ZlcnJpZGluZyB0aGUgdmFsdWUgdW5kZXIga2V5IDAgd2l0aCA0MgogICAgbXlNYXAuZ2V0KDApISE7ICAgICAgICAgICAgLy8gNDIsIGJlY2F1c2UgZ2V0IGNhbiByZXR1cm4gbnVsbCBpZiB0aGUga2V5IGRvZXNuJ3QgZXhpc3QKICAgIG15TWFwLnJlcGxhY2UoMSwgNTUpOyAgICAgIC8vIGZhbHNlLCBiZWNhdXNlIHRoZXJlIHdhcyBubyBrZXkgMSBhbmQgbWFwIGRpZG4ndCBjaGFuZ2UKICAgIG15TWFwLnJlcGxhY2VHZXQoMCwgMTApISE7IC8vIDQyLCBiZWNhdXNlIHRoZSBrZXkgMCBleGlzdHMgYW5kIHRoZSBvbGQgdmFsdWUgdGhlcmUgd2FzIDQyCiAgICBteU1hcC5nZXQoMCkhITsgICAgICAgICAgICAvLyAxMCwgc2luY2Ugd2UndmUganVzdCByZXBsYWNlZCB0aGUgdmFsdWUgd2l0aCAucmVwbGFjZUdldAogICAgbXlNYXAuZGVsKDApOyAgICAgICAgICAgICAgLy8gdHJ1ZSwgYmVjYXVzZSB0aGUgbWFwIGNvbnRhaW5lZCBhbiBlbnRyeSB1bmRlciBrZXkgMAogICAgbXlNYXAuZGVsKDApOyAgICAgICAgICAgICAgLy8gZmFsc2UgYW5kIG5vdCBhbiBlcnJvciwgYmVjYXVzZSBkZWxldGlvbiBpcyBpZGVtcG90ZW50CiAgICBteU1hcC5leGlzdHMoMCk7ICAgICAgICAgICAvLyBmYWxzZSwgdGhlcmUgaXMgbm8gZW50cnkgdW5kZXIga2V5IDAKICAgIG15TWFwLmlzRW1wdHkoKTsgICAgICAgICAgIC8vIHRydWUsIHRoZXJlIGlzIG5vIG90aGVyIGVudHJpZXMKCiAgICAvLyBTdGF0aWNhbGx5IGtub3duIGAuc2V0YHMgY2FuIGJlIHJlcGxhY2VkIGJ5IG1hcCBsaXRlcmFscy4KICAgIC8vIFRoYXQgd2F5LCBtYXAgZW50cmllcyB3aWxsIGJlIGRlZmluZWQgYXQgY29tcGlsZS10aW1lIGFuZCBjb25zdW1lIG11Y2ggbGVzcyBnYXMuCiAgICBsZXQgbXlNYXAyOiBtYXA8SW50IGFzIHVpbnQ4LCBJbnQgYXMgaW50MTM%2BID0gbWFwPEludCBhcyB1aW50OCwgSW50IGFzIGludDEzPiB7CiAgICAgICAgLy8gS2V5IGV4cHJlc3Npb246IFZhbHVlIGV4cHJlc3Npb24KICAgICAgICAxICsgMjogMTAgKiBwb3cyKDMpLCAvLyBrZXkgMywgdmFsdWUgODAKICAgICAgICAxICsgMzogMjAgKiBwb3cyKDQpLCAvLyBrZXkgNCwgdmFsdWUgMzIwCiAgICB9OwoKICAgIC8vIEluIG1vc3QgY2FzZXMsIHRvIGNvbXBhcmUgdHdvIG1hcHMgaXQncyBzdWZmaWNpZW50IHRvIHVzZSB0aGUgc2hhbGxvdwogICAgLy8gY29tcGFyaXNvbiB2aWEgdGhlIGVxdWFsaXR5ID09IGFuZCBpbmVxdWFsaXR5ICE9IG9wZXJhdG9ycy4KICAgIG15TWFwID09IGVtcHR5TWFwKCk7IC8vIHRydWUKCiAgICAvLyBUbyB0cmF2ZXJzZSBtYXBzLCB0aGUgZm9yZWFjaCBzdGF0ZW1lbnQgaXMgdXNlZC4KICAgIC8vIFNlZSB0aGUgIlN0YXRlbWVudHMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mby4KICAgIGZvcmVhY2ggKGssIHYgaW4gbXlNYXApIHsKICAgICAgICAvLyAuLi5kbyBzb21ldGhpbmcgZm9yIGVhY2ggZW50cnksIGlmIGFueQogICAgfQoKICAgIC8vIFRoZXJlIGFyZSBtYW55IG90aGVyIGFsbG93ZWQga2luZHMgb2YgbWFwIHZhbHVlIHR5cGVzIGZvciBJbnQga2V5cwogICAgbGV0IF86IG1hcDxJbnQsIEJvb2w%2BID0gZW1wdHlNYXAoKTsgICAgLy8gSW50IGtleXMgdG8gQm9vbCB2YWx1ZXMKICAgIGxldCBfOiBtYXA8SW50LCBDZWxsPiA9IGVtcHR5TWFwKCk7ICAgIC8vIEludHMgdG8gQ2VsbHMKICAgIGxldCBfOiBtYXA8SW50LCBBZGRyZXNzPiA9IGVtcHR5TWFwKCk7IC8vIEludHMgdG8gQWRkcmVzc2VzCiAgICBsZXQgXzogbWFwPEludCwgQW55U3RydWN0PiA9IGVtcHR5TWFwKCk7ICAvLyBJbnRzIHRvIHNvbWUgc3RydWN0cwogICAgbGV0IF86IG1hcDxJbnQsIEFueU1lc3NhZ2U%2BID0gZW1wdHlNYXAoKTsgLy8gSW50cyB0byBzb21lIG1lc3NhZ2Ugc3RydWN0cwoKICAgIC8vIEFuZCBhbGwgdGhlIHNhbWUgdmFsdWUgdHlwZXMgZm9yIG1hcHMgd2l0aCBBZGRyZXNzIGtleXMgYXJlIGFsc28gYWxsb3dlZC4KICAgIGxldCBfOiBtYXA8QWRkcmVzcywgSW50PiA9IGVtcHR5TWFwKCk7ICAgICAvLyBBZGRyZXNzIGtleXMgdG8gSW50IHZhbHVlcwogICAgbGV0IF86IG1hcDxBZGRyZXNzLCBCb29sPiA9IGVtcHR5TWFwKCk7ICAgIC8vIEFkZHJlc3NlcyB0byBCb29scwogICAgbGV0IF86IG1hcDxBZGRyZXNzLCBDZWxsPiA9IGVtcHR5TWFwKCk7ICAgIC8vIEFkZHJlc3NlcyB0byBDZWxscwogICAgbGV0IF86IG1hcDxBZGRyZXNzLCBBZGRyZXNzPiA9IGVtcHR5TWFwKCk7IC8vIEFkZHJlc3NlcyB0byBBZGRyZXNzZXMKICAgIGxldCBfOiBtYXA8QWRkcmVzcywgQW55U3RydWN0PiA9IGVtcHR5TWFwKCk7ICAvLyBBZGRyZXNzZXMgdG8gc29tZSBzdHJ1Y3RzCiAgICBsZXQgXzogbWFwPEFkZHJlc3MsIEFueU1lc3NhZ2U%2BID0gZW1wdHlNYXAoKTsgLy8gQWRkcmVzc2VzIHRvIHNvbWUgbWVzc2FnZSBzdHJ1Y3RzCgogICAgLy8gVW5kZXIgdGhlIGhvb2QsIGVtcHR5IG1hcHMgYXJlIG51bGxzLCB3aGljaCBpcyB3aHkgaXQncyBpbXBvcnRhbnQgdG8gcHJvdmlkZSBhIHR5cGUgYXNjcmlwdGlvbi4KICAgIGxldCBfOiBtYXA8SW50LCBJbnQ%2BID0gbnVsbDsgLy8gbGlrZSBlbXB0eU1hcCgpLCBidXQgbGVzcyBkZXNjcmlwdGl2ZSBhbmQgZ2VuZXJhbGx5IGRpc2NvdXJhZ2VkCgogICAgLy8gRnVydGhlcm1vcmUsIGFzIHdpdGggbWFueSBvdGhlciB0eXBlcywgbWFwcyBhcmUganVzdCBDZWxscyB3aXRoIGEgZGlzdGluY3QgZGF0YSBsYXlvdXQuCiAgICAvLyBUaGVyZWZvcmUsIHlvdSBjYW4gdHlwZSBjYXN0IGFueSBtYXAgYmFjayB0byBpdHMgdW5kZXJseWluZyBDZWxsIHR5cGUuCiAgICBteU1hcC5hc0NlbGwoKTsKfQoKLy8gU2VyaWFsaXphdGlvbiBvZiBpbnRlZ2VyIGtleXMgb3IgdmFsdWVzIGlzIHBvc3NpYmxlIGJ1dCBvbmx5IG1lYW5pbmdmdWwKLy8gZm9yIG1hcHMgYXMgZmllbGRzIG9mIHN0cnVjdHVyZXMgYW5kIG1hcHMgaW4gdGhlIGNvbnRyYWN0J3MgcGVyc2lzdGVudCBzdGF0ZS4KLy8gU2VlIHRoZSAiU3RydWN0cyBhbmQgbWVzc2FnZSBzdHJ1Y3RzIiBhbmQgIlBlcnNpc3RlbnQgc3RhdGUiCi8vIHNlY3Rpb25zIGJlbG93IGZvciBtb3JlIGluZm8uCgovLyBGaW5hbGx5LCBtaW5kIHRoZSBsaW1pdHMg4oCUIG1hcHMgYXJlIHF1aXRlIGdhcy1leHBlbnNpdmUKLy8gYW5kIGhhdmUgYW4gdXBwZXIgbGltaXQgb2YgYXJvdW5kIDMyayBlbnRyaWVzIGZvciB0aGUgd2hvbGUgY29udHJhY3QuCi8vCi8vIE9uIFRPTiwgY29udHJhY3RzIGFyZSB2ZXJ5IGxpbWl0ZWQgaW4gdGhlaXIgc3RhdGUsIGFuZCBmb3IgbGFyZ2UKLy8gb3IgdW5ib3VuZGVkIChpbmZpbml0ZWx5IGxhcmdlKSBtYXBzLCBpdCBpcyBiZXR0ZXIgdG8gdXNlIGNvbnRyYWN0IHNoYXJkaW5nCi8vIGFuZCBlc3NlbnRpYWxseSBtYWtlIHRoZSBlbnRpcmUgYmxvY2tjaGFpbiBwYXJ0IG9mIHlvdXIgbWFwcy4KLy8KLy8gU2VlIHRoaXMgYXBwcm9hY2ggaW4gYWN0aW9uIGZvciB0aGUgSmV0dG9uICh0b2tlbikKLy8gY29udHJhY3Qgc3lzdGVtIGJ5IHRoZSBlbmQgb2YgdGhpcyB0b3VyLgoKLy8gVGhlIGZvbGxvd2luZyBhcmUgZHVtbXkgc3RydWN0dXJlcyBuZWVkZWQgZm9yIHRoZSBzaG93Y2FzZSBhYm92ZSB0byB3b3JrLgpzdHJ1Y3QgQW55U3RydWN0IHsgZmllbGQ6IEludCB9Cm1lc3NhZ2UgQW55TWVzc2FnZSB7IGZpZWxkOiBJbnQgfQ%3D%3D)
Read more:
* [Maps in the Book](/book/maps).
* [Map-based array data structure in the Cookbook](/cookbook/data-structures#array).
### Structs and message structs[](#composite-structures)
```tact
// Structs and message structs allow multiple values to be packed together
// in a single type. They are very useful for (de)serialization of Cells
// and for usage as parameters or return types in functions.
// Struct containing a single value
struct One { number: Int; }
// Struct with default fields, fields of optional types, and nested structs
struct Params {
name: String = "Satoshi"; // default value
age: Int?; // field with an optional type Int?
// and an implicit default value of null
val: One; // nested struct One
}
// You can instruct how to (de)compose the Cells to and from structs
// by specifying certain serialization options after the `as` keyword.
struct SeriesXX {
i64: Int as int64; // signed 64-bit integer
u32: Int as uint32; // unsigned 32-bit integer
ufo51: Int as uint51; // uneven formats are allowed too,
// so this is an unsigned 51-bit integer
// In general, uint1 through uint256 and int1 through int257
// are valid serialization formats for integer values.
maxi: Int as int257; // Int is serialized as int257 by default,
// but now it is explicitly specified
// If this struct will be obtained from some Slice,
// you can instruct the compiler to place the remainder of that Slice
// as the last field of the struct, and even type cast the value
// of that field to Cell, Builder or Slice at runtime.
lastFieldName: Cell as remaining; // there can only be a single `remaining` field,
// and it must be the last one in the struct
}
// The order of fields matters, as it corresponds to the resulting
// memory layout when the struct will be used to compose a Cell
// or to parse a Slice back to the struct.
struct Order {
first: Int; // 257 continuously laid out bits
second: Cell; // up to 1023 bits,
// which will be placed in a separate ref
// when composing a Cell
third: Address; // 267 bits
}
// Message structs are almost the same as regular structs,
// but they have a 32-bit integer header in their serialization.
// This unique numeric ID is commonly referred to as an opcode (operation code),
// and it allows message structs to be used with special receiver functions
// that distinguish incoming messages based on this ID.
message ImplicitlyAssignedId {} // no fields,
// but not empty because of the automatically
// generated and implicitly set 32-bit Int opcode
// You can manually override an opcode with any compile-time expression
// that evaluates to a non-negative 32-bit integer.
// This message has an opcode of 898001897, which is the evaluated
// integer value of the specified compile-time expression.
message((crc32("Tact") + 42) & 0xFFFF_FFFF) MsgWithExprOpcode {
// All the contents are defined identical to regular structs.
field1: Int as uint4; // serialization
field2: Bool?; // optionals
field3: One; // nested structs
field4: ImplicitlyAssignedId; // nested message structs
}
// Some usage examples.
fun usage() {
// Instantiation of a struct.
// Notice the lack of the "new" keyword used for this in many
// other traditional languages.
let val: One = One { number: 50 };
// You can omit the fields with default values.
let _ = Params { val }; // the field punning works —
// instead of `val: val` you could write just `val`
// Convert a struct to a Cell or a Slice.
let valCell = val.toCell();
let valSlice = val.toSlice();
// Obtain a struct from a Cell or a Slice.
let _ = One.fromCell(valCell);
let _ = One.fromSlice(valSlice);
// Conversion works both ways.
One.fromCell(val.toCell()).toCell() == valCell;
One.fromSlice(val.toSlice()).toSlice() == valSlice;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gU3RydWN0cyBhbmQgbWVzc2FnZSBzdHJ1Y3RzIGFsbG93IG11bHRpcGxlIHZhbHVlcyB0byBiZSBwYWNrZWQgdG9nZXRoZXIKLy8gaW4gYSBzaW5nbGUgdHlwZS4gVGhleSBhcmUgdmVyeSB1c2VmdWwgZm9yIChkZSlzZXJpYWxpemF0aW9uIG9mIENlbGxzCi8vIGFuZCBmb3IgdXNhZ2UgYXMgcGFyYW1ldGVycyBvciByZXR1cm4gdHlwZXMgaW4gZnVuY3Rpb25zLgoKLy8gU3RydWN0IGNvbnRhaW5pbmcgYSBzaW5nbGUgdmFsdWUKc3RydWN0IE9uZSB7IG51bWJlcjogSW50OyB9CgovLyBTdHJ1Y3Qgd2l0aCBkZWZhdWx0IGZpZWxkcywgZmllbGRzIG9mIG9wdGlvbmFsIHR5cGVzLCBhbmQgbmVzdGVkIHN0cnVjdHMKc3RydWN0IFBhcmFtcyB7CiAgICBuYW1lOiBTdHJpbmcgPSAiU2F0b3NoaSI7IC8vIGRlZmF1bHQgdmFsdWUKCiAgICBhZ2U6IEludD87IC8vIGZpZWxkIHdpdGggYW4gb3B0aW9uYWwgdHlwZSBJbnQ%2FCiAgICAgICAgICAgICAgIC8vIGFuZCBhbiBpbXBsaWNpdCBkZWZhdWx0IHZhbHVlIG9mIG51bGwKCiAgICB2YWw6IE9uZTsgLy8gbmVzdGVkIHN0cnVjdCBPbmUKfQoKLy8gWW91IGNhbiBpbnN0cnVjdCBob3cgdG8gKGRlKWNvbXBvc2UgdGhlIENlbGxzIHRvIGFuZCBmcm9tIHN0cnVjdHMKLy8gYnkgc3BlY2lmeWluZyBjZXJ0YWluIHNlcmlhbGl6YXRpb24gb3B0aW9ucyBhZnRlciB0aGUgYGFzYCBrZXl3b3JkLgpzdHJ1Y3QgU2VyaWVzWFggewogICAgaTY0OiBJbnQgYXMgaW50NjQ7ICAvLyBzaWduZWQgNjQtYml0IGludGVnZXIKICAgIHUzMjogSW50IGFzIHVpbnQzMjsgLy8gdW5zaWduZWQgMzItYml0IGludGVnZXIKICAgIHVmbzUxOiBJbnQgYXMgdWludDUxOyAvLyB1bmV2ZW4gZm9ybWF0cyBhcmUgYWxsb3dlZCB0b28sCiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc28gdGhpcyBpcyBhbiB1bnNpZ25lZCA1MS1iaXQgaW50ZWdlcgoKICAgIC8vIEluIGdlbmVyYWwsIHVpbnQxIHRocm91Z2ggdWludDI1NiBhbmQgaW50MSB0aHJvdWdoIGludDI1NwogICAgLy8gYXJlIHZhbGlkIHNlcmlhbGl6YXRpb24gZm9ybWF0cyBmb3IgaW50ZWdlciB2YWx1ZXMuCiAgICBtYXhpOiBJbnQgYXMgaW50MjU3OyAvLyBJbnQgaXMgc2VyaWFsaXplZCBhcyBpbnQyNTcgYnkgZGVmYXVsdCwKICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJ1dCBub3cgaXQgaXMgZXhwbGljaXRseSBzcGVjaWZpZWQKCiAgICAvLyBJZiB0aGlzIHN0cnVjdCB3aWxsIGJlIG9idGFpbmVkIGZyb20gc29tZSBTbGljZSwKICAgIC8vIHlvdSBjYW4gaW5zdHJ1Y3QgdGhlIGNvbXBpbGVyIHRvIHBsYWNlIHRoZSByZW1haW5kZXIgb2YgdGhhdCBTbGljZQogICAgLy8gYXMgdGhlIGxhc3QgZmllbGQgb2YgdGhlIHN0cnVjdCwgYW5kIGV2ZW4gdHlwZSBjYXN0IHRoZSB2YWx1ZQogICAgLy8gb2YgdGhhdCBmaWVsZCB0byBDZWxsLCBCdWlsZGVyIG9yIFNsaWNlIGF0IHJ1bnRpbWUuCiAgICBsYXN0RmllbGROYW1lOiBDZWxsIGFzIHJlbWFpbmluZzsgLy8gdGhlcmUgY2FuIG9ubHkgYmUgYSBzaW5nbGUgYHJlbWFpbmluZ2AgZmllbGQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIGl0IG11c3QgYmUgdGhlIGxhc3Qgb25lIGluIHRoZSBzdHJ1Y3QKfQoKLy8gVGhlIG9yZGVyIG9mIGZpZWxkcyBtYXR0ZXJzLCBhcyBpdCBjb3JyZXNwb25kcyB0byB0aGUgcmVzdWx0aW5nCi8vIG1lbW9yeSBsYXlvdXQgd2hlbiB0aGUgc3RydWN0IHdpbGwgYmUgdXNlZCB0byBjb21wb3NlIGEgQ2VsbAovLyBvciB0byBwYXJzZSBhIFNsaWNlIGJhY2sgdG8gdGhlIHN0cnVjdC4Kc3RydWN0IE9yZGVyIHsKICAgIGZpcnN0OiBJbnQ7ICAgICAvLyAyNTcgY29udGludW91c2x5IGxhaWQgb3V0IGJpdHMKICAgIHNlY29uZDogQ2VsbDsgICAvLyB1cCB0byAxMDIzIGJpdHMsCiAgICAgICAgICAgICAgICAgICAgLy8gd2hpY2ggd2lsbCBiZSBwbGFjZWQgaW4gYSBzZXBhcmF0ZSByZWYKICAgICAgICAgICAgICAgICAgICAvLyB3aGVuIGNvbXBvc2luZyBhIENlbGwKICAgIHRoaXJkOiBBZGRyZXNzOyAvLyAyNjcgYml0cwp9CgovLyBNZXNzYWdlIHN0cnVjdHMgYXJlIGFsbW9zdCB0aGUgc2FtZSBhcyByZWd1bGFyIHN0cnVjdHMsCi8vIGJ1dCB0aGV5IGhhdmUgYSAzMi1iaXQgaW50ZWdlciBoZWFkZXIgaW4gdGhlaXIgc2VyaWFsaXphdGlvbi4KLy8gVGhpcyB1bmlxdWUgbnVtZXJpYyBJRCBpcyBjb21tb25seSByZWZlcnJlZCB0byBhcyBhbiBvcGNvZGUgKG9wZXJhdGlvbiBjb2RlKSwKLy8gYW5kIGl0IGFsbG93cyBtZXNzYWdlIHN0cnVjdHMgdG8gYmUgdXNlZCB3aXRoIHNwZWNpYWwgcmVjZWl2ZXIgZnVuY3Rpb25zCi8vIHRoYXQgZGlzdGluZ3Vpc2ggaW5jb21pbmcgbWVzc2FnZXMgYmFzZWQgb24gdGhpcyBJRC4KbWVzc2FnZSBJbXBsaWNpdGx5QXNzaWduZWRJZCB7fSAvLyBubyBmaWVsZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYnV0IG5vdCBlbXB0eSBiZWNhdXNlIG9mIHRoZSBhdXRvbWF0aWNhbGx5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZ2VuZXJhdGVkIGFuZCBpbXBsaWNpdGx5IHNldCAzMi1iaXQgSW50IG9wY29kZQoKLy8gWW91IGNhbiBtYW51YWxseSBvdmVycmlkZSBhbiBvcGNvZGUgd2l0aCBhbnkgY29tcGlsZS10aW1lIGV4cHJlc3Npb24KLy8gdGhhdCBldmFsdWF0ZXMgdG8gYSBub24tbmVnYXRpdmUgMzItYml0IGludGVnZXIuCgovLyBUaGlzIG1lc3NhZ2UgaGFzIGFuIG9wY29kZSBvZiA4OTgwMDE4OTcsIHdoaWNoIGlzIHRoZSBldmFsdWF0ZWQKLy8gaW50ZWdlciB2YWx1ZSBvZiB0aGUgc3BlY2lmaWVkIGNvbXBpbGUtdGltZSBleHByZXNzaW9uLgptZXNzYWdlKChjcmMzMigiVGFjdCIpICsgNDIpICYgMHhGRkZGX0ZGRkYpIE1zZ1dpdGhFeHByT3Bjb2RlIHsKICAgIC8vIEFsbCB0aGUgY29udGVudHMgYXJlIGRlZmluZWQgaWRlbnRpY2FsIHRvIHJlZ3VsYXIgc3RydWN0cy4KICAgIGZpZWxkMTogSW50IGFzIHVpbnQ0OyAgICAgICAgIC8vIHNlcmlhbGl6YXRpb24KICAgIGZpZWxkMjogQm9vbD87ICAgICAgICAgICAgICAgIC8vIG9wdGlvbmFscwogICAgZmllbGQzOiBPbmU7ICAgICAgICAgICAgICAgICAgLy8gbmVzdGVkIHN0cnVjdHMKICAgIGZpZWxkNDogSW1wbGljaXRseUFzc2lnbmVkSWQ7IC8vIG5lc3RlZCBtZXNzYWdlIHN0cnVjdHMKfQoKLy8gU29tZSB1c2FnZSBleGFtcGxlcy4KZnVuIHVzYWdlKCkgewogICAgLy8gSW5zdGFudGlhdGlvbiBvZiBhIHN0cnVjdC4KICAgIC8vIE5vdGljZSB0aGUgbGFjayBvZiB0aGUgIm5ldyIga2V5d29yZCB1c2VkIGZvciB0aGlzIGluIG1hbnkKICAgIC8vIG90aGVyIHRyYWRpdGlvbmFsIGxhbmd1YWdlcy4KICAgIGxldCB2YWw6IE9uZSA9IE9uZSB7IG51bWJlcjogNTAgfTsKCiAgICAvLyBZb3UgY2FuIG9taXQgdGhlIGZpZWxkcyB3aXRoIGRlZmF1bHQgdmFsdWVzLgogICAgbGV0IF8gPSBQYXJhbXMgeyB2YWwgfTsgLy8gdGhlIGZpZWxkIHB1bm5pbmcgd29ya3Mg4oCUCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGluc3RlYWQgb2YgYHZhbDogdmFsYCB5b3UgY291bGQgd3JpdGUganVzdCBgdmFsYAoKICAgIC8vIENvbnZlcnQgYSBzdHJ1Y3QgdG8gYSBDZWxsIG9yIGEgU2xpY2UuCiAgICBsZXQgdmFsQ2VsbCA9IHZhbC50b0NlbGwoKTsKICAgIGxldCB2YWxTbGljZSA9IHZhbC50b1NsaWNlKCk7CgogICAgLy8gT2J0YWluIGEgc3RydWN0IGZyb20gYSBDZWxsIG9yIGEgU2xpY2UuCiAgICBsZXQgXyA9IE9uZS5mcm9tQ2VsbCh2YWxDZWxsKTsKICAgIGxldCBfID0gT25lLmZyb21TbGljZSh2YWxTbGljZSk7CgogICAgLy8gQ29udmVyc2lvbiB3b3JrcyBib3RoIHdheXMuCiAgICBPbmUuZnJvbUNlbGwodmFsLnRvQ2VsbCgpKS50b0NlbGwoKSA9PSB2YWxDZWxsOwogICAgT25lLmZyb21TbGljZSh2YWwudG9TbGljZSgpKS50b1NsaWNlKCkgPT0gdmFsU2xpY2U7Cn0%3D)
Read more: [Structs and Messages](/book/structs-and-messages).
## Operators[](#operators)
```tact
fun showcase() {
// Let's omit the type ascriptions and let the compiler infer the types.
let five = 5; // = is an assignment operator,
// but it can be a part of the assignment statement only,
// because there is no assignment expression
let four = 4;
// Most operators below have augmented assignment versions, like +=, -=, etc.
// See the "Statements" section below for more info.
// Common arithmetic operators have predictable precedences.
five + four - five * four / five % four; // 9
// You can change order of operations with parentheses.
(five + (four - five)) * four / (five % four); // 16
// The % is the modulo, not the remainder operator.
1 % five; // 1
1 % -five; // -4
// Negation and bitwise NOT.
-five; // -5: negation of 5
~five; // -6: bitwise NOT of 5
-(~five); // 6: bitwise NOT, then negation
~(-five); // 4: negation, then bitwise NOT
// Bitwise shifts.
five << 2; // 20
four >> 2; // 1
-four >> 2; // -1, because negation is applied first
// and >> performs arithmetic or sign-propagating right shift
// Other common bitwise operators.
five & four; // 4, due to bitwise AND
five | four; // 5, due to bitwise OR
five ^ four; // 1, due to bitwise XOR
// Relations.
five == four; // false
five != four; // true
five > four; // true
five < four; // false
five - 1 >= four; // true
five - 1 <= four; // true
// Logical checks.
!(five == 5); // false, because of the inverse ! operator
false && five == 5; // false, because && is short-circuited
true || five != 5; // true, because || is also short-circuited
// The non-null assertion operator raises a compilation error if the value
// is null or if the type of the value is not optional,
// i.e., it can never be null.
let maybeFive: Int? = five;
maybeFive!!; // 5
// Ternary operator ?: is right-associative.
false ? 1 : (false ? 2 : 3); // 3
false ? 1 : true ? 2 : 3; // 2
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gTGV0J3Mgb21pdCB0aGUgdHlwZSBhc2NyaXB0aW9ucyBhbmQgbGV0IHRoZSBjb21waWxlciBpbmZlciB0aGUgdHlwZXMuCiAgICBsZXQgZml2ZSA9IDU7IC8vID0gaXMgYW4gYXNzaWdubWVudCBvcGVyYXRvciwKICAgICAgICAgICAgICAgICAgLy8gYnV0IGl0IGNhbiBiZSBhIHBhcnQgb2YgdGhlIGFzc2lnbm1lbnQgc3RhdGVtZW50IG9ubHksCiAgICAgICAgICAgICAgICAgIC8vIGJlY2F1c2UgdGhlcmUgaXMgbm8gYXNzaWdubWVudCBleHByZXNzaW9uCiAgICBsZXQgZm91ciA9IDQ7CgogICAgLy8gTW9zdCBvcGVyYXRvcnMgYmVsb3cgaGF2ZSBhdWdtZW50ZWQgYXNzaWdubWVudCB2ZXJzaW9ucywgbGlrZSArPSwgLT0sIGV0Yy4KICAgIC8vIFNlZSB0aGUgIlN0YXRlbWVudHMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mby4KCiAgICAvLyBDb21tb24gYXJpdGhtZXRpYyBvcGVyYXRvcnMgaGF2ZSBwcmVkaWN0YWJsZSBwcmVjZWRlbmNlcy4KICAgIGZpdmUgKyBmb3VyIC0gZml2ZSAqIGZvdXIgLyBmaXZlICUgZm91cjsgLy8gOQoKICAgIC8vIFlvdSBjYW4gY2hhbmdlIG9yZGVyIG9mIG9wZXJhdGlvbnMgd2l0aCBwYXJlbnRoZXNlcy4KICAgIChmaXZlICsgKGZvdXIgLSBmaXZlKSkgKiBmb3VyIC8gKGZpdmUgJSBmb3VyKTsgLy8gMTYKCiAgICAvLyBUaGUgJSBpcyB0aGUgbW9kdWxvLCBub3QgdGhlIHJlbWFpbmRlciBvcGVyYXRvci4KICAgIDEgJSBmaXZlOyAgLy8gMQogICAgMSAlIC1maXZlOyAvLyAtNAoKICAgIC8vIE5lZ2F0aW9uIGFuZCBiaXR3aXNlIE5PVC4KICAgIC1maXZlOyAgICAvLyAtNTogbmVnYXRpb24gb2YgNQogICAgfmZpdmU7ICAgIC8vIC02OiBiaXR3aXNlIE5PVCBvZiA1CiAgICAtKH5maXZlKTsgLy8gNjogYml0d2lzZSBOT1QsIHRoZW4gbmVnYXRpb24KICAgIH4oLWZpdmUpOyAvLyA0OiBuZWdhdGlvbiwgdGhlbiBiaXR3aXNlIE5PVAoKICAgIC8vIEJpdHdpc2Ugc2hpZnRzLgogICAgZml2ZSA8PCAyOyAvLyAyMAogICAgZm91ciA%2BPiAyOyAvLyAxCiAgICAtZm91ciA%2BPiAyOyAvLyAtMSwgYmVjYXVzZSBuZWdhdGlvbiBpcyBhcHBsaWVkIGZpcnN0CiAgICAgICAgICAgICAgICAvLyBhbmQgPj4gcGVyZm9ybXMgYXJpdGhtZXRpYyBvciBzaWduLXByb3BhZ2F0aW5nIHJpZ2h0IHNoaWZ0CgogICAgLy8gT3RoZXIgY29tbW9uIGJpdHdpc2Ugb3BlcmF0b3JzLgogICAgZml2ZSAmIGZvdXI7IC8vIDQsIGR1ZSB0byBiaXR3aXNlIEFORAogICAgZml2ZSB8IGZvdXI7IC8vIDUsIGR1ZSB0byBiaXR3aXNlIE9SCiAgICBmaXZlIF4gZm91cjsgLy8gMSwgZHVlIHRvIGJpdHdpc2UgWE9SCgogICAgLy8gUmVsYXRpb25zLgogICAgZml2ZSA9PSBmb3VyOyAgICAgLy8gZmFsc2UKICAgIGZpdmUgIT0gZm91cjsgICAgIC8vIHRydWUKICAgIGZpdmUgPiBmb3VyOyAgICAgIC8vIHRydWUKICAgIGZpdmUgPCBmb3VyOyAgICAgIC8vIGZhbHNlCiAgICBmaXZlIC0gMSA%2BPSBmb3VyOyAvLyB0cnVlCiAgICBmaXZlIC0gMSA8PSBmb3VyOyAvLyB0cnVlCgogICAgLy8gTG9naWNhbCBjaGVja3MuCiAgICAhKGZpdmUgPT0gNSk7ICAgICAgIC8vIGZhbHNlLCBiZWNhdXNlIG9mIHRoZSBpbnZlcnNlICEgb3BlcmF0b3IKICAgIGZhbHNlICYmIGZpdmUgPT0gNTsgLy8gZmFsc2UsIGJlY2F1c2UgJiYgaXMgc2hvcnQtY2lyY3VpdGVkCiAgICB0cnVlIHx8IGZpdmUgIT0gNTsgIC8vIHRydWUsIGJlY2F1c2UgfHwgaXMgYWxzbyBzaG9ydC1jaXJjdWl0ZWQKCiAgICAvLyBUaGUgbm9uLW51bGwgYXNzZXJ0aW9uIG9wZXJhdG9yIHJhaXNlcyBhIGNvbXBpbGF0aW9uIGVycm9yIGlmIHRoZSB2YWx1ZQogICAgLy8gaXMgbnVsbCBvciBpZiB0aGUgdHlwZSBvZiB0aGUgdmFsdWUgaXMgbm90IG9wdGlvbmFsLAogICAgLy8gaS5lLiwgaXQgY2FuIG5ldmVyIGJlIG51bGwuCiAgICBsZXQgbWF5YmVGaXZlOiBJbnQ%2FID0gZml2ZTsKICAgIG1heWJlRml2ZSEhOyAvLyA1CgogICAgLy8gVGVybmFyeSBvcGVyYXRvciA%2FOiBpcyByaWdodC1hc3NvY2lhdGl2ZS4KICAgIGZhbHNlID8gMSA6IChmYWxzZSA%2FIDIgOiAzKTsgLy8gMwogICAgZmFsc2UgPyAxIDogdHJ1ZSA%2FIDIgOiAzOyAgICAvLyAyCn0%3D)
Read more: [Operators](/book/operators).
## Expressions[](#expressions)
```tact
contract MyContract() {
fun showcase() {
// Integer literals.
0; 42; 1_000; 020; // decimal, base 10
0xABC; 0xf; 0x001; // hexadecimal, base 16
0o777; 0o00000001; // octal, base 8
0b111010101111010; // binary, base 2
// Boolean literals.
true; false;
// String literals.
"You can be The Good Guy or the guy who saves the world... You can't be both.";
"1234"; // a string, not a number
"👻"; // strings support Unicode
"\\ \" \n \r \t \v \b \f \x00 through \xFF"; // common escape sequences
"\u0000 through \uFFFF and \u{0} through \u{10FFFF}"; // unicode escape sequences
// `null` and `self` literals.
null; // not an instance of a primitive type, but
// a special value that represents the intentional absence
// of any other value
self; // used to reference the current contract from within
// and the value of the currently extended type inside
// the extension function. See the "Functions" section below for more.
// Map literals.
map { 11: 11 };
// Identifiers, with usual naming conventions:
// They may contain Latin lowercase letters `a-z`,
// Latin uppercase letters `A-Z`, underscores `_`,
// and digits 0 - 9, but may not start with a digit.
// No other symbols are allowed, and Unicode identifiers are prohibited.
// They also cannot start with __gen or __tact since those prefixes
// are reserved by the Tact compiler.
let azAZ09_ = 5; azAZ09_;
// Instantiations or instance expressions of structs and message structs.
let addr = BasechainAddress { hash: null, };
// Field access.
addr.hash; // null
self.MOON_RADIUS_KM; // 1738, a contract-level constant
// defined below this function
// Extension function calls (methods).
self.MOON_RADIUS_KM.toString(); // "1738"
self.notify("Cashback".asComment()); // rather expensive,
// use cashback() instead
"hey".asComment(); // allowed on literals
// Global function calls.
now(); // UNIX timestamp in seconds
cashback(sender());
// Some of the functions can be computed at compile-time given enough data.
sha256("hey, I'll produce the SHA256 number at compile-time");
// But there are special, compile-time-only functions.
let _: Address = address("EQDtFpEwcFAEcRe5mLVh2N6C0x-_hJEM7W61_JLnSF74p4q2");
let _: Cell = cell("te6cckEBAQEAAgAAAEysuc0="); // an empty Cell
let _: Slice = slice("te6cckEBAQEADgAAGEhlbGxvIHdvcmxkIXgtxbw="); // a Slice with Hello world!
let _: Slice = rawSlice("000DEADBEEF000"); // CS{Cell{03f...430} bits: 588..644; refs: 1..1}
let _: Int = ascii("⚡"); // 14850721 or 0xE29AA1, 3 bytes in total
let _: Int = crc32("000DEADBEEF000"); // 1821923098
let _: Int = ton("1"); // 10^9 nanoToncoin = one Toncoin,
// the main currency of TON Blockchain
// initOf, which obtains the initial code and initial data
// of the given contract, i.e., it's initial state.
initOf MyContract(); // StateInit { code, data }
// codeOf, which only obtains the code.
codeOf MyContract;
}
// Constants support compile-time expressions
const MOON_RADIUS_KM: Int = 1730 + (8 | 8);
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgTXlDb250cmFjdCgpIHsKICAgIGZ1biBzaG93Y2FzZSgpIHsKICAgICAgICAvLyBJbnRlZ2VyIGxpdGVyYWxzLgogICAgICAgIDA7IDQyOyAxXzAwMDsgMDIwOyAvLyBkZWNpbWFsLCBiYXNlIDEwCiAgICAgICAgMHhBQkM7IDB4ZjsgMHgwMDE7IC8vIGhleGFkZWNpbWFsLCBiYXNlIDE2CiAgICAgICAgMG83Nzc7IDBvMDAwMDAwMDE7IC8vIG9jdGFsLCBiYXNlIDgKICAgICAgICAwYjExMTAxMDEwMTExMTAxMDsgLy8gYmluYXJ5LCBiYXNlIDIKCiAgICAgICAgLy8gQm9vbGVhbiBsaXRlcmFscy4KICAgICAgICB0cnVlOyBmYWxzZTsKCiAgICAgICAgLy8gU3RyaW5nIGxpdGVyYWxzLgogICAgICAgICJZb3UgY2FuIGJlIFRoZSBHb29kIEd1eSBvciB0aGUgZ3V5IHdobyBzYXZlcyB0aGUgd29ybGQuLi4gWW91IGNhbid0IGJlIGJvdGguIjsKICAgICAgICAiMTIzNCI7IC8vIGEgc3RyaW5nLCBub3QgYSBudW1iZXIKICAgICAgICAi8J%2BRuyI7IC8vIHN0cmluZ3Mgc3VwcG9ydCBVbmljb2RlCiAgICAgICAgIlxcIFwiIFxuIFxyIFx0IFx2IFxiIFxmIFx4MDAgdGhyb3VnaCBceEZGIjsgLy8gY29tbW9uIGVzY2FwZSBzZXF1ZW5jZXMKICAgICAgICAiXHUwMDAwIHRocm91Z2ggXHVGRkZGIGFuZCBcdXswfSB0aHJvdWdoIFx1ezEwRkZGRn0iOyAvLyB1bmljb2RlIGVzY2FwZSBzZXF1ZW5jZXMKCiAgICAgICAgLy8gYG51bGxgIGFuZCBgc2VsZmAgbGl0ZXJhbHMuCiAgICAgICAgbnVsbDsgLy8gbm90IGFuIGluc3RhbmNlIG9mIGEgcHJpbWl0aXZlIHR5cGUsIGJ1dAogICAgICAgICAgICAgIC8vIGEgc3BlY2lhbCB2YWx1ZSB0aGF0IHJlcHJlc2VudHMgdGhlIGludGVudGlvbmFsIGFic2VuY2UKICAgICAgICAgICAgICAvLyBvZiBhbnkgb3RoZXIgdmFsdWUKCiAgICAgICAgc2VsZjsgLy8gdXNlZCB0byByZWZlcmVuY2UgdGhlIGN1cnJlbnQgY29udHJhY3QgZnJvbSB3aXRoaW4KICAgICAgICAgICAgICAvLyBhbmQgdGhlIHZhbHVlIG9mIHRoZSBjdXJyZW50bHkgZXh0ZW5kZWQgdHlwZSBpbnNpZGUKICAgICAgICAgICAgICAvLyB0aGUgZXh0ZW5zaW9uIGZ1bmN0aW9uLiBTZWUgdGhlICJGdW5jdGlvbnMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUuCgogICAgICAgIC8vIE1hcCBsaXRlcmFscy4KICAgICAgICBtYXA8SW50LCBJbnQgYXMgY29pbnM%2BIHsgMTE6IDExIH07CgogICAgICAgIC8vIElkZW50aWZpZXJzLCB3aXRoIHVzdWFsIG5hbWluZyBjb252ZW50aW9uczoKICAgICAgICAvLyBUaGV5IG1heSBjb250YWluIExhdGluIGxvd2VyY2FzZSBsZXR0ZXJzIGBhLXpgLAogICAgICAgIC8vIExhdGluIHVwcGVyY2FzZSBsZXR0ZXJzIGBBLVpgLCB1bmRlcnNjb3JlcyBgX2AsCiAgICAgICAgLy8gYW5kIGRpZ2l0cyAwIC0gOSwgYnV0IG1heSBub3Qgc3RhcnQgd2l0aCBhIGRpZ2l0LgogICAgICAgIC8vIE5vIG90aGVyIHN5bWJvbHMgYXJlIGFsbG93ZWQsIGFuZCBVbmljb2RlIGlkZW50aWZpZXJzIGFyZSBwcm9oaWJpdGVkLgogICAgICAgIC8vIFRoZXkgYWxzbyBjYW5ub3Qgc3RhcnQgd2l0aCBfX2dlbiBvciBfX3RhY3Qgc2luY2UgdGhvc2UgcHJlZml4ZXMKICAgICAgICAvLyBhcmUgcmVzZXJ2ZWQgYnkgdGhlIFRhY3QgY29tcGlsZXIuCiAgICAgICAgbGV0IGF6QVowOV8gPSA1OyBhekFaMDlfOwoKICAgICAgICAvLyBJbnN0YW50aWF0aW9ucyBvciBpbnN0YW5jZSBleHByZXNzaW9ucyBvZiBzdHJ1Y3RzIGFuZCBtZXNzYWdlIHN0cnVjdHMuCiAgICAgICAgbGV0IGFkZHIgPSBCYXNlY2hhaW5BZGRyZXNzIHsgaGFzaDogbnVsbCwgfTsKCiAgICAgICAgLy8gRmllbGQgYWNjZXNzLgogICAgICAgIGFkZHIuaGFzaDsgLy8gbnVsbAogICAgICAgIHNlbGYuTU9PTl9SQURJVVNfS007IC8vIDE3MzgsIGEgY29udHJhY3QtbGV2ZWwgY29uc3RhbnQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBkZWZpbmVkIGJlbG93IHRoaXMgZnVuY3Rpb24KCiAgICAgICAgLy8gRXh0ZW5zaW9uIGZ1bmN0aW9uIGNhbGxzIChtZXRob2RzKS4KICAgICAgICBzZWxmLk1PT05fUkFESVVTX0tNLnRvU3RyaW5nKCk7IC8vICIxNzM4IgogICAgICAgIHNlbGYubm90aWZ5KCJDYXNoYmFjayIuYXNDb21tZW50KCkpOyAvLyByYXRoZXIgZXhwZW5zaXZlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB1c2UgY2FzaGJhY2soKSBpbnN0ZWFkCiAgICAgICAgImhleSIuYXNDb21tZW50KCk7IC8vIGFsbG93ZWQgb24gbGl0ZXJhbHMKCiAgICAgICAgLy8gR2xvYmFsIGZ1bmN0aW9uIGNhbGxzLgogICAgICAgIG5vdygpOyAvLyBVTklYIHRpbWVzdGFtcCBpbiBzZWNvbmRzCiAgICAgICAgY2FzaGJhY2soc2VuZGVyKCkpOwoKICAgICAgICAvLyBTb21lIG9mIHRoZSBmdW5jdGlvbnMgY2FuIGJlIGNvbXB1dGVkIGF0IGNvbXBpbGUtdGltZSBnaXZlbiBlbm91Z2ggZGF0YS4KICAgICAgICBzaGEyNTYoImhleSwgSSdsbCBwcm9kdWNlIHRoZSBTSEEyNTYgbnVtYmVyIGF0IGNvbXBpbGUtdGltZSIpOwoKICAgICAgICAvLyBCdXQgdGhlcmUgYXJlIHNwZWNpYWwsIGNvbXBpbGUtdGltZS1vbmx5IGZ1bmN0aW9ucy4KICAgICAgICBsZXQgXzogQWRkcmVzcyA9IGFkZHJlc3MoIkVRRHRGcEV3Y0ZBRWNSZTVtTFZoMk42QzB4LV9oSkVNN1c2MV9KTG5TRjc0cDRxMiIpOwogICAgICAgIGxldCBfOiBDZWxsID0gY2VsbCgidGU2Y2NrRUJBUUVBQWdBQUFFeXN1YzA9Iik7IC8vIGFuIGVtcHR5IENlbGwKICAgICAgICBsZXQgXzogU2xpY2UgPSBzbGljZSgidGU2Y2NrRUJBUUVBRGdBQUdFaGxiR3h2SUhkdmNteGtJWGd0eGJ3PSIpOyAvLyBhIFNsaWNlIHdpdGggSGVsbG8gd29ybGQhCiAgICAgICAgbGV0IF86IFNsaWNlID0gcmF3U2xpY2UoIjAwMERFQURCRUVGMDAwIik7IC8vIENTe0NlbGx7MDNmLi4uNDMwfSBiaXRzOiA1ODguLjY0NDsgcmVmczogMS4uMX0KICAgICAgICBsZXQgXzogSW50ID0gYXNjaWkoIuKaoSIpOyAvLyAxNDg1MDcyMSBvciAweEUyOUFBMSwgMyBieXRlcyBpbiB0b3RhbAogICAgICAgIGxldCBfOiBJbnQgPSBjcmMzMigiMDAwREVBREJFRUYwMDAiKTsgLy8gMTgyMTkyMzA5OAogICAgICAgIGxldCBfOiBJbnQgPSB0b24oIjEiKTsgLy8gMTBeOSBuYW5vVG9uY29pbiA9IG9uZSBUb25jb2luLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIG1haW4gY3VycmVuY3kgb2YgVE9OIEJsb2NrY2hhaW4KCiAgICAgICAgLy8gaW5pdE9mLCB3aGljaCBvYnRhaW5zIHRoZSBpbml0aWFsIGNvZGUgYW5kIGluaXRpYWwgZGF0YQogICAgICAgIC8vIG9mIHRoZSBnaXZlbiBjb250cmFjdCwgaS5lLiwgaXQncyBpbml0aWFsIHN0YXRlLgogICAgICAgIGluaXRPZiBNeUNvbnRyYWN0KCk7IC8vIFN0YXRlSW5pdCB7IGNvZGUsIGRhdGEgfQoKICAgICAgICAvLyBjb2RlT2YsIHdoaWNoIG9ubHkgb2J0YWlucyB0aGUgY29kZS4KICAgICAgICBjb2RlT2YgTXlDb250cmFjdDsKICAgIH0KCiAgICAvLyBDb25zdGFudHMgc3VwcG9ydCBjb21waWxlLXRpbWUgZXhwcmVzc2lvbnMKICAgIGNvbnN0IE1PT05fUkFESVVTX0tNOiBJbnQgPSAxNzMwICsgKDggfCA4KTsKfQ%3D%3D)
Read more: [Expressions](/book/expressions).
## Statements and control flow[](#statements)
```tact
fun showcase() {
// As we've seen above, the let statement defines new variables.
// You must always provide an initial value, but type ascriptions
// aren't mandatory except for maps and null values.
let theAnswer = 42; // type ascription is not required here,
let m: map = emptyMap(); // but we must specify it for maps
let opt: Int? = null; // and when assigning a null value.
// Block statement creates an enclosed scope.
{
// theAnswer is accessible here
let privateVal = theAnswer + 27;
// but privateVal is no longer visible after this block ends.
}
// Assignment statement allows reassigning variables.
theAnswer = -(~theAnswer + 1);
// Almost every binary operator can form an augmented assignment,
// except for relational and equality ones,
// and excluding the assignment operator itself.
theAnswer += 5; // equivalent to: theAnswer = theAnswer + 5;
theAnswer -= 5; // equivalent to: theAnswer = theAnswer - 5;
theAnswer *= 5; // and so on, see the Operators page for more.
// Destructuring assignment is a concise way to
// unpack structures into distinct variables.
let st = StdAddress { workchain: 0, address: 0 }; // let statement
let StdAddress { address, .. } = st; // destructuring statement
// ------- --
// ↑ ↑
// | ignores all unspecified fields
// Int as uint256,
// a variable out of the second field of StdAddress struct
address; // 0
// You can also define new names for variables
// derived from the struct fields.
let StdAddress { address: someNewName, .. } = st;
someNewName; // 0
// Conditional branching with if...else.
if (false) { // curly brackets (code blocks) are required!
// ...then branch
} else if (false) {
// ...else branch
} else {
// ...last else
}
// Try and try...catch, with partial rollback.
try {
throw(777);
} catch (exitCode) { // 777
// An exit code is an integer that indicates whether the transaction
// was successful, and if not — holds the code of the exception that occurred.
//
// The catch block that can catch run-time (compute phase) exit codes
// will roll back almost all changes made in the try block,
// except for: codepage changes, gas usage counters, etc.
//
// See the "Testing and debugging" section below for more info.
}
// Repeat something N times.
repeat (2003) {
dump("mine"); // greet the Nemo
}
// Loop with a pre-condition: while.
while (theAnswer > 42) {
theAnswer /= 5;
}
// Loop with a post-condition: do...until.
do {
// This block will be executed at least once,
// because the condition in the until close
// is checked after each iteration.
m = emptyMap();
} until (false);
// Traverse over all map entries with foreach.
m.set(100, 456);
m.set(23, 500);
foreach (key, value in m) { // or just k, v: naming is up to you
// Goes from smaller to bigger keys:
// first iteration key = 23
// second iteration key = 100
}
// If you don't want key, value, or both, then use a wildcard.
let len = 0;
foreach (_, _ in m) {
len += 1; // don't mind me, just counting the size of the map
}
// Finally, return statement works as usual.
return; // implicitly produces nothing (named "void" in the compiler)
// return 5; // would explicitly produce 5
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gQXMgd2UndmUgc2VlbiBhYm92ZSwgdGhlIGxldCBzdGF0ZW1lbnQgZGVmaW5lcyBuZXcgdmFyaWFibGVzLgogICAgLy8gWW91IG11c3QgYWx3YXlzIHByb3ZpZGUgYW4gaW5pdGlhbCB2YWx1ZSwgYnV0IHR5cGUgYXNjcmlwdGlvbnMKICAgIC8vIGFyZW4ndCBtYW5kYXRvcnkgZXhjZXB0IGZvciBtYXBzIGFuZCBudWxsIHZhbHVlcy4KICAgIGxldCB0aGVBbnN3ZXIgPSA0MjsgICAgICAgICAgICAgICAgLy8gdHlwZSBhc2NyaXB0aW9uIGlzIG5vdCByZXF1aXJlZCBoZXJlLAogICAgbGV0IG06IG1hcDxJbnQsIEludD4gPSBlbXB0eU1hcCgpOyAvLyBidXQgd2UgbXVzdCBzcGVjaWZ5IGl0IGZvciBtYXBzCiAgICBsZXQgb3B0OiBJbnQ%2FID0gbnVsbDsgICAgICAgICAgICAgIC8vIGFuZCB3aGVuIGFzc2lnbmluZyBhIG51bGwgdmFsdWUuCgogICAgLy8gQmxvY2sgc3RhdGVtZW50IGNyZWF0ZXMgYW4gZW5jbG9zZWQgc2NvcGUuCiAgICB7CiAgICAgICAgLy8gdGhlQW5zd2VyIGlzIGFjY2Vzc2libGUgaGVyZQogICAgICAgIGxldCBwcml2YXRlVmFsID0gdGhlQW5zd2VyICsgMjc7CiAgICAgICAgLy8gYnV0IHByaXZhdGVWYWwgaXMgbm8gbG9uZ2VyIHZpc2libGUgYWZ0ZXIgdGhpcyBibG9jayBlbmRzLgogICAgfQoKICAgIC8vIEFzc2lnbm1lbnQgc3RhdGVtZW50IGFsbG93cyByZWFzc2lnbmluZyB2YXJpYWJsZXMuCiAgICB0aGVBbnN3ZXIgPSAtKH50aGVBbnN3ZXIgKyAxKTsKCiAgICAvLyBBbG1vc3QgZXZlcnkgYmluYXJ5IG9wZXJhdG9yIGNhbiBmb3JtIGFuIGF1Z21lbnRlZCBhc3NpZ25tZW50LAogICAgLy8gZXhjZXB0IGZvciByZWxhdGlvbmFsIGFuZCBlcXVhbGl0eSBvbmVzLAogICAgLy8gYW5kIGV4Y2x1ZGluZyB0aGUgYXNzaWdubWVudCBvcGVyYXRvciBpdHNlbGYuCiAgICB0aGVBbnN3ZXIgKz0gNTsgLy8gZXF1aXZhbGVudCB0bzogdGhlQW5zd2VyID0gdGhlQW5zd2VyICsgNTsKICAgIHRoZUFuc3dlciAtPSA1OyAvLyBlcXVpdmFsZW50IHRvOiB0aGVBbnN3ZXIgPSB0aGVBbnN3ZXIgLSA1OwogICAgdGhlQW5zd2VyICo9IDU7IC8vIGFuZCBzbyBvbiwgc2VlIHRoZSBPcGVyYXRvcnMgcGFnZSBmb3IgbW9yZS4KCiAgICAvLyBEZXN0cnVjdHVyaW5nIGFzc2lnbm1lbnQgaXMgYSBjb25jaXNlIHdheSB0bwogICAgLy8gdW5wYWNrIHN0cnVjdHVyZXMgaW50byBkaXN0aW5jdCB2YXJpYWJsZXMuCiAgICBsZXQgc3QgPSBTdGRBZGRyZXNzIHsgd29ya2NoYWluOiAwLCBhZGRyZXNzOiAwIH07IC8vIGxldCBzdGF0ZW1lbnQKICAgIGxldCBTdGRBZGRyZXNzIHsgYWRkcmVzcywgLi4gfSA9IHN0OyAgICAgICAgICAgICAgLy8gZGVzdHJ1Y3R1cmluZyBzdGF0ZW1lbnQKICAgIC8vICAgICAgICAgICAgICAgLS0tLS0tLSAgLS0KICAgIC8vICAgICAgICAgICAgICAg4oaRICAgICAgICDihpEKICAgIC8vICAgICAgICAgICAgICAgfCAgICAgICAgaWdub3JlcyBhbGwgdW5zcGVjaWZpZWQgZmllbGRzCiAgICAvLyAgICAgICAgICAgICAgIEludCBhcyB1aW50MjU2LAogICAgLy8gICAgICAgICAgICAgICBhIHZhcmlhYmxlIG91dCBvZiB0aGUgc2Vjb25kIGZpZWxkIG9mIFN0ZEFkZHJlc3Mgc3RydWN0CiAgICBhZGRyZXNzOyAvLyAwCgogICAgLy8gWW91IGNhbiBhbHNvIGRlZmluZSBuZXcgbmFtZXMgZm9yIHZhcmlhYmxlcwogICAgLy8gZGVyaXZlZCBmcm9tIHRoZSBzdHJ1Y3QgZmllbGRzLgogICAgbGV0IFN0ZEFkZHJlc3MgeyBhZGRyZXNzOiBzb21lTmV3TmFtZSwgLi4gfSA9IHN0OwogICAgc29tZU5ld05hbWU7IC8vIDAKCiAgICAvLyBDb25kaXRpb25hbCBicmFuY2hpbmcgd2l0aCBpZi4uLmVsc2UuCiAgICBpZiAoZmFsc2UpIHsgLy8gY3VybHkgYnJhY2tldHMgKGNvZGUgYmxvY2tzKSBhcmUgcmVxdWlyZWQhCiAgICAgICAgLy8gLi4udGhlbiBicmFuY2gKICAgIH0gZWxzZSBpZiAoZmFsc2UpIHsKICAgICAgICAvLyAuLi5lbHNlIGJyYW5jaAogICAgfSBlbHNlIHsKICAgICAgICAvLyAuLi5sYXN0IGVsc2UKICAgIH0KCiAgICAvLyBUcnkgYW5kIHRyeS4uLmNhdGNoLCB3aXRoIHBhcnRpYWwgcm9sbGJhY2suCiAgICB0cnkgewogICAgICAgIHRocm93KDc3Nyk7CiAgICB9IGNhdGNoIChleGl0Q29kZSkgeyAvLyA3NzcKICAgICAgICAvLyBBbiBleGl0IGNvZGUgaXMgYW4gaW50ZWdlciB0aGF0IGluZGljYXRlcyB3aGV0aGVyIHRoZSB0cmFuc2FjdGlvbgogICAgICAgIC8vIHdhcyBzdWNjZXNzZnVsLCBhbmQgaWYgbm90IOKAlCBob2xkcyB0aGUgY29kZSBvZiB0aGUgZXhjZXB0aW9uIHRoYXQgb2NjdXJyZWQuCiAgICAgICAgLy8KICAgICAgICAvLyBUaGUgY2F0Y2ggYmxvY2sgdGhhdCBjYW4gY2F0Y2ggcnVuLXRpbWUgKGNvbXB1dGUgcGhhc2UpIGV4aXQgY29kZXMKICAgICAgICAvLyB3aWxsIHJvbGwgYmFjayBhbG1vc3QgYWxsIGNoYW5nZXMgbWFkZSBpbiB0aGUgdHJ5IGJsb2NrLAogICAgICAgIC8vIGV4Y2VwdCBmb3I6IGNvZGVwYWdlIGNoYW5nZXMsIGdhcyB1c2FnZSBjb3VudGVycywgZXRjLgogICAgICAgIC8vCiAgICAgICAgLy8gU2VlIHRoZSAiVGVzdGluZyBhbmQgZGVidWdnaW5nIiBzZWN0aW9uIGJlbG93IGZvciBtb3JlIGluZm8uCiAgICB9CgogICAgLy8gUmVwZWF0IHNvbWV0aGluZyBOIHRpbWVzLgogICAgcmVwZWF0ICgyMDAzKSB7CiAgICAgICAgZHVtcCgibWluZSIpOyAvLyBncmVldCB0aGUgTmVtbwogICAgfQoKICAgIC8vIExvb3Agd2l0aCBhIHByZS1jb25kaXRpb246IHdoaWxlLgogICAgd2hpbGUgKHRoZUFuc3dlciA%2BIDQyKSB7CiAgICAgICAgdGhlQW5zd2VyIC89IDU7CiAgICB9CgogICAgLy8gTG9vcCB3aXRoIGEgcG9zdC1jb25kaXRpb246IGRvLi4udW50aWwuCiAgICBkbyB7CiAgICAgICAgLy8gVGhpcyBibG9jayB3aWxsIGJlIGV4ZWN1dGVkIGF0IGxlYXN0IG9uY2UsCiAgICAgICAgLy8gYmVjYXVzZSB0aGUgY29uZGl0aW9uIGluIHRoZSB1bnRpbCBjbG9zZQogICAgICAgIC8vIGlzIGNoZWNrZWQgYWZ0ZXIgZWFjaCBpdGVyYXRpb24uCiAgICAgICAgbSA9IGVtcHR5TWFwKCk7CiAgICB9IHVudGlsIChmYWxzZSk7CgogICAgLy8gVHJhdmVyc2Ugb3ZlciBhbGwgbWFwIGVudHJpZXMgd2l0aCBmb3JlYWNoLgogICAgbS5zZXQoMTAwLCA0NTYpOwogICAgbS5zZXQoMjMsIDUwMCk7CiAgICBmb3JlYWNoIChrZXksIHZhbHVlIGluIG0pIHsgLy8gb3IganVzdCBrLCB2OiBuYW1pbmcgaXMgdXAgdG8geW91CiAgICAgICAgLy8gR29lcyBmcm9tIHNtYWxsZXIgdG8gYmlnZ2VyIGtleXM6CiAgICAgICAgLy8gZmlyc3QgaXRlcmF0aW9uIGtleSA9IDIzCiAgICAgICAgLy8gc2Vjb25kIGl0ZXJhdGlvbiBrZXkgPSAxMDAKICAgIH0KCiAgICAvLyBJZiB5b3UgZG9uJ3Qgd2FudCBrZXksIHZhbHVlLCBvciBib3RoLCB0aGVuIHVzZSBhIHdpbGRjYXJkLgogICAgbGV0IGxlbiA9IDA7CiAgICBmb3JlYWNoIChfLCBfIGluIG0pIHsKICAgICAgICBsZW4gKz0gMTsgLy8gZG9uJ3QgbWluZCBtZSwganVzdCBjb3VudGluZyB0aGUgc2l6ZSBvZiB0aGUgbWFwCiAgICB9CgogICAgLy8gRmluYWxseSwgcmV0dXJuIHN0YXRlbWVudCB3b3JrcyBhcyB1c3VhbC4KICAgIHJldHVybjsgLy8gaW1wbGljaXRseSBwcm9kdWNlcyBub3RoaW5nIChuYW1lZCAidm9pZCIgaW4gdGhlIGNvbXBpbGVyKQogICAgLy8gcmV0dXJuIDU7IC8vIHdvdWxkIGV4cGxpY2l0bHkgcHJvZHVjZSA1Cn0%3D)
Read more: [Statements](/book/statements).
## Functions[](#functions)
```tact
// Global function with parameters and return type.
fun add(a: Int, b: Int): Int {
return a + b;
}
// Global function have a set of optional attributes that can change their demeanor.
// For example, inline attribute will make the body of this
// function inlined in all places where this function is called,
// increasing the total code size and possibly reducing computational fees.
inline fun reply(str: String) {
message(MessageParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
body: str.asComment(),
});
}
// The extends attribute allows to implement extension functions for any type.
// Its first parameter in the signature must be named self,
// and its type is the type this function is extending.
// Think of extension functions as very flexible method definitions
// in popular programming languages.
extends fun toCoinsString2(self: Int): String {
return self.toFloatString(9);
}
/// On top of the extends attribute, you may add the mutates attribute,
/// which would allow mutating the value of the currently extended type.
extends mutates fun hippityHoppity(self: Int) {
// ...something that would mutate `self`
self += 1;
}
/// Tact allows you to import Tact and FunC files.
/// To bind to or wrap the respective functions in FunC,
/// the so-called native functions are used.
///
/// Prior to defining them, make sure to add the
/// required `import "./path/to/file.fc";` on top of the file.
@name(get_data) // here, import is not needed,
// because the stdlib.fc is always implicitly imported
native getData(): Cell;
/// Finally, there are advanced module-level functions that allow you
/// to write Tact assembly. Unlike all other functions, their bodies consist
/// only of TVM instructions and some other primitives as arguments to instructions.
asm fun rawReserveExtra(amount: Int, extraAmount: Cell, mode: Int) { RAWRESERVEX }
// Examples of calling the functions defined above
fun showcase() {
// Global function
add(1, 2); // 3
// Inlined global function
reply("Viltrum Empire");
// Extension function
5.toCoinsString2(); // 0.000000005
// Extension mutation function
let val = 10;
val.hippityHoppity();
val; // 11
// Native function, called just like global functions
getData(); // Cell with the contract's persistent storage data.
// Assembly function, called just like global functions
rawReserveExtra(ton("0.1"), emptyCell(), 0);
}
// The functions discussed above are helpful but not mandatory for
// the contracts to operate, unlike the receiver functions,
// which can only be defined at the contract and trait level.
//
// See the "Contracts and traits" section below for more info.
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gR2xvYmFsIGZ1bmN0aW9uIHdpdGggcGFyYW1ldGVycyBhbmQgcmV0dXJuIHR5cGUuCmZ1biBhZGQoYTogSW50LCBiOiBJbnQpOiBJbnQgewogICAgcmV0dXJuIGEgKyBiOwp9CgovLyBHbG9iYWwgZnVuY3Rpb24gaGF2ZSBhIHNldCBvZiBvcHRpb25hbCBhdHRyaWJ1dGVzIHRoYXQgY2FuIGNoYW5nZSB0aGVpciBkZW1lYW5vci4KLy8gRm9yIGV4YW1wbGUsIGlubGluZSBhdHRyaWJ1dGUgd2lsbCBtYWtlIHRoZSBib2R5IG9mIHRoaXMKLy8gZnVuY3Rpb24gaW5saW5lZCBpbiBhbGwgcGxhY2VzIHdoZXJlIHRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkLAovLyBpbmNyZWFzaW5nIHRoZSB0b3RhbCBjb2RlIHNpemUgYW5kIHBvc3NpYmx5IHJlZHVjaW5nIGNvbXB1dGF0aW9uYWwgZmVlcy4KaW5saW5lIGZ1biByZXBseShzdHI6IFN0cmluZykgewogICAgbWVzc2FnZShNZXNzYWdlUGFyYW1ldGVycyB7CiAgICAgICAgdG86IHNlbmRlcigpLAogICAgICAgIHZhbHVlOiAwLAogICAgICAgIG1vZGU6IFNlbmRSZW1haW5pbmdWYWx1ZSB8IFNlbmRJZ25vcmVFcnJvcnMsCiAgICAgICAgYm9keTogc3RyLmFzQ29tbWVudCgpLAogICAgfSk7Cn0KCi8vIFRoZSBleHRlbmRzIGF0dHJpYnV0ZSBhbGxvd3MgdG8gaW1wbGVtZW50IGV4dGVuc2lvbiBmdW5jdGlvbnMgZm9yIGFueSB0eXBlLgovLyBJdHMgZmlyc3QgcGFyYW1ldGVyIGluIHRoZSBzaWduYXR1cmUgbXVzdCBiZSBuYW1lZCBzZWxmLAovLyBhbmQgaXRzIHR5cGUgaXMgdGhlIHR5cGUgdGhpcyBmdW5jdGlvbiBpcyBleHRlbmRpbmcuCi8vIFRoaW5rIG9mIGV4dGVuc2lvbiBmdW5jdGlvbnMgYXMgdmVyeSBmbGV4aWJsZSBtZXRob2QgZGVmaW5pdGlvbnMKLy8gaW4gcG9wdWxhciBwcm9ncmFtbWluZyBsYW5ndWFnZXMuCmV4dGVuZHMgZnVuIHRvQ29pbnNTdHJpbmcyKHNlbGY6IEludCk6IFN0cmluZyB7CiAgICByZXR1cm4gc2VsZi50b0Zsb2F0U3RyaW5nKDkpOwp9CgovLy8gT24gdG9wIG9mIHRoZSBleHRlbmRzIGF0dHJpYnV0ZSwgeW91IG1heSBhZGQgdGhlIG11dGF0ZXMgYXR0cmlidXRlLAovLy8gd2hpY2ggd291bGQgYWxsb3cgbXV0YXRpbmcgdGhlIHZhbHVlIG9mIHRoZSBjdXJyZW50bHkgZXh0ZW5kZWQgdHlwZS4KZXh0ZW5kcyBtdXRhdGVzIGZ1biBoaXBwaXR5SG9wcGl0eShzZWxmOiBJbnQpIHsKICAgIC8vIC4uLnNvbWV0aGluZyB0aGF0IHdvdWxkIG11dGF0ZSBgc2VsZmAKICAgIHNlbGYgKz0gMTsKfQoKLy8vIFRhY3QgYWxsb3dzIHlvdSB0byBpbXBvcnQgVGFjdCBhbmQgRnVuQyBmaWxlcy4KLy8vIFRvIGJpbmQgdG8gb3Igd3JhcCB0aGUgcmVzcGVjdGl2ZSBmdW5jdGlvbnMgaW4gRnVuQywKLy8vIHRoZSBzby1jYWxsZWQgbmF0aXZlIGZ1bmN0aW9ucyBhcmUgdXNlZC4KLy8vCi8vLyBQcmlvciB0byBkZWZpbmluZyB0aGVtLCBtYWtlIHN1cmUgdG8gYWRkIHRoZQovLy8gcmVxdWlyZWQgYGltcG9ydCAiLi9wYXRoL3RvL2ZpbGUuZmMiO2Agb24gdG9wIG9mIHRoZSBmaWxlLgpAbmFtZShnZXRfZGF0YSkgLy8gaGVyZSwgaW1wb3J0IGlzIG5vdCBuZWVkZWQsCiAgICAgICAgICAgICAgICAvLyBiZWNhdXNlIHRoZSBzdGRsaWIuZmMgaXMgYWx3YXlzIGltcGxpY2l0bHkgaW1wb3J0ZWQKbmF0aXZlIGdldERhdGEoKTogQ2VsbDsKCi8vLyBGaW5hbGx5LCB0aGVyZSBhcmUgYWR2YW5jZWQgbW9kdWxlLWxldmVsIGZ1bmN0aW9ucyB0aGF0IGFsbG93IHlvdQovLy8gdG8gd3JpdGUgVGFjdCBhc3NlbWJseS4gVW5saWtlIGFsbCBvdGhlciBmdW5jdGlvbnMsIHRoZWlyIGJvZGllcyBjb25zaXN0Ci8vLyBvbmx5IG9mIFRWTSBpbnN0cnVjdGlvbnMgYW5kIHNvbWUgb3RoZXIgcHJpbWl0aXZlcyBhcyBhcmd1bWVudHMgdG8gaW5zdHJ1Y3Rpb25zLgphc20gZnVuIHJhd1Jlc2VydmVFeHRyYShhbW91bnQ6IEludCwgZXh0cmFBbW91bnQ6IENlbGwsIG1vZGU6IEludCkgeyBSQVdSRVNFUlZFWCB9CgovLyBFeGFtcGxlcyBvZiBjYWxsaW5nIHRoZSBmdW5jdGlvbnMgZGVmaW5lZCBhYm92ZQpmdW4gc2hvd2Nhc2UoKSB7CiAgICAvLyBHbG9iYWwgZnVuY3Rpb24KICAgIGFkZCgxLCAyKTsgLy8gMwoKICAgIC8vIElubGluZWQgZ2xvYmFsIGZ1bmN0aW9uCiAgICByZXBseSgiVmlsdHJ1bSBFbXBpcmUiKTsKCiAgICAvLyBFeHRlbnNpb24gZnVuY3Rpb24KICAgIDUudG9Db2luc1N0cmluZzIoKTsgLy8gMC4wMDAwMDAwMDUKCiAgICAvLyBFeHRlbnNpb24gbXV0YXRpb24gZnVuY3Rpb24KICAgIGxldCB2YWwgPSAxMDsKICAgIHZhbC5oaXBwaXR5SG9wcGl0eSgpOwogICAgdmFsOyAvLyAxMQoKICAgIC8vIE5hdGl2ZSBmdW5jdGlvbiwgY2FsbGVkIGp1c3QgbGlrZSBnbG9iYWwgZnVuY3Rpb25zCiAgICBnZXREYXRhKCk7IC8vIENlbGwgd2l0aCB0aGUgY29udHJhY3QncyBwZXJzaXN0ZW50IHN0b3JhZ2UgZGF0YS4KCiAgICAvLyBBc3NlbWJseSBmdW5jdGlvbiwgY2FsbGVkIGp1c3QgbGlrZSBnbG9iYWwgZnVuY3Rpb25zCiAgICByYXdSZXNlcnZlRXh0cmEodG9uKCIwLjEiKSwgZW1wdHlDZWxsKCksIDApOwp9CgovLyBUaGUgZnVuY3Rpb25zIGRpc2N1c3NlZCBhYm92ZSBhcmUgaGVscGZ1bCBidXQgbm90IG1hbmRhdG9yeSBmb3IKLy8gdGhlIGNvbnRyYWN0cyB0byBvcGVyYXRlLCB1bmxpa2UgdGhlIHJlY2VpdmVyIGZ1bmN0aW9ucywKLy8gd2hpY2ggY2FuIG9ubHkgYmUgZGVmaW5lZCBhdCB0aGUgY29udHJhY3QgYW5kIHRyYWl0IGxldmVsLgovLwovLyBTZWUgdGhlICJDb250cmFjdHMgYW5kIHRyYWl0cyIgc2VjdGlvbiBiZWxvdyBmb3IgbW9yZSBpbmZvLg%3D%3D)
Read more: [Functions](/book/functions).
## Message exchange and communication[](#messaging)
```tact
// On TON, contracts cannot read each other's states and cannot synchronously
// call each other's functions. Instead, the actor model of communication is
// applied — contracts send or receive asynchronous messages that may or may not
// influence each other's state.
//
// Each message is a Cell with a well-defined, complex structure of serialization.
// However, Tact provides you with simple abstractions to send, receive, and
// (de)serialize messages to and from various structures.
//
// Each message has a so-called message body,
// which can be represented by message structs with certain opcodes.
message(123) MyMsg { someVal: Int as uint8 }
// Messages can also omit their bodies, or have them be empty,
// in which case they won't have any opcode and could only be handled
// by the empty message body receiver or "empty receiver" for short.
//
// See the "Contracts and traits" section below for more info.
// Finally, sending messages is not free and requires
// some forward fees to be paid upfront.
fun examples() {
// To keep some amount of nanoToncoins on the balance,
// use nativeReserve() prior to calling message-sending functions:
nativeReserve(ton("0.01"), ReserveAtMost);
// There are many message-sending functions for various cases.
// See the links given right after this code block.
//
// This is most general and simple function to send an internal message:
message(MessageParameters {
// Recipient address.
to: address("UQDtFpEwcFAEcRe5mLVh2N6C0x-_hJEM7W61_JLnSF74p9dz"),
// Optional message body.
body: null, // empty body, no opcodes, nothing
// Some nanoToncoins to send, possibly none.
value: 0, // do not attach any nanoToncoins to the message
// Configure various modes of sending the message in regards to how
// the funds will be charged, how message will be processed, etc.
mode: SendPayFwdFeesSeparately | SendIgnoreErrors,
// Whether to allow this message to bounce back to this contract
// in case the recipient contract doesn't exist or wasn't able to
// process the message.
bounce: true, // to handle messages that bounced back, a special bounced
// receiver function is used. See the "Contracts and traits"
// section below for more info.
});
// To do refunds and forward excess values from the incoming message
// back to the original sender, use the cashback message-sending function:
cashback(sender());
// Note that all message-sending functions only queue the messages when called.
// The actual processing and sending will be done in the next, action phase
// of the transaction, where many messages can fail for various reasons.
//
// For example, if the remaining value from the incoming message was used by
// the first function, the subsequent functions that would try to do the same
// will fail. The optional SendIgnoreErrors flag seen above hides those failures
// and ignores the unprocessed messages. It's not a silver bullet, and you're
// advised to always double-check the message flow in your contracts.
}
// Already bounced messages cannot be sent by any contract and are guaranteed
// to be received only by the current contract that did sent them as internal
// messages first.
//
// Additionally, external messages cannot be sent by the contract,
// only processed by it.
//
// To receive internal messages (bounced or sent directly) and external messages,
// provide corresponding receiver functions. See the "Contracts and traits"
// section below for more info.
//
// To organize child-parent contract message exchange, see the "Jetton contracts"
// section below.
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gT24gVE9OLCBjb250cmFjdHMgY2Fubm90IHJlYWQgZWFjaCBvdGhlcidzIHN0YXRlcyBhbmQgY2Fubm90IHN5bmNocm9ub3VzbHkKLy8gY2FsbCBlYWNoIG90aGVyJ3MgZnVuY3Rpb25zLiBJbnN0ZWFkLCB0aGUgYWN0b3IgbW9kZWwgb2YgY29tbXVuaWNhdGlvbiBpcwovLyBhcHBsaWVkIOKAlCBjb250cmFjdHMgc2VuZCBvciByZWNlaXZlIGFzeW5jaHJvbm91cyBtZXNzYWdlcyB0aGF0IG1heSBvciBtYXkgbm90Ci8vIGluZmx1ZW5jZSBlYWNoIG90aGVyJ3Mgc3RhdGUuCi8vCi8vIEVhY2ggbWVzc2FnZSBpcyBhIENlbGwgd2l0aCBhIHdlbGwtZGVmaW5lZCwgY29tcGxleCBzdHJ1Y3R1cmUgb2Ygc2VyaWFsaXphdGlvbi4KLy8gSG93ZXZlciwgVGFjdCBwcm92aWRlcyB5b3Ugd2l0aCBzaW1wbGUgYWJzdHJhY3Rpb25zIHRvIHNlbmQsIHJlY2VpdmUsIGFuZAovLyAoZGUpc2VyaWFsaXplIG1lc3NhZ2VzIHRvIGFuZCBmcm9tIHZhcmlvdXMgc3RydWN0dXJlcy4KLy8KLy8gRWFjaCBtZXNzYWdlIGhhcyBhIHNvLWNhbGxlZCBtZXNzYWdlIGJvZHksCi8vIHdoaWNoIGNhbiBiZSByZXByZXNlbnRlZCBieSBtZXNzYWdlIHN0cnVjdHMgd2l0aCBjZXJ0YWluIG9wY29kZXMuCm1lc3NhZ2UoMTIzKSBNeU1zZyB7IHNvbWVWYWw6IEludCBhcyB1aW50OCB9CgovLyBNZXNzYWdlcyBjYW4gYWxzbyBvbWl0IHRoZWlyIGJvZGllcywgb3IgaGF2ZSB0aGVtIGJlIGVtcHR5LAovLyBpbiB3aGljaCBjYXNlIHRoZXkgd29uJ3QgaGF2ZSBhbnkgb3Bjb2RlIGFuZCBjb3VsZCBvbmx5IGJlIGhhbmRsZWQKLy8gYnkgdGhlIGVtcHR5IG1lc3NhZ2UgYm9keSByZWNlaXZlciBvciAiZW1wdHkgcmVjZWl2ZXIiIGZvciBzaG9ydC4KLy8KLy8gU2VlIHRoZSAiQ29udHJhY3RzIGFuZCB0cmFpdHMiIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mby4KCi8vIEZpbmFsbHksIHNlbmRpbmcgbWVzc2FnZXMgaXMgbm90IGZyZWUgYW5kIHJlcXVpcmVzCi8vIHNvbWUgZm9yd2FyZCBmZWVzIHRvIGJlIHBhaWQgdXBmcm9udC4KZnVuIGV4YW1wbGVzKCkgewogICAgLy8gVG8ga2VlcCBzb21lIGFtb3VudCBvZiBuYW5vVG9uY29pbnMgb24gdGhlIGJhbGFuY2UsCiAgICAvLyB1c2UgbmF0aXZlUmVzZXJ2ZSgpIHByaW9yIHRvIGNhbGxpbmcgbWVzc2FnZS1zZW5kaW5nIGZ1bmN0aW9uczoKICAgIG5hdGl2ZVJlc2VydmUodG9uKCIwLjAxIiksIFJlc2VydmVBdE1vc3QpOwoKICAgIC8vIFRoZXJlIGFyZSBtYW55IG1lc3NhZ2Utc2VuZGluZyBmdW5jdGlvbnMgZm9yIHZhcmlvdXMgY2FzZXMuCiAgICAvLyBTZWUgdGhlIGxpbmtzIGdpdmVuIHJpZ2h0IGFmdGVyIHRoaXMgY29kZSBibG9jay4KICAgIC8vCiAgICAvLyBUaGlzIGlzIG1vc3QgZ2VuZXJhbCBhbmQgc2ltcGxlIGZ1bmN0aW9uIHRvIHNlbmQgYW4gaW50ZXJuYWwgbWVzc2FnZToKICAgIG1lc3NhZ2UoTWVzc2FnZVBhcmFtZXRlcnMgewogICAgICAgIC8vIFJlY2lwaWVudCBhZGRyZXNzLgogICAgICAgIHRvOiBhZGRyZXNzKCJVUUR0RnBFd2NGQUVjUmU1bUxWaDJONkMweC1faEpFTTdXNjFfSkxuU0Y3NHA5ZHoiKSwKCiAgICAgICAgLy8gT3B0aW9uYWwgbWVzc2FnZSBib2R5LgogICAgICAgIGJvZHk6IG51bGwsIC8vIGVtcHR5IGJvZHksIG5vIG9wY29kZXMsIG5vdGhpbmcKCiAgICAgICAgLy8gU29tZSBuYW5vVG9uY29pbnMgdG8gc2VuZCwgcG9zc2libHkgbm9uZS4KICAgICAgICB2YWx1ZTogMCwgLy8gZG8gbm90IGF0dGFjaCBhbnkgbmFub1RvbmNvaW5zIHRvIHRoZSBtZXNzYWdlCgogICAgICAgIC8vIENvbmZpZ3VyZSB2YXJpb3VzIG1vZGVzIG9mIHNlbmRpbmcgdGhlIG1lc3NhZ2UgaW4gcmVnYXJkcyB0byBob3cKICAgICAgICAvLyB0aGUgZnVuZHMgd2lsbCBiZSBjaGFyZ2VkLCBob3cgbWVzc2FnZSB3aWxsIGJlIHByb2Nlc3NlZCwgZXRjLgogICAgICAgIG1vZGU6IFNlbmRQYXlGd2RGZWVzU2VwYXJhdGVseSB8IFNlbmRJZ25vcmVFcnJvcnMsCgogICAgICAgIC8vIFdoZXRoZXIgdG8gYWxsb3cgdGhpcyBtZXNzYWdlIHRvIGJvdW5jZSBiYWNrIHRvIHRoaXMgY29udHJhY3QKICAgICAgICAvLyBpbiBjYXNlIHRoZSByZWNpcGllbnQgY29udHJhY3QgZG9lc24ndCBleGlzdCBvciB3YXNuJ3QgYWJsZSB0bwogICAgICAgIC8vIHByb2Nlc3MgdGhlIG1lc3NhZ2UuCiAgICAgICAgYm91bmNlOiB0cnVlLCAvLyB0byBoYW5kbGUgbWVzc2FnZXMgdGhhdCBib3VuY2VkIGJhY2ssIGEgc3BlY2lhbCBib3VuY2VkCiAgICAgICAgICAgICAgICAgICAgICAvLyByZWNlaXZlciBmdW5jdGlvbiBpcyB1c2VkLiBTZWUgdGhlICJDb250cmFjdHMgYW5kIHRyYWl0cyIKICAgICAgICAgICAgICAgICAgICAgIC8vIHNlY3Rpb24gYmVsb3cgZm9yIG1vcmUgaW5mby4KICAgIH0pOwoKICAgIC8vIFRvIGRvIHJlZnVuZHMgYW5kIGZvcndhcmQgZXhjZXNzIHZhbHVlcyBmcm9tIHRoZSBpbmNvbWluZyBtZXNzYWdlCiAgICAvLyBiYWNrIHRvIHRoZSBvcmlnaW5hbCBzZW5kZXIsIHVzZSB0aGUgY2FzaGJhY2sgbWVzc2FnZS1zZW5kaW5nIGZ1bmN0aW9uOgogICAgY2FzaGJhY2soc2VuZGVyKCkpOwoKICAgIC8vIE5vdGUgdGhhdCBhbGwgbWVzc2FnZS1zZW5kaW5nIGZ1bmN0aW9ucyBvbmx5IHF1ZXVlIHRoZSBtZXNzYWdlcyB3aGVuIGNhbGxlZC4KICAgIC8vIFRoZSBhY3R1YWwgcHJvY2Vzc2luZyBhbmQgc2VuZGluZyB3aWxsIGJlIGRvbmUgaW4gdGhlIG5leHQsIGFjdGlvbiBwaGFzZQogICAgLy8gb2YgdGhlIHRyYW5zYWN0aW9uLCB3aGVyZSBtYW55IG1lc3NhZ2VzIGNhbiBmYWlsIGZvciB2YXJpb3VzIHJlYXNvbnMuCiAgICAvLwogICAgLy8gRm9yIGV4YW1wbGUsIGlmIHRoZSByZW1haW5pbmcgdmFsdWUgZnJvbSB0aGUgaW5jb21pbmcgbWVzc2FnZSB3YXMgdXNlZCBieQogICAgLy8gdGhlIGZpcnN0IGZ1bmN0aW9uLCB0aGUgc3Vic2VxdWVudCBmdW5jdGlvbnMgdGhhdCB3b3VsZCB0cnkgdG8gZG8gdGhlIHNhbWUKICAgIC8vIHdpbGwgZmFpbC4gVGhlIG9wdGlvbmFsIFNlbmRJZ25vcmVFcnJvcnMgZmxhZyBzZWVuIGFib3ZlIGhpZGVzIHRob3NlIGZhaWx1cmVzCiAgICAvLyBhbmQgaWdub3JlcyB0aGUgdW5wcm9jZXNzZWQgbWVzc2FnZXMuIEl0J3Mgbm90IGEgc2lsdmVyIGJ1bGxldCwgYW5kIHlvdSdyZQogICAgLy8gYWR2aXNlZCB0byBhbHdheXMgZG91YmxlLWNoZWNrIHRoZSBtZXNzYWdlIGZsb3cgaW4geW91ciBjb250cmFjdHMuCn0KCi8vIEFscmVhZHkgYm91bmNlZCBtZXNzYWdlcyBjYW5ub3QgYmUgc2VudCBieSBhbnkgY29udHJhY3QgYW5kIGFyZSBndWFyYW50ZWVkCi8vIHRvIGJlIHJlY2VpdmVkIG9ubHkgYnkgdGhlIGN1cnJlbnQgY29udHJhY3QgdGhhdCBkaWQgc2VudCB0aGVtIGFzIGludGVybmFsCi8vIG1lc3NhZ2VzIGZpcnN0LgovLwovLyBBZGRpdGlvbmFsbHksIGV4dGVybmFsIG1lc3NhZ2VzIGNhbm5vdCBiZSBzZW50IGJ5IHRoZSBjb250cmFjdCwKLy8gb25seSBwcm9jZXNzZWQgYnkgaXQuCi8vCi8vIFRvIHJlY2VpdmUgaW50ZXJuYWwgbWVzc2FnZXMgKGJvdW5jZWQgb3Igc2VudCBkaXJlY3RseSkgYW5kIGV4dGVybmFsIG1lc3NhZ2VzLAovLyBwcm92aWRlIGNvcnJlc3BvbmRpbmcgcmVjZWl2ZXIgZnVuY3Rpb25zLiBTZWUgdGhlICJDb250cmFjdHMgYW5kIHRyYWl0cyIKLy8gc2VjdGlvbiBiZWxvdyBmb3IgbW9yZSBpbmZvLgovLwovLyBUbyBvcmdhbml6ZSBjaGlsZC1wYXJlbnQgY29udHJhY3QgbWVzc2FnZSBleGNoYW5nZSwgc2VlIHRoZSAiSmV0dG9uIGNvbnRyYWN0cyIKLy8gc2VjdGlvbiBiZWxvdy4%3D)
Read more:
* [Receive messages](/book/receive).
* [Send messages](/book/send).
* [Message-sending functions](/book/send#message-sending-functions).
* [Message mode](/book/message-mode).
## Contracts and traits[](#contracts-and-traits)
```tact
// Tact allows you to import Tact and FunC code.
// Additionally, there's a versatile set of standard libraries
// which come bundled in with a compiler, but are not included
// in projects right away.
//
// To import a standard library, instead of specifying a path to a file
// start the import string with @stdlib/.
import "@stdlib/ownable"; // for the Ownable trait
// Traits have the same structure as contracts and are used
// to provide some means of inheritance and common code reuse.
//
// Like contracts, traits can also inherit other traits.
trait MyTrait with Ownable {
owner: Address; // required field from the Ownable trait
// Within traits and contracts, you can define scoped functions
// and only accessible from them or their successors. Those functions
// are often called internal functions.
//
// If you won't be using any contract fields, it's better to define
// such functions as global, i.e., on the top-level.
fun addIfOwner(a: Int, b: Int): Int {
self.requireOwner();
return a + b;
}
// Adding an abstract attribute to the internal function requires us
// to omit their body definitions and demand that from contracts that
// will inherit the trait.
abstract fun trust(msg: MyMsg);
// Adding a virtual attribute to the internal function allows their
// body definitions to be be overridden in the contracts that will
// inherit the trait.
virtual fun verify(msg: MyMsg) {
self.requireOwner();
require(msg.someVal > 42, "Too low!");
}
}
// Contract definitions in Tact conveniently represent smart contracts
// on TON Blockchain. They hold all variables, functions, getters and receivers,
// while providing accessible abstractions for working with them.
contract MyContract(
// Persistent state variables of the contract:
owner: Address, // required field from the Ownable trait
accumulator: Int as uint8,
// Their default or initial values are supplied during deployment.
) with MyTrait, Ownable {
// The internal message receiver is a function that handles messages received
// by this contract on-chain: from other contracts and never from outside.
receive(msg: MyMsg) {
self.requireOwner();
self.accumulator += msg.someVal;
// Send a message back to the sender() with MyMsg
message(MessageParameters {
to: sender(),
value: ton("0.04"),
body: MyMsg{ someVal: self.accumulator }.toCell(),
});
}
// For deployments, it is common to use the following receiver
// often called an "empty receiver", which handles `null` (empty)
// message bodies of internal messages.
receive() {
// Forward the remaining value in the
// incoming message (surplus) back to the sender.
cashback(sender());
}
// The bounced message receiver is a function that handles messages sent
// from this contract and bounced back to it because of a malformed payload or
// some issues on the recipient side.
bounced(msg: bounced) {
// Bounced message bodies are limited by their first 256 bits, which
// means that excluding their 32-bit opcode there are only 224 bits left
// for other contents of MyMsg.
//
// Thus, in message structs prefer to put small important fields first.
require(msg.someVal > 42, "Unexpected bounce!");
self.accumulator = msg.someVal;
}
// The external message receiver is a function that handles messages sent
// to this contract from outside the blockchain. That is often the case
// for user wallets, where apps that present some UI for them have to
// communicate with contracts on chain to perform transfers on their behalf.
external(msg: MyMsg) {
// There is no sender, i.e., calling sender() here won't work.
// Additionally, there are no guarantees that the received message
// is authentic and is not malicious. Therefore, when receiving
// such messages one has to first check the signature to validate the sender,
// and explicitly agree to accept the message and fund its processing
// in the current transaction with acceptMessage() function.
require(msg.someVal > 42, "Nothing short of 42 is allowed!");
self.accumulator = msg.someVal;
acceptMessage();
}
// Getter functions or get methods are special functions that can only
// be called from within this contract or off-chain, and never by other contracts.
// They cannot modify the contract's state and they do not affect its balance.
// The IO analogy would be that they can only "read", not "write".
get fun data(): MyContract {
// This getter returns the current state of the contract's variables,
// which is convenient for tests but not advised for production.
return self;
}
// Finally, for each inherited trait contract may override its virtual internal
// functions and it MUST override its abstract internal functions as to provide
// their defined bodies.
override fun trust(msg: MyMsg) {
require(msg.someVal == 42, "Always bring your towel with you");
}
}
// Message struct with 123 as its 32-bit opcode.
message(123) MyMsg {
someVal: Int as uint8;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gVGFjdCBhbGxvd3MgeW91IHRvIGltcG9ydCBUYWN0IGFuZCBGdW5DIGNvZGUuCi8vIEFkZGl0aW9uYWxseSwgdGhlcmUncyBhIHZlcnNhdGlsZSBzZXQgb2Ygc3RhbmRhcmQgbGlicmFyaWVzCi8vIHdoaWNoIGNvbWUgYnVuZGxlZCBpbiB3aXRoIGEgY29tcGlsZXIsIGJ1dCBhcmUgbm90IGluY2x1ZGVkCi8vIGluIHByb2plY3RzIHJpZ2h0IGF3YXkuCi8vCi8vIFRvIGltcG9ydCBhIHN0YW5kYXJkIGxpYnJhcnksIGluc3RlYWQgb2Ygc3BlY2lmeWluZyBhIHBhdGggdG8gYSBmaWxlCi8vIHN0YXJ0IHRoZSBpbXBvcnQgc3RyaW5nIHdpdGggQHN0ZGxpYi8uCmltcG9ydCAiQHN0ZGxpYi9vd25hYmxlIjsgLy8gZm9yIHRoZSBPd25hYmxlIHRyYWl0CgovLyBUcmFpdHMgaGF2ZSB0aGUgc2FtZSBzdHJ1Y3R1cmUgYXMgY29udHJhY3RzIGFuZCBhcmUgdXNlZAovLyB0byBwcm92aWRlIHNvbWUgbWVhbnMgb2YgaW5oZXJpdGFuY2UgYW5kIGNvbW1vbiBjb2RlIHJldXNlLgovLwovLyBMaWtlIGNvbnRyYWN0cywgdHJhaXRzIGNhbiBhbHNvIGluaGVyaXQgb3RoZXIgdHJhaXRzLgp0cmFpdCBNeVRyYWl0IHdpdGggT3duYWJsZSB7CiAgICBvd25lcjogQWRkcmVzczsgLy8gcmVxdWlyZWQgZmllbGQgZnJvbSB0aGUgT3duYWJsZSB0cmFpdAoKICAgIC8vIFdpdGhpbiB0cmFpdHMgYW5kIGNvbnRyYWN0cywgeW91IGNhbiBkZWZpbmUgc2NvcGVkIGZ1bmN0aW9ucwogICAgLy8gYW5kIG9ubHkgYWNjZXNzaWJsZSBmcm9tIHRoZW0gb3IgdGhlaXIgc3VjY2Vzc29ycy4gVGhvc2UgZnVuY3Rpb25zCiAgICAvLyBhcmUgb2Z0ZW4gY2FsbGVkIGludGVybmFsIGZ1bmN0aW9ucy4KICAgIC8vCiAgICAvLyBJZiB5b3Ugd29uJ3QgYmUgdXNpbmcgYW55IGNvbnRyYWN0IGZpZWxkcywgaXQncyBiZXR0ZXIgdG8gZGVmaW5lCiAgICAvLyBzdWNoIGZ1bmN0aW9ucyBhcyBnbG9iYWwsIGkuZS4sIG9uIHRoZSB0b3AtbGV2ZWwuCiAgICBmdW4gYWRkSWZPd25lcihhOiBJbnQsIGI6IEludCk6IEludCB7CiAgICAgICAgc2VsZi5yZXF1aXJlT3duZXIoKTsKICAgICAgICByZXR1cm4gYSArIGI7CiAgICB9CgogICAgLy8gQWRkaW5nIGFuIGFic3RyYWN0IGF0dHJpYnV0ZSB0byB0aGUgaW50ZXJuYWwgZnVuY3Rpb24gcmVxdWlyZXMgdXMKICAgIC8vIHRvIG9taXQgdGhlaXIgYm9keSBkZWZpbml0aW9ucyBhbmQgZGVtYW5kIHRoYXQgZnJvbSBjb250cmFjdHMgdGhhdAogICAgLy8gd2lsbCBpbmhlcml0IHRoZSB0cmFpdC4KICAgIGFic3RyYWN0IGZ1biB0cnVzdChtc2c6IE15TXNnKTsKCiAgICAvLyBBZGRpbmcgYSB2aXJ0dWFsIGF0dHJpYnV0ZSB0byB0aGUgaW50ZXJuYWwgZnVuY3Rpb24gYWxsb3dzIHRoZWlyCiAgICAvLyBib2R5IGRlZmluaXRpb25zIHRvIGJlIGJlIG92ZXJyaWRkZW4gaW4gdGhlIGNvbnRyYWN0cyB0aGF0IHdpbGwKICAgIC8vIGluaGVyaXQgdGhlIHRyYWl0LgogICAgdmlydHVhbCBmdW4gdmVyaWZ5KG1zZzogTXlNc2cpIHsKICAgICAgICBzZWxmLnJlcXVpcmVPd25lcigpOwogICAgICAgIHJlcXVpcmUobXNnLnNvbWVWYWwgPiA0MiwgIlRvbyBsb3chIik7CiAgICB9Cn0KCi8vIENvbnRyYWN0IGRlZmluaXRpb25zIGluIFRhY3QgY29udmVuaWVudGx5IHJlcHJlc2VudCBzbWFydCBjb250cmFjdHMKLy8gb24gVE9OIEJsb2NrY2hhaW4uIFRoZXkgaG9sZCBhbGwgdmFyaWFibGVzLCBmdW5jdGlvbnMsIGdldHRlcnMgYW5kIHJlY2VpdmVycywKLy8gd2hpbGUgcHJvdmlkaW5nIGFjY2Vzc2libGUgYWJzdHJhY3Rpb25zIGZvciB3b3JraW5nIHdpdGggdGhlbS4KY29udHJhY3QgTXlDb250cmFjdCgKICAgIC8vIFBlcnNpc3RlbnQgc3RhdGUgdmFyaWFibGVzIG9mIHRoZSBjb250cmFjdDoKICAgIG93bmVyOiBBZGRyZXNzLCAvLyByZXF1aXJlZCBmaWVsZCBmcm9tIHRoZSBPd25hYmxlIHRyYWl0CiAgICBhY2N1bXVsYXRvcjogSW50IGFzIHVpbnQ4LAogICAgLy8gVGhlaXIgZGVmYXVsdCBvciBpbml0aWFsIHZhbHVlcyBhcmUgc3VwcGxpZWQgZHVyaW5nIGRlcGxveW1lbnQuCikgd2l0aCBNeVRyYWl0LCBPd25hYmxlIHsKCiAgICAvLyBUaGUgaW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciBpcyBhIGZ1bmN0aW9uIHRoYXQgaGFuZGxlcyBtZXNzYWdlcyByZWNlaXZlZAogICAgLy8gYnkgdGhpcyBjb250cmFjdCBvbi1jaGFpbjogZnJvbSBvdGhlciBjb250cmFjdHMgYW5kIG5ldmVyIGZyb20gb3V0c2lkZS4KICAgIHJlY2VpdmUobXNnOiBNeU1zZykgewogICAgICAgIHNlbGYucmVxdWlyZU93bmVyKCk7CiAgICAgICAgc2VsZi5hY2N1bXVsYXRvciArPSBtc2cuc29tZVZhbDsKCiAgICAgICAgLy8gU2VuZCBhIG1lc3NhZ2UgYmFjayB0byB0aGUgc2VuZGVyKCkgd2l0aCBNeU1zZwogICAgICAgIG1lc3NhZ2UoTWVzc2FnZVBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VuZGVyKCksCiAgICAgICAgICAgIHZhbHVlOiB0b24oIjAuMDQiKSwKICAgICAgICAgICAgYm9keTogTXlNc2d7IHNvbWVWYWw6IHNlbGYuYWNjdW11bGF0b3IgfS50b0NlbGwoKSwKICAgICAgICB9KTsKICAgIH0KCiAgICAvLyBGb3IgZGVwbG95bWVudHMsIGl0IGlzIGNvbW1vbiB0byB1c2UgdGhlIGZvbGxvd2luZyByZWNlaXZlcgogICAgLy8gb2Z0ZW4gY2FsbGVkIGFuICJlbXB0eSByZWNlaXZlciIsIHdoaWNoIGhhbmRsZXMgYG51bGxgIChlbXB0eSkKICAgIC8vIG1lc3NhZ2UgYm9kaWVzIG9mIGludGVybmFsIG1lc3NhZ2VzLgogICAgcmVjZWl2ZSgpIHsKICAgICAgICAvLyBGb3J3YXJkIHRoZSByZW1haW5pbmcgdmFsdWUgaW4gdGhlCiAgICAgICAgLy8gaW5jb21pbmcgbWVzc2FnZSAoc3VycGx1cykgYmFjayB0byB0aGUgc2VuZGVyLgogICAgICAgIGNhc2hiYWNrKHNlbmRlcigpKTsKICAgIH0KCiAgICAvLyBUaGUgYm91bmNlZCBtZXNzYWdlIHJlY2VpdmVyIGlzIGEgZnVuY3Rpb24gdGhhdCBoYW5kbGVzIG1lc3NhZ2VzIHNlbnQKICAgIC8vIGZyb20gdGhpcyBjb250cmFjdCBhbmQgYm91bmNlZCBiYWNrIHRvIGl0IGJlY2F1c2Ugb2YgYSBtYWxmb3JtZWQgcGF5bG9hZCBvcgogICAgLy8gc29tZSBpc3N1ZXMgb24gdGhlIHJlY2lwaWVudCBzaWRlLgogICAgYm91bmNlZChtc2c6IGJvdW5jZWQ8TXlNc2c%2BKSB7CiAgICAgICAgLy8gQm91bmNlZCBtZXNzYWdlIGJvZGllcyBhcmUgbGltaXRlZCBieSB0aGVpciBmaXJzdCAyNTYgYml0cywgd2hpY2gKICAgICAgICAvLyBtZWFucyB0aGF0IGV4Y2x1ZGluZyB0aGVpciAzMi1iaXQgb3Bjb2RlIHRoZXJlIGFyZSBvbmx5IDIyNCBiaXRzIGxlZnQKICAgICAgICAvLyBmb3Igb3RoZXIgY29udGVudHMgb2YgTXlNc2cuCiAgICAgICAgLy8KICAgICAgICAvLyBUaHVzLCBpbiBtZXNzYWdlIHN0cnVjdHMgcHJlZmVyIHRvIHB1dCBzbWFsbCBpbXBvcnRhbnQgZmllbGRzIGZpcnN0LgogICAgICAgIHJlcXVpcmUobXNnLnNvbWVWYWwgPiA0MiwgIlVuZXhwZWN0ZWQgYm91bmNlISIpOwogICAgICAgIHNlbGYuYWNjdW11bGF0b3IgPSBtc2cuc29tZVZhbDsKICAgIH0KCiAgICAvLyBUaGUgZXh0ZXJuYWwgbWVzc2FnZSByZWNlaXZlciBpcyBhIGZ1bmN0aW9uIHRoYXQgaGFuZGxlcyBtZXNzYWdlcyBzZW50CiAgICAvLyB0byB0aGlzIGNvbnRyYWN0IGZyb20gb3V0c2lkZSB0aGUgYmxvY2tjaGFpbi4gVGhhdCBpcyBvZnRlbiB0aGUgY2FzZQogICAgLy8gZm9yIHVzZXIgd2FsbGV0cywgd2hlcmUgYXBwcyB0aGF0IHByZXNlbnQgc29tZSBVSSBmb3IgdGhlbSBoYXZlIHRvCiAgICAvLyBjb21tdW5pY2F0ZSB3aXRoIGNvbnRyYWN0cyBvbiBjaGFpbiB0byBwZXJmb3JtIHRyYW5zZmVycyBvbiB0aGVpciBiZWhhbGYuCiAgICBleHRlcm5hbChtc2c6IE15TXNnKSB7CiAgICAgICAgLy8gVGhlcmUgaXMgbm8gc2VuZGVyLCBpLmUuLCBjYWxsaW5nIHNlbmRlcigpIGhlcmUgd29uJ3Qgd29yay4KICAgICAgICAvLyBBZGRpdGlvbmFsbHksIHRoZXJlIGFyZSBubyBndWFyYW50ZWVzIHRoYXQgdGhlIHJlY2VpdmVkIG1lc3NhZ2UKICAgICAgICAvLyBpcyBhdXRoZW50aWMgYW5kIGlzIG5vdCBtYWxpY2lvdXMuIFRoZXJlZm9yZSwgd2hlbiByZWNlaXZpbmcKICAgICAgICAvLyBzdWNoIG1lc3NhZ2VzIG9uZSBoYXMgdG8gZmlyc3QgY2hlY2sgdGhlIHNpZ25hdHVyZSB0byB2YWxpZGF0ZSB0aGUgc2VuZGVyLAogICAgICAgIC8vIGFuZCBleHBsaWNpdGx5IGFncmVlIHRvIGFjY2VwdCB0aGUgbWVzc2FnZSBhbmQgZnVuZCBpdHMgcHJvY2Vzc2luZwogICAgICAgIC8vIGluIHRoZSBjdXJyZW50IHRyYW5zYWN0aW9uIHdpdGggYWNjZXB0TWVzc2FnZSgpIGZ1bmN0aW9uLgogICAgICAgIHJlcXVpcmUobXNnLnNvbWVWYWwgPiA0MiwgIk5vdGhpbmcgc2hvcnQgb2YgNDIgaXMgYWxsb3dlZCEiKTsKICAgICAgICBzZWxmLmFjY3VtdWxhdG9yID0gbXNnLnNvbWVWYWw7CiAgICAgICAgYWNjZXB0TWVzc2FnZSgpOwogICAgfQoKICAgIC8vIEdldHRlciBmdW5jdGlvbnMgb3IgZ2V0IG1ldGhvZHMgYXJlIHNwZWNpYWwgZnVuY3Rpb25zIHRoYXQgY2FuIG9ubHkKICAgIC8vIGJlIGNhbGxlZCBmcm9tIHdpdGhpbiB0aGlzIGNvbnRyYWN0IG9yIG9mZi1jaGFpbiwgYW5kIG5ldmVyIGJ5IG90aGVyIGNvbnRyYWN0cy4KICAgIC8vIFRoZXkgY2Fubm90IG1vZGlmeSB0aGUgY29udHJhY3QncyBzdGF0ZSBhbmQgdGhleSBkbyBub3QgYWZmZWN0IGl0cyBiYWxhbmNlLgogICAgLy8gVGhlIElPIGFuYWxvZ3kgd291bGQgYmUgdGhhdCB0aGV5IGNhbiBvbmx5ICJyZWFkIiwgbm90ICJ3cml0ZSIuCiAgICBnZXQgZnVuIGRhdGEoKTogTXlDb250cmFjdCB7CiAgICAgICAgLy8gVGhpcyBnZXR0ZXIgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgY29udHJhY3QncyB2YXJpYWJsZXMsCiAgICAgICAgLy8gd2hpY2ggaXMgY29udmVuaWVudCBmb3IgdGVzdHMgYnV0IG5vdCBhZHZpc2VkIGZvciBwcm9kdWN0aW9uLgogICAgICAgIHJldHVybiBzZWxmOwogICAgfQoKICAgIC8vIEZpbmFsbHksIGZvciBlYWNoIGluaGVyaXRlZCB0cmFpdCBjb250cmFjdCBtYXkgb3ZlcnJpZGUgaXRzIHZpcnR1YWwgaW50ZXJuYWwKICAgIC8vIGZ1bmN0aW9ucyBhbmQgaXQgTVVTVCBvdmVycmlkZSBpdHMgYWJzdHJhY3QgaW50ZXJuYWwgZnVuY3Rpb25zIGFzIHRvIHByb3ZpZGUKICAgIC8vIHRoZWlyIGRlZmluZWQgYm9kaWVzLgogICAgb3ZlcnJpZGUgZnVuIHRydXN0KG1zZzogTXlNc2cpIHsKICAgICAgICByZXF1aXJlKG1zZy5zb21lVmFsID09IDQyLCAiQWx3YXlzIGJyaW5nIHlvdXIgdG93ZWwgd2l0aCB5b3UiKTsKICAgIH0KfQoKLy8gTWVzc2FnZSBzdHJ1Y3Qgd2l0aCAxMjMgYXMgaXRzIDMyLWJpdCBvcGNvZGUuCm1lc3NhZ2UoMTIzKSBNeU1zZyB7CiAgICBzb21lVmFsOiBJbnQgYXMgdWludDg7Cn0%3D)
Read more: [Contracts](/book/contracts).
## Constants[](#constants)
```tact
// Global, top-level constants.
// Type ascription is mandatory.
const MY_CONSTANT: Int =
ascii("⚡"); // expressions are computed at compile-time
// Trait-level constants.
trait MyTrait {
const I_AM_ON_THE_TRAIT_LEVEL: Int = 420;
// On the trait-level, you can make constants abstract,
// which requires the contracts that inherit this trait
// to override those constants with some values.
abstract const OVERRIDE_ME: Int;
// Virtual constants allow overrides, but do not require them.
virtual const YOU_CAN_OVERRIDE_ME: Int = crc32("babecafe");
}
// Contract-level constants.
contract MyContract() with MyTrait {
const iAmOnTheContractLevel: Int = 4200;
// Because this contract inherits from MyTrait,
// the I_AM_ON_THE_TRAIT_LEVEL constant is also in scope of this contract,
// but we cannot override it.
// However, we can override the virtual constant.
override const YOU_CAN_OVERRIDE_ME: Int = crc32("deadbeef");
// And we MUST override and define the value of the abstract constant.
override const OVERRIDE_ME: Int = ton("0.5");
}
// All constants are inlined, i.e., their values are embedded in the resulting
// code in all places where their values are referenced in Tact code.
//
// The main difference is the scope — global can be referenced
// from anywhere, while contract and trait-level constants are
// only accessible within them via `self` references.
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gR2xvYmFsLCB0b3AtbGV2ZWwgY29uc3RhbnRzLgovLyBUeXBlIGFzY3JpcHRpb24gaXMgbWFuZGF0b3J5Lgpjb25zdCBNWV9DT05TVEFOVDogSW50ID0KICAgIGFzY2lpKCLimqEiKTsgLy8gZXhwcmVzc2lvbnMgYXJlIGNvbXB1dGVkIGF0IGNvbXBpbGUtdGltZQoKLy8gVHJhaXQtbGV2ZWwgY29uc3RhbnRzLgp0cmFpdCBNeVRyYWl0IHsKICAgIGNvbnN0IElfQU1fT05fVEhFX1RSQUlUX0xFVkVMOiBJbnQgPSA0MjA7CgogICAgLy8gT24gdGhlIHRyYWl0LWxldmVsLCB5b3UgY2FuIG1ha2UgY29uc3RhbnRzIGFic3RyYWN0LAogICAgLy8gd2hpY2ggcmVxdWlyZXMgdGhlIGNvbnRyYWN0cyB0aGF0IGluaGVyaXQgdGhpcyB0cmFpdAogICAgLy8gdG8gb3ZlcnJpZGUgdGhvc2UgY29uc3RhbnRzIHdpdGggc29tZSB2YWx1ZXMuCiAgICBhYnN0cmFjdCBjb25zdCBPVkVSUklERV9NRTogSW50OwoKICAgIC8vIFZpcnR1YWwgY29uc3RhbnRzIGFsbG93IG92ZXJyaWRlcywgYnV0IGRvIG5vdCByZXF1aXJlIHRoZW0uCiAgICB2aXJ0dWFsIGNvbnN0IFlPVV9DQU5fT1ZFUlJJREVfTUU6IEludCA9IGNyYzMyKCJiYWJlY2FmZSIpOwp9CgovLyBDb250cmFjdC1sZXZlbCBjb25zdGFudHMuCmNvbnRyYWN0IE15Q29udHJhY3QoKSB3aXRoIE15VHJhaXQgewogICAgY29uc3QgaUFtT25UaGVDb250cmFjdExldmVsOiBJbnQgPSA0MjAwOwoKICAgIC8vIEJlY2F1c2UgdGhpcyBjb250cmFjdCBpbmhlcml0cyBmcm9tIE15VHJhaXQsCiAgICAvLyB0aGUgSV9BTV9PTl9USEVfVFJBSVRfTEVWRUwgY29uc3RhbnQgaXMgYWxzbyBpbiBzY29wZSBvZiB0aGlzIGNvbnRyYWN0LAogICAgLy8gYnV0IHdlIGNhbm5vdCBvdmVycmlkZSBpdC4KCiAgICAvLyBIb3dldmVyLCB3ZSBjYW4gb3ZlcnJpZGUgdGhlIHZpcnR1YWwgY29uc3RhbnQuCiAgICBvdmVycmlkZSBjb25zdCBZT1VfQ0FOX09WRVJSSURFX01FOiBJbnQgPSBjcmMzMigiZGVhZGJlZWYiKTsKCiAgICAvLyBBbmQgd2UgTVVTVCBvdmVycmlkZSBhbmQgZGVmaW5lIHRoZSB2YWx1ZSBvZiB0aGUgYWJzdHJhY3QgY29uc3RhbnQuCiAgICBvdmVycmlkZSBjb25zdCBPVkVSUklERV9NRTogSW50ID0gdG9uKCIwLjUiKTsKfQoKLy8gQWxsIGNvbnN0YW50cyBhcmUgaW5saW5lZCwgaS5lLiwgdGhlaXIgdmFsdWVzIGFyZSBlbWJlZGRlZCBpbiB0aGUgcmVzdWx0aW5nCi8vIGNvZGUgaW4gYWxsIHBsYWNlcyB3aGVyZSB0aGVpciB2YWx1ZXMgYXJlIHJlZmVyZW5jZWQgaW4gVGFjdCBjb2RlLgovLwovLyBUaGUgbWFpbiBkaWZmZXJlbmNlIGlzIHRoZSBzY29wZSDigJQgZ2xvYmFsIGNhbiBiZSByZWZlcmVuY2VkCi8vIGZyb20gYW55d2hlcmUsIHdoaWxlIGNvbnRyYWN0IGFuZCB0cmFpdC1sZXZlbCBjb25zdGFudHMgYXJlCi8vIG9ubHkgYWNjZXNzaWJsZSB3aXRoaW4gdGhlbSB2aWEgYHNlbGZgIHJlZmVyZW5jZXMu)
Read more: [Constants](/book/constants).
## Persistent state[](#state)
```tact
// Contracts can define state variables that persist between contract calls,
// and thus commonly referred to as storage variables.
// Contracts in TON pay rent in proportion to the amount of persistent space
// they consume, so compact representations via serialization are encouraged.
// Unlike variables, constants do not consume space in the persistent state.
contract StateActor(
// Persistent state variables
oneByte: Int as uint8, // ranges from -128 to 127
twoBytes: Int as int16, // ranges from -32,768 to 32,767
currency: Int as coins, // variable bit-width format, which occupies
// between 4 and 124 bits
// and ranges from 0 to 2^120 - 1
) {
receive() {
// Serialization to smaller values only applies for the state between
// transactions and incoming or outgoing message bodies.
// This is because at runtime everything is computed
// at their maximum capacity and all integers are assumed to
// be 257-bit signed ones.
//
// That is, the following would not cause any runtime overflows,
// but will throw an out of range error only after the execution of
// this receiver is completed.
self.oneByte = -1; // this won't fail immediately
self.oneByte = 500; // and this won't fail right away either
} // only here, at the end of the compute phase,
// would an error be thrown with exit code 5:
// Integer out of expected range
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gQ29udHJhY3RzIGNhbiBkZWZpbmUgc3RhdGUgdmFyaWFibGVzIHRoYXQgcGVyc2lzdCBiZXR3ZWVuIGNvbnRyYWN0IGNhbGxzLAovLyBhbmQgdGh1cyBjb21tb25seSByZWZlcnJlZCB0byBhcyBzdG9yYWdlIHZhcmlhYmxlcy4KLy8gQ29udHJhY3RzIGluIFRPTiBwYXkgcmVudCBpbiBwcm9wb3J0aW9uIHRvIHRoZSBhbW91bnQgb2YgcGVyc2lzdGVudCBzcGFjZQovLyB0aGV5IGNvbnN1bWUsIHNvIGNvbXBhY3QgcmVwcmVzZW50YXRpb25zIHZpYSBzZXJpYWxpemF0aW9uIGFyZSBlbmNvdXJhZ2VkLgovLyBVbmxpa2UgdmFyaWFibGVzLCBjb25zdGFudHMgZG8gbm90IGNvbnN1bWUgc3BhY2UgaW4gdGhlIHBlcnNpc3RlbnQgc3RhdGUuCgpjb250cmFjdCBTdGF0ZUFjdG9yKAogICAgLy8gUGVyc2lzdGVudCBzdGF0ZSB2YXJpYWJsZXMKICAgIG9uZUJ5dGU6IEludCBhcyB1aW50OCwgIC8vIHJhbmdlcyBmcm9tIC0xMjggdG8gMTI3CiAgICB0d29CeXRlczogSW50IGFzIGludDE2LCAvLyByYW5nZXMgZnJvbSAtMzIsNzY4IHRvIDMyLDc2NwogICAgY3VycmVuY3k6IEludCBhcyBjb2lucywgLy8gdmFyaWFibGUgYml0LXdpZHRoIGZvcm1hdCwgd2hpY2ggb2NjdXBpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJldHdlZW4gNCBhbmQgMTI0IGJpdHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFuZCByYW5nZXMgZnJvbSAwIHRvIDJeMTIwIC0gMQopIHsKCiAgICByZWNlaXZlKCkgewogICAgICAgIC8vIFNlcmlhbGl6YXRpb24gdG8gc21hbGxlciB2YWx1ZXMgb25seSBhcHBsaWVzIGZvciB0aGUgc3RhdGUgYmV0d2VlbgogICAgICAgIC8vIHRyYW5zYWN0aW9ucyBhbmQgaW5jb21pbmcgb3Igb3V0Z29pbmcgbWVzc2FnZSBib2RpZXMuCiAgICAgICAgLy8gVGhpcyBpcyBiZWNhdXNlIGF0IHJ1bnRpbWUgZXZlcnl0aGluZyBpcyBjb21wdXRlZAogICAgICAgIC8vIGF0IHRoZWlyIG1heGltdW0gY2FwYWNpdHkgYW5kIGFsbCBpbnRlZ2VycyBhcmUgYXNzdW1lZCB0bwogICAgICAgIC8vIGJlIDI1Ny1iaXQgc2lnbmVkIG9uZXMuCiAgICAgICAgLy8KICAgICAgICAvLyBUaGF0IGlzLCB0aGUgZm9sbG93aW5nIHdvdWxkIG5vdCBjYXVzZSBhbnkgcnVudGltZSBvdmVyZmxvd3MsCiAgICAgICAgLy8gYnV0IHdpbGwgdGhyb3cgYW4gb3V0IG9mIHJhbmdlIGVycm9yIG9ubHkgYWZ0ZXIgdGhlIGV4ZWN1dGlvbiBvZgogICAgICAgIC8vIHRoaXMgcmVjZWl2ZXIgaXMgY29tcGxldGVkLgogICAgICAgIHNlbGYub25lQnl0ZSA9IC0xOyAgLy8gdGhpcyB3b24ndCBmYWlsIGltbWVkaWF0ZWx5CiAgICAgICAgc2VsZi5vbmVCeXRlID0gNTAwOyAvLyBhbmQgdGhpcyB3b24ndCBmYWlsIHJpZ2h0IGF3YXkgZWl0aGVyCgogICAgfSAvLyBvbmx5IGhlcmUsIGF0IHRoZSBlbmQgb2YgdGhlIGNvbXB1dGUgcGhhc2UsCiAgICAgIC8vIHdvdWxkIGFuIGVycm9yIGJlIHRocm93biB3aXRoIGV4aXQgY29kZSA1OgogICAgICAvLyBJbnRlZ2VyIG91dCBvZiBleHBlY3RlZCByYW5nZQp9)
Read more: [Persistent state variables](/book/contracts#variables).
## Testing and debugging[](#debug)
```tact
fun showcase() {
// An exit code is an integer that indicates whether the transaction
// was successful and, if not — holds the code of the exception that occurred.
//
// They are the simplest litmus tests for your contracts,
// indicating what happened and, if you are lucky, where, and why.
try {
dump(
beginCell()
.storeInt(0, 250)
.storeInt(0, 250)
.storeInt(0, 250)
.storeInt(0, 250)
.storeUint(0, 24) // oh no, we're trying to store 1024 bits,
// while cells can only store up to 1023 bits
);
} catch (exitCode) {
// exitCode is 8, which means the cell overflow has happened somewhere.
// However, there is no clear indication there just from the code alone —
// you need to either view transaction logs or know many pitfalls in advance.
//
// Additionally, runtime computations aren't free and require gas to be spent.
// The catch block can revert the state before the try block,
// but it cannot revert the gas spent for computations in the try block.
}
// Contrary to this reactive approach, we can be proactive and state
// our expectations upfront with require() function.
// It will also throw an exit code, but this time we can map that exit code
// onto the error message and trace our way back to the this call to require().
require(now() >= 1000, "We're too early, now() is less than 1000");
// Sometimes, its also helpful to log the events as they unfold to view
// the data off-chain. Use the emit() message-sending function for this.
emit("Doing X, then Y, currently at R".asComment());
}
// Those tools are handy, but they are not enough.
// To fully understand what went wrong, you might need to read the TON Virtual
// Machine (TVM) execution logs when running contracts in the Sandbox.
// And to ensure that encountered issues won't happen again, do write tests
// in Tact and TypeScript using the Sandbox + Jest toolkit provided by
// the Blueprint framework or tact-template.
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gQW4gZXhpdCBjb2RlIGlzIGFuIGludGVnZXIgdGhhdCBpbmRpY2F0ZXMgd2hldGhlciB0aGUgdHJhbnNhY3Rpb24KICAgIC8vIHdhcyBzdWNjZXNzZnVsIGFuZCwgaWYgbm90IOKAlCBob2xkcyB0aGUgY29kZSBvZiB0aGUgZXhjZXB0aW9uIHRoYXQgb2NjdXJyZWQuCiAgICAvLwogICAgLy8gVGhleSBhcmUgdGhlIHNpbXBsZXN0IGxpdG11cyB0ZXN0cyBmb3IgeW91ciBjb250cmFjdHMsCiAgICAvLyBpbmRpY2F0aW5nIHdoYXQgaGFwcGVuZWQgYW5kLCBpZiB5b3UgYXJlIGx1Y2t5LCB3aGVyZSwgYW5kIHdoeS4KICAgIHRyeSB7CiAgICAgICAgZHVtcCgKICAgICAgICAgICAgYmVnaW5DZWxsKCkKICAgICAgICAgICAgLnN0b3JlSW50KDAsIDI1MCkKICAgICAgICAgICAgLnN0b3JlSW50KDAsIDI1MCkKICAgICAgICAgICAgLnN0b3JlSW50KDAsIDI1MCkKICAgICAgICAgICAgLnN0b3JlSW50KDAsIDI1MCkKICAgICAgICAgICAgLnN0b3JlVWludCgwLCAyNCkgLy8gb2ggbm8sIHdlJ3JlIHRyeWluZyB0byBzdG9yZSAxMDI0IGJpdHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdoaWxlIGNlbGxzIGNhbiBvbmx5IHN0b3JlIHVwIHRvIDEwMjMgYml0cwogICAgICAgICk7CiAgICB9IGNhdGNoIChleGl0Q29kZSkgewogICAgICAgIC8vIGV4aXRDb2RlIGlzIDgsIHdoaWNoIG1lYW5zIHRoZSBjZWxsIG92ZXJmbG93IGhhcyBoYXBwZW5lZCBzb21ld2hlcmUuCiAgICAgICAgLy8gSG93ZXZlciwgdGhlcmUgaXMgbm8gY2xlYXIgaW5kaWNhdGlvbiB0aGVyZSBqdXN0IGZyb20gdGhlIGNvZGUgYWxvbmUg4oCUCiAgICAgICAgLy8geW91IG5lZWQgdG8gZWl0aGVyIHZpZXcgdHJhbnNhY3Rpb24gbG9ncyBvciBrbm93IG1hbnkgcGl0ZmFsbHMgaW4gYWR2YW5jZS4KICAgICAgICAvLwogICAgICAgIC8vIEFkZGl0aW9uYWxseSwgcnVudGltZSBjb21wdXRhdGlvbnMgYXJlbid0IGZyZWUgYW5kIHJlcXVpcmUgZ2FzIHRvIGJlIHNwZW50LgogICAgICAgIC8vIFRoZSBjYXRjaCBibG9jayBjYW4gcmV2ZXJ0IHRoZSBzdGF0ZSBiZWZvcmUgdGhlIHRyeSBibG9jaywKICAgICAgICAvLyBidXQgaXQgY2Fubm90IHJldmVydCB0aGUgZ2FzIHNwZW50IGZvciBjb21wdXRhdGlvbnMgaW4gdGhlIHRyeSBibG9jay4KICAgIH0KCiAgICAvLyBDb250cmFyeSB0byB0aGlzIHJlYWN0aXZlIGFwcHJvYWNoLCB3ZSBjYW4gYmUgcHJvYWN0aXZlIGFuZCBzdGF0ZQogICAgLy8gb3VyIGV4cGVjdGF0aW9ucyB1cGZyb250IHdpdGggcmVxdWlyZSgpIGZ1bmN0aW9uLgogICAgLy8gSXQgd2lsbCBhbHNvIHRocm93IGFuIGV4aXQgY29kZSwgYnV0IHRoaXMgdGltZSB3ZSBjYW4gbWFwIHRoYXQgZXhpdCBjb2RlCiAgICAvLyBvbnRvIHRoZSBlcnJvciBtZXNzYWdlIGFuZCB0cmFjZSBvdXIgd2F5IGJhY2sgdG8gdGhlIHRoaXMgY2FsbCB0byByZXF1aXJlKCkuCiAgICByZXF1aXJlKG5vdygpID49IDEwMDAsICJXZSdyZSB0b28gZWFybHksIG5vdygpIGlzIGxlc3MgdGhhbiAxMDAwIik7CgogICAgLy8gU29tZXRpbWVzLCBpdHMgYWxzbyBoZWxwZnVsIHRvIGxvZyB0aGUgZXZlbnRzIGFzIHRoZXkgdW5mb2xkIHRvIHZpZXcKICAgIC8vIHRoZSBkYXRhIG9mZi1jaGFpbi4gVXNlIHRoZSBlbWl0KCkgbWVzc2FnZS1zZW5kaW5nIGZ1bmN0aW9uIGZvciB0aGlzLgogICAgZW1pdCgiRG9pbmcgWCwgdGhlbiBZLCBjdXJyZW50bHkgYXQgUiIuYXNDb21tZW50KCkpOwp9CgovLyBUaG9zZSB0b29scyBhcmUgaGFuZHksIGJ1dCB0aGV5IGFyZSBub3QgZW5vdWdoLgovLyBUbyBmdWxseSB1bmRlcnN0YW5kIHdoYXQgd2VudCB3cm9uZywgeW91IG1pZ2h0IG5lZWQgdG8gcmVhZCB0aGUgVE9OIFZpcnR1YWwKLy8gTWFjaGluZSAoVFZNKSBleGVjdXRpb24gbG9ncyB3aGVuIHJ1bm5pbmcgY29udHJhY3RzIGluIHRoZSBTYW5kYm94LgovLyBBbmQgdG8gZW5zdXJlIHRoYXQgZW5jb3VudGVyZWQgaXNzdWVzIHdvbid0IGhhcHBlbiBhZ2FpbiwgZG8gd3JpdGUgdGVzdHMKLy8gaW4gVGFjdCBhbmQgVHlwZVNjcmlwdCB1c2luZyB0aGUgU2FuZGJveCArIEplc3QgdG9vbGtpdCBwcm92aWRlZCBieQovLyB0aGUgQmx1ZXByaW50IGZyYW1ld29yayBvciB0YWN0LXRlbXBsYXRlLg%3D%3D)
Read more:
* [Debugging and testing](/book/debug).
* [Exit codes](/book/exit-codes).
* [Gas best practices](/book/gas-best-practices).
* [Security best practices](/book/security-best-practices).
* [Transaction retracer on retracer.ton.org](https://retracer.ton.org/).
* [Blueprint framework on GitHub](https://github.com/ton-org/blueprint).
* [tact-template on GitHub](https://github.com/tact-lang/tact-template).
## Contract deployment[](#deploy)
```tact
fun showcase() {
// Contract deployment is done by sending messages. For deployments,
// one must send the new contract's initial state, i.e.,
// its initial code and initial data, to its Address,
// which is deterministically obtained from the initial state.
deploy(DeployParameters {
// Use initOf expression to provide initial code and data
init: initOf MyContract(),
// Attaching 1 Toncoin, which will be used to pay various fees
value: ton("1"),
// Notice that we do not need to explicitly specify the Address.
// That's because it will be computed on the fly from the initial package.
});
}
// However, before your contracts can start deploying other contracts on-chain,
// it is common to first send an external message to your TON wallet from off-chain.
// Then, your wallet will be the contract that deploys the target one.
// An empty contract needed for the showcase above to work.
contract MyContract() {}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIHNob3djYXNlKCkgewogICAgLy8gQ29udHJhY3QgZGVwbG95bWVudCBpcyBkb25lIGJ5IHNlbmRpbmcgbWVzc2FnZXMuIEZvciBkZXBsb3ltZW50cywKICAgIC8vIG9uZSBtdXN0IHNlbmQgdGhlIG5ldyBjb250cmFjdCdzIGluaXRpYWwgc3RhdGUsIGkuZS4sCiAgICAvLyBpdHMgaW5pdGlhbCBjb2RlIGFuZCBpbml0aWFsIGRhdGEsIHRvIGl0cyBBZGRyZXNzLAogICAgLy8gd2hpY2ggaXMgZGV0ZXJtaW5pc3RpY2FsbHkgb2J0YWluZWQgZnJvbSB0aGUgaW5pdGlhbCBzdGF0ZS4KICAgIGRlcGxveShEZXBsb3lQYXJhbWV0ZXJzIHsKICAgICAgICAvLyBVc2UgaW5pdE9mIGV4cHJlc3Npb24gdG8gcHJvdmlkZSBpbml0aWFsIGNvZGUgYW5kIGRhdGEKICAgICAgICBpbml0OiBpbml0T2YgTXlDb250cmFjdCgpLAogICAgICAgIC8vIEF0dGFjaGluZyAxIFRvbmNvaW4sIHdoaWNoIHdpbGwgYmUgdXNlZCB0byBwYXkgdmFyaW91cyBmZWVzCiAgICAgICAgdmFsdWU6IHRvbigiMSIpLAogICAgICAgIC8vIE5vdGljZSB0aGF0IHdlIGRvIG5vdCBuZWVkIHRvIGV4cGxpY2l0bHkgc3BlY2lmeSB0aGUgQWRkcmVzcy4KICAgICAgICAvLyBUaGF0J3MgYmVjYXVzZSBpdCB3aWxsIGJlIGNvbXB1dGVkIG9uIHRoZSBmbHkgZnJvbSB0aGUgaW5pdGlhbCBwYWNrYWdlLgogICAgfSk7Cn0KCi8vIEhvd2V2ZXIsIGJlZm9yZSB5b3VyIGNvbnRyYWN0cyBjYW4gc3RhcnQgZGVwbG95aW5nIG90aGVyIGNvbnRyYWN0cyBvbi1jaGFpbiwKLy8gaXQgaXMgY29tbW9uIHRvIGZpcnN0IHNlbmQgYW4gZXh0ZXJuYWwgbWVzc2FnZSB0byB5b3VyIFRPTiB3YWxsZXQgZnJvbSBvZmYtY2hhaW4uCi8vIFRoZW4sIHlvdXIgd2FsbGV0IHdpbGwgYmUgdGhlIGNvbnRyYWN0IHRoYXQgZGVwbG95cyB0aGUgdGFyZ2V0IG9uZS4KCi8vIEFuIGVtcHR5IGNvbnRyYWN0IG5lZWRlZCBmb3IgdGhlIHNob3djYXNlIGFib3ZlIHRvIHdvcmsuCmNvbnRyYWN0IE15Q29udHJhY3QoKSB7fQ%3D%3D)
Read more: [Deployment](/book/deploy).
## Example contracts[](#examples)
Let’s put our newly acquired information of syntax and some semantics to the test.
### Counter contract[](#examples-counter)
```tact
// Defining a new Message type, which has one field
// and an automatically assigned 32-bit opcode prefix
message Add {
// unsigned integer value stored in 4 bytes
amount: Int as uint32;
}
// Defining a contract
contract SimpleCounter(
// Persistent state variables of the contract:
counter: Int as uint32, // actual value of the counter
id: Int as uint32, // a unique id to deploy multiple instances
// of this contract in a same workchain
// Their default or initial values are supplied during deployment.
) {
// Registers a receiver of empty messages from other contracts.
// It handles internal messages with `null` body
// and is very handy and cheap for the deployments.
receive() {
// Forward the remaining value in the
// incoming message back to the sender.
cashback(sender());
}
// Registers a binary receiver of the Add message bodies.
receive(msg: Add) {
self.counter += msg.amount; // <- increase the counter
// Forward the remaining value in the
// incoming message back to the sender.
cashback(sender());
}
// A getter function, which can only be called from off-chain
// and never by other contracts. This one is useful to see the counter state.
get fun counter(): Int {
return self.counter; // <- return the counter value
}
// Another getter function, but for the id:
get fun id(): Int {
return self.id; // <- return the id value
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gRGVmaW5pbmcgYSBuZXcgTWVzc2FnZSB0eXBlLCB3aGljaCBoYXMgb25lIGZpZWxkCi8vIGFuZCBhbiBhdXRvbWF0aWNhbGx5IGFzc2lnbmVkIDMyLWJpdCBvcGNvZGUgcHJlZml4Cm1lc3NhZ2UgQWRkIHsKICAgIC8vIHVuc2lnbmVkIGludGVnZXIgdmFsdWUgc3RvcmVkIGluIDQgYnl0ZXMKICAgIGFtb3VudDogSW50IGFzIHVpbnQzMjsKfQoKLy8gRGVmaW5pbmcgYSBjb250cmFjdApjb250cmFjdCBTaW1wbGVDb3VudGVyKAogICAgLy8gUGVyc2lzdGVudCBzdGF0ZSB2YXJpYWJsZXMgb2YgdGhlIGNvbnRyYWN0OgogICAgY291bnRlcjogSW50IGFzIHVpbnQzMiwgLy8gYWN0dWFsIHZhbHVlIG9mIHRoZSBjb3VudGVyCiAgICBpZDogSW50IGFzIHVpbnQzMiwgLy8gYSB1bmlxdWUgaWQgdG8gZGVwbG95IG11bHRpcGxlIGluc3RhbmNlcwogICAgICAgICAgICAgICAgICAgICAgIC8vIG9mIHRoaXMgY29udHJhY3QgaW4gYSBzYW1lIHdvcmtjaGFpbgogICAgLy8gVGhlaXIgZGVmYXVsdCBvciBpbml0aWFsIHZhbHVlcyBhcmUgc3VwcGxpZWQgZHVyaW5nIGRlcGxveW1lbnQuCikgewogICAgLy8gUmVnaXN0ZXJzIGEgcmVjZWl2ZXIgb2YgZW1wdHkgbWVzc2FnZXMgZnJvbSBvdGhlciBjb250cmFjdHMuCiAgICAvLyBJdCBoYW5kbGVzIGludGVybmFsIG1lc3NhZ2VzIHdpdGggYG51bGxgIGJvZHkKICAgIC8vIGFuZCBpcyB2ZXJ5IGhhbmR5IGFuZCBjaGVhcCBmb3IgdGhlIGRlcGxveW1lbnRzLgogICAgcmVjZWl2ZSgpIHsKICAgICAgICAvLyBGb3J3YXJkIHRoZSByZW1haW5pbmcgdmFsdWUgaW4gdGhlCiAgICAgICAgLy8gaW5jb21pbmcgbWVzc2FnZSBiYWNrIHRvIHRoZSBzZW5kZXIuCiAgICAgICAgY2FzaGJhY2soc2VuZGVyKCkpOwogICAgfQoKICAgIC8vIFJlZ2lzdGVycyBhIGJpbmFyeSByZWNlaXZlciBvZiB0aGUgQWRkIG1lc3NhZ2UgYm9kaWVzLgogICAgcmVjZWl2ZShtc2c6IEFkZCkgewogICAgICAgIHNlbGYuY291bnRlciArPSBtc2cuYW1vdW50OyAvLyA8LSBpbmNyZWFzZSB0aGUgY291bnRlcgogICAgICAgIC8vIEZvcndhcmQgdGhlIHJlbWFpbmluZyB2YWx1ZSBpbiB0aGUKICAgICAgICAvLyBpbmNvbWluZyBtZXNzYWdlIGJhY2sgdG8gdGhlIHNlbmRlci4KICAgICAgICBjYXNoYmFjayhzZW5kZXIoKSk7CiAgICB9CgogICAgLy8gQSBnZXR0ZXIgZnVuY3Rpb24sIHdoaWNoIGNhbiBvbmx5IGJlIGNhbGxlZCBmcm9tIG9mZi1jaGFpbgogICAgLy8gYW5kIG5ldmVyIGJ5IG90aGVyIGNvbnRyYWN0cy4gVGhpcyBvbmUgaXMgdXNlZnVsIHRvIHNlZSB0aGUgY291bnRlciBzdGF0ZS4KICAgIGdldCBmdW4gY291bnRlcigpOiBJbnQgewogICAgICAgIHJldHVybiBzZWxmLmNvdW50ZXI7IC8vIDwtIHJldHVybiB0aGUgY291bnRlciB2YWx1ZQogICAgfQoKICAgIC8vIEFub3RoZXIgZ2V0dGVyIGZ1bmN0aW9uLCBidXQgZm9yIHRoZSBpZDoKICAgIGdldCBmdW4gaWQoKTogSW50IHsKICAgICAgICByZXR1cm4gc2VsZi5pZDsgLy8gPC0gcmV0dXJuIHRoZSBpZCB2YWx1ZQogICAgfQp9)
### Jetton contracts[](#examples-jetton)
The tokens on TON Blockchain are commonly called Jettons. The distinction is made because they work differently from ERC-20 tokens or others.
This is due to the scalable and distributed approach that works best on TON: instead of having a single giant contract with a big hashmap of addresses of token holders, Jettons instead have a single minter contract that creates individual contracts called Jetton wallets per each holder.
For more, refer to the following resources:
* [TON Jettons Processing](https://docs.ton.org/v3/guidelines/dapps/asset-processing/jettons) in TON Docs.
* Jetton standards: [TEP-64](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md), [TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md), and [TEP-89](https://github.com/ton-blockchain/TEPs/blob/master/text/0089-jetton-wallet-discovery.md).
#### JettonWallet[](#jettonwallet)
```tact
/// Child contract per each holder of N amount of given Jetton (token)
contract JettonWallet(
/// Balance in Jettons.
balance: Int as coins,
/// Address of the user's wallet which owns this JettonWallet, and messages
/// from whom should be recognized and fully processed.
owner: Address,
/// Address of the main minting contract,
/// which deployed this Jetton wallet for the specific user's wallet.
master: Address,
) {
/// Registers a binary receiver of the JettonTransfer message body.
/// Transfers Jettons from the current owner to the target user's JettonWallet.
/// If that wallet does not exist, it is deployed on-chain in the same transfer.
receive(msg: JettonTransfer) {
// Ensure the basechain (workchain ID = 0)
require(parseStdAddress(msg.destination.asSlice()).workchain == 0, "Invalid destination workchain");
// Ensure the owner.
require(sender() == self.owner, "Incorrect sender");
// Ensure the balance does not go negative.
self.balance -= msg.amount;
require(self.balance >= 0, "Incorrect balance after send");
// Ensure the payload has enough bits.
require(msg.forwardPayload.bits() >= 1, "Invalid forward payload");
let ctx = context();
// msg.forwardTonAmount cannot be negative
// because its serialized as "coins"
let fwdCount = 1 + sign(msg.forwardTonAmount);
// Ensure there are enough Toncoin for transferring Jettons.
require(
ctx.value >
msg.forwardTonAmount + fwdCount * ctx.readForwardFee() +
(2 * getComputeFee(GAS_FOR_TRANSFER, false) + MIN_TONCOIN_FOR_STORAGE),
"Insufficient amount of TON attached",
);
// Transfer Jetton from the current owner to the target user's JettonWallet.
// If that wallet does not exist, it is deployed on-chain in the same transfer.
deploy(DeployParameters {
value: 0,
mode: SendRemainingValue,
bounce: true,
body: JettonTransferInternal{
queryId: msg.queryId,
amount: msg.amount,
sender: self.owner,
responseDestination: msg.responseDestination,
forwardTonAmount: msg.forwardTonAmount,
forwardPayload: msg.forwardPayload,
}.toCell(),
// Notice that we do not need to explicitly specify the Address,
// because it will be computed on the fly from the initial package.
init: initOf JettonWallet(0, msg.destination, self.master),
});
}
/// Registers a binary receiver of messages with JettonTransferInternal opcode.
/// Those are expected to be sent from the JettonMinter
/// or from other JettonWallets, and indicate incoming Jetton transfers.
receive(msg: JettonTransferInternal) {
self.balance += msg.amount;
// This message should come only from JettonMinter,
// or from other JettonWallet.
let wallet: StateInit = initOf JettonWallet(0, msg.sender, self.master);
if (sender() != contractAddress(wallet)) {
require(self.master == sender(), "Incorrect sender");
}
let ctx: Context = context();
let msgValue: Int = ctx.value;
let tonBalanceBeforeMsg = myBalance() - msgValue;
// If there are some funds to forward a message
// let's notify the user's wallet about the Jetton transfer we just got.
if (msg.forwardTonAmount > 0) {
let fwdFee: Int = ctx.readForwardFee();
msgValue -= msg.forwardTonAmount + fwdFee;
message(MessageParameters {
to: self.owner,
value: msg.forwardTonAmount,
mode: SendPayFwdFeesSeparately,
bounce: false,
body: JettonNotification{
queryId: msg.queryId,
amount: msg.amount,
sender: msg.sender,
forwardPayload: msg.forwardPayload,
}.toCell(),
});
}
// In general, let's try to reserve minimal amount of Toncoin
// to keep this contract running and paying storage fees.
nativeReserve(max(tonBalanceBeforeMsg, MIN_TONCOIN_FOR_STORAGE), ReserveAtMost);
// And forward excesses (cashback) to the original sender.
if (msg.responseDestination != null && msgValue > 0) {
message(MessageParameters {
to: msg.responseDestination!!,
value: msgValue,
mode: SendRemainingBalance + SendIgnoreErrors,
bounce: false,
body: JettonExcesses{ queryId: msg.queryId }.toCell(),
});
}
}
/// Registers a binary receiver of messages with JettonBurn opcode.
receive(msg: JettonBurn) {
// Ensure the owner.
require(sender() == self.owner, "Incorrect sender");
// Ensure the balance does not go negative.
self.balance -= msg.amount;
require(self.balance >= 0, "Incorrect balance after send");
// Ensure there are enough Toncoin for transferring Jettons.
let ctx = context();
let fwdFee: Int = ctx.readForwardFee();
require(
ctx.value >
(fwdFee + 2 * getComputeFee(GAS_FOR_BURN, false)),
"Insufficient amount of TON attached",
);
// Send a message to the JettonMinter to reduce the total supply
// of the Jettons. That is, to burn some.
message(MessageParameters {
to: self.master,
value: 0,
mode: SendRemainingValue,
bounce: true,
body: JettonBurnNotification{
queryId: msg.queryId,
amount: msg.amount,
sender: self.owner,
responseDestination: msg.responseDestination,
}.toCell(),
});
}
/// Registers a bounced binary receiver of messages
/// with the JettonTransferInternal opcode.
/// It handles such outgoing messages that bounced back to this contract.
bounced(msg: bounced) { self.balance += msg.amount; }
/// Registers a bounced binary receiver of messages
/// with the JettonBurnNotification opcode.
/// It handles such outgoing messages that bounced back to this contract.
bounced(msg: bounced) { self.balance += msg.amount; }
/// An off-chain getter function which returns useful data about this wallet.
get fun get_wallet_data(): JettonWalletData {
return JettonWalletData{
balance: self.balance,
owner: self.owner,
master: self.master,
code: myCode(),
};
}
}
//
// Helper structs, message structs and constants,
// which would otherwise be imported from another file
//
struct JettonWalletData {
balance: Int;
owner: Address;
master: Address;
code: Cell;
}
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell?;
forwardTonAmount: Int as coins;
forwardPayload: Slice as remaining;
}
message(0x178d4519) JettonTransferInternal {
queryId: Int as uint64;
amount: Int as coins;
sender: Address;
responseDestination: Address?;
forwardTonAmount: Int as coins;
forwardPayload: Slice as remaining;
}
message(0x7362d09c) JettonNotification {
queryId: Int as uint64;
amount: Int as coins;
sender: Address;
forwardPayload: Slice as remaining;
}
message(0x595f07bc) JettonBurn {
queryId: Int as uint64;
amount: Int as coins;
responseDestination: Address?;
customPayload: Cell?;
}
message(0x7bdd97de) JettonBurnNotification {
queryId: Int as uint64;
amount: Int as coins;
sender: Address;
responseDestination: Address?;
}
message(0xd53276db) JettonExcesses {
queryId: Int as uint64;
}
const GAS_FOR_BURN: Int = 6000;
const GAS_FOR_TRANSFER: Int = 8000;
const MIN_TONCOIN_FOR_STORAGE: Int = ton("0.01");
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIENoaWxkIGNvbnRyYWN0IHBlciBlYWNoIGhvbGRlciBvZiBOIGFtb3VudCBvZiBnaXZlbiBKZXR0b24gKHRva2VuKQpjb250cmFjdCBKZXR0b25XYWxsZXQoCiAgICAvLy8gQmFsYW5jZSBpbiBKZXR0b25zLgogICAgYmFsYW5jZTogSW50IGFzIGNvaW5zLAoKICAgIC8vLyBBZGRyZXNzIG9mIHRoZSB1c2VyJ3Mgd2FsbGV0IHdoaWNoIG93bnMgdGhpcyBKZXR0b25XYWxsZXQsIGFuZCBtZXNzYWdlcwogICAgLy8vIGZyb20gd2hvbSBzaG91bGQgYmUgcmVjb2duaXplZCBhbmQgZnVsbHkgcHJvY2Vzc2VkLgogICAgb3duZXI6IEFkZHJlc3MsCgogICAgLy8vIEFkZHJlc3Mgb2YgdGhlIG1haW4gbWludGluZyBjb250cmFjdCwKICAgIC8vLyB3aGljaCBkZXBsb3llZCB0aGlzIEpldHRvbiB3YWxsZXQgZm9yIHRoZSBzcGVjaWZpYyB1c2VyJ3Mgd2FsbGV0LgogICAgbWFzdGVyOiBBZGRyZXNzLAopIHsKICAgIC8vLyBSZWdpc3RlcnMgYSBiaW5hcnkgcmVjZWl2ZXIgb2YgdGhlIEpldHRvblRyYW5zZmVyIG1lc3NhZ2UgYm9keS4KICAgIC8vLyBUcmFuc2ZlcnMgSmV0dG9ucyBmcm9tIHRoZSBjdXJyZW50IG93bmVyIHRvIHRoZSB0YXJnZXQgdXNlcidzIEpldHRvbldhbGxldC4KICAgIC8vLyBJZiB0aGF0IHdhbGxldCBkb2VzIG5vdCBleGlzdCwgaXQgaXMgZGVwbG95ZWQgb24tY2hhaW4gaW4gdGhlIHNhbWUgdHJhbnNmZXIuCiAgICByZWNlaXZlKG1zZzogSmV0dG9uVHJhbnNmZXIpIHsKICAgICAgICAvLyBFbnN1cmUgdGhlIGJhc2VjaGFpbiAod29ya2NoYWluIElEID0gMCkKICAgICAgICByZXF1aXJlKHBhcnNlU3RkQWRkcmVzcyhtc2cuZGVzdGluYXRpb24uYXNTbGljZSgpKS53b3JrY2hhaW4gPT0gMCwgIkludmFsaWQgZGVzdGluYXRpb24gd29ya2NoYWluIik7CiAgICAgICAgLy8gRW5zdXJlIHRoZSBvd25lci4KICAgICAgICByZXF1aXJlKHNlbmRlcigpID09IHNlbGYub3duZXIsICJJbmNvcnJlY3Qgc2VuZGVyIik7CgogICAgICAgIC8vIEVuc3VyZSB0aGUgYmFsYW5jZSBkb2VzIG5vdCBnbyBuZWdhdGl2ZS4KICAgICAgICBzZWxmLmJhbGFuY2UgLT0gbXNnLmFtb3VudDsKICAgICAgICByZXF1aXJlKHNlbGYuYmFsYW5jZSA%2BPSAwLCAiSW5jb3JyZWN0IGJhbGFuY2UgYWZ0ZXIgc2VuZCIpOwogICAgICAgIC8vIEVuc3VyZSB0aGUgcGF5bG9hZCBoYXMgZW5vdWdoIGJpdHMuCiAgICAgICAgcmVxdWlyZShtc2cuZm9yd2FyZFBheWxvYWQuYml0cygpID49IDEsICJJbnZhbGlkIGZvcndhcmQgcGF5bG9hZCIpOwoKICAgICAgICBsZXQgY3R4ID0gY29udGV4dCgpOwogICAgICAgIC8vIG1zZy5mb3J3YXJkVG9uQW1vdW50IGNhbm5vdCBiZSBuZWdhdGl2ZQogICAgICAgIC8vIGJlY2F1c2UgaXRzIHNlcmlhbGl6ZWQgYXMgImNvaW5zIgogICAgICAgIGxldCBmd2RDb3VudCA9IDEgKyBzaWduKG1zZy5mb3J3YXJkVG9uQW1vdW50KTsKCiAgICAgICAgLy8gRW5zdXJlIHRoZXJlIGFyZSBlbm91Z2ggVG9uY29pbiBmb3IgdHJhbnNmZXJyaW5nIEpldHRvbnMuCiAgICAgICAgcmVxdWlyZSgKICAgICAgICAgICAgY3R4LnZhbHVlID4KICAgICAgICAgICAgbXNnLmZvcndhcmRUb25BbW91bnQgKyBmd2RDb3VudCAqIGN0eC5yZWFkRm9yd2FyZEZlZSgpICsKICAgICAgICAgICAgKDIgKiBnZXRDb21wdXRlRmVlKEdBU19GT1JfVFJBTlNGRVIsIGZhbHNlKSArIE1JTl9UT05DT0lOX0ZPUl9TVE9SQUdFKSwKICAgICAgICAgICAgIkluc3VmZmljaWVudCBhbW91bnQgb2YgVE9OIGF0dGFjaGVkIiwKICAgICAgICApOwoKICAgICAgICAvLyBUcmFuc2ZlciBKZXR0b24gZnJvbSB0aGUgY3VycmVudCBvd25lciB0byB0aGUgdGFyZ2V0IHVzZXIncyBKZXR0b25XYWxsZXQuCiAgICAgICAgLy8gSWYgdGhhdCB3YWxsZXQgZG9lcyBub3QgZXhpc3QsIGl0IGlzIGRlcGxveWVkIG9uLWNoYWluIGluIHRoZSBzYW1lIHRyYW5zZmVyLgogICAgICAgIGRlcGxveShEZXBsb3lQYXJhbWV0ZXJzIHsKICAgICAgICAgICAgdmFsdWU6IDAsCiAgICAgICAgICAgIG1vZGU6IFNlbmRSZW1haW5pbmdWYWx1ZSwKICAgICAgICAgICAgYm91bmNlOiB0cnVlLAogICAgICAgICAgICBib2R5OiBKZXR0b25UcmFuc2ZlckludGVybmFsewogICAgICAgICAgICAgICAgcXVlcnlJZDogbXNnLnF1ZXJ5SWQsCiAgICAgICAgICAgICAgICBhbW91bnQ6IG1zZy5hbW91bnQsCiAgICAgICAgICAgICAgICBzZW5kZXI6IHNlbGYub3duZXIsCiAgICAgICAgICAgICAgICByZXNwb25zZURlc3RpbmF0aW9uOiBtc2cucmVzcG9uc2VEZXN0aW5hdGlvbiwKICAgICAgICAgICAgICAgIGZvcndhcmRUb25BbW91bnQ6IG1zZy5mb3J3YXJkVG9uQW1vdW50LAogICAgICAgICAgICAgICAgZm9yd2FyZFBheWxvYWQ6IG1zZy5mb3J3YXJkUGF5bG9hZCwKICAgICAgICAgICAgfS50b0NlbGwoKSwKICAgICAgICAgICAgLy8gTm90aWNlIHRoYXQgd2UgZG8gbm90IG5lZWQgdG8gZXhwbGljaXRseSBzcGVjaWZ5IHRoZSBBZGRyZXNzLAogICAgICAgICAgICAvLyBiZWNhdXNlIGl0IHdpbGwgYmUgY29tcHV0ZWQgb24gdGhlIGZseSBmcm9tIHRoZSBpbml0aWFsIHBhY2thZ2UuCiAgICAgICAgICAgIGluaXQ6IGluaXRPZiBKZXR0b25XYWxsZXQoMCwgbXNnLmRlc3RpbmF0aW9uLCBzZWxmLm1hc3RlciksCiAgICAgICAgfSk7CiAgICB9CgogICAgLy8vIFJlZ2lzdGVycyBhIGJpbmFyeSByZWNlaXZlciBvZiBtZXNzYWdlcyB3aXRoIEpldHRvblRyYW5zZmVySW50ZXJuYWwgb3Bjb2RlLgogICAgLy8vIFRob3NlIGFyZSBleHBlY3RlZCB0byBiZSBzZW50IGZyb20gdGhlIEpldHRvbk1pbnRlcgogICAgLy8vIG9yIGZyb20gb3RoZXIgSmV0dG9uV2FsbGV0cywgYW5kIGluZGljYXRlIGluY29taW5nIEpldHRvbiB0cmFuc2ZlcnMuCiAgICByZWNlaXZlKG1zZzogSmV0dG9uVHJhbnNmZXJJbnRlcm5hbCkgewogICAgICAgIHNlbGYuYmFsYW5jZSArPSBtc2cuYW1vdW50OwoKICAgICAgICAvLyBUaGlzIG1lc3NhZ2Ugc2hvdWxkIGNvbWUgb25seSBmcm9tIEpldHRvbk1pbnRlciwKICAgICAgICAvLyBvciBmcm9tIG90aGVyIEpldHRvbldhbGxldC4KICAgICAgICBsZXQgd2FsbGV0OiBTdGF0ZUluaXQgPSBpbml0T2YgSmV0dG9uV2FsbGV0KDAsIG1zZy5zZW5kZXIsIHNlbGYubWFzdGVyKTsKICAgICAgICBpZiAoc2VuZGVyKCkgIT0gY29udHJhY3RBZGRyZXNzKHdhbGxldCkpIHsKICAgICAgICAgICAgcmVxdWlyZShzZWxmLm1hc3RlciA9PSBzZW5kZXIoKSwgIkluY29ycmVjdCBzZW5kZXIiKTsKICAgICAgICB9CgogICAgICAgIGxldCBjdHg6IENvbnRleHQgPSBjb250ZXh0KCk7CiAgICAgICAgbGV0IG1zZ1ZhbHVlOiBJbnQgPSBjdHgudmFsdWU7CiAgICAgICAgbGV0IHRvbkJhbGFuY2VCZWZvcmVNc2cgPSBteUJhbGFuY2UoKSAtIG1zZ1ZhbHVlOwoKICAgICAgICAvLyBJZiB0aGVyZSBhcmUgc29tZSBmdW5kcyB0byBmb3J3YXJkIGEgbWVzc2FnZQogICAgICAgIC8vIGxldCdzIG5vdGlmeSB0aGUgdXNlcidzIHdhbGxldCBhYm91dCB0aGUgSmV0dG9uIHRyYW5zZmVyIHdlIGp1c3QgZ290LgogICAgICAgIGlmIChtc2cuZm9yd2FyZFRvbkFtb3VudCA%2BIDApIHsKICAgICAgICAgICAgbGV0IGZ3ZEZlZTogSW50ID0gY3R4LnJlYWRGb3J3YXJkRmVlKCk7CiAgICAgICAgICAgIG1zZ1ZhbHVlIC09IG1zZy5mb3J3YXJkVG9uQW1vdW50ICsgZndkRmVlOwogICAgICAgICAgICBtZXNzYWdlKE1lc3NhZ2VQYXJhbWV0ZXJzIHsKICAgICAgICAgICAgICAgIHRvOiBzZWxmLm93bmVyLAogICAgICAgICAgICAgICAgdmFsdWU6IG1zZy5mb3J3YXJkVG9uQW1vdW50LAogICAgICAgICAgICAgICAgbW9kZTogU2VuZFBheUZ3ZEZlZXNTZXBhcmF0ZWx5LAogICAgICAgICAgICAgICAgYm91bmNlOiBmYWxzZSwKICAgICAgICAgICAgICAgIGJvZHk6IEpldHRvbk5vdGlmaWNhdGlvbnsKICAgICAgICAgICAgICAgICAgICBxdWVyeUlkOiBtc2cucXVlcnlJZCwKICAgICAgICAgICAgICAgICAgICBhbW91bnQ6IG1zZy5hbW91bnQsCiAgICAgICAgICAgICAgICAgICAgc2VuZGVyOiBtc2cuc2VuZGVyLAogICAgICAgICAgICAgICAgICAgIGZvcndhcmRQYXlsb2FkOiBtc2cuZm9yd2FyZFBheWxvYWQsCiAgICAgICAgICAgICAgICB9LnRvQ2VsbCgpLAogICAgICAgICAgICB9KTsKICAgICAgICB9CgogICAgICAgIC8vIEluIGdlbmVyYWwsIGxldCdzIHRyeSB0byByZXNlcnZlIG1pbmltYWwgYW1vdW50IG9mIFRvbmNvaW4KICAgICAgICAvLyB0byBrZWVwIHRoaXMgY29udHJhY3QgcnVubmluZyBhbmQgcGF5aW5nIHN0b3JhZ2UgZmVlcy4KICAgICAgICBuYXRpdmVSZXNlcnZlKG1heCh0b25CYWxhbmNlQmVmb3JlTXNnLCBNSU5fVE9OQ09JTl9GT1JfU1RPUkFHRSksIFJlc2VydmVBdE1vc3QpOwoKICAgICAgICAvLyBBbmQgZm9yd2FyZCBleGNlc3NlcyAoY2FzaGJhY2spIHRvIHRoZSBvcmlnaW5hbCBzZW5kZXIuCiAgICAgICAgaWYgKG1zZy5yZXNwb25zZURlc3RpbmF0aW9uICE9IG51bGwgJiYgbXNnVmFsdWUgPiAwKSB7CiAgICAgICAgICAgIG1lc3NhZ2UoTWVzc2FnZVBhcmFtZXRlcnMgewogICAgICAgICAgICAgICAgdG86IG1zZy5yZXNwb25zZURlc3RpbmF0aW9uISEsCiAgICAgICAgICAgICAgICB2YWx1ZTogbXNnVmFsdWUsCiAgICAgICAgICAgICAgICBtb2RlOiBTZW5kUmVtYWluaW5nQmFsYW5jZSArIFNlbmRJZ25vcmVFcnJvcnMsCiAgICAgICAgICAgICAgICBib3VuY2U6IGZhbHNlLAogICAgICAgICAgICAgICAgYm9keTogSmV0dG9uRXhjZXNzZXN7IHF1ZXJ5SWQ6IG1zZy5xdWVyeUlkIH0udG9DZWxsKCksCiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgIH0KCiAgICAvLy8gUmVnaXN0ZXJzIGEgYmluYXJ5IHJlY2VpdmVyIG9mIG1lc3NhZ2VzIHdpdGggSmV0dG9uQnVybiBvcGNvZGUuCiAgICByZWNlaXZlKG1zZzogSmV0dG9uQnVybikgewogICAgICAgIC8vIEVuc3VyZSB0aGUgb3duZXIuCiAgICAgICAgcmVxdWlyZShzZW5kZXIoKSA9PSBzZWxmLm93bmVyLCAiSW5jb3JyZWN0IHNlbmRlciIpOwoKICAgICAgICAvLyBFbnN1cmUgdGhlIGJhbGFuY2UgZG9lcyBub3QgZ28gbmVnYXRpdmUuCiAgICAgICAgc2VsZi5iYWxhbmNlIC09IG1zZy5hbW91bnQ7CiAgICAgICAgcmVxdWlyZShzZWxmLmJhbGFuY2UgPj0gMCwgIkluY29ycmVjdCBiYWxhbmNlIGFmdGVyIHNlbmQiKTsKCiAgICAgICAgLy8gRW5zdXJlIHRoZXJlIGFyZSBlbm91Z2ggVG9uY29pbiBmb3IgdHJhbnNmZXJyaW5nIEpldHRvbnMuCiAgICAgICAgbGV0IGN0eCA9IGNvbnRleHQoKTsKICAgICAgICBsZXQgZndkRmVlOiBJbnQgPSBjdHgucmVhZEZvcndhcmRGZWUoKTsKICAgICAgICByZXF1aXJlKAogICAgICAgICAgICBjdHgudmFsdWUgPgogICAgICAgICAgICAoZndkRmVlICsgMiAqIGdldENvbXB1dGVGZWUoR0FTX0ZPUl9CVVJOLCBmYWxzZSkpLAogICAgICAgICAgICAiSW5zdWZmaWNpZW50IGFtb3VudCBvZiBUT04gYXR0YWNoZWQiLAogICAgICAgICk7CgogICAgICAgIC8vIFNlbmQgYSBtZXNzYWdlIHRvIHRoZSBKZXR0b25NaW50ZXIgdG8gcmVkdWNlIHRoZSB0b3RhbCBzdXBwbHkKICAgICAgICAvLyBvZiB0aGUgSmV0dG9ucy4gVGhhdCBpcywgdG8gYnVybiBzb21lLgogICAgICAgIG1lc3NhZ2UoTWVzc2FnZVBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VsZi5tYXN0ZXIsCiAgICAgICAgICAgIHZhbHVlOiAwLAogICAgICAgICAgICBtb2RlOiBTZW5kUmVtYWluaW5nVmFsdWUsCiAgICAgICAgICAgIGJvdW5jZTogdHJ1ZSwKICAgICAgICAgICAgYm9keTogSmV0dG9uQnVybk5vdGlmaWNhdGlvbnsKICAgICAgICAgICAgICAgIHF1ZXJ5SWQ6IG1zZy5xdWVyeUlkLAogICAgICAgICAgICAgICAgYW1vdW50OiBtc2cuYW1vdW50LAogICAgICAgICAgICAgICAgc2VuZGVyOiBzZWxmLm93bmVyLAogICAgICAgICAgICAgICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogbXNnLnJlc3BvbnNlRGVzdGluYXRpb24sCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9CgogICAgLy8vIFJlZ2lzdGVycyBhIGJvdW5jZWQgYmluYXJ5IHJlY2VpdmVyIG9mIG1lc3NhZ2VzCiAgICAvLy8gd2l0aCB0aGUgSmV0dG9uVHJhbnNmZXJJbnRlcm5hbCBvcGNvZGUuCiAgICAvLy8gSXQgaGFuZGxlcyBzdWNoIG91dGdvaW5nIG1lc3NhZ2VzIHRoYXQgYm91bmNlZCBiYWNrIHRvIHRoaXMgY29udHJhY3QuCiAgICBib3VuY2VkKG1zZzogYm91bmNlZDxKZXR0b25UcmFuc2ZlckludGVybmFsPikgeyBzZWxmLmJhbGFuY2UgKz0gbXNnLmFtb3VudDsgfQoKICAgIC8vLyBSZWdpc3RlcnMgYSBib3VuY2VkIGJpbmFyeSByZWNlaXZlciBvZiBtZXNzYWdlcwogICAgLy8vIHdpdGggdGhlIEpldHRvbkJ1cm5Ob3RpZmljYXRpb24gb3Bjb2RlLgogICAgLy8vIEl0IGhhbmRsZXMgc3VjaCBvdXRnb2luZyBtZXNzYWdlcyB0aGF0IGJvdW5jZWQgYmFjayB0byB0aGlzIGNvbnRyYWN0LgogICAgYm91bmNlZChtc2c6IGJvdW5jZWQ8SmV0dG9uQnVybk5vdGlmaWNhdGlvbj4pIHsgc2VsZi5iYWxhbmNlICs9IG1zZy5hbW91bnQ7IH0KCiAgICAvLy8gQW4gb2ZmLWNoYWluIGdldHRlciBmdW5jdGlvbiB3aGljaCByZXR1cm5zIHVzZWZ1bCBkYXRhIGFib3V0IHRoaXMgd2FsbGV0LgogICAgZ2V0IGZ1biBnZXRfd2FsbGV0X2RhdGEoKTogSmV0dG9uV2FsbGV0RGF0YSB7CiAgICAgICAgcmV0dXJuIEpldHRvbldhbGxldERhdGF7CiAgICAgICAgICAgIGJhbGFuY2U6IHNlbGYuYmFsYW5jZSwKICAgICAgICAgICAgb3duZXI6IHNlbGYub3duZXIsCiAgICAgICAgICAgIG1hc3Rlcjogc2VsZi5tYXN0ZXIsCiAgICAgICAgICAgIGNvZGU6IG15Q29kZSgpLAogICAgICAgIH07CiAgICB9Cn0KCi8vCi8vIEhlbHBlciBzdHJ1Y3RzLCBtZXNzYWdlIHN0cnVjdHMgYW5kIGNvbnN0YW50cywKLy8gd2hpY2ggd291bGQgb3RoZXJ3aXNlIGJlIGltcG9ydGVkIGZyb20gYW5vdGhlciBmaWxlCi8vCgpzdHJ1Y3QgSmV0dG9uV2FsbGV0RGF0YSB7CiAgICBiYWxhbmNlOiBJbnQ7CiAgICBvd25lcjogQWRkcmVzczsKICAgIG1hc3RlcjogQWRkcmVzczsKICAgIGNvZGU6IENlbGw7Cn0KCm1lc3NhZ2UoMHhmOGE3ZWE1KSBKZXR0b25UcmFuc2ZlciB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBkZXN0aW5hdGlvbjogQWRkcmVzczsKICAgIHJlc3BvbnNlRGVzdGluYXRpb246IEFkZHJlc3M%2FOwogICAgY3VzdG9tUGF5bG9hZDogQ2VsbD87CiAgICBmb3J3YXJkVG9uQW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBmb3J3YXJkUGF5bG9hZDogU2xpY2UgYXMgcmVtYWluaW5nOwp9CgptZXNzYWdlKDB4MTc4ZDQ1MTkpIEpldHRvblRyYW5zZmVySW50ZXJuYWwgewogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NDsKICAgIGFtb3VudDogSW50IGFzIGNvaW5zOwogICAgc2VuZGVyOiBBZGRyZXNzOwogICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogQWRkcmVzcz87CiAgICBmb3J3YXJkVG9uQW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBmb3J3YXJkUGF5bG9hZDogU2xpY2UgYXMgcmVtYWluaW5nOwp9CgptZXNzYWdlKDB4NzM2MmQwOWMpIEpldHRvbk5vdGlmaWNhdGlvbiB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBzZW5kZXI6IEFkZHJlc3M7CiAgICBmb3J3YXJkUGF5bG9hZDogU2xpY2UgYXMgcmVtYWluaW5nOwp9CgptZXNzYWdlKDB4NTk1ZjA3YmMpIEpldHRvbkJ1cm4gewogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NDsKICAgIGFtb3VudDogSW50IGFzIGNvaW5zOwogICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogQWRkcmVzcz87CiAgICBjdXN0b21QYXlsb2FkOiBDZWxsPzsKfQoKbWVzc2FnZSgweDdiZGQ5N2RlKSBKZXR0b25CdXJuTm90aWZpY2F0aW9uIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7CiAgICBhbW91bnQ6IEludCBhcyBjb2luczsKICAgIHNlbmRlcjogQWRkcmVzczsKICAgIHJlc3BvbnNlRGVzdGluYXRpb246IEFkZHJlc3M%2FOwp9CgptZXNzYWdlKDB4ZDUzMjc2ZGIpIEpldHRvbkV4Y2Vzc2VzIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7Cn0KCmNvbnN0IEdBU19GT1JfQlVSTjogSW50ID0gNjAwMDsKY29uc3QgR0FTX0ZPUl9UUkFOU0ZFUjogSW50ID0gODAwMDsKY29uc3QgTUlOX1RPTkNPSU5fRk9SX1NUT1JBR0U6IEludCA9IHRvbigiMC4wMSIpOw%3D%3D)
#### JettonMinter[](#jettonminter)
It is a parent contract that deploys individual [Jetton wallets](#jettonwallet) per each holder.
See: [`JettonMinter` in tact-lang/jetton repository](https://github.com/tact-lang/jetton/blob/9db75a5a828e9093be5c425605c5f5c9903f505d/src/contracts/jetton-minter.tact).
---
# Message Lifecycle
> Every transaction on TON Blockchain has multiple stages, where the compute and action stages are the most important for the message lifecycle.
There are several stages of message processing by a contract. While there are more stages, we will focus on the most important ones:
## Receive Phase[](#receive-phase)
This phase combines multiple low-level phases.
It starts by adding a **message value to the contract balance**. The value of an incoming message is the maximum price that a contract can pay for gas to process this message. The contract can overwrite this limit, but it is not recommended and is suitable only for advanced developers since it could lead to a contract being drained. The maximum amount of gas that a contract can spend in a single transaction is 1 million, which currently equals 0.4 TON for basechain. If the message value is zero, execution is aborted.
Then, a (usually small) amount of nanotons gets subtracted from the contract balance for storage. This means that you cannot perfectly predict balance changes and must adjust your code to account for this instability.
Next, it deploys the contract if it has not yet been deployed and if the message contains the init package. If the init package is not present, this step is skipped.
## Compute Phase[](#compute-phase)
This phase executes the code of a smart contract and produces either a list of actions or an exception. Currently, only two types of actions are supported: **send message** and **reserve**.
Sending a message could use a fixed value or a dynamic value like the **remaining value of a message**, which is the remaining value of the incoming message. A message can be sent with the flag `SendIgnoreErrors`, which causes errors during message sending to be ignored and the execution to continue to the next action. This flag is useful when you have multiple actions. When sending a message with some value, this value is first subtracted from the incoming message value and only then, if necessary, from the contract balance (before processing).
## Action Phase[](#action-phase)
Actions are executed in sequence, but bear in mind: **AN EXCEPTION DURING THE PROCESSING OF ACTIONS WILL NOT REVERT THE TRANSACTION**
For example, if you subtract 1 TON from a customer’s balance and then send an invalid message, it could lead to a situation where the customer’s balance is reduced, but the customer does not receive it.
---
# Maps
> The composite type map is used as a way to associate keys with corresponding values of various types.
The [composite type](/book/types#composite-types) `map` is used as a way to associate keys of type `K` with corresponding values of type `V`.
For example, `map` uses the [`Int`](/book/integers) type for its keys and values:
```tact
struct IntToInt {
counters: map;
}
```
Since maps can use any given [struct](/book/structs-and-messages#structs) or [message struct](/book/structs-and-messages#messages) as their [value types](#allowed-types), nested maps can be created via helper structures like this:
```tact
// A `map` packed into the `AllowanceMap` structure
struct AllowanceMap { unbox: map }
contract NestedMaps {
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
get fun test(): Int {
// An outer map `map`,
// with `AllowanceMap` structs as values,
// each containing maps of type `map`
let allowances: map = emptyMap();
// An inner map in the `unbox` field of the `AllowanceMap` struct
let allowance = AllowanceMap { unbox: emptyMap() };
// Setting the inner map entry
allowance.unbox.set(myAddress(), 42);
// Setting the outer map entry
allowances.set(myAddress(), allowance);
// Produces 42
return allowances.get(myAddress())!!.unbox.get(myAddress())!!;
}
}
```
Keep in mind that on [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview), maps are represented as the [`Cell`](/book/cells#cells) type, which is very gas-intensive. Also, nested maps will reach the [limits](#limits-and-drawbacks) faster than regular maps.
## Allowed types[](#allowed-types)
Allowed key types:
* [`Int`](/book/integers)
* [`Address`](/book/types#primitive-types)
Allowed value types:
* [`Int`](/book/integers)
* [`Bool`](/book/types#booleans)
* [`Cell`](/book/cells#cells)
* [`Address`](/book/types#primitive-types)
* any [struct](/book/structs-and-messages#structs) type
* any [Message](/book/structs-and-messages#messages) type
Neither key nor value types can be made [optional](/book/optionals).
```tact
// COMPILATION ERROR! Map key types cannot be optional
let myMap: map = emptyMap();
// ~~~~
```
## Serialization[](#serialization)
It is possible to perform [integer serialization](/book/integers#common-serialization-types) of map keys, values, or both to [preserve space and reduce storage costs](/book/integers#serialization):
```tact
struct SerializedMapInside {
// Both keys and values here are serialized as 8-bit unsigned integers,
// thus preserving space and reducing storage costs:
countersButCompact: map;
}
```
Since map keys can only be of fixed width, [variable integer types](/book/integers#serialization-varint) are not allowed for them. Instead, use [fixed-width serialization formats](/book/integers#serialization-fixed).
However, map values of type [`Int`](/book/integers) can have either [fixed](/book/integers#serialization-fixed) or [variable](/book/integers#serialization-varint) bit-length serialization formats specified.
No other [allowed key or value types](#allowed-types) besides [`Int`](/book/integers) have serialization formats available.
Note
Read more about serialization in Tact: [Compatibility with FunC](/book/func#convert-serialization).
## Low-level representation[](#low-level-representation)
On [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview), maps are represented as a [`Cell`](/book/cells#cells) type, and it’s possible to construct and parse them directly. However, doing so is highly error-prone and quite messy, which is why Tact provides maps as a standalone composite type with many of the helper methods [described below](#operations).
Essentially, maps are cells with a special bits layouts, which have many supporting TVM instructions for their modification and usage. They are broadly called [“hashmaps”](https://docs.ton.org/v3/documentation/data-formats/tlb/tl-b-types#hashmap), although they are closer to balanced trees.
Maps always have fixed key lengths which can be one of two kinds: long and short. For the distinction and composition of maps with either of key types, see the [description of the `.deepEquals()`](#deepequals) map method.
## Operations[](#operations)
### Declare, `emptyMap()`[](#emptymap)
```tact
// K and V correspond to the key and value types of the target map
fun emptyMap(): map;
```
Declaring a map as a [local variable](/book/statements#let), using the `emptyMap()` function from the standard library:
```tact
let fizz: map = emptyMap();
let fizz: map = null; // identical to the previous line, but less descriptive
```
Declaring a map as a [persistent state variable](/book/contracts#variables):
```tact
contract Example {
fizz: map; // Int keys to Int values
init() {
self.fizz = emptyMap(); // redundant and can be removed!
}
}
```
Note that [persistent state variables](/book/contracts#variables) of type `map` are initialized empty by default and do not need default values or initialization in the [`init()` function](/book/contracts#init-function).
### Initialize with a map literal[](#initialize)
Available since Tact 1.6.7
```tact
// K and V correspond to the key and value types of the target map
map { key1: value1, key2: value2, /* ... */, keyN: valueN };
```
Map literals are expressions that provide a concise and gas-effective way to create maps. First goes the `map` type expression, then a curly-brace enclosed comma-delimited list of zero or more predefined key-value pairs.
```tact
// Declaring a map as a local variable via a map literal expression
let myMap: map = map {
// Key: Value
1: 100, // key 1, value 100
2: 200, // key 2, value 200
};
// However, if you specify the type of ascription in the let statement,
// it should exactly match the one in the map literal, or it will not compile.
let mismatch: map = map {}; // COMPILATION ERROR! Type mismatch
```
Map literals with an empty body are also supported. They produce the same value as the [`emptyMap()`](#emptymap) function and also require type ascriptions for the variable definition.
```tact
let myMap: map = map {};
let myMap2: map = emptyMap();
myMap == myMap2; // true
```
Since map literals define map entries at compile-time, they are significantly less gas consuming compared to a series of consecutive [`.set()`](#set) calls.
```tact
// If at least some entries are known in advance, prefer doing this
let myMap: map = map {
1: 100,
2: 200,
};
// Over this
let myMap2: map = emptyMap();
myMap2.set(1, 100);
myMap2.set(2, 200);
// Because maps composed either way are equivalent
myMap == myMap2; // true
```
Notice that keys and values of the [`Int`](/book/integers) type must be defined with [storage annotations via `as` keyword](/book/integers#serialization).
```tact
let smartMoney: map = map {};
// Notice that annotations are checked and
let tryAndSerializeMe = map {
1: 100,
2: 200, // COMPILATION ERROR! bitLength is too small
};
// If you explicitly specify the type of ascription in the let statement,
// it should exactly match the one in the map literal, or it will not compile.
let nope: map = map {};
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// COMPILATION ERROR! Type mismatch
```
When using the same key for the multiple entries, the last occurrence of each key-value pair takes precedence. That is, if there are multiple entries with the same key, only the last one will be used.
```tact
let allTheSame: map = map {
1: 100,
1: 200,
1: 300,
1: 400,
};
allTheSame.get(1)!!; // 400
```
Both keys and values can be arbitrary compile-time expressions as long as their resulting types match the respective key-value types of the map literal.
```tact
fun getExchangesList(): map {
return map {
address("UQD5vcDeRhwaLgAvralVC7sJXI-fc2aNcMUXqcx-BQ-OWi5c"): "One Known eXchange".asCell(),
address("UQABGo8KCza3ea8DNHMnSWZmbRzW-05332eTdfvW-XDQEmnJ"): "yRacket".asCell(),
};
}
```
Note
Support for runtime initialization values that are not resolved at [compile-time](/ref/core-comptime) is planned for future Tact releases.
### Set values, `.set()`[](#set)
```tact
// K and V correspond to the key and value types of the given map
extends mutates fun set(self: map, key: K, val: V?);
```
To set or replace the value under a key, call the `.set()` [method](/book/functions#extensions), which is accessible for all maps.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 7);
fizz.set(42, 42);
// Overriding one of the existing key-value pairs
fizz.set(7, 68); // key 7 now points to value 68
```
### Get values, `.get()`[](#get)
```tact
// K and V correspond to the key and value types of the given map
extends fun get(self: map, key: K): V?;
```
You can check if a key is found in the map by calling the `.get()` [method](/book/functions#extensions), which is accessible for all maps. This will return [`null`](/book/optionals) if the key is missing or the value if the key is found.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a value
fizz.set(68, 0);
// Getting the value by its key
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 crash at runtime if the value is, in fact, null
// Alternatively, we can check for the key in an if statement
if (gotButUnsure != null) {
// Hooray, let's use !! without fear now and cast Int? to Int
let definitelyGotIt: Int = fizz.get(68)!!;
} else {
// Do something else...
}
```
### Replace values, `.replace()`[](#replace)
Available since Tact 1.6
```tact
// K and V correspond to the key and value types of the given map
extends mutates fun replace(self: map, key: K, val: V): Bool;
```
To replace the value associated with a key, if such a key exists, use the `.replace()` [method](/book/functions#extensions). It returns `true` upon successful replacement and `false` otherwise.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 70);
fizz.set(42, 42);
// Overriding one of the existing key-value pairs
let replaced1 = fizz.replace(7, 68); // key 7 now points to value 68
replaced1; // true
// Trying to replace the value of a non-existing key does nothing
let replaced2 = fizz.replace(8, 68); // no key 8, so nothing was altered
replaced2; // false
```
If the given value is [`null`](/book/optionals) and the key exists, the entry is deleted from the map.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 70);
fizz.set(42, 42);
// Overriding one of the existing key-value pairs
let replaced1 = fizz.replace(7, null); // the entry under key 7 is now deleted
replaced1; // true
// Trying to replace the value of a non-existing key does nothing
let replaced2 = fizz.replace(8, null); // no key 8, so nothing was altered
replaced2; // false
```
### Replace and get old value, `.replaceGet()`[](#replaceget)
Available since Tact 1.6
```tact
// K and V correspond to the key and value types of the given map
extends mutates fun replaceGet(self: map, key: K, val: V): V?;
```
Like [`.replace()`](#replace), but instead of returning a [`Bool`](/book/types#booleans), it returns the old (pre-replacement) value on a successful replacement and [`null`](/book/optionals) otherwise.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 70);
fizz.set(42, 42);
// Overriding one of the existing key-value pairs
let oldVal1 = fizz.replaceGet(7, 68); // key 7 now points to value 68
oldVal1; // 70
// Trying to replace the value of a non-existing key-value pair will do nothing
let oldVal2 = fizz.replaceGet(8, 68); // no key 8, so nothing was altered
oldVal2; // null
```
If the given value is [`null`](/book/optionals) and the key exists, the entry will be deleted from the map.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 70);
fizz.set(42, 42);
// Overriding one of the existing key-value pairs
let oldVal1 = fizz.replaceGet(7, null); // the entry under key 7 is now deleted
oldVal1; // 70
// Trying to replace the value of a non-existing key-value pair will do nothing
let oldVal2 = fizz.replaceGet(8, null); // no key 8, so nothing was altered
oldVal2; // null
```
### Delete entries, `.del()`[](#del)
```tact
// K and V correspond to the key and value types of the given map
extends mutates fun del(self: map, key: K): Bool;
```
To delete a single key-value pair (a single entry), use the `.del()` [method](/book/functions#extensions). It returns `true` in the case of successful deletion and `false` otherwise.
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 123);
fizz.set(42, 321);
// Deleting one of the keys
let deletionSuccess: Bool = fizz.del(7); // true, because the map contained the entry under key 7
fizz.del(7); // false, because the map no longer has an entry under key 7
// Note that assigning the `null` value to a key when using the `.set()` method
// is equivalent to calling `.del()`, although this approach is much less descriptive
// and is generally discouraged:
fizz.set(42, null); // the entry under key 42 is now deleted
```
To delete all the entries from the map, re-assign the map using the `emptyMap()` function:
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(7, 123);
fizz.set(42, 321);
// Deleting all of the entries at once
fizz = emptyMap();
fizz = null; // identical to the previous line, but less descriptive
```
With this approach, all previous entries of the map are completely discarded from the contract, even if the map was declared as a persistent state variable. As a result, assigning maps to `emptyMap()` **does not** incur any hidden or sudden [storage fees](https://docs.ton.org/develop/smart-contracts/fees#storage-fee).
### Check if entry exists, `.exists()`[](#exists)
Available since Tact 1.5
```tact
// K and V correspond to the key and value types of the given map
extends fun exists(self: map, key: K): Bool;
```
The `.exists()` [method](/book/functions#extensions) on maps returns `true` if a value under the given key exists in the map and `false` otherwise.
```tact
let fizz: map = emptyMap();
fizz.set(0, 0);
if (fizz.exists(2 + 2)) { // false
dump("Something doesn't add up!");
}
if (fizz.exists(1 / 2)) { // true
dump("I told a fraction joke once. It was half funny.");
}
if (fizz.get(1 / 2) != null) { // also true, but consumes more gas
dump("Gotta pump more!");
}
```
Note
Calling `m.exists(key)` is more gas-efficient than executing `m.get(key) != null`, although both approaches yield the same results.
### Check if empty, `.isEmpty()`[](#isempty)
```tact
// K and V correspond to the key and value types of the given map
extends fun isEmpty(self: map): Bool;
```
The `.isEmpty()` [method](/book/functions#extensions) on maps returns `true` if the map is empty and `false` otherwise:
```tact
let fizz: map = emptyMap();
if (fizz.isEmpty()) {
dump("Empty maps are empty, duh!");
}
// Note that comparing the map to `null` behaves the same as the `.isEmpty()` method,
// although such a direct comparison is much less descriptive and is generally discouraged:
if (fizz == null) {
dump("Empty maps are null, which isn't obvious");
}
```
### Compare with `.deepEquals()`[](#deepequals)
500+ gas Available since Tact 1.5
```tact
// K and V correspond to the key and value types of the given map
extends fun deepEquals(self: map, other: map): Bool;
```
The `.deepEquals()` [method](/book/functions#extensions) on maps returns `true` if all entries of the map match corresponding entries of another map, ignoring possible differences in the [underlying serialization logic](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap). Returns `false` otherwise.
```tact
let fizz: map = emptyMap();
let buzz: map = emptyMap();
fizz.set(1, 2);
buzz.set(1, 2);
fizz.deepEquals(buzz); // true
fizz == buzz; // true, and uses much less gas to compute
```
Using `.deepEquals()` is very important in cases where a map comes from a third-party source that doesn’t provide any guarantees about the [serialization layout](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap). For one such example, consider the following code:
some-typescript-code.ts
```typescript
// First map, with long labels
const m1 = beginCell()
.storeUint(2, 2) // long label
.storeUint(8, 4) // key length
.storeUint(1, 8) // key
.storeBit(true) // value
.endCell();
// Second map, with short labels
const m2 = beginCell()
.storeUint(0, 1) // short label
.storeUint(0b111111110, 9) // key length
.storeUint(1, 8) // key
.storeBit(true) // value
.endCell();
```
Here, both maps are formed manually and both contain the same key-value pair. If you were to send both of these maps in a message to a Tact contract and then compare them with `.deepEquals()` and the [equality operator `==`](/book/operators#binary-equality), the former would produce `true` because both maps have the same entry, while the latter would produce `false` as it performs only a shallow comparison of map hashes, which differ since the maps are serialized differently.
Note
This function is very gas expensive, and for the majority of cases it will be sufficient to use the shallow comparison via the [equality `==`](/book/operators#binary-equality) or [inequality `!=`](/book/operators#binary-equality) operators.
### Convert to a `Cell`, `.asCell()`[](#ascell)
```tact
// K and V correspond to the key and value types of the given map
extends fun asCell(self: map): Cell?;
```
To cast maps back to the [underlying](#low-level-representation) [`Cell`](/book/cells#cells) type, use the `.asCell()` [method](/book/functions#extensions). Since maps are initialized to `null`, calling `.asCell()` on a map with no values assigned will return `null` and **not** an empty [`Cell`](/book/cells#cells).
As an example, this method is useful for sending small maps directly in the body of a reply:
```tact
contract Example {
// Persistent state variables
fizz: map; // our map
// Constructor (initialization) function of the contract
init() {
// Setting a bunch of values
self.fizz.set(0, 3);
self.fizz.set(1, 14);
self.fizz.set(2, 15);
self.fizz.set(3, 926);
self.fizz.set(4, 5_358_979_323_846);
}
// Internal message receiver, which responds to empty messages
receive() {
// Here we're converting the map to a Cell and making a reply with it
self.reply(self.fizz.asCell()!!); // explicitly asserting that the map isn't null
}
}
```
### Traverse over entries[](#traverse)
To iterate over map entries, there is a [`foreach`](/book/statements#foreach-loop) loop statement:
```tact
// Empty map
let fizz: map = emptyMap();
// Setting a couple of values under different keys
fizz.set(42, 321);
fizz.set(7, 123);
// Iterating in sequential order: from the smallest keys to the biggest ones
foreach (key, value in fizz) {
dump(key); // Will dump 7 on the first iteration, then 42 on the second
}
```
Read more about it: [`foreach` loop in Book→Statements](/book/statements#foreach-loop).
Note that it is also possible to use maps as simple arrays if you define a `map` with an [`Int`](/book/integers) type for the keys, any allowed `V` type for the values, and keep track of the number of items in a separate variable:
```tact
contract Iteration {
// Persistent state variables
counter: Int as uint32; // Counter of map entries, serialized as a 32-bit unsigned integer
record: map; // Int to Address map
// Constructor (initialization) function of the contract
init() {
self.counter = 0; // Setting the self.counter to 0
}
// Internal message receiver, which responds to a String message "Add"
receive("Add") {
// Get the Context struct
let ctx: Context = context();
// Set the entry: counter Int as the key, ctx.sender Address as the value
self.record.set(self.counter, ctx.sender);
// Increase the counter
self.counter += 1;
}
// Internal message receiver, which responds to a String message "Send"
receive("Send") {
// Loop until reaching the value of self.counter (over all the self.record entries)
let i: Int = 0; // Declare i as usual for loop iterations
while (i < self.counter) {
send(SendParameters {
bounce: false, // Do not bounce back this message
to: self.record.get(i)!!, // Set the sender address, knowing that key i exists in the map
value: ton("0.0000001"), // 100 nanoToncoin (nano-tons)
mode: SendIgnoreErrors, // Send ignoring any transaction errors
body: "SENDING".asComment() // String "SENDING" converted to a Cell as a message body
});
i += 1; // Don't forget to increase i
}
}
// Getter function for obtaining the value of self.record
get fun map(): map {
return self.record;
}
// Getter function for obtaining the value of self.counter
get fun counter(): Int {
return self.counter;
}
}
```
It’s often useful to set an upper-bound restriction on such maps, so that you [don’t hit the limits](#limits-and-drawbacks).
Caution
Note that manually keeping track of the number of items or checking the length of such maps is very error-prone and generally discouraged. Instead, try to wrap your map into a [struct](/book/structs-and-messages#structs) and define [extension functions](/book/functions#extensions) on it. See an example in the Cookbook: [How to emulate an array using a map wrapped in a struct](/cookbook/data-structures#array).
Note
See other examples of map usage in the Cookbook:\
[How to emulate a stack using a map wrapped in a struct](/cookbook/data-structures#stack)\
[How to emulate a circular buffer using a map wrapped in a struct](/cookbook/data-structures#circular-buffer)
## Limits and drawbacks[](#limits-and-drawbacks)
While maps can be convenient to work with on a small scale, they cause a number of issues if the number of items is unbounded and the map significantly grows in size:
* As the upper bound of the smart contract state size is around 65000 items of type [`Cell`](/book/cells#cells), it constrains the storage limit of maps to about 30000 key-value pairs for the whole contract.
* The more entries you have in a map, the higher [compute fees](https://docs.ton.org/develop/howto/fees-low-level#computation-fees) you will incur. Thus, working with large maps makes compute fees difficult to predict and manage.
* Using a large map in a single contract does not allow distributing its workload. Hence, this can significantly degrade overall performance compared to using a smaller map along with multiple interacting smart contracts.
To resolve such issues, you can set an upper-bound restriction on a map as a constant and check against it every time you set a new value in the map:
```tact
contract Example {
// Declare a compile-time constant upper-bound for our map
const MaxMapSize: Int = 42;
// Persistent state variables
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: Int) {
if (self.arrLength >= self.MaxMapSize) {
// Do something, for example, stop the operation
} else {
// Proceed with adding a new item
self.arr.set(self.arrLength, item);
self.arrLength += 1;
}
}
}
```
If you still need a large or unbounded (infinitely large) map, it is better to architect your smart contracts according to the [asynchronous and actor-based model of TON blockchain](https://docs.ton.org/learn/overviews/ton-blockchain). That is, use contract sharding and essentially make the entire blockchain part of your map(s).
---
# Message mode
> Messages are sent with the mode param of the struct SendParameters. It's an Int value, which is combined from base modes and optional flags, which are also Int values
As previously mentioned, messages sent via the [`send()`](/ref/core-send#send) function utilize the `mode` parameter of the `SendParameters` structure. The `mode` is an [`Int`](/book/integers) value, which is combined from base modes and optional flags, which are also [`Int`](/book/integers) values.
It’s possible to use raw [`Int`](/book/integers) values and manually provide them for the `mode`, but for your convenience there is a set of constants you may use to easily construct the compound `mode`. Take a look at the following tables for more information on base modes and optional flags.
Note that there are other [message-sending functions](/book/send#message-sending-functions) — they do not use the `SendParameters` [struct](/book/structs-and-messages#structs), but accept the `mode` as one of their parameters.
## Base modes[](#base-modes)
| Mode value | Constant name | Description |
| ---------: | :-------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0 | Since Tact 1.6 `SendDefaultMode` | Ordinary message (default). |
| 64 | `SendRemainingValue` | Carries all the remaining value of the inbound message in addition to the value initially indicated in the new message. |
| 128 | Use with caution `SendRemainingBalance` | Carries **all the remaining balance** of the current smart contract instead of the value originally indicated in the message. |
| 1024 | Since Tact 1.5 `SendOnlyEstimateFee` | Doesn’t send the message, only estimates the forward fees if the [message-sending function](/book/send#message-sending-functions) computes these. |
The base mode `SendRemainingValue` does **not** take previous actions into account, i.e., it doesn’t recalculate the remaining value of the incoming message based on previously sent messages or actions performed during the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases).
Unlike `SendRemainingValue`, the base mode `SendRemainingBalance` always calculates the current value of the contract balance, which can help solve problems with [complex outbound message processing](/book/send#outbound-message-processing).
However, be **very** careful when using `SendRemainingBalance`, because it works with the balance of the entire contract, and any mistake with it can lead to a total loss of funds.
## Optional flags[](#optional-flags)
| Flag value | Constant name | Description |
| ---------: | :------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| +1 | ~~`SendPayGasSeparately`~~ | Deprecated since Tact 1.6.5Use `SendPayFwdFeesSeparately` instead. |
| +1 | `SendPayFwdFeesSeparately` | Pay [forward fees](https://docs.ton.org/develop/howto/fees-low-level#forward-fees) separately from the message value. |
| +2 | `SendIgnoreErrors` | Ignore any errors arising while processing this message during the action phase. |
| +16 | `SendBounceIfActionFail` | Bounce the transaction in case of any errors during the action phase. Has no effect if flag +2, `SendIgnoreErrors`, is used. |
| +32 | `SendDestroyIfZero` | The current account (contract) will be destroyed if its resulting balance is zero. This flag is often used with mode 128, `SendRemainingBalance`. |
## Combining modes with flags[](#combining-modes-with-flags)
To create the [`Int`](/book/integers) value for the `mode` field of `SendParameters`, you simply combine a base mode with optional flags using the [bitwise OR](/book/operators#binary-bitwise-or) operation.
For example, if you want to send a regular message and pay transfer fees separately, use the default mode 0 and add flag +1 to obtain `mode = 1`, which is equivalent to using the constant `SendPayFwdFeesSeparately`.
Alternatively, if you want to send the entire contract balance and destroy it immediately, use mode 128 and add flag +32 to get `mode = 160`, which is equivalent to `SendRemainingBalance | SendDestroyIfZero`.
Here’s how the latter example would look in code:
```tact
let to: Address = address("...");
let value: Int = ton("1");
send(SendParameters {
to: to,
value: value,
mode: SendRemainingBalance | SendDestroyIfZero,
body: "Hello, World!".asComment(),
});
```
Note that there can be only **one** [base mode](#base-modes), but the number of [optional flags](#optional-flags) may vary: you can use all, none, or only some of them.
Caution
While adding ([`+`](/book/operators#binary-add)) base modes together with optional flags is possible, it is discouraged due to the possibility of obtaining incorrect values. Instead, use the [bitwise OR `|`](/book/operators#binary-bitwise-or), as it is specifically designed for correctly combining flags and performing bit manipulations of the `mode`.
## Functions with implicit mode[](#functions-with-implicit-mode)
Some [message-sending functions](/book/send#message-sending-functions) do not allow setting a mode by passing an argument. This is because their internal logic requires a specific fixed set of modes to be used instead:
* [`emit()`](/ref/core-send#emit) sends a message with the `SendDefaultMode` (0).
* [`self.reply()`](/ref/core-base#self-reply), [`self.notify()`](/ref/core-base#self-notify), and [`self.forward()`](/ref/core-base#self-forward) all use the `SendRemainingValue` mode unless the [`self.storageReserve`](/ref/core-base#self-storagereserve) constant is overridden to be greater than 0, in which case they attempt to use the `SendRemainingBalance` mode.
---
# Operators
> This page lists all the operators in Tact in decreasing order of their precedence, with examples of usage
Almost every contract operates on data: transforming some values into others. The scope may vary, but operators lie at the core of such modifications.
This page lists all the operators in Tact in decreasing order of their [precedence](#precedence), with examples of usage.
Note
Note that there are no implicit type conversions in Tact, so operators can’t be used to, say, add values of different types or compare them in terms of equality without explicitly casting them to the same type. That is done with certain functions from the standard library. See [`Int.toString()`](/ref/core-strings#inttostring) for an example of such a function.
## Table of operators[](#table)
The following table lists operators in order of decreasing [precedence](#precedence), from highest to lowest.
| Brief description | Operators |
| :---------------- | :-------------------------------------------------------------------------------------------------------- |
| Parentheses | [`()`](#parentheses) |
| Unary postfix | [`!!`](#unary-non-null-assert) |
| Unary prefix | [`+`](#unary-plus) [`-`](#unary-negate) [`!`](#unary-inverse) [`~`](#unary-bitwise-not) |
| Multiplicative | [`*`](#binary-multiply) [`/`](#binary-divide) [`%`](#binary-modulo) |
| Additive | [`+`](#binary-add) [`-`](#binary-subtract) |
| Shift | [`>>`](#binary-bitwise-shift-right) [`<<`](#binary-bitwise-shift-left) |
| Relational | [`>`](#binary-greater) [`>=`](#binary-greater-equal) [`<`](#binary-less) [`<=`](#binary-less-equal) |
| Equality | [`==`](#binary-equality) [`!=`](#binary-equality) |
| Bitwise AND | [`&`](#binary-bitwise-and) |
| Bitwise XOR | [`^`](#binary-bitwise-xor) |
| Bitwise OR | [`\|`](#binary-bitwise-or) |
| Logical AND | [`&&`](#binary-logical-and) |
| Logical OR | [`\|\|`](#binary-logical-or) |
| Ternary | [`?:`](#ternary) |
| Assignment | [`=`](#assignment) and [all augmented assignment operators](#augmented-assignment) |
## Precedence[](#precedence)
All operators on this page are given in order of decreasing precedence, from highest to lowest. Precedence is used to determine which operator should be considered in a particular situation. Whenever ambiguity arises, Tact prefers operators with higher precedence over those with lower precedence.
For example, the minus sign (`-`) may be considered either a subtraction operator or a negation operator, which reverses the sign of the expression from plus to minus or vice versa. As the latter has a higher precedence over the former, in cases of ambiguity between the two, Tact will first consider `-` as a negation operator. Only if that interpretation does not make sense for the given expression will Tact consider it as a subtraction operator.
Consider the following code:
```tact
5 + -5; // here, the minus sign would be viewed as a negation operator
5 -5; // while here it would be viewed as a subtraction operator, despite formatting
```
Even though this example may be simple, neglecting precedence rules can often lead to confusing situations with operators. The correct order of operations can be ensured by wrapping every operation in [parentheses](#parentheses), since parentheses have the highest precedence of all expressions and operators.
## Parentheses, `()`[](#parentheses)
Parentheses (also called round brackets, `()`) are more punctuation symbols than actual operators, but their [precedence](#precedence) is higher than the precedence of any other operator. Use parentheses to override the order of operations:
```tact
5 * 5 - 2; // 23
5 * (5 - 2); // 15
```
Note
The current maximum allowed nesting level of expressions is 83. An attempt to write a deeper expression will result in a compilation error:
```tact
fun elegantWeaponsForCivilizedAge(): Int {
return
((((((((((((((((((((((((((((((((
((((((((((((((((((((((((((((((((
(((((((((((((((((((( // 84 parens, compilation error!
42
))))))))))))))))))))
))))))))))))))))))))))))))))))))
))))))))))))))))))))))))))))))));
}
```
## Unary[](#unary)
Unary here means that they are applied only to one operand of the given expression. All unary operators, except for the [non-null assertion](#unary-non-null-assert), have the same [precedence](#precedence).
Unary operators can be one of two types:
* Prefix — placed before the expression.
* Postfix (or suffix) — placed after the expression.
### Non-null assert, `!!`[](#unary-non-null-assert)
The unary double-exclamation mark (*non-null assertion*) operator `!!` is a postfix operator that enforces non-`null` values and allows direct access to the value of the optional variable if it’s not `null`. Otherwise, it raises a compilation error if the compiler can track it, and if not, throws an exception with [exit code 128](/book/exit-codes#128): `Null reference exception`. It can be applied to any optional variable regardless of its non-`null` type.
Note
Read more about optional variables and fields here: [Optionals](/book/optionals)
### Plus, `+`[](#unary-plus)
The unary plus sign operator `+` is a prefix operator that does not alter the value it is applied to. Essentially, it works similar to an [identity function](https://en.wikipedia.org/wiki/Identity_function), but it can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = +2;
+ two; // 2
+(+(+2)); // any number of applications gives back the original value, which is 2
- + - two; // 2
+ - + two; // -2
```
### Negate, `-`[](#unary-negate)
The unary minus sign (*negation*) operator `-` is a prefix operator, which reverses the sign of the expression. It can only be applied to values of type [`Int`](/book/integers):
```tact
let five: Int = 5;
five + -five; // here, the minus sign is a negation operator, not a subtraction operator
-(-1); // double application gives back the original value, which is 1
--1; // 1
```
### Inverse, `!`[](#unary-inverse)
The unary exclamation mark (*inversion*) operator `!` is a prefix operator, which inverts the boolean value of the expression—changing `true` to `false`, and vice versa. It can only be applied to values of type [`Bool`](/book/types#booleans):
```tact
let iLikeTact: Bool = true;
!iLikeTact; // false
!false; // true
!(!false); // false
!!false; // false
```
### Bitwise NOT, `~`[](#unary-bitwise-not)
The unary tilde (*bitwise NOT*) operator `~` is a prefix operator, which inverts or *flips* each bit in the binary representation of the expression — changing each 1 to 0, and vice versa. It can only be applied to values of type [`Int`](/book/integers):
```tact
let answer: Int = 42;
~answer; // -43
~(~answer); // 42
~(~0); // 0
~~0; // 0
```
## Binary[](#binary)
Binary operators are split into several subsections, in order of decreasing [precedence](#precedence). Operators within each subsection have the same [precedence](#precedence) as the subsection itself.
### Multiplication[](#binary-multiplication)
Multiply, divide, or obtain a remainder.
#### Multiply, `*`[](#binary-multiply)
The binary asterisk (*multiplication*) operator `*` is used for multiplication of two values. It can cause [integer overflows](/book/integers#operations).
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two * two; // 4
0 * 1_000_000_000; // 0
-1 * 5; // -5
pow(2, 255) * pow(2, 255); // build error: integer overflow!
```
#### Divide, `/`[](#binary-divide)
The binary slash (*division*) operator `/` is used for integer division of two values, which truncates toward zero if the result is positive and away from zero if the result is negative. This is also called [rounding down](https://en.wikipedia.org/wiki/Rounding#Rounding_down) or rounding toward −∞.
An attempt to divide by zero results in an error with [exit code 4](/book/exit-codes#4): `Integer overflow`.
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two / 2; // 1
two / 1; // 2
-1 / 5; // -1
-1 / -5; // 0
1 / -5; // -1
1 / 5; // 0
6 / 5; // 1, rounding down
-6 / 5; // -2, rounding down (toward -∞)
```
Note
The following relationship between the division and [modulo](#binary-modulo) operators always holds for the `Int` type:
```tact
a / b * b + a % b == a; // true for any Int values of `a` and `b`,
// except when `b` is equal to 0 and we divide `a` by 0,
// which is an attempt to divide by zero resulting in an error
```
#### Modulo, `%`[](#binary-modulo)
The binary percent sign (*modulo*) operator `%` is used for obtaining the modulo of integer division, which must not be confused with obtaining the remainder. For two values with the same sign, modulo and remainder operations are equivalent, but when the operands have different signs, the modulo result always has the same sign as the *divisor* (the value on the right), while the remainder has the same sign as the *dividend* (the value on the left). This difference can cause the results to differ by one unit of the *divisor*.
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two % 2; // 0
two % 1; // 0
1 % 5; // 1
-1 % 5; // 4
1 % -5; // -4
-1 % -5; // -1
```
The simplest way to avoid confusion between obtaining the modulo and obtaining the remainder is to [use only unsigned integers](/book/security-best-practices#misuse-of-signed-integers). Alternatively, consider using the [`abs()`](/ref/core-math#abs) function to ensure non-negative values:
```tact
abs(-1) % abs(-5); // 1
```
Note
The following relationship between the [division](#binary-divide) and modulo operators always holds for the `Int` type:
```tact
a / b * b + a % b == a; // true for any Int values of `a` and `b`,
// except when `b` is equal to 0 and we divide `a` by 0,
// which is an attempt to divide by zero and results in an error
```
Note
Did you know that in JavaScript, `%` works as a *remainder* operator and not a *modulo* operator (as it does in Tact)?\
[Remainder (%) - JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder#description)\
[Modulo - Wikipedia](https://en.wikipedia.org/wiki/Modulo)
### Addition[](#binary-addition)
Add or subtract.
#### Add, `+`[](#binary-add)
The binary plus (*addition*) operator `+` is used for adding numbers together. Going beyond the maximum value of an [`Int`](/book/integers) will result in an error with [exit code 4](/book/exit-codes#4): `Integer overflow`.
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two + 2; // 4
-1 + 1; // 0
pow(2, 254) + pow(2, 254); // 2 * 2^{254}
pow(2, 255) + pow(2, 255); // build error: integer overflow!
pow(2, 255) - 1 + pow(2, 255); // 2^{256} - 1, maximal value of any integer in Tact!
```
#### Subtract, `-`[](#binary-subtract)
The binary minus (*subtraction*) operator `-` is used for subtracting numbers from each other. Going beyond the minimum value of an [`Int`](/book/integers) will result in an error with [exit code 4](/book/exit-codes#4): `Integer overflow`.
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two - 2; // 0
-1 - 1; // -2
pow(2, 254) - pow(2, 254); // 0
pow(2, 255) - pow(2, 255); // 0
pow(2, 256) - pow(2, 256); // build error: integer overflow!
```
### Bitwise shifts[](#binary-bitwise-shifts)
Shift bits to the left or to the right.
#### Shift right, `>>`[](#binary-bitwise-shift-right)
The binary double greater than (*bitwise shift right*) operator `>>` returns an integer whose binary representation is the *left operand* value shifted by the *right operand* number of bits to the right. Excess bits shifted off to the right are discarded, and copies of the leftmost bit are shifted in from the left. This operation is also called “sign-propagating right shift” or “arithmetic right shift” because the sign of the resulting number is the same as the sign of the *left operand*. This is a more efficient way to divide the *left operand* by 2n, where n is equal to the *right operand*.
Can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two >> 1; // 1
-two >> 1; // -1, because >> performs arithmetic shift right,
// which preserves the sign of the left operand
4 >> 1; // 2
5 >> 1; // 2, due to flooring of integer values
pow(2, 254) >> 254; // 1
```
Note
[Bit shifts - Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation#Bit_shifts)\
[Bit manipulation - Wikipedia](https://en.wikipedia.org/wiki/Bit_manipulation)
#### Shift left, `<<`[](#binary-bitwise-shift-left)
The binary double less-than (*bitwise shift left*) operator `<<` returns an integer whose binary representation is the *left operand* value shifted to the left by the number of bits specified by the *right operand*. Excess bits shifted off from the left are discarded, and zero bits are shifted in from the right. This is a more efficient way to multiply the *left operand* by 2n, where n is equal to the *right operand*. Exceeding the maximum value of an [`Int`](/book/integers) will result in an error with [exit code 4](/book/exit-codes#4): `Integer overflow`.
Can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two << 1; // 4
1 << 5; // 1 * 2^5, which is 32
2 << 5; // 2 * 2^5, which is 64
pow(2, 254) == (1 << 254); // true
pow(2, 254) == 1 << 254; // true, no parentheses needed due to higher precedence of << over ==
pow(2, 255) == 1 << 255; // true, but we're very close to overflow here!
```
Note
[Bit shifts - Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation#Bit_shifts)\
[Bit manipulation - Wikipedia](https://en.wikipedia.org/wiki/Bit_manipulation)
### Relation[](#binary-relation)
Find greater, smaller, or equal values.
#### Greater than, `>`[](#binary-greater)
The binary *greater than* operator `>` returns `true` if the left operand is greater than the right operand and `false` otherwise. Can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two > 2; // false
-1 > -3; // true
```
#### Greater than or equal to, `>=`[](#binary-greater-equal)
The binary *greater than or equal to* operator `>=` returns `true` if the left operand is greater than or equal to the right operand and `false` otherwise. Can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two >= 2; // true
-1 >= -3; // true
```
#### Less than, `<`[](#binary-less)
The binary *less than* operator `<` returns `true` if the left operand is less than the right operand, and `false` otherwise. It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two < 2; // false
-1 < -3; // false
```
#### Less than or equal to, `<=`[](#binary-less-equal)
The binary *less than or equal to* operator `<=` returns `true` if the left operand is less than or equal to the right operand, and `false` otherwise. It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two <= 2; // true
-1 <= -3; // false
```
### Equality and inequality, `==` `!=`[](#binary-equality)
The binary equality (*equal*) operator `==` checks whether its two operands are *equal*, returning a result of type [`Bool`](/book/types#booleans).
The binary inequality (*not equal*) operator `!=` checks whether its two operands are *not equal*, returning a result of type [`Bool`](/book/types#booleans).
Both operators require operands to be of the same type, and neither operator performs implicit type conversions, except for the [`Cell`](/book/cells#cells) and [`Slice`](/book/cells#slices) types, which are implicitly compared by their hashes.
Both operators can be applied to the following list of types and values:
* [`Int`](/book/integers)
* [`Bool`](/book/types#booleans)
* [`Address`](/book/types#primitive-types)
* [`Cell`](/book/cells#cells), implicitly compared via [`.hash()`](/ref/core-cells#cellhash)
* [`Slice`](/book/cells#slices), implicitly compared via [`.hash()`](/ref/core-cells#slicehash)
* [`String`](/book/types#primitive-types)
* [`map`](/book/maps), but only if their key and value types are identical
* [Optionals and `null` value](/book/optionals)
```tact
// Int:
2 == 3; // false
2 != 3; // true
// Bool:
true == true; // true
false != true; // true
// Address:
myAddress() == myAddress(); // true
myAddress() != myAddress(); // false
// Cell:
emptyCell() == emptyCell(); // true
emptyCell() != emptyCell(); // false
// Slice:
"A".asSlice() == "A".asSlice(); // true
"A".asSlice() != "A".asSlice(); // false
// String:
"A" == "A"; // true
"A" != "A"; // false
// map:
let map1: map = emptyMap();
let map2: map = emptyMap();
map1 == map2; // true
map1 != map2; // false
// Optionals and null values themselves
let nullable: Int? = null;
nullable == null; // true
null == null; // true
nullable != null; // false
null != null; // false
let anotherNullable: Int? = 5;
nullable == anotherNullable; // false
nullable != anotherNullable; // true
```
Note
The binary equality `==` and inequality `!=` operators implicitly compare [maps](/book/maps) by the hashes of their respective [cells](/book/cells#cells) via the [`.hash()`](/ref/core-cells#cellhash) function. While this is acceptable in the majority of cases—since most map serializers behave identically to the serializer from TON Blockchain sources—it is still possible to obtain false-negative results if a map is serialized manually or if the serialization logic is modified in certain libraries.
If you need to guarantee that compared maps are equal and are willing to pay significantly more gas, use the [`map.deepEquals()`](/book/maps#deepequals) function.
### Bitwise AND, `&`[](#binary-bitwise-and)
The binary ampersand (*bitwise AND*) operator `&` applies a [bitwise AND](https://en.wikipedia.org/wiki/Bitwise_operation#AND), which performs the [logical AND](#binary-logical-and) operation on each pair of corresponding bits of the operands. This is useful when we want to clear selected bits of a number, where each bit represents an individual flag or a boolean state. This makes it possible to “store” up to 257 boolean values per integer, as all integers in Tact are 257-bit signed.
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two & 1; // 0
4 & 1; // 0
3 & 1; // 1
1 & 1; // 1
255 & 0b00001111; // 15
0b11111111 & 0b00001111; // 15
```
Note
[Bitwise AND - Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation#AND)\
[Bit manipulation - Wikipedia](https://en.wikipedia.org/wiki/Bit_manipulation)
### Bitwise XOR, `^`[](#binary-bitwise-xor)
The binary caret (*bitwise XOR*) operator `^` applies a [bitwise XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR), performing the [logical exclusive OR](https://en.wikipedia.org/wiki/Exclusive_or) operation on each pair of corresponding bits of the operands. The result in each position is 1 if exactly one of the bits is 1, or 0 if both bits are 0 or both bits are 1. Thus, it compares two bits, yielding 1 if the bits are different and 0 if they are the same.
It is useful for inverting selected bits of an operand (also called toggling or flipping), as any bit can be toggled by “XORing” it with 1.
It can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two ^ 3; // 1
4 ^ 1; // 5
3 ^ 1; // 2
1 ^ 1; // 0
255 ^ 0b00001111; // 240
0b11111111 ^ 0b00001111; // 240
```
Note
[Bitwise XOR - Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation#XOR)\
[Bit manipulation - Wikipedia](https://en.wikipedia.org/wiki/Bit_manipulation)
### Bitwise OR, `|`[](#binary-bitwise-or)
The binary bar (*bitwise OR*) operator `|` applies a [bitwise OR](https://en.wikipedia.org/wiki/Bitwise_operation#OR), which performs the [logical OR](#binary-logical-or) operation on each pair of corresponding bits of the operands. This is useful when we want to apply a specific [bitmask](https://en.wikipedia.org/wiki/Mask_\(computing\)).
For example, *bitwise OR* is commonly used in Tact to [combine base modes with optional flags](/book/message-mode#combining-modes-with-flags) by masking specific bits to 1 in order to construct a target [message `mode`](/book/message-mode).
Can only be applied to values of type [`Int`](/book/integers):
```tact
let two: Int = 2;
two | 1; // 3
4 | 1; // 5
3 | 1; // 3
1 | 1; // 1
255 | 0b00001111; // 255
0b11111111 | 0b00001111; // 255
```
Note
[Bitwise OR - Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation#OR)\
[Bit manipulation - Wikipedia](https://en.wikipedia.org/wiki/Bit_manipulation)
### Logical AND, `&&`[](#binary-logical-and)
The binary logical AND ([logical conjunction](https://en.wikipedia.org/wiki/Logical_conjunction)) operator `&&` returns `true` if both operands are `true` and `false` otherwise. It’s short-circuited, meaning that it immediately evaluates the entire expression as `false` if the left operand is `false`, without evaluating the right one.
Can only be applied to values of type [`Bool`](/book/types#booleans):
```tact
let iLikeTact: Bool = true;
iLikeTact && true; // true, evaluated both operands
iLikeTact && false; // false, evaluated both operands
false && iLikeTact; // false, didn't evaluate iLikeTact
```
### Logical OR, `||`[](#binary-logical-or)
The binary logical OR ([logical disjunction](https://en.wikipedia.org/wiki/Logical_disjunction)) operator `||` returns `false` only if both operands are `false`, and `true` otherwise. It is short-circuited, meaning that it immediately evaluates the whole expression as `true` if the left operand is `true`, without evaluating the right one.
This operator can only be applied to values of type [`Bool`](/book/types#booleans):
```tact
let iLikeSnails: Bool = false;
iLikeSnails || true; // true, evaluated both operands
iLikeSnails || false; // false, evaluated both operands
true || iLikeSnails; // true, didn't evaluate iLikeSnails
```
## Ternary, `?:`[](#ternary)
The conditional (*ternary*) operator is the only Tact operator that takes three operands: a condition followed by a question mark (`?`), then an expression to execute if the condition evaluates to `true`, followed by a colon (`:`), and finally the expression to execute if the condition evaluates to `false`. This operator is frequently used as an alternative to an [`if...else`](/book/statements#if-else) statement.
The condition must resolve to type [`Bool`](/book/types#booleans):
```tact
// condition
// ↓
true ? "incredibly so" : "absolutely not"; // "incredibly so"
// --------------- ----------------
// ↑ ↑
// | alternative, when condition is false
// |
// consequence, when condition is true
2 + 2 == 4 ? true : false; // true
```
The ternary operator is the only operator with right associativity, besides [assignment-related ones](#assignment). This means that in ambiguous situations, Tact will prefer the longest matching sequence. In short, this makes bracket-less nesting of ternary operators possible, but only for alternative cases (the part that comes after the colon sign `:`):
```tact
// don't need additional parentheses for alternative cases
false ? 1 : (false ? 2 : 3); // 3
false ? 1 : false ? 2 : 3; // also 3
false ? 1 : true ? 2 : 3; // 2
// need additional parentheses for consequence cases (parts between ? and :)
false ? (false ? 1 : 2) : 3; // 3
false ? false ? 1 : 2 : 3; // SYNTAX ERROR!
true ? (false ? 1 : 2) : 3; // 2
```
## Assignment, `=`[](#assignment)
The assignment operator `=` is used to assign a value to a variable or to a field of a [structure](/book/structs-and-messages). The assignment is a statement, and it does not return a value.
```tact
let someVar: Int = 5; // assignment operator = is used here...
someVar = 4; // ...and here
someVar = (someVar = 5); // SYNTAX ERROR!
```
### Augmented assignment[](#augmented-assignment)
Augmented (or compound) assignment operators such as `+=` combine an operation with an [assignment](#assignment). An augmented assignment is a statement and does not return a value.
Augmented assignments are semantically equivalent to regular assignments but include an operation:
```tact
let value: Int = 5;
// this:
value += 5;
// is equivalent to this:
value = value + 5;
```
List of augmented assignment operators:
* `+=`, which uses the [addition operator `+`](#binary-add). Can only be applied to values of type [`Int`](/book/integers).
* `-=`, which uses the [subtraction operator `-`](#binary-subtract). Can only be applied to values of type [`Int`](/book/integers).
* `*=`, which uses the [multiplication operator `*`](#binary-multiply). Can only be applied to values of type [`Int`](/book/integers).
* `/=`, which uses the [division operator `/`](#binary-divide). Can only be applied to values of type [`Int`](/book/integers).
* `%=`, which uses the [modulo operator `%`](#binary-modulo). Can only be applied to values of type [`Int`](/book/integers).
* `&=`, which uses the [bitwise AND operator `&`](#binary-bitwise-and). Can only be applied to values of type [`Int`](/book/integers).
* `^=`, which uses the [bitwise XOR operator `^`](#binary-bitwise-xor). Can only be applied to values of type [`Int`](/book/integers).
* `|=`, which uses the [bitwise OR operator `|`](#binary-bitwise-or). Can only be applied to values of type [`Int`](/book/integers).
* `&&=`, which uses the [logical AND operator `&&`](#binary-logical-and). Can only be applied to values of type [`Bool`](/book/types#primitive-types). Available since Tact 1.6.
* `||=`, which uses the [logical OR operator `||`](#binary-logical-or). Can only be applied to values of type [`Bool`](/book/types#primitive-types). Available since Tact 1.6.
* `<<=`, which uses the [bitwise shift left operator `<<`](#binary-bitwise-shift-left). Can only be applied to values of type [`Int`](/book/integers). Available since Tact 1.6.
* `>>=`, which uses the [bitwise shift right operator `>>`](#binary-bitwise-shift-right). Can only be applied to values of type [`Int`](/book/integers). Available since Tact 1.6.
```tact
let value: Int = 5;
// +=
value + 5; // adds 5
value = value + 5; // adds 5 and assigns result back
value += 5; // also adds 5 and assigns result back
// -=
value - 5; // subtracts 5
value = value - 5; // subtracts 5 and assigns result back
value -= 5; // also subtracts 5 and assigns result back
// *=
value * 5; // multiplies by 5
value = value * 5; // multiplies by 5 and assigns result back
value *= 5; // also multiplies by 5 and assigns result back
// /=
value / 5; // divides by 5
value = value / 5; // divides by 5 and assigns result back
value /= 5; // also divides by 5 and assigns result back
// %=
value % 5; // gets modulo by 5
value = value % 5; // gets modulo by 5 and assigns result back
value %= 5; // also gets modulo by 5 and assigns result back
// &=
value & 5; // bitwise ANDs with 5
value = value & 5; // bitwise ANDs with 5 and assigns result back
value &= 5; // also bitwise ANDs with 5 and assigns result back
// ^=
value ^ 5; // bitwise XORs with 5
value = value ^ 5; // bitwise XORs with 5 and assigns result back
value ^= 5; // also bitwise XORs with 5 and assigns result back
// |=
value | 5; // bitwise ORs with 5
value = value | 5; // bitwise ORs with 5 and assigns result back
value |= 5; // also bitwise ORs with 5 and assigns result back
//
// The following augmented assignment operators are available since Tact 1.6
//
// <<=
value << 5; // bitwise shifts left by 5
value = value << 5; // bitwise shifts left by 5 and assigns result back
value <<= 5; // also bitwise shifts left by 5 and assigns result back
// >>=
value >> 5; // bitwise shifts right by 5
value = value >> 5; // bitwise shifts right by 5 and assigns result back
value >>= 5; // also bitwise shifts right by 5 and assigns result back
let bValue: Bool = true;
// &&=
bValue && false; // logically ANDs with false
bValue = bValue && false; // logically ANDs with false and assigns result back
bValue &&= false; // also logically ANDs with false and assigns result back
// ||=
bValue || true; // logically ORs with true
bValue = bValue || true; // logically ORs with true and assigns result back
bValue ||= true; // also logically ORs with true and assigns result back
```
---
# Optionals
> Data types that can contain the null value in addition to values of their encapsulated primitive or struct types.
As mentioned in the [type system overview](/book/types#optionals), all [primitive types](/book/types#primitive-types), [structs](/book/structs-and-messages#structs), and [message structs](/book/structs-and-messages#messages) can be made nullable. That is, [variables](/book/statements#let), [function parameters](/book/functions), [contract parameters](/book/contracts#parameters) and [structure fields](/book/structs-and-messages) of primitive or struct types can hold the special `null` value that represents the intentional absence of any other value.
Such data types that may or may not contain the `null` value are called *optionals*.
You can make a primitive or struct type into an optional by adding a question mark `?` after its type declaration.
```tact
struct StOpt {
// Optionals as struct fields
opt: Int?; // Int or null
}
message MsOpt {
// Optionals as message fields
opt: StOpt?; // notice how the struct StOpt is used in this definition
}
contract Optionals(
// Optionals as contract parameters
opt: Int?,
address: Address?,
) {
// Optionals as function parameters
fun reset(opt: Int?) {
self.opt = opt;
self.address = null; // explicit null value
}
receive(msg: MsOpt) {
// Optionals as local variables
let opt: Int? = 12;
// Explicit check of the message struct field
if (msg.opt != null) {
// Non-null assertion to work with its inner value
self.reset(msg.opt!!.opt);
}
}
}
```
Since [`map`](/book/maps) and [`bounced`](/book/bounced) are not primitive or struct types, they cannot be made optional. Furthermore, their inner key-value types (in the case of a map) and the inner [message struct](/book/structs-and-messages#messages) (in the case of a bounced constructor) cannot be optional too.
```tact
// COMPILATION ERROR! Map key types cannot be optional
let myMap: map = emptyMap();
// ~~~~
```
Creating a nested optional type by adding multiple question marks `?` is not allowed, as optionals are neither a primitive nor a struct type.
```tact
// COMPILATION ERROR! Nested optional types are not allowed
fun invalidNestedOptional(a: Int??) {}
// ~~~~~
```
Optional fields of [structures](/book/structs-and-messages) that are not defined implicitly hold the `null` value by default. That said, optionals as local variables as optionals require initialization.
```tact
struct StOpt {
// Defaults to null
nullDef: Int?;
}
fun locVar() {
// Requires an initial value: either null or a value of the Int type
let mayBeeBayBee: Int? = null;
}
```
When initializing a new local variable to `null` in the [`let` statement](/book/statements#let), you must explicitly provide the type ascription as it cannot be inferred.
```tact
let opt: Int? = null;
let myMap: map = emptyMap(); // = null, since empty maps are nulls
```
You can assign the current value of one optional to another if their types match. However, to access the non-`null` value of an optional in an expression, you must use the [non-null assertion operator `!!`](/book/operators#unary-non-null-assert).
Attempts to assign or directly access an optional value in an expression will result in a compilation error.
```tact
let opt1: Int? = 42;
let opt2: Int? = 378;
opt1 = opt2; // 378
let notOpt: Int = 42;
notOpt = opt2!!; // opt2 isn't null, so notOpt is 378
notOpt = opt2; // COMPILATION ERROR! Type mismatch
```
To access the non-`null` value of an optional in an expression, you must use the [non-null assertion operator `!!`](/book/operators#unary-non-null-assert) to unwrap the value. If you are sure the value is not `null` at the time of the assertion, use the `!!` operator directly, without prior [`if...else`](/book/statements#if-else) checks.
In the general case it is better to explicitly check for `null` before asserting its absence. Otherwise, when the value is `null`, assertions with `!!` operator will result in a compilation error if the compiler can track it at compile-time, or, if it cannot, in an exception with [exit code 128](/book/exit-codes#128): `Null reference exception`.
```tact
fun misplacedCourage(opt: Int?) {
// `opt` could be null, and the following assertion could throw an exit code 128:
dump(opt!!);
}
```
## Serialization[](#serialization)
When serialized to a [`Cell`](/book/cells#cells) or to [contract’s persistent state](/book/contracts#variables), optionals occupy no less than one bit and, at most, one bit on top of the size of the wrapped type.
That is, if their value is `null`, only a single 0 bit is stored in a [`Builder`](/book/cells#builders). Otherwise, a single 1 bit is stored, followed by the non-`null` value.
Deserialization works inversely. First, a single bit is loaded from a [`Slice`](/book/cells#slices). If it is 0, the value is read as `null`. If it is 1, then the value is loaded from the following data bits.
```tact
struct Wasp {
hasSting: Bool?, // 2 bits max: 1 for the optional, 0 or 1 for the boolean
stingLength: Int?, // 258 bits max: 1 for the optional, 0 or 257 for the integer
}
```
Optionals can have serialization annotations provided after the `as` keyword and have all the same serialization options as their encapsulated primitive or struct types. As such, the optional [`Int?`](/book/integers) type has the most serialization formats available.
```tact
contract IntResting(
// Persistent state variables (contract parameters)
maybeOneByte: Int? as int8, // takes either 1 (when null) or 9 (when not null) bits
maybeTwoBytes: Int? as int16, // takes either 1 or 17 bits
maybeCoins: Int? as coins, // takes either 1 or up to 125 bits, depending on the value
) {
// ...
}
```
---
# Receive messages
> The most common type of message is the internal message - a message sent from one contract to another
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.
## Receive internal messages[](#receive-internal-messages)
To receive a message of the required type, you need to declare a receiver function. For example, `receive("increment")`. This notation means the declaration of a receiver function that will be called when a text with the value `"increment"` 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.
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:
* `receive()` - called when an empty message is sent to the contract
* `receive("message")` - called when a text message with a specific comment is sent to the contract (maximum `"message"` length is 123 bytes)
* `receive(str: String)` - called when an arbitrary text message is sent to the contract
* `receive(msg: MyMessage)` - called when a binary message of type `MyMessage` is sent to the contract
* `receive(msg: Slice)` - called when a binary message of unknown type is sent to the contract
For example, an empty message gets processed by `receive()` and not by `receive(msg: Slice)`, because the former occurs before the latter in the above list. Similarly, a message with the specific comment `"message"` gets processed by `receive("message")` and not by `receive(str: String)`.
```tact
message MyMessage {
value: Int;
}
contract MyContract {
receive() {
// ...
}
receive("message") {
// ...
}
receive(str: String) {
// ...
}
receive(msg: MyMessage) {
// ...
}
receive(msg: Slice) {
// ...
}
}
```
In a contract, the order of declaration of receivers has no effect on how receivers process messages. Hence, changing the order of receivers in the above contract produces an equivalent contract.
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")` in the above contract, then when a message with the comment `"message"` arrives, it will be processed by `receive(str: String)`.
Note that the receiver `receive(msg: Slice)` 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)` is not declared, the transaction will fail with exit code [130](/book/exit-codes/#130).
Naming the parameter of a receiver function with an underscore `_` makes its value considered unused and discarded. This is useful when you don’t need to inspect the message received and only want it to convey a specific opcode:
```tact
message(42) UniverseCalls {}
contract Example {
receive(_: UniverseCalls) {
// Got a Message with opcode 42
}
}
```
---
# Security best practices
> Several anti-patterns and potential attack vectors, as well as best practices, that Tact smart contract developers should be aware of
There are several anti-patterns and potential attack vectors that Tact smart contract developers should be aware of. These can affect the security, efficiency, and correctness of the contracts. Below we discuss the do’s and don’ts specific to writing and maintaining secure Tact smart contracts.
For a deeper understanding, refer to the following resources:
* [Smart contracts guidelines in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/guidelines)
* [Secure Smart Contract Programming in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/security/secure-programming)
* [Curated list of awesome TON security resources](https://github.com/Polaristow/awesome-ton-security/blob/main/README.md)
In addition, consider reading the detailed article by CertiK, a Web3 smart contract auditor: [Secure Smart Contract Programming in Tact: Popular Mistakes in the TON Ecosystem](https://www.certik.com/resources/blog/secure-smart-contract-programming-in-tact-popular-mistakes-in-the-ton).
## Sending sensitive data on-chain[](#sending-sensitive-data-on-chain)
The entire smart contract computation is transparent, and if you have confidential values at runtime, they can be retrieved through simple emulation.
##### Do’s ✅[](#dos)
Do **not** send or store sensitive data on-chain.
##### Don’ts ❌[](#donts)
```tact
message Login {
privateKey: Int as uint256;
signature: Slice;
data: Slice;
}
contract Test() {
receive(msg: Login) {
let publicKey = getPublicKey(msg.privateKey);
require(checkDataSignature(msg.data, msg.signature, publicKey), "Invalid signature!");
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Misuse of signed integers[](#misuse-of-signed-integers)
Unsigned integers are safer because they prevent most errors by design, while signed integers can have unpredictable consequences if not used carefully. Therefore, signed integers should be used only when absolutely necessary.
##### Do’s ✅[](#dos--1)
Prefer to use unsigned integers unless signed integers are required.
##### Don’ts ❌[](#donts--1)
The following is an example of the incorrect use of a signed integer. In the `Vote` [Message](/book/structs-and-messages#messages), the type of the `votes` field is `Int as int32`, which is a 32-bit signed integer. This can lead to spoofing if an attacker sends a negative number of votes instead of a positive one.
```tact
message Vote { votes: Int as int32 }
contract VoteCounter(
votes: Int as uint32,
) {
receive(msg: Vote) {
self.votes += msg.votes;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Invalid throw values[](#invalid-throw-values)
[Exit codes](/book/exit-codes) 0 and 1 indicate normal execution of the compute phase of the transaction. Execution can be unexpectedly aborted by calling a [`throw()`](/ref/core-debug#throw) or [similar functions](/ref/core-debug) directly with exit codes 0 and 1. This can make debugging very difficult since such aborted execution would be indistinguishable from a normal one.
##### Do’s ✅[](#dos--2)
Prefer to use the [`require()`](/ref/core-debug#require) function to state expectations.
```tact
require(isDataValid(msg.data), "Invalid data!");
```
##### Don’ts ❌[](#donts--2)
Don’t throw 0 or 1 directly.
```tact
throw(0);
throw(1);
```
## Insecure random numbers[](#insecure-random-numbers)
Generating truly secure random numbers in TON is challenging. The [`random()`](/ref/core-random#random) function is pseudo-random and depends on [logical time](https://docs.ton.org/develop/smart-contracts/guidelines/message-delivery-guarantees#what-is-a-logical-time). An attacker can predict the randomized number by [brute-forcing](https://en.wikipedia.org/wiki/Brute-force_attack) the logical time in the current block.
##### Do’s ✅[](#dos--3)
* For critical applications, **avoid relying solely on on-chain solutions**.
* Use [`random()`](/ref/core-random#random) with randomized logical time to enhance security by making predictions harder for attackers without access to a validator node. Note, however, that it is still **not entirely foolproof**.
* Consider using the **commit-and-disclose scheme**:
1. Participants generate random numbers off-chain and send their hashes to the contract.
2. Once all hashes are received, participants disclose their original numbers.
3. Combine the disclosed numbers (e.g., summing them) to produce a secure random value.
For more details, refer to the [Secure Random Number Generation page in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/security/random-number-generation).
##### Don’ts ❌[](#donts--3)
Don’t rely on the [`random()`](/ref/core-random#random) function.
```tact
if (random(1, 10) == 7) {
// ...subsequent logic...
}
```
Don’t use randomization in [`external()`](/book/external) message receivers, as it remains vulnerable even with randomized logical time.
## Optimized message handling[](#optimized-message-handling)
String parsing from human-friendly formats into machine-readable binary structures should be done **off-chain**. This approach ensures that only optimized and compact messages are sent to the blockchain, minimizing computational and storage costs while avoiding unnecessary gas overhead.
##### Do’s ✅[](#dos--4)
Perform string parsing from human-readable formats into machine-readable binary structures **off-chain** to keep the contract efficient.
```tact
message Sample { parsedField: Slice }
contract Example() {
receive(msg: Sample) {
// Process msg.parsedField directly
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
##### Don’ts ❌[](#donts--4)
Avoid parsing strings from human-readable formats into binary structures **on-chain**, as this increases computational overhead and gas costs.
```tact
message Sample { field: String }
contract Example {
receive(msg: Sample) {
// Parsing occurs on-chain, which is inefficient
let parsed = field.fromBase64();
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Gas limitation[](#gas-limitation)
Be careful with the `Out of gas error`. It cannot be handled, so try to pre-calculate the gas consumption for each receiver [using tests](/book/debug#tests) whenever possible. This will help avoid wasting extra gas, as the transaction will fail anyway.
##### Do’s ✅[](#dos--5)
```tact
message Vote { votes: Int as int32 }
contract VoteCounter() {
const voteGasUsage = 10000; // precompute with tests
receive(msg: Vote) {
require(context().value > getComputeFee(self.voteGasUsage, false), "Not enough gas!");
// ...subsequent logic...
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Identity validation[](#identity-validation)
Always validate the identity of the sender if your contract logic revolves around trusted senders. This can be done using the [`Ownable`](/ref/stdlib-ownable) trait or using [state init](/book/expressions#initof) validation. You can read more about [Jetton validation](/cookbook/jettons#accepting-jetton-transfer) and [NFT validation](/cookbook/nfts#accepting-nft-ownership-assignment).
##### Do’s ✅[](#dos--6)
Use the [`Ownable`](/ref/stdlib-ownable) trait.
```tact
import "@stdlib/ownable";
message Inc { amount: Int as uint32 }
contract Counter with Ownable {
owner: Address;
val: Int as uint32;
init() {
self.owner = address("...SOME ADDRESS...");
self.val = 0;
}
receive(msg: Inc) {
self.requireOwner();
self.val += msg.amount;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
##### Don’ts ❌[](#donts--5)
Do not execute a message without validating the sender’s identity!
```tact
contract Jetton {
myJettonWalletAddress: Address;
myJettonAmount: Int as coins = 0;
init(jettonWalletCode: Cell, jettonMasterAddress: Address) {
self.myJettonWalletAddress = calculateJettonWalletAddress(
myAddress(),
jettonMasterAddress,
jettonWalletCode,
);
}
receive(msg: JettonTransferNotification) {
// There's no check of the ownership here!
self.myJettonAmount += msg.amount;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Replay protection[](#replay-protection)
Replay protection is a security mechanism that prevents an attacker from reusing a previous message. More information about replay protection can be found on the [External messages page in TON Docs](https://docs.ton.org/develop/smart-contracts/guidelines/external-messages).
##### Do’s ✅[](#dos--7)
To differentiate messages, always include and validate a unique identifier, such as `seqno`. Update the identifier after successful processing to avoid duplicates.
Alternatively, you can implement replay protection similar to the one in the [highload v3 wallet](https://github.com/ton-blockchain/highload-wallet-contract-v3/blob/main/contracts/highload-wallet-v3.func#L60), which is not based on `seqno`.
```tact
message MsgWithSignedData {
bundle: SignedBundle;
seqno: Int as uint64;
rawMsg: Cell;
}
contract Sample(
publicKey: Int as uint256,
seqno: Int as uint64,
) {
external(msg: MsgWithSignedData) {
require(msg.bundle.verifySignature(self.publicKey), "Invalid signature");
acceptMessage();
self.seqno += 1;
sendRawMessage(msg.rawMsg, 0);
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
##### Don’ts ❌[](#donts--6)
Do not rely on signature verification without the inclusion of a sequence number. Messages without replay protection can be resent by attackers because there is nothing to distinguish a valid original message from a replayed one.
```tact
message Msg {
newMessage: Cell;
signature: Slice;
}
contract Sample(
publicKey: Int as uint256,
) {
external(msg: Msg) {
require(
checkDataSignature(msg.toSlice(), msg.signature, self.publicKey),
"Invalid signature",
);
acceptMessage();
sendRawMessage(msg.newMessage, 0);
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Preventing front-running with signature verification[](#preventing-front-running-with-signature-verification)
In TON blockchain, all pending messages are publicly visible in the mempool. Front-running can occur when an attacker observes a pending transaction containing a valid signature and quickly submits their own transaction using the same signature before the original transaction is processed.
##### Do’s ✅[](#dos--8)
Include critical parameters like the recipient address (`to`) within the data that is signed. This ensures that the signature is valid only for the intended operation and recipient, preventing attackers from reusing the signature for their benefit. Also, implement replay protection to prevent the same signed message from being used multiple times.
```tact
struct RequestBody {
to: Address;
seqno: Int as uint64;
}
message(0x988d4037) Request {
signature: Slice as bytes64;
requestBody: RequestBody;
}
contract SecureChecker(
publicKey: Int as uint256,
seqno: Int as uint64, // Add seqno for replay protection
) {
receive(request: Request) {
// Verify the signature against the reconstructed data hash
require(checkSignature(request.requestBody.toCell().hash(), request.signature, self.publicKey), "Invalid signature!");
// Check replay protection
require(request.requestBody.seqno == self.seqno, "Invalid seqno"); // Assuming external message with seqno
self.seqno += 1; // Increment seqno after successful processing
// Ensure the message is sent to the address specified in the signed data
message(MessageParameters {
to: request.requestBody.to, // Use the 'to' from the signed request
value: 0,
mode: SendRemainingBalance, // Caution: sending the whole balance!
bounce: false,
body: "Your action payload here".asComment(), // Example body
});
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
get fun seqno(): Int {
return self.seqno;
}
}
```
Remember to also implement [replay protection](#replay-protection) to prevent reusing the same signature even if it’s correctly targeted.
##### Don’ts ❌[](#donts--7)
Do not sign data without including essential context like the recipient address. An attacker could intercept the message, copy the signature, and replace the recipient address in their own transaction, effectively redirecting the intended action or funds.
```tact
message(0x988d4037) Request {
signature: Slice as bytes64;
data: Slice as remaining; // 'to' address is not part of the signed data
}
contract InsecureChecker(
publicKey: Int as uint256,
) {
receive(request: Request) {
// The signature only verifies 'request.data', not the intended recipient.
if (checkDataSignature(request.data.hash(), request.signature, self.publicKey)) {
// Attacker can see this message, copy the signature, and send their own
// message to a different 'to' address before this one confirms.
// The 'sender()' here is the original sender, but the attacker can initiate
// a similar transaction targeting themselves or another address.
message(MessageParameters {
to: sender(), // Vulnerable: recipient isn't verified by the signature
value: 0,
mode: SendRemainingBalance, // Caution: sending the whole balance!
bounce: false,
});
}
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
Sandbox Limitations
This specific front-running scenario is not reproducible in the `@ton/sandbox` environment due to differences in transaction processing and the absence of a mempool compared to the real network. Always be mindful that local testing environments like the sandbox may not fully capture all real-world network conditions and potential attack vectors.
Furthermore, once a signature is used in a transaction, it becomes publicly visible on the blockchain. Without proper replay protection, anyone can potentially reuse this signature and the associated data in a new transaction if the contract logic doesn’t prevent it.
## Race condition of messages[](#race-condition-of-messages)
A message cascade can be processed over many blocks. Assume that while one message flow is running, an attacker can initiate a second message flow in parallel. That is, if a property was checked at the beginning, such as whether the user has enough tokens, do not assume that it will still be satisfied at the third stage in the same contract.
## Handle/Send bounced messages[](#handlesend-bounced-messages)
Send messages with the bounce flag set to `true`, which is the default for the [`send()`](/ref/core-send#send), [`message()`](/ref/core-send#message), and [`deploy()`](/ref/core-send#deploy) functions. Messages bounce when the execution of a contract fails. You may want to handle this by rolling back the state of the contract using [`try...catch`](/book/statements#try-catch) statements and performing additional processing depending on your logic.
##### Do’s ✅[](#dos--9)
Handle bounced messages via a [bounced message receiver](/book/bounced/#bounced-message-receiver) to correctly react to failed messages.
```tact
contract JettonWalletSample(
owner: Address,
master: Address,
balance: Int,
) {
const minTonsForStorage: Int = ton("0.01");
const gasConsumption: Int = ton("0.01");
receive(msg: TokenBurn) {
let ctx: Context = context();
require(ctx.sender == self.owner, "Invalid sender");
self.balance = self.balance - msg.amount;
require(self.balance >= 0, "Invalid balance");
let fwdFee: Int = ctx.readForwardFee();
require(
ctx.value >
fwdFee + 2 * self.gasConsumption + self.minTonsForStorage,
"Invalid value - Burn",
);
message(MessageParameters {
to: self.master,
value: 0,
mode: SendRemainingValue,
bounce: true,
body: TokenBurnNotification {
queryId: msg.queryId,
amount: msg.amount,
owner: self.owner,
response_destination: self.owner,
}.toCell(),
});
}
bounced(src: bounced) {
self.balance = self.balance + src.amount;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Transaction and phases[](#transaction-and-phases)
From the [Sending messages page](/book/send#outbound-message-processing) of the Book:
> Each transaction on TON Blockchain consists of multiple phases. Outbound messages are evaluated in the compute phase but are **not** sent in that phase. Instead, they’re queued in order of appearance for the action phase, where all actions listed in the compute phase, such as outbound messages or reserve requests, are executed.
Hence, if the compute phase fails, [registers](https://docs.ton.org/v3/documentation/tvm/tvm-overview#control-registers) `c4` (persistent data) and `c5` (actions) won’t be updated. However, it is possible to manually save their state using the [`commit()`](/ref/core-contextstate#commit) function.
## Return gas excesses carefully[](#return-gas-excesses-carefully)
If excess gas is not returned to the sender, the funds will accumulate in your contracts over time. This isn’t terrible in principle, just a suboptimal practice. You can add a function to rake out excess, but popular contracts like TON Jetton still return it to the sender with the [Message](/book/structs-and-messages#messages) using the `0xd53276db` opcode.
##### Do’s ✅[](#dos--10)
Return excesses using a [Message](/book/structs-and-messages#messages) with the `0xd53276db` opcode.
```tact
message(0xd53276db) Excesses {}
message Vote { votes: Int as int32 }
contract Sample(
votes: Int as uint32,
) {
receive(msg: Vote) {
self.votes += msg.votes;
message(MessageParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
body: Excesses {}.toCell(),
});
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Pulling data from another contract[](#pulling-data-from-another-contract)
Contracts in the blockchain can reside in separate shards processed by another set of validators. This means that one contract cannot pull data from another contract. Specifically, no contract can call a [getter function](/book/functions#get) from another contract.
Thus, any on-chain communication is asynchronous and done by sending and receiving messages.
##### Do’s ✅[](#dos--11)
Exchange messages to pull data from another contract.
```tact
message GetMoney {}
message ProvideMoney {}
message TakeMoney { money: Int as coins }
contract OneContract(
money: Int as coins,
) {
receive(msg: ProvideMoney) {
message(MessageParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
body: TakeMoney { money: self.money }.toCell(),
});
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
contract AnotherContract(
oneContractAddress: Address,
) {
receive(_: GetMoney) {
message(MessageParameters {
to: self.oneContractAddress,
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
bounce: false,
body: ProvideMoney {}.toCell(),
});
}
receive(msg: TakeMoney) {
require(sender() == self.oneContractAddress, "Invalid money provider!");
// ...further processing...
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
```
## Pay attention to `safety` option set of `tact.config.json`[](#pay-attention-to-safety-option-set-of-tactconfigjson)
The security of the Tact compiler can be hardened or slightly relaxed by tweaking the [`safety`](/book/config#options-safety) option set in the [`tact.config.json`](/book/config).
Use those settings **wisely** — disabling them often gives performance boosts at the cost of runtime checks and reduced contract safety. On the flip side, enabling them would harden the contracts but make them a bit more expensive to execute.
---
# Sending messages
> TON Blockchain is message-based — to communicate with other contracts and to deploy new ones, you need to send messages.
TON Blockchain is message-based — to communicate with other contracts and to deploy new ones, you need to send messages.
Messages in Tact are commonly composed using a built-in [struct](/book/structs-and-messages#structs) `SendParameters`, which consists of the following fields:
| Field | Type | Description |
| :------- | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mode` | [`Int`](/book/integers) | An 8-bit value that configures how to send a message; defaults to 0. See: [Message `mode`](/book/message-mode). |
| `body` | [`Cell?`](/book/cells#cells) | [Optional](/book/optionals) message body as a [`Cell`](/book/cells#cells). |
| `code` | [`Cell?`](/book/cells#cells) | [Optional](/book/optionals) initial code of the contract (compiled bitcode). |
| `data` | [`Cell?`](/book/cells#cells) | [Optional](/book/optionals) initial data of the contract (arguments of the [`init()` function](/book/contracts#init-function) or values of [contract parameters](/book/contracts#parameters)). |
| `value` | [`Int`](/book/integers) | The amount of [nanoToncoins](/book/integers#nanotoncoin) you want to send with the message. This value is used to cover [forward fees](https://docs.ton.org/develop/howto/fees-low-level#forward-fees) unless the optional flag [`SendPayFwdFeesSeparately`](/book/message-mode#optional-flags) is used. |
| `to` | [`Address`](/book/types#primitive-types) | Recipient internal [`Address`](/book/types#primitive-types) on TON Blockchain. |
| `bounce` | [`Bool`](/book/types#primitive-types) | When set to `true` (default), the message bounces back to the sender if the recipient contract doesn’t exist or wasn’t able to process the message. |
The fields `code` and `data` are what’s called an [init package](/book/expressions#initof), which is used in deployments of new contracts.
## Send a simple reply[](#send-simple-reply)
The simplest message is a reply to an incoming message that returns all excess value from the message:
```tact
self.reply("Hello, World!".asComment()); // asComment converts a String to a Cell with a comment
```
## Send message[](#send-message)
If you need more advanced logic, you can use the `send()` function and the `SendParameters` [struct](/book/structs-and-messages#structs) directly.
In fact, the previous example with [`.reply()`](#send-simple-reply) can be made using the following call to the `send()` function:
```tact
send(SendParameters {
// bounce is set to true by default
to: sender(), // sending message back to the sender
value: 0, // don't add Toncoin to the message...
mode: SendRemainingValue | SendIgnoreErrors, // ...except for the ones received from the sender due to SendRemainingValue
body: "Hello, World".asComment(), // asComment converts a String to a Cell with a comment
});
```
Another example sends a message to the specified [`Address`](/book/types#primitive-types) with a `value` of 1 TON and the `body` as a comment containing the [`String`](/book/types#primitive-types) `"Hello, World!"`:
```tact
let recipient: Address = address("...");
let value: Int = ton("1");
send(SendParameters {
// bounce is set to true by default
to: recipient,
value: value,
mode: SendIgnoreErrors, // skip the message in case of errors
body: "Hello, World!".asComment(),
});
```
The [optional flag](/book/message-mode#optional-flags) `SendIgnoreErrors` means that if an error occurs during [message sending](#outbound-message-processing), it will be ignored, and the given message will be skipped. Message-related [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) [exit codes](/book/exit-codes) that might be thrown without the `SendIgnoreErrors` set are:
* 36: [`Invalid destination address in outbound message`](/book/exit-codes#36)
* 37: [`Not enough Toncoin`](/book/exit-codes#37)
* 39: [`Outbound message doesn't fit into a cell`](/book/exit-codes#39)
* 40: [`Cannot process a message`](/book/exit-codes#40)
## Send typed message[](#send-typed-message)
To send a typed message, you can use the following code:
```tact
let recipient: Address = address("...");
let value: Int = ton("1");
send(SendParameters {
// bounce is set to true by default
to: recipient,
value: value,
mode: SendIgnoreErrors, // skip the message in case of errors
body: SomeMessage { arg1: 123, arg2: 1234 }.toCell(),
});
```
## Deploy contract[](#deploy-contract)
To deploy a contract, you need to calculate its address and initial state with [`initOf`](/book/expressions#initof), then send them in the initialization message:
```tact
let init: StateInit = initOf SecondContract(arg1, arg2);
let address: Address = contractAddress(init);
let value: Int = ton("1");
send(SendParameters {
// bounce is set to true by default
to: address,
value: value,
mode: SendIgnoreErrors, // skip the message in case of errors
code: init.code,
data: init.data,
body: "Hello, World!".asComment(), // not necessary, can be omitted
});
```
Available since Tact 1.6
For cheaper on-chain deployments, prefer using the [`deploy()`](/ref/core-send#deploy) function instead. It computes the address of the contract based on its initial code and data and efficiently composes the resulting message:
```tact
deploy(DeployParameters {
// bounce is set to true by default
init: initOf SecondContract(arg1, arg2), // initial code and data
mode: SendIgnoreErrors, // skip the message in case of errors
value: ton("1"), // a whole Toncoin
body: "Hello, World!".asComment(), // not necessary, can be omitted
});
```
## Outbound message processing[](#outbound-message-processing)
Each transaction on TON Blockchain consists of [multiple phases](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases). Outbound messages are evaluated in the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase), but are **not** sent in that phase. Instead, they are queued for execution in the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) in the order of their appearance in the compute phase. The queue is called an *output action list*, which contains other actions such as [reservations](/ref/core-contextstate#nativereserve).
Outgoing message sends may fail in the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) due to insufficient [action fees](https://docs.ton.org/develop/howto/fees-low-level#action-fee) or [forward fees](https://docs.ton.org/develop/howto/fees-low-level#forward-fees), in which case they will not bounce and **will not revert** the transaction. This can happen because all values are calculated in the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase), all fees are computed by its end, and exceptions do not roll back the transaction during the action phase.
To skip or ignore the queued messages at the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases) in case they cannot be sent, set the optional [`SendIgnoreErrors`](/book/message-mode#optional-flags) flag when composing the message.
Consider the following example:
```tact
// This contract initially has 0 nanoToncoins on the balance
contract FailureIsNothingButAnotherStep {
// All the funds it obtains are from inbound internal messages
receive() {
// 1st outbound message evaluated and queued (but not yet sent)
send(SendParameters {
to: sender(),
value: ton("0.042"), // plus forward fee due to SendPayFwdFeesSeparately
mode: SendIgnoreErrors | SendPayFwdFeesSeparately,
// body is null by default
});
// 2nd outbound message evaluated and queued,
// but not yet sent, and never will be!
send(SendParameters {
to: sender(),
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
// body is null by default
});
} // exit code 37 during action phase!
}
```
There, the second message will not actually be sent:
* After finishing the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase), the remaining value R of the contract is computed.
* During outbound message processing and assuming that sufficient value was provided in the inbound message, the first message leaves R−(0.042+forward\_fees) [nanoToncoins](/book/integers#nanotoncoin) on the balance.
* When the second message is processed, the contract attempts to send R [nanoToncoins](/book/integers#nanotoncoin), but fails because a smaller amount remains.
* Thus, an error with [exit code 37](/book/exit-codes#37) is thrown: `Not enough Toncoin`.
Note that such failures are not exclusive to the [`send()`](/ref/core-send#send) function and may also occur when using other [message-sending functions](#message-sending-functions).
For instance, let us replace the first call to the [`send()`](/ref/core-send#send) function in the previous example with the [`emit()`](/ref/core-send#emit) function. The latter queues the message using the default mode, i.e. 0, and spends some [nanoToncoins](/book/integers#nanotoncoin) to pay the [forward fees](https://docs.ton.org/develop/howto/fees-low-level#forward-fees).
If a subsequent message is then sent with a [`SendRemainingValue`](/book/message-mode#base-modes) base mode, it will cause the same error as before:
```tact
// This contract initially has 0 nanoToncoins on the balance
contract IfItDiesItDies {
// All the funds it obtains are from inbound internal messages
receive() {
// 1st outbound message evaluated and queued (but not yet sent)
// with the mode 0, which is the default
emit("Have you seen this message?".asComment());
// 2nd outbound message evaluated and queued,
// but not yet sent, and never will be!
send(SendParameters {
to: sender(),
value: 0,
bounce: false, // brave and bold
mode: SendRemainingValue,
body: "Not this again!".asComment(),
});
} // exit code 37 during action phase!
}
```
Note
To avoid dealing with similar cases and to simplify future [debugging sessions](/book/debug), consider having only one call to one of the [message-sending functions](#message-sending-functions) per [receiver function](/book/receive).
Alternatively, see the suggested solutions below.
The previous examples discussed a case where the contract has 0 [nanoToncoins](/book/integers#nanotoncoin) on the balance, which is rather rare—in most real-world scenarios, some funds would be present. As such, it is usually better to use the [`SendRemainingBalance`](/book/message-mode#base-modes) base mode, paired with the *necessary* call to the [`nativeReserve()`](/ref/core-contextstate#nativereserve) function.
Like outbound messages, [reserve requests](/ref/core-contextstate#nativereserve) are queued during the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) and executed during the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases).
```tact
// This contract has some Toncoins on the balance, e.g., 0.2 or more
contract MyPrecious {
// Extra funds can be received via a "topup" message
receive("topup") {}
// The rest of the logic is expressed here
receive() {
// 1st outbound message evaluated and queued (but not yet sent)
// with the mode 0, which is the default
emit("Have you seen this message?".asComment());
// Try to keep most of the balance from before this transaction
// Note that nativeReserve() only queues an action to be performed during the action phase
nativeReserve(ton("0.05"), ReserveAtMost | ReserveAddOriginalBalance);
// ----------- ------------- -------------------------
// ↑ ↑ ↑
// | | keeping the balance from before compute phase start
// | might keep less, but will not fail in doing so
// just a tad more on top of the balance, for the fees
// 2nd outbound message evaluated and queued
// with SendRemainingBalance mode
send(SendParameters {
to: sender(),
value: 0,
mode: SendRemainingBalance, // because of the prior nativeReserve(),
// using this mode is safe and will keep
// the original balance plus a little more
body: "I give you my all! Well, all that's not mine!".asComment(),
});
}
}
```
If, instead, you want all outgoing messages to preserve a fixed amount of funds on the balance and **send the rest of the balance**, consider using one of the following functions. Note that these functions require a prior override of the [`self.storageReserve`](/ref/core-base#self-storagereserve) constant:
* [`self.reply()`](/ref/core-base#self-reply)
* [`self.notify()`](/ref/core-base#self-notify)
* [`self.forward()`](/ref/core-base#self-forward)
If you take only one thing away from this section, please remember this: be very careful with the [base modes](/book/message-mode#base-modes) of the message-sending functions, including the [implicitly set modes](/book/message-mode#functions-with-implicit-mode).
## Message sending limits[](#message-sending-limits)
In total, there can be no more than 255 actions queued for execution, meaning that the maximum allowed number of messages sent per transaction is 255.
Attempts to queue more throw an exception with an [exit code 33](/book/exit-codes#33) during the [action phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases): `Action list is too long`.
## Message-sending functions[](#message-sending-functions)
Read more about all message-sending functions in the Reference:
* [`send()`](/ref/core-send#send)
* [`message()`](/ref/core-send#message)
* [`deploy()`](/ref/core-send#deploy)
* [`emit()`](/ref/core-send#emit)
* [`cashback()`](/ref/core-send#cashback)
* [`self.notify()`](/ref/core-base#self-notify)
* [`self.reply()`](/ref/core-base#self-reply)
* [`self.forward()`](/ref/core-base#self-forward)
* [`sendRawMessage()`](/ref/core-send#sendrawmessage)
* [`sendRawMessageReturnForwardFee()`](/ref/core-send#sendrawmessagereturnforwardfee)
---
# Statements
> This page lists all the statements in Tact that can appear anywhere in function bodies.
The following statements can appear anywhere in a [function](/book/functions) body.
## `let` statement[](#let)
The `let` statement allows local and [block](#block)-scoped variable definitions. In Tact, variables are mutable, but **require** to be initialized with an expression.
However, type ascriptions can be omitted, and Tact will infer the type of the new variable from the computed value of the expression:
```tact
let value: Int = 123; // full definition with type and value
let vInferred = 123; // inferred type Int from the mandatory value
let vExplicitCtx: Context = context(); // explicit type Context, a built-in struct
let vCtx = context(); // inferred type Context
```
Note that the initial value of `null` can mean either an empty [`map`](/book/maps) with arbitrary `K` and `V` types or the intentional absence of any other value for the [optional](/book/optionals) type. Therefore, whenever you declare a [`map`](/book/maps) or assign a [`null`](/book/optionals) value, you must explicitly specify the type, as it cannot be inferred:
```tact
let vOptional: Int? = null; // explicit type Int or null
let vOptInt = 42; // implicit type Int
vOptInt = null; // COMPILATION ERROR, type mismatch!
let vOpt = null; // COMPILATION ERROR, cannot infer type!
let vMap: map = emptyMap(); // explicit type map
let vMapWithSerialization: map = emptyMap();
```
Naming a local variable with an underscore `_` causes its value to be considered unused and discarded. This is useful if you do not need the return value of a function with side effects and want to explicitly mark the variable as unused. Note that such wildcard variable name `_` cannot be accessed:
```tact
let _ = someFunctionWithSideEffects(); // with type inference
let _: map = emptyMap(); // with explicit type
dump(_); // COMPILATION ERROR! Cannot access _
```
## `return` statement[](#return)
The `return` statement ends [function](/book/functions) execution and specifies a value to be returned to the [function](/book/functions) caller.
```tact
// Simple wrapper over stdlib function now()
fun getTimeFromNow(offset: Int): Int {
return now() + offset;
}
```
If the function does not have an explicit return type, it has an implicit return type of `void`. As such, the `return` statement must be empty.
```tact
extends mutates fun equalize(self: Int, num: Int) {
if (self == num) {
return;
} else {
self = num;
return;
}
}
```
All statements after the `return` statement are unreachable and will not be executed. Such statements are detected by the Tact compiler, producing an “Unreachable code” error.
This is done to help avoid potential logical errors in the code, although `return`-reachability analysis is not almighty and might reject valid examples.
```tact
extends mutates fun equalize(self: Int, num: Int) {
if (self == num) {
return;
} else {
self = num;
return;
}
throw(42); // COMPILATION ERROR! Unreachable statement
// ~~~~~~~~~
}
fun retWhenNot(flag: Bool): Int {
if (flag) {
throw(200);
} else {
return 42;
}
return 1000; // COMPILATION ERROR! Unreachable statement
// ~~~~~~~~~~~
}
fun throwWrapped(code: Int) {
throw(code);
}
// The following function always throws, but this cannot be
// determined without a thorough inter-procedural analysis
// and, as such, compiler won't allow it.
//
// COMPILATION ERROR! Function does not always return a result
fun triggerCompiler(): Int {
// ~~~~~~~~~~~~~~~
throwWrapped(42);
}
```
## Block[](#block)
A block statement is used to group zero or more statements. The block is delimited by a pair of braces (“curly braces”, `{}`) and contains a list of zero or more statements and declarations.
Some statements, such as [`let`](#let) or [`return`](#return), must end with a terminating semicolon `;`. However, the semicolon of the last statement in the block is optional and may be omitted.
```tact
{ // <- start of the block
// arbitrary statements:
let value: Int = 2 + 2;
dump(value);
} // <- end of the block
{ dump(2 + 2) } // a block with only one statement,
// omitting the last and only semicolon
{
let nah = 3 * 3 * 3; // a block with two statements,
let yay = nah + 42 // but without the last semicolon
}
```
## Expression[](#expression)
An expression statement is an expression used in a place where a statement is expected. The expression is evaluated, and its result is discarded. Therefore, it makes sense only for expressions that have side effects, such as executing a function or updating a variable.
```tact
dump(2 + 2); // stdlib function
```
## Assignment[](#assignment)
Assignment statements use an [assignment operator](/book/operators#assignment) (`=`) or [augmented assignment operators](/book/operators#augmented-assignment) (assignments combined with an operation):
```tact
let value: Int = 0; // definition
value = 5; // assignment
value += 5; // augmented assignment (one of many)
```
Note
Read more about assignment and augmented assignment in their dedicated section: [assignment operators](/book/operators#assignment).
## Destructuring assignment[](#destructuring-assignment)
Available since Tact 1.6
The destructuring assignment is a concise way to unpack [structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) into distinct variables. It mirrors the [instantiation syntax](/book/expressions#instantiation), but instead of creating a new structure it binds every field or some of the fields to their respective variables.
The syntax is derived from the [`let` statement](#let), and instead of specifying the variable name directly, it involves specifying the structure type on the left side of the [assignment operator `=`](/book/operators#assignment), which corresponds to the structure type of the value on the right side.
```tact
// Definition of Example
struct Example { number: Int }
// An arbitrary helper function
fun get42(): Example { return Example { number: 42 } }
fun basic() {
// Basic syntax of destructuring assignment (to the left of "="):
let Example { number } = get42();
// ------- ------ -------
// ↑ ↑ ↑
// | | gives the Example struct
// | definition of "number" variable, derived
// | from the field "number" in Example struct
// target structure type "Example"
// to destructure fields from
// Same as above, but with an instantiation
// to showcase how destructuring syntax mirrors it:
let Example { number } = Example { number: 42 };
// ----------------------
// ↑
// instantiation of Example struct
// Above examples of syntax are roughly equivalent
// to the following series of statements:
let example = Example { number: 42 };
let number = example.number;
}
```
Just like in [instantiation](/book/expressions#instantiation), a trailing comma is allowed.
```tact
struct Example { number: Int }
fun trailblazing() {
let Example {
number, // trailing comma inside variable list
} = Example {
number: 42, // trailing comma inside field list
};
}
```
Note
[Augmented assignment operators](/book/operators#augmented-assignment) do not make sense for such assignments and will therefore be reported as parsing errors:
```tact
struct Example { number: Int }
fun get42(): Example { return Example { number: 42 } }
fun basic() {
let Example { number } += get42();
// ^ this will result in the parse error:
// expected "="
}
```
To create a binding under a different variable name, specify it after the semicolon `:`.
```tact
// Similar definition, but this time the field is called "field", not "number"
struct Example { field: Int }
fun naming(s: Example) {
let Example { field: varFromField } = s;
// ------------ ↑
// ↑ |
// | instance of Example struct, received
// | as a parameter of the function "naming"
// definition of "varFromField" variable, derived
// from the field "field" in Example struct
}
```
Note that the order of bindings doesn’t matter — all fields retain their values and types under their names regardless of the order in which they appear in their definition in the respective [struct](/book/structs-and-messages#structs) or [Message](/book/structs-and-messages#messages).
```tact
// "first" goes first, then goes "second"
struct Two { first: Int; second: String }
fun order(s: Two) {
let Two { second, first } = s;
// ------ -----
// ↑ ↑
// | this variable will be of type Int,
// | same as the "first" field in struct Two
// this variable will be of type String,
// same as the "second" field in struct Two
}
```
Destructuring assignment is exhaustive and requires specifying all the fields as variables. To deliberately ignore some of the fields, use an underscore `_`, which discards the relevant field’s value. Note that such wildcard variable name `_` cannot be accessed:
```tact
// "first" goes first, then goes "second"
struct Two { first: Int; second: String }
fun discard(s: Two) {
let Two { second: _, first } = s;
// ---
// ↑
// discards the "second" field, only taking the "first"
}
```
To completely ignore the rest of the fields, use `..` at the end of the list:
```tact
struct Many { one: Int; two: Int; three: Int; fans: Int }
fun ignore(s: Many) {
let Many { fans, .. } = s;
// --
// ↑
// ignores all the unspecified fields,
// defining only "fans"
}
```
Caution
At the moment, destructuring of nested [structs](/book/structs-and-messages#structs) or [Messages](/book/structs-and-messages#messages) isn’t allowed. That is, the following won’t work:
```tact
struct First { nested: Second }
struct Second { field: Int }
fun example() {
let prep = First { nested: Second { field: 42 } };
let First { nested: Second { field: thing } } = prep;
// ^ this will result in the parse error:
// expected "," or "}"
}
```
## Branches[](#branches)
Control the flow of the code.
### `if...else`[](#if-else)
Caution
Curly brackets (code blocks) are required!
When executing an `if...else` statement, first, the specified condition is evaluated. If the resulting value is `true`, the following statement block is executed. Otherwise, if the condition evaluates to `false`, the optional `else` block is executed. If the `else` block is missing, nothing happens, and execution continues further.
Regular `if` statement:
```tact
// condition
// ↓
if (true) { // consequence, when condition is true
dump(2 + 2);
}
```
With `else` block:
```tact
// condition
// ↓
if (2 + 2 == 4) {
// consequence, when condition is true
dump(true);
} else {
// alternative, when condition is false
dump(false);
}
```
With nested `if...else`:
```tact
// condition
// ↓
if (2 + 2 == 3) {
// consequence, when condition is true
dump("3?");
// condition2
// ↓
} else if (2 + 2 == 4) {
// another consequence, when condition2 is true
dump(true);
} else {
// alternative, when both condition and condition2 are false
dump(false);
}
```
Note
Tact also has a ternary expression `?:`, which is described earlier in the Book: [Ternary](/book/operators#ternary).
### `try...catch`[](#try-catch)
The `try...catch` statement consists of a `try` block and an optional `catch` block, which receives an [`Int`](/book/integers) [exit code](/book/exit-codes) as its only argument. The code in the `try` block is executed first, and if it fails, the code in the `catch` block will be executed, and changes made in the `try` block will be rolled back, if possible.
Note
Note that some TVM state parameters, such as codepage and gas counters, will not be rolled back. That is, all gas usage in the `try` block will be taken into account, and the effects of opcodes that change the gas limit will be preserved.
Regular `try` statement:
```tact
fun braveAndTrue() {
// Let's try and do something erroneous
try {
throw(1042); // throwing with exit code 1042
}
// The following will be executed as the erroneous code above was wrapped in a try block
dump(1042);
}
```
With `catch (e)` block:
```tact
fun niceCatch() {
// Let's try and do something erroneous
try {
throw(1042); // throwing with exit code 1042
} catch (err) {
dump(err); // this will dump the exit code caught, which is 1042
}
}
```
With nested `try...catch`:
```tact
try {
// Preparing an x equal to 0, in such a way that the Tact compiler won't realize it (yet!)
let xs: Slice = beginCell().storeUint(0, 1).endCell().beginParse();
let x: Int = xs.loadUint(1); // 0
try {
throw(101); // 1. throws with exit code 101
} catch (err) { // 2. catches the error and captures its exit code (101) as err
return err / x; // 3. divides err by x, which is zero, throwing with exit code 4
}
} catch (err) { // 4. catches the new error and captures its exit code (4) as err
// ^^^ this works without name collisions because the previous err
// has a different scope and is only visible inside the previous catch block
dump(err); // 5. dumps the last caught exit code (4)
}
```
Note that similar to the [`let` statement](#let), the captured [exit code](/book/exit-codes) in the `catch ()` clause can be discarded by specifying an underscore `_` in its place:
```tact
try {
throw(42);
} catch (_) {
dump("I don't know the exit code anymore");
}
```
Note
Read more about exit codes on the dedicated page: [Exit codes in the Book](/book/exit-codes).
## Loops[](#loops)
Conditionally repeat certain blocks of code multiple times.
### `repeat`[](#repeat-loop)
The `repeat` loop executes a block of code a specified number of times. The number of repetitions should be given as a positive 32-bit [`Int`](/book/integers) in the inclusive range from 1 to 231−1. If the value is greater, an error with [exit code 5](/book/exit-codes#5), `Integer out of expected range`, will be thrown.
If the specified number of repetitions is equal to 0 or any negative number in the inclusive range from −2256 to −1, it is ignored, and the code block is not executed at all.
```tact
let twoPow: Int = 1;
// Repeat exactly 10 times
repeat (10) {
twoPow *= 2;
}
// Skipped
repeat (-1) {
twoPow *= 3333;
}
twoPow; // 1024
```
### `while`[](#while-loop)
The `while` loop continues executing the block of code as long as the given condition is `true`.
In the following example, the value of `x` is decremented by 1 on each iteration, so the loop will run 10 times:
```tact
let x: Int = 10;
while (x > 0) {
x -= 1;
}
```
### `do...until`[](#do-until-loop)
The `do...until` loop is a post-test loop that executes the block of code at least once and then continues to execute it until the given condition becomes `true`.
In the following example, the value of `x` is decremented by 1 on each iteration, so the loop will run 10 times:
```tact
let x: Int = 10;
do {
x -= 1; // executes this code block at least once
} until (x <= 0);
```
### `foreach`[](#foreach-loop)
The `foreach` loop operates on key-value pairs (entries) of the [`map`](/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 are in the map or don’t want to explicitly look for each of the entries using the [`.get()`](/book/maps#get) [method](/book/functions#extensions) of maps.
Note that the names of captured keys and values in each iteration are arbitrary and can be any valid Tact identifier, provided they are new to the current scope. The most common options are: `k` and `v`, or `key` and `value`.
In the following example, the map `cells` has 4 entries, so the loop will run 4 times:
```tact
// Empty map
let cells: map = emptyMap();
// Setting four entries
cells.set(1, beginCell().storeUint(100, 16).endCell());
cells.set(2, beginCell().storeUint(200, 16).endCell());
cells.set(3, beginCell().storeUint(300, 16).endCell());
cells.set(4, beginCell().storeUint(400, 16).endCell());
// A variable for summing up the values
let sum: Int = 0;
// For each key and value pair in the cells map, do:
foreach (key, value in cells) { // or just k, v
let s: Slice = value.beginParse(); // convert Cell to Slice
sum += s.loadUint(16); // sum the Slice values
}
dump(sum); // 1000
```
It’s also possible to iterate over a map in contract storage, and over maps as members of instances of [structure](/book/structs-and-messages) types:
```tact
import "@stdlib/deploy";
struct Fizz { oh_my: map }
message Buzz { oh_my: map }
contract Iterated {
oh_my: map;
receive("call to iterate!") {
let oh_my: map = emptyMap();
oh_my.set(0, 42);
oh_my.set(1, 27);
self.oh_my = oh_my; // assigning local map to the storage one
let fizz = Fizz { oh_my }; // field punning
let buzz = Buzz { oh_my }; // field punning
// Iterating over map in contract storage
foreach (key, value in self.oh_my) {
// ...
}
// Iterating over map member of a struct Fizz instance
foreach (key, value in fizz.oh_my) {
// ...
}
// Iterating over map member of a Message Buzz instance
foreach (key, value in buzz.oh_my) {
// ...
}
}
}
```
Similar to the [`let` statement](#let), either of the captured key or value (or both) can be discarded by specifying an underscore `_` in their place:
```tact
// Empty map
let quartiles: map = emptyMap();
// Setting some entries
quartiles.set(1, 25);
quartiles.set(2, 50);
quartiles.set(3, 75);
// Discarding captured keys
// without modifying them in the map itself
foreach (_, value in quartiles) {}
// Discarding captured values
// without modifying them in the map itself
foreach (key, _ in quartiles) {}
// Discarding both keys and values
// without modifying them in the map itself
foreach (_, _ in quartiles) {
// Can't access via _, but can do desired operations
// n times, where n is the current length of the map
}
```
Caution
At the moment, `foreach` works only with explicitly provided map identifiers and nested identifier constructions, like `foo.bar.targetMap` or `self.baz.targetMap`. That is, returning a map from a function and trying to iterate over its entries won’t work:
```tact
foreach (k, v in emptyMap()) {
// ^ this will give the following error message:
// foreach is only allowed over maps that are path expressions,
// i.e. identifiers, or sequences of direct contract/struct/message accesses,
// like "self.foo" or "self.structure.field"
}
```
Trying to iterate over a map member of a [struct](/book/structs-and-messages#structs) returned from a function also won’t work, because the function call is an expression and neither an identifier nor a nested identifier access:
```tact
foreach (k, v in genCoolStruct().map) {
// ^ this will give the following error message:
// foreach is only allowed over maps that are path expressions,
// i.e. identifiers, or sequences of direct contract/struct/message accesses,
// like "self.foo" or "self.structure.field"
}
```
Note
For additional loop examples, see: [Loops in Tact-By-Example](https://tact-by-example.org/04-loops).
---
# Structs and Messages
> Structs can define complex data types that contain multiple fields of different types, while Messages also have a 32-bit header and are convenient for receiving and sending message bodies on TON Blockchain.
Tact supports a number of [primitive data types](/book/types#primitive-types) that are tailored for smart contract use. However, using individual means of storage often becomes cumbersome, so there are [structs](#structs) and [Messages](#messages), which allow combining types together.
After successful compilation, Tact produces a [compilation report](/book/compile), which features all the declared structs and Messages, including those from the Core standard library. See the [Structures section of the compilation report](/book/compile#structures) for details.
Caution
Currently, circular types are **not** possible. This means that struct or message struct `A` can’t have a field of struct or message struct type `B` if `B` has a field of type `A`.
Therefore, the following code **won’t** compile:
```tact
struct A {
circularFieldA: B;
}
struct B {
impossibleFieldB: A;
}
```
## Structs[](#structs)
Structs can define complex data types that contain multiple fields of different types. They can also be nested.
```tact
struct Point {
x: Int as int64;
y: Int as int64;
}
struct Line {
start: Point;
end: Point;
}
```
Structs can also contain default fields and define fields of [optional types](/book/optionals). This can be useful if you have a lot of fields but don’t want to keep specifying common values for them in [new instances](#instantiate).
```tact
struct Params {
name: String = "Satoshi"; // default value
age: Int?; // field with an optional type Int?
// and default value of null
point: Point; // nested structs
}
```
Structs are also useful as return values from getters or other internal functions. They effectively allow a single getter to return multiple values.
```tact
contract StructsShowcase {
params: Params; // struct as a contract's persistent state variable
init() {
self.params = Params {
point: Point {
x: 4,
y: 2,
},
};
}
get fun params(): Params {
return self.params;
}
}
```
Note that the last semicolon `;` in a struct definition is optional and may be omitted:
```tact
struct Mad { ness: Bool }
struct MoviesToWatch {
wolverine: String;
redFunnyGuy: String
}
```
The order of fields matters, as it corresponds to the resulting memory layout in [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language). However, unlike some languages with manual memory management, Tact does not have any padding between fields.
Consequently, structs cannot be empty and must declare at least one field.
## Messages[](#messages)
Messages can hold [structs](#structs) in them:
```tact
struct Point {
x: Int;
y: Int;
}
message Add {
point: Point; // holds a struct Point
}
```
### Message opcodes[](#message-opcodes)
Messages are almost the same as [structs](#structs), with the only difference being that Messages have a 32-bit integer header in their serialization containing their unique numeric id, commonly referred to as an *opcode* (operation code). This allows Messages to be used with [receivers](/book/receive), since the contract can distinguish different types of messages based on this id.
Tact automatically generates these unique ids (opcodes) for every received Message, which can be observed in the [Structures section of the compilation report](/book/compile#structures).
Additionally and unlike regular [structs](#structs), this allows Messages to be declared empty:
```tact
message TotallyValid {}
```
However, opcodes can be overridden manually:
```tact
// This Message overrides its unique id (opcode) with 411,
// which allows it to be recognized in the receiver functions.
message(411) InfoNotification {}
// This Message overrides its opcode with 0x7362d09c
message(0x7362d09c) TokenNotification {
forwardPayload: Slice as remaining;
}
// Since those Messages have unique opcode prefixes,
// incoming message bodies can be differentiated based on them.
contract OpcodeRecognition {
receive(msg: InfoNotification) {
// ...
}
receive(msg: TokenNotification) {
// ...
}
}
```
This is useful in cases where you want to handle certain opcodes of a given smart contract, such as the [Jetton standard](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md). The messages and their respective opcodes that this contract can process are defined [here in the Tact’s Jetton implementation](https://github.com/tact-lang/jetton/blob/3f02e1065b871cbab300e019f578c3fb0b19effa/src/contracts/base/messages.tact). They serve as an interface to the smart contract.
Available since Tact 1.6 A message opcode can be any [compile-time](/ref/core-comptime) expression that evaluates to a positive 32-bit integer, so the following is also valid:
```tact
// This Message overrides its unique id (opcode) with 898001897,
// which is the evaluated integer value of the specified compile-time expression
message((crc32("Tact") + 42) & 0xFFFF_FFFF) MsgWithExprOpcode {
field: Int as uint4;
}
```
Note
For more in-depth information on this, see:\
[Convert received messages to `op` operations](/book/func#convert-received-messages-to-op-operations)\
[Internal message body layout in TON Docs](https://docs.ton.org/develop/smart-contracts/guidelines/internal-messages#internal-message-body)\
[Messages of the Jetton implementation in Tact](https://github.com/tact-lang/jetton/blob/3f02e1065b871cbab300e019f578c3fb0b19effa/src/contracts/base/messages.tact)\
[Common examples of working with Fungible Tokens (Jettons) in Tact](/cookbook/jettons)
Available since Tact 1.6.7 A message opcode can be obtained by calling the `opcode()` method on any message type:
```tact
message(0x777) TripleAxe {
prize: Int as uint32;
}
contract Example {
receive(msg: TripleAxe) {
dump(TripleAxe.opcode()); // 0x777
}
}
```
## Operations[](#operations)
### Instantiate[](#instantiate)
The creation of [struct](#structs) and [Message](#messages) instances resembles [function calls](/book/expressions#static-function-call), but instead of parentheses `()`, one needs to specify arguments in braces `{}` (curly brackets):
```tact
struct StA {
field1: Int;
field2: Int;
}
message MsgB {
field1: String;
field2: String;
}
fun example() {
// Instance of a struct StA
StA {
field1: 42,
field2: 68 + 1, // trailing comma is allowed
};
// Instance of a Message MsgB
MsgB {
field1: "May the 4th",
field2: "be with you!", // trailing comma is allowed
};
}
```
When the name of a variable or constant assigned to a field coincides with the name of that field, Tact provides a handy syntactic shortcut sometimes called field punning. With it, you don’t have to type more than necessary:
```tact
struct PopQuiz {
vogonsCount: Int;
nicestNumber: Int;
}
fun example() {
// Let's introduce a couple of variables
let vogonsCount: Int = 42;
let nicestNumber: Int = 68 + 1;
// You may instantiate the struct as usual and assign variables to fields,
// but that can be a bit repetitive and tedious at times
PopQuiz { vogonsCount: vogonsCount, nicestNumber: nicestNumber };
// Let's use field punning and type less,
// because our variable names happen to be the same as the field names
PopQuiz {
vogonsCount,
nicestNumber, // trailing comma is allowed here too!
};
}
```
Note
Because instantiation is an expression in Tact, it’s also described on the related page: [Instantiation expression](/book/expressions#instantiation).
### Convert to a `Cell`, `.toCell()`[](#tocell)
It is possible to convert an arbitrary [struct](#structs) or [Message](#messages) to the [`Cell`](/book/cells#cells) type by using the `.toCell()` [extension function](/book/functions#extensions):
```tact
struct Big {
f1: Int;
f2: Int;
f3: Int;
f4: Int;
f5: Int;
f6: Int;
}
fun conversionFun() {
dump(Big {
f1: 10000000000, f2: 10000000000, f3: 10000000000,
f4: 10000000000, f5: 10000000000, f6: 10000000000,
}.toCell()); // x{...cell with references...}
}
```
Note
See these extension functions in the Reference:\
[`Struct.toCell()`](/ref/core-cells#structtocell)\
[`Message.toCell()`](/ref/core-cells#messagetocell)
### Obtain from a `Cell` or `Slice`, `.fromCell()` and `.fromSlice()`[](#fromcellslice)
Instead of manually parsing a [`Cell`](/book/cells#cells) or [`Slice`](/book/cells#slices) via a series of relevant `.loadSomething()` function calls, one can use `.fromCell()` and `.fromSlice()` [extension functions](/book/functions#extensions) to convert the provided [`Cell`](/book/cells#cells) or [`Slice`](/book/cells#slices) into the needed [struct](#structs) or [Message](#messages).
These extension functions only attempt to parse a [`Cell`](/book/cells#cells) or [`Slice`](/book/cells#slices) according to the structure of your struct or Message. In case the layouts don’t match, various exceptions may be thrown — make sure to wrap your code in [`try...catch`](/book/statements#try-catch) blocks to prevent unexpected results.
```tact
struct Fizz { foo: Int }
message(100) Buzz { bar: Int }
fun constructThenParse() {
let fizzCell = Fizz { foo: 42 }.toCell();
let buzzCell = Buzz { bar: 27 }.toCell();
let parsedFizz: Fizz = Fizz.fromCell(fizzCell);
let parsedBuzz: Buzz = Buzz.fromCell(buzzCell);
}
```
Note
See these extension functions in the Reference:\
[`Struct.fromCell()`](/ref/core-cells#structfromcell)\
[`Struct.fromSlice()`](/ref/core-cells#structfromslice)\
[`Message.fromCell()`](/ref/core-cells#messagefromcell)\
[`Message.fromSlice()`](/ref/core-cells#messagefromslice)
### Conversion laws[](#conversion-laws)
Whenever one converts between [`Cell`](/book/cells#cells)/[`Slice`](/book/cells#slices) and [struct](#structs)/[Message](#messages) via `.toCell()` and `.fromCell()` functions, the following laws hold:
* For any instance of type [struct](#structs)/[Message](#messages), calling `.toCell()` on it and then applying `Struct.fromCell()` (or `Message.fromCell()`) to the result gives back a copy of the original instance:
```tact
struct ArbitraryStruct { fieldNotFound: Int = 404 }
message(0x2A) ArbitraryMessage {}
fun lawOne() {
let structInst = ArbitraryStruct {};
let messageInst = ArbitraryMessage {};
ArbitraryStruct.fromCell(structInst.toCell()); // = structInst
ArbitraryMessage.fromCell(messageInst.toCell()); // = messageInst
// Same goes for Slices, with .toCell().asSlice() and .fromSlice()
ArbitraryStruct.fromSlice(structInst.toCell().asSlice()); // = structInst
ArbitraryMessage.fromSlice(messageInst.toCell().asSlice()); // = messageInst
}
```
* For any [`Cell`](/book/cells#cells) with the same [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) layout as a given [struct](#structs)/[Message](#messages), calling `Struct.fromCell()` (or `Message.fromCell()`) on it and then converting the result to a [`Cell`](/book/cells#cells) via `.toCell()` will give a copy of the original [`Cell`](/book/cells#cells):
```tact
struct ArbitraryStruct { val: Int as uint32 }
message(0x2A) ArbitraryMessage {}
fun lawTwo() {
// Using 32 bits to store 42 just so this cellInst can be
// reused for working with both ArbitraryStruct and ArbitraryMessage
let cellInst = beginCell().storeUint(42, 32).endCell();
ArbitraryStruct.fromCell(cellInst).toCell(); // = cellInst
ArbitraryMessage.fromCell(cellInst).toCell(); // = cellInst
// Same goes for Slices, with .fromSlice() and .toCell().asSlice()
let sliceInst = cellInst.asSlice();
ArbitraryStruct.fromSlice(sliceInst).toCell().asSlice(); // = sliceInst
ArbitraryMessage.fromSlice(sliceInst).toCell().asSlice(); // = sliceInst
}
```
---
# Type system overview
> Every variable, item, and value in Tact programs has a type
Every variable, item, and value in Tact programs has a type. They can be:
* One of the [primitive types](#primitive-types)
* Or one of the [composite types](#composite-types)
Additionally, many of these types [can be made nullable](#optionals).
## Primitive types[](#primitive-types)
Tact supports a number of primitive data types that are tailored for smart contract use:
* [`Int`](/book/integers) — All numbers in Tact are 257-bit signed integers, but [smaller representations](/book/integers#serialization) can be used to reduce storage costs.
* [`Bool`](#booleans) — Classical boolean with `true` and `false` values.
* `Address` — Standard [smart contract address](https://docs.ton.org/learn/overviews/addresses#address-of-smart-contract) in TON Blockchain.
* [`Cell`](/book/cells#cells), [`Builder`](/book/cells#builders), [`Slice`](/book/cells#slices) — Low-level primitives of [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview).
* `String` — Immutable text strings.
* `StringBuilder` — Helper type that allows you to concatenate strings in a gas-efficient way.
### Booleans[](#booleans)
The primitive type `Bool` is the classical boolean type, which can hold only two values: `true` and `false`. It is convenient for boolean and logical operations, as well as for storing flags.
There are no implicit type conversions in Tact, so addition ([`+`](/book/operators#binary-add)) of two boolean values is not possible. However, many comparison [operators](/book/operators) are available, such as:
* `&&` for [logical AND](/book/operators#binary-logical-and) with its [augmented assignment version `&&=`](/book/operators#augmented-assignment),
* `||` for [logical OR](/book/operators#binary-logical-or) with its [augmented assignment version `||=`](/book/operators#augmented-assignment),
* `!` for [logical inversion](/book/operators#unary-inverse),
* `==` and `!=` for checking [equality](/book/operators#binary-equality),
* and `!!` for [non-null assertion](/book/optionals).
Persisting bools to state is very space-efficient, as they only occupy 1 bit. Storing 1000 bools in state [costs](https://ton.org/docs/develop/smart-contracts/fees#how-to-calculate-fees) about 0.00072 TON per year.
## Composite types[](#composite-types)
Using individual means of storage often becomes cumbersome, so there are ways to combine multiple [primitive types](#primitive-types) together to create composite types:
* [Maps](#maps) — associations of keys with values.
* [Structs and Messages](#structs-and-messages) — data structures with typed fields.
* [Optionals](#optionals) — `null` values for variables, parameters, and fields of [structs and Messages](#structs-and-messages).
In addition to the composite types above, Tact provides a special type constructor [`bounced`](/book/bounced), which can only be specified in [bounced message receivers](/book/bounced).
While [contracts](#contracts) and [traits](#traits) are also considered a part of the Tact type system, one cannot pass them around like [structs and Messages](#structs-and-messages). Instead, it is possible to obtain the initial state of a given contract by using the [`initOf`](/book/expressions#initof) expression.
It is also possible to obtain only the code of a given contract by using the [`codeOf`](/book/expressions#codeof) expression.
### Maps[](#maps)
The type [`map`](/book/maps) is used as a way to associate keys of type `K` with corresponding values of type `V`.
Example of a [`map`](/book/maps):
```tact
let mapExample: map = emptyMap(); // empty map with Int keys and values
```
Learn more about them on the dedicated page: [Maps](/book/maps).
### Structs and Messages[](#structs-and-messages)
[Structs](/book/structs-and-messages#structs) and [Messages](/book/structs-and-messages#messages) are the two main ways of combining multiple [primitive types](#primitive-types) into a composite one.
Example of a [struct](/book/structs-and-messages#structs):
```tact
struct Point {
x: Int;
y: Int;
}
```
Example of a [Message](/book/structs-and-messages#messages):
```tact
// Custom numeric id of the Message
message(0x11111111) SetValue {
key: Int;
value: Int?; // Optional, Int or null
coins: Int as coins; // Serialization into TL-B types
}
```
Learn more about them on the dedicated page: [structs and Messages](/book/structs-and-messages).
### Optionals[](#optionals)
All [primitive types](#primitive-types), as well as [structs and Messages](#structs-and-messages), can be nullable and hold a special `null` value.
Example of an [optional](/book/optionals):
```tact
let opt: Int? = null; // Int or null, explicitly assigned null
```
Learn more about them on the dedicated page: [Optionals](/book/optionals).
### Contracts[](#contracts)
[Contracts](/book/contracts) in Tact conveniently represent smart contracts on TON blockchain. They hold all [functions](/book/functions), [getters](/book/functions#get), and [receivers](/book/functions#receivers) of a TON contract, and much more.
Example of a [contract](/book/contracts):
```tact
contract HelloWorld {
// Persistent state variable
counter: Int;
// Constructor function init(), where all the variables are initialized
init() {
self.counter = 0;
}
// Internal message receiver, which responds to a string message "increment"
receive("increment") {
self.counter += 1;
}
// Getter function with return type Int
get fun counter(): Int {
return self.counter;
}
}
```
Read more about them on the dedicated page: [Contracts](/book/contracts).
### Traits[](#traits)
Tact doesn’t support classical class inheritance but instead introduces the concept of *traits*, which can be viewed as abstract contracts (like abstract classes in popular object-oriented languages). They have the same structure as [contracts](#contracts) but can’t [initialize persistent state variables](/book/contracts#init-function).
A trait can also allow the contract inheriting it to override the behavior of its [functions](/book/functions#inheritance) and the values of its [constants](/book/constants#virtual-and-abstract-constants).
Example of a trait [`Ownable`](/ref/stdlib-ownable#ownable) from [`@stdlib/ownable`](/ref/stdlib-ownable):
```tact
trait Ownable {
// Persistent state variable, which cannot be initialized in the trait
owner: Address;
// Internal function
fun requireOwner() {
throwUnless(TactExitCodeAccessDenied, context().sender == self.owner);
}
// Getter function with return type Address
get fun owner(): Address {
return self.owner;
}
}
```
And the [contract](#contracts) that uses the trait [`Ownable`](/ref/stdlib-ownable#ownable):
```tact
contract Treasure with Ownable {
// Persistent state variable, which MUST be defined in the contract
owner: Address;
// Constructor function init(), where all the variables are initialized on-chain
init(owner: Address) {
self.owner = owner;
}
}
```
Alternatively, a contract may use the [contract parameter syntax](/book/contracts#parameters), in which case it must list all the persistent state variables inherited from all of its traits:
```tact
contract Treasure(
// Persistent state variable, to be defined at deployment
owner: Address,
) with Ownable {}
```
---
# Contract upgrades
> The Tact compiler allows, but does not encourage, code changes or upgrades after the contract is deployed.
The Tact compiler allows, but does not encourage, code changes or upgrades after the contract is deployed. While nice in theory, runtime code replacements introduce possible security, stability, and trust issues.
The latter is not negligible — many people expect smart contracts to behave like regular contracts, i.e., something that can be changed or reverted only by introducing a different contract, and **not** by modifying the existing one. Giving the owner a way to replace the code of an entire smart contract is usually considered a bad practice that can easily lead to rug pulls or other malicious actions that result in the loss of funds for the smart contract users.
It’s safer to impose some restrictions, such as a time-locked upgrade that is applied only after it has been thoroughly tested and discussed within your community. For a sample implementation, read the following Cookbook page at your discretion and apply at your own risk: [Code and data upgrades](/cookbook/upgrades).
---
# Access control
> This page lists common examples of working with privileges, ownership, and access control.
This page lists common examples of working with privileges, ownership, and access control.
## How to check sender privileges using the Ownable trait[](#how-to-check-sender-privileges-using-the-ownable-trait)
```tact
// Ownable has to be imported from stdlib
import "@stdlib/ownable";
message FooBarMsg {
newVal: Int as uint32;
}
// Ownable trait can limit certain actions to the owner only
contract SenderChecker with Ownable {
// Persistent state variables
owner: Address; // Ownable trait requires you to add this exact state variable
val: Int as uint32; // some value
init() {
// We can initialize owner to any value we want, the deployer in this case:
self.owner = sender();
self.val = 0;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
receive("inc") {
self.requireOwner(); // Throws exit code 132 if the sender isn't the owner
self.val += 1;
}
receive(msg: FooBarMsg) {
self.requireOwner(); // Throws exit code 132 if the sender isn't the owner
self.val = msg.newVal;
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gT3duYWJsZSBoYXMgdG8gYmUgaW1wb3J0ZWQgZnJvbSBzdGRsaWIKaW1wb3J0ICJAc3RkbGliL293bmFibGUiOwoKbWVzc2FnZSBGb29CYXJNc2cgewogICAgbmV3VmFsOiBJbnQgYXMgdWludDMyOwp9CgovLyBPd25hYmxlIHRyYWl0IGNhbiBsaW1pdCBjZXJ0YWluIGFjdGlvbnMgdG8gdGhlIG93bmVyIG9ubHkKY29udHJhY3QgU2VuZGVyQ2hlY2tlciB3aXRoIE93bmFibGUgewogICAgLy8gUGVyc2lzdGVudCBzdGF0ZSB2YXJpYWJsZXMKICAgIG93bmVyOiBBZGRyZXNzOyAvLyBPd25hYmxlIHRyYWl0IHJlcXVpcmVzIHlvdSB0byBhZGQgdGhpcyBleGFjdCBzdGF0ZSB2YXJpYWJsZQogICAgdmFsOiBJbnQgYXMgdWludDMyOyAvLyBzb21lIHZhbHVlCgogICAgaW5pdCgpIHsKICAgICAgICAvLyBXZSBjYW4gaW5pdGlhbGl6ZSBvd25lciB0byBhbnkgdmFsdWUgd2Ugd2FudCwgdGhlIGRlcGxveWVyIGluIHRoaXMgY2FzZToKICAgICAgICBzZWxmLm93bmVyID0gc2VuZGVyKCk7CiAgICAgICAgc2VsZi52YWwgPSAwOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIHJlY2VpdmUoImluYyIpIHsKICAgICAgICBzZWxmLnJlcXVpcmVPd25lcigpOyAvLyBUaHJvd3MgZXhpdCBjb2RlIDEzMiBpZiB0aGUgc2VuZGVyIGlzbid0IHRoZSBvd25lcgogICAgICAgIHNlbGYudmFsICs9IDE7CiAgICB9CgogICAgcmVjZWl2ZShtc2c6IEZvb0Jhck1zZykgewogICAgICAgIHNlbGYucmVxdWlyZU93bmVyKCk7IC8vIFRocm93cyBleGl0IGNvZGUgMTMyIGlmIHRoZSBzZW5kZXIgaXNuJ3QgdGhlIG93bmVyCiAgICAgICAgc2VsZi52YWwgPSBtc2cubmV3VmFsOwogICAgfQp9)
Useful links:
[`trait Ownable` in Core library](/ref/stdlib-ownable#ownable)
Hey there!
Didn’t find your favorite example of access control? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Algorithms
> Common algorithm implementations in Tact, generally geared towards contract development
An algorithm is a finite sequence of rigorous instructions, typically used to solve a class of specific problems or to perform a computation.
Not implemented
This page is a stub. [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Data structures
> This page lists a handy collection of data structures implemented in Tact for your day-to-day needs and beyond.
Data structures are formats for data organization, management, and storage that are usually chosen for efficient access to data. More precisely, a data structure is a collection of data values, the relationships among them, and the functions or operations that can be applied to the data.
This page lists a handy collection of data structures implemented in Tact for your day-to-day needs and beyond.
All of the data structures listed here are made using the built-in [`map`](/book/maps) type. For a description and basic usage of maps, see the [dedicated page in the Book](/book/maps).
## Array[](#array)
An [array](https://en.wikipedia.org/wiki/Array_\(data_structure\)) is a data structure consisting of a continuous block of memory, which represents a collection of elements of the same memory size, each identified by at least one array key or *index*.
The following example emulates an array using a [`map`](/book/maps) wrapped in a [struct](/book/structs-and-messages#structs), where `V` can be any of the [allowed value types](/book/maps#allowed-types) of the map:
```tact
struct Array {
// An array of Int values as a map of Ints to Ints,
// with serialization of its keys to uint16 to save space
m: map;
// Length of the array, defaults to 0
length: Int = 0;
}
// Compile-time constant upper bound for our map representing an array.
const MaxArraySize: Int = 5_000; // 5,000 entries max, to stay reasonably far from limits
// Extension mutation function for adding new entries to the end of the array
extends mutates fun append(self: Array, item: Int) {
require(self.length + 1 <= MaxArraySize, "No space in the array left for new items!");
self.m.set(self.length, item); // set the entry (key-value pair)
self.length += 1; // increase the length field
}
// Extension mutation function for inserting new entries at the given index
extends mutates fun insert(self: Array, item: Int, idx: Int) {
require(self.length + 1 <= MaxArraySize, "No space in the array left for new items!");
require(idx >= 0, "Index of the item cannot be negative!");
require(idx < self.length, "Index is out of array bounds!");
// Move all items from idx to the right
let i: Int = self.length; // not a typo, as we need to start from the non-existing place
while (i > idx) {
// Note that we use the !! operator, as we know for sure the value would be there
self.m.set(i, self.m.get(i - 1)!!);
i -= 1;
}
// Insert the new item
self.m.set(idx, item); // set the entry (key-value pair)
self.length += 1; // increase the length field
}
// Extension function for getting the value at the given index
extends fun getIdx(self: Array, idx: Int): Int {
require(self.length > 0, "No items in the array!");
require(idx >= 0, "Index of the item cannot be negative!");
require(idx < self.length, "Index is out of array bounds!");
// Note that we use the !! operator, as we know for sure the value would be there
return self.m.get(idx)!!;
}
// Extension function for returning the last value
extends fun getLast(self: Array): Int {
require(self.length > 0, "No items in the array!");
// Note that we use the !! operator, as we know for sure the value would be there
return self.m.get(self.length - 1)!!;
}
// Extension mutation function for deleting an entry at the given index and returning its value
extends mutates fun deleteIdx(self: Array, idx: Int): Int {
require(self.length > 0, "No items in the array to delete!");
require(idx >= 0, "Index of the item cannot be negative!");
require(idx < self.length, "Index is out of array bounds!");
// Remember the value that is going to be deleted
let memorized: Int = self.m.get(idx)!!;
// Move all items from idx onwards to the left
let i: Int = idx;
while (i + 1 < self.length) {
// Note that we use the !! operator, as we know for sure the value would be there
self.m.set(i, self.m.get(i + 1)!!);
i += 1;
}
self.m.set(self.length - 1, null); // delete the last entry
self.length -= 1; // decrease the length field
return memorized;
}
// Extension mutation function for deleting the last entry and returning its value
extends fun deleteLast(self: Array): Int {
require(self.length > 0, "No items in the array!");
// Note that we use the !! operator, as we know for sure the value would be there
let lastItem: Int = self.m.get(self.length - 1)!!;
self.m.set(self.length - 1, null); // delete the entry
self.length -= 1; // decrease the length field
return lastItem;
}
// Extension function for deleting all items in the Array
extends mutates fun deleteAll(self: Array) {
self.m = emptyMap();
self.length = 0;
}
// Global static function for creating an empty Array
fun emptyArray(): Array {
return Array { m: emptyMap(), length: 0 }; // length defaults to 0
}
// Contract emulating an Array using the map
contract MapAsArray {
// Persistent state variables
array: Array;
// Constructor (initialization) function of the contract
init() {
self.array = emptyArray();
}
// Internal message receiver, which responds to a `null` message body
// If used for deployment, forwards the remaining value back to the sender
receive() { cashback(sender()) }
// Internal message receiver, which responds to a String message "append"
receive("append") {
// Add a new item
self.array.append(42);
}
// Internal message receiver, which responds to a String message "delete_5th"
receive("delete_5th") {
// Remove the 5th item if it exists and reply back with its value, or raise an error
self.reply(self.array.deleteIdx(4).toCoinsString().asComment()); // index offset 0 + 4 gives the 5th item
}
// Internal message receiver, which responds to a String message "del_last"
receive("del_last") {
// Remove the last item and reply back with its value, or raise an error
self.reply(self.array.deleteLast().toCoinsString().asComment());
}
// Internal message receiver, which responds to a String message "get_last"
receive("get_last") {
// Reply back with the latest item in the array if it exists, or raise an error
self.reply(self.array.getLast().toCoinsString().asComment());
}
// Internal message receiver, which responds to a String message "delete_all"
receive("delete_all") {
self.array.deleteAll();
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IEFycmF5IHsKICAgIC8vIEFuIGFycmF5IG9mIEludCB2YWx1ZXMgYXMgYSBtYXAgb2YgSW50cyB0byBJbnRzLAogICAgLy8gd2l0aCBzZXJpYWxpemF0aW9uIG9mIGl0cyBrZXlzIHRvIHVpbnQxNiB0byBzYXZlIHNwYWNlCiAgICBtOiBtYXA8SW50IGFzIHVpbnQxNiwgSW50PjsKCiAgICAvLyBMZW5ndGggb2YgdGhlIGFycmF5LCBkZWZhdWx0cyB0byAwCiAgICBsZW5ndGg6IEludCA9IDA7Cn0KCi8vIENvbXBpbGUtdGltZSBjb25zdGFudCB1cHBlciBib3VuZCBmb3Igb3VyIG1hcCByZXByZXNlbnRpbmcgYW4gYXJyYXkuCmNvbnN0IE1heEFycmF5U2l6ZTogSW50ID0gNV8wMDA7IC8vIDUsMDAwIGVudHJpZXMgbWF4LCB0byBzdGF5IHJlYXNvbmFibHkgZmFyIGZyb20gbGltaXRzCgovLyBFeHRlbnNpb24gbXV0YXRpb24gZnVuY3Rpb24gZm9yIGFkZGluZyBuZXcgZW50cmllcyB0byB0aGUgZW5kIG9mIHRoZSBhcnJheQpleHRlbmRzIG11dGF0ZXMgZnVuIGFwcGVuZChzZWxmOiBBcnJheSwgaXRlbTogSW50KSB7CiAgICByZXF1aXJlKHNlbGYubGVuZ3RoICsgMSA8PSBNYXhBcnJheVNpemUsICJObyBzcGFjZSBpbiB0aGUgYXJyYXkgbGVmdCBmb3IgbmV3IGl0ZW1zISIpOwoKICAgIHNlbGYubS5zZXQoc2VsZi5sZW5ndGgsIGl0ZW0pOyAvLyBzZXQgdGhlIGVudHJ5IChrZXktdmFsdWUgcGFpcikKICAgIHNlbGYubGVuZ3RoICs9IDE7IC8vIGluY3JlYXNlIHRoZSBsZW5ndGggZmllbGQKfQoKLy8gRXh0ZW5zaW9uIG11dGF0aW9uIGZ1bmN0aW9uIGZvciBpbnNlcnRpbmcgbmV3IGVudHJpZXMgYXQgdGhlIGdpdmVuIGluZGV4CmV4dGVuZHMgbXV0YXRlcyBmdW4gaW5zZXJ0KHNlbGY6IEFycmF5LCBpdGVtOiBJbnQsIGlkeDogSW50KSB7CiAgICByZXF1aXJlKHNlbGYubGVuZ3RoICsgMSA8PSBNYXhBcnJheVNpemUsICJObyBzcGFjZSBpbiB0aGUgYXJyYXkgbGVmdCBmb3IgbmV3IGl0ZW1zISIpOwogICAgcmVxdWlyZShpZHggPj0gMCwgIkluZGV4IG9mIHRoZSBpdGVtIGNhbm5vdCBiZSBuZWdhdGl2ZSEiKTsKICAgIHJlcXVpcmUoaWR4IDwgc2VsZi5sZW5ndGgsICJJbmRleCBpcyBvdXQgb2YgYXJyYXkgYm91bmRzISIpOwoKICAgIC8vIE1vdmUgYWxsIGl0ZW1zIGZyb20gaWR4IHRvIHRoZSByaWdodAogICAgbGV0IGk6IEludCA9IHNlbGYubGVuZ3RoOyAvLyBub3QgYSB0eXBvLCBhcyB3ZSBuZWVkIHRvIHN0YXJ0IGZyb20gdGhlIG5vbi1leGlzdGluZyBwbGFjZQogICAgd2hpbGUgKGkgPiBpZHgpIHsKICAgICAgICAvLyBOb3RlIHRoYXQgd2UgdXNlIHRoZSAhISBvcGVyYXRvciwgYXMgd2Uga25vdyBmb3Igc3VyZSB0aGUgdmFsdWUgd291bGQgYmUgdGhlcmUKICAgICAgICBzZWxmLm0uc2V0KGksIHNlbGYubS5nZXQoaSAtIDEpISEpOwogICAgICAgIGkgLT0gMTsKICAgIH0KCiAgICAvLyBJbnNlcnQgdGhlIG5ldyBpdGVtCiAgICBzZWxmLm0uc2V0KGlkeCwgaXRlbSk7IC8vIHNldCB0aGUgZW50cnkgKGtleS12YWx1ZSBwYWlyKQogICAgc2VsZi5sZW5ndGggKz0gMTsgLy8gaW5jcmVhc2UgdGhlIGxlbmd0aCBmaWVsZAp9CgovLyBFeHRlbnNpb24gZnVuY3Rpb24gZm9yIGdldHRpbmcgdGhlIHZhbHVlIGF0IHRoZSBnaXZlbiBpbmRleApleHRlbmRzIGZ1biBnZXRJZHgoc2VsZjogQXJyYXksIGlkeDogSW50KTogSW50IHsKICAgIHJlcXVpcmUoc2VsZi5sZW5ndGggPiAwLCAiTm8gaXRlbXMgaW4gdGhlIGFycmF5ISIpOwogICAgcmVxdWlyZShpZHggPj0gMCwgIkluZGV4IG9mIHRoZSBpdGVtIGNhbm5vdCBiZSBuZWdhdGl2ZSEiKTsKICAgIHJlcXVpcmUoaWR4IDwgc2VsZi5sZW5ndGgsICJJbmRleCBpcyBvdXQgb2YgYXJyYXkgYm91bmRzISIpOwoKICAgIC8vIE5vdGUgdGhhdCB3ZSB1c2UgdGhlICEhIG9wZXJhdG9yLCBhcyB3ZSBrbm93IGZvciBzdXJlIHRoZSB2YWx1ZSB3b3VsZCBiZSB0aGVyZQogICAgcmV0dXJuIHNlbGYubS5nZXQoaWR4KSEhOwp9CgovLyBFeHRlbnNpb24gZnVuY3Rpb24gZm9yIHJldHVybmluZyB0aGUgbGFzdCB2YWx1ZQpleHRlbmRzIGZ1biBnZXRMYXN0KHNlbGY6IEFycmF5KTogSW50IHsKICAgIHJlcXVpcmUoc2VsZi5sZW5ndGggPiAwLCAiTm8gaXRlbXMgaW4gdGhlIGFycmF5ISIpOwoKICAgIC8vIE5vdGUgdGhhdCB3ZSB1c2UgdGhlICEhIG9wZXJhdG9yLCBhcyB3ZSBrbm93IGZvciBzdXJlIHRoZSB2YWx1ZSB3b3VsZCBiZSB0aGVyZQogICAgcmV0dXJuIHNlbGYubS5nZXQoc2VsZi5sZW5ndGggLSAxKSEhOwp9CgovLyBFeHRlbnNpb24gbXV0YXRpb24gZnVuY3Rpb24gZm9yIGRlbGV0aW5nIGFuIGVudHJ5IGF0IHRoZSBnaXZlbiBpbmRleCBhbmQgcmV0dXJuaW5nIGl0cyB2YWx1ZQpleHRlbmRzIG11dGF0ZXMgZnVuIGRlbGV0ZUlkeChzZWxmOiBBcnJheSwgaWR4OiBJbnQpOiBJbnQgewogICAgcmVxdWlyZShzZWxmLmxlbmd0aCA%2BIDAsICJObyBpdGVtcyBpbiB0aGUgYXJyYXkgdG8gZGVsZXRlISIpOwogICAgcmVxdWlyZShpZHggPj0gMCwgIkluZGV4IG9mIHRoZSBpdGVtIGNhbm5vdCBiZSBuZWdhdGl2ZSEiKTsKICAgIHJlcXVpcmUoaWR4IDwgc2VsZi5sZW5ndGgsICJJbmRleCBpcyBvdXQgb2YgYXJyYXkgYm91bmRzISIpOwoKICAgIC8vIFJlbWVtYmVyIHRoZSB2YWx1ZSB0aGF0IGlzIGdvaW5nIHRvIGJlIGRlbGV0ZWQKICAgIGxldCBtZW1vcml6ZWQ6IEludCA9IHNlbGYubS5nZXQoaWR4KSEhOwoKICAgIC8vIE1vdmUgYWxsIGl0ZW1zIGZyb20gaWR4IG9ud2FyZHMgdG8gdGhlIGxlZnQKICAgIGxldCBpOiBJbnQgPSBpZHg7CiAgICB3aGlsZSAoaSArIDEgPCBzZWxmLmxlbmd0aCkgewogICAgICAgIC8vIE5vdGUgdGhhdCB3ZSB1c2UgdGhlICEhIG9wZXJhdG9yLCBhcyB3ZSBrbm93IGZvciBzdXJlIHRoZSB2YWx1ZSB3b3VsZCBiZSB0aGVyZQogICAgICAgIHNlbGYubS5zZXQoaSwgc2VsZi5tLmdldChpICsgMSkhISk7CiAgICAgICAgaSArPSAxOwogICAgfQoKICAgIHNlbGYubS5zZXQoc2VsZi5sZW5ndGggLSAxLCBudWxsKTsgLy8gZGVsZXRlIHRoZSBsYXN0IGVudHJ5CiAgICBzZWxmLmxlbmd0aCAtPSAxOyAvLyBkZWNyZWFzZSB0aGUgbGVuZ3RoIGZpZWxkCgogICAgcmV0dXJuIG1lbW9yaXplZDsKfQoKLy8gRXh0ZW5zaW9uIG11dGF0aW9uIGZ1bmN0aW9uIGZvciBkZWxldGluZyB0aGUgbGFzdCBlbnRyeSBhbmQgcmV0dXJuaW5nIGl0cyB2YWx1ZQpleHRlbmRzIGZ1biBkZWxldGVMYXN0KHNlbGY6IEFycmF5KTogSW50IHsKICAgIHJlcXVpcmUoc2VsZi5sZW5ndGggPiAwLCAiTm8gaXRlbXMgaW4gdGhlIGFycmF5ISIpOwoKICAgIC8vIE5vdGUgdGhhdCB3ZSB1c2UgdGhlICEhIG9wZXJhdG9yLCBhcyB3ZSBrbm93IGZvciBzdXJlIHRoZSB2YWx1ZSB3b3VsZCBiZSB0aGVyZQogICAgbGV0IGxhc3RJdGVtOiBJbnQgPSBzZWxmLm0uZ2V0KHNlbGYubGVuZ3RoIC0gMSkhITsKICAgIHNlbGYubS5zZXQoc2VsZi5sZW5ndGggLSAxLCBudWxsKTsgLy8gZGVsZXRlIHRoZSBlbnRyeQogICAgc2VsZi5sZW5ndGggLT0gMTsgLy8gZGVjcmVhc2UgdGhlIGxlbmd0aCBmaWVsZAoKICAgIHJldHVybiBsYXN0SXRlbTsKfQoKLy8gRXh0ZW5zaW9uIGZ1bmN0aW9uIGZvciBkZWxldGluZyBhbGwgaXRlbXMgaW4gdGhlIEFycmF5CmV4dGVuZHMgbXV0YXRlcyBmdW4gZGVsZXRlQWxsKHNlbGY6IEFycmF5KSB7CiAgICBzZWxmLm0gPSBlbXB0eU1hcCgpOwogICAgc2VsZi5sZW5ndGggPSAwOwp9CgovLyBHbG9iYWwgc3RhdGljIGZ1bmN0aW9uIGZvciBjcmVhdGluZyBhbiBlbXB0eSBBcnJheQpmdW4gZW1wdHlBcnJheSgpOiBBcnJheSB7CiAgICByZXR1cm4gQXJyYXkgeyBtOiBlbXB0eU1hcCgpLCBsZW5ndGg6IDAgfTsgLy8gbGVuZ3RoIGRlZmF1bHRzIHRvIDAKfQoKLy8gQ29udHJhY3QgZW11bGF0aW5nIGFuIEFycmF5IHVzaW5nIHRoZSBtYXAKY29udHJhY3QgTWFwQXNBcnJheSB7CiAgICAvLyBQZXJzaXN0ZW50IHN0YXRlIHZhcmlhYmxlcwogICAgYXJyYXk6IEFycmF5OwoKICAgIC8vIENvbnN0cnVjdG9yIChpbml0aWFsaXphdGlvbikgZnVuY3Rpb24gb2YgdGhlIGNvbnRyYWN0CiAgICBpbml0KCkgewogICAgICAgIHNlbGYuYXJyYXkgPSBlbXB0eUFycmF5KCk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBgbnVsbGAgbWVzc2FnZSBib2R5CiAgICAvLyBJZiB1c2VkIGZvciBkZXBsb3ltZW50LCBmb3J3YXJkcyB0aGUgcmVtYWluaW5nIHZhbHVlIGJhY2sgdG8gdGhlIHNlbmRlcgogICAgcmVjZWl2ZSgpIHsgY2FzaGJhY2soc2VuZGVyKCkpIH0KCiAgICAvLyBJbnRlcm5hbCBtZXNzYWdlIHJlY2VpdmVyLCB3aGljaCByZXNwb25kcyB0byBhIFN0cmluZyBtZXNzYWdlICJhcHBlbmQiCiAgICByZWNlaXZlKCJhcHBlbmQiKSB7CiAgICAgICAgLy8gQWRkIGEgbmV3IGl0ZW0KICAgICAgICBzZWxmLmFycmF5LmFwcGVuZCg0Mik7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAiZGVsZXRlXzV0aCIKICAgIHJlY2VpdmUoImRlbGV0ZV81dGgiKSB7CiAgICAgICAgLy8gUmVtb3ZlIHRoZSA1dGggaXRlbSBpZiBpdCBleGlzdHMgYW5kIHJlcGx5IGJhY2sgd2l0aCBpdHMgdmFsdWUsIG9yIHJhaXNlIGFuIGVycm9yCiAgICAgICAgc2VsZi5yZXBseShzZWxmLmFycmF5LmRlbGV0ZUlkeCg0KS50b0NvaW5zU3RyaW5nKCkuYXNDb21tZW50KCkpOyAvLyBpbmRleCBvZmZzZXQgMCArIDQgZ2l2ZXMgdGhlIDV0aCBpdGVtCiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAiZGVsX2xhc3QiCiAgICByZWNlaXZlKCJkZWxfbGFzdCIpIHsKICAgICAgICAvLyBSZW1vdmUgdGhlIGxhc3QgaXRlbSBhbmQgcmVwbHkgYmFjayB3aXRoIGl0cyB2YWx1ZSwgb3IgcmFpc2UgYW4gZXJyb3IKICAgICAgICBzZWxmLnJlcGx5KHNlbGYuYXJyYXkuZGVsZXRlTGFzdCgpLnRvQ29pbnNTdHJpbmcoKS5hc0NvbW1lbnQoKSk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAiZ2V0X2xhc3QiCiAgICByZWNlaXZlKCJnZXRfbGFzdCIpIHsKICAgICAgICAvLyBSZXBseSBiYWNrIHdpdGggdGhlIGxhdGVzdCBpdGVtIGluIHRoZSBhcnJheSBpZiBpdCBleGlzdHMsIG9yIHJhaXNlIGFuIGVycm9yCiAgICAgICAgc2VsZi5yZXBseShzZWxmLmFycmF5LmdldExhc3QoKS50b0NvaW5zU3RyaW5nKCkuYXNDb21tZW50KCkpOwogICAgfQoKICAgIC8vIEludGVybmFsIG1lc3NhZ2UgcmVjZWl2ZXIsIHdoaWNoIHJlc3BvbmRzIHRvIGEgU3RyaW5nIG1lc3NhZ2UgImRlbGV0ZV9hbGwiCiAgICByZWNlaXZlKCJkZWxldGVfYWxsIikgewogICAgICAgIHNlbGYuYXJyYXkuZGVsZXRlQWxsKCk7CiAgICB9Cn0%3D)
## Stack[](#stack)
A [stack](https://en.wikipedia.org/wiki/Stack_\(abstract_data_type\)) is a data structure consisting of a collection of elements with two main operations:
* push, which adds an element to the end of the collection
* pop, which removes the most recently added element
The following example emulates a stack using a [`map`](/book/maps) wrapped in a [struct](/book/structs-and-messages#structs), where `V` can be any of the [allowed value types](/book/maps#allowed-types) of the map:
```tact
struct Stack {
// A stack of Int values as a map of Ints to Ints,
// with serialization of its keys to uint16 to save space
m: map;
// Length of the stack, defaults to 0
length: Int = 0;
}
// Compile-time constant upper bound for our map representing a stack.
const MaxStackSize: Int = 5_000; // 5,000 entries max, to stay reasonably far from limits
// Extension mutation function for adding new entries to the end of the stack
extends mutates fun push(self: Stack, item: Int) {
require(self.length + 1 <= MaxStackSize, "No space in the stack left for new items!");
self.m.set(self.length, item); // set the entry (key-value pair)
self.length += 1; // increase the length field
}
// Extension mutation function for deleting the last entry and returning its value
extends mutates fun pop(self: Stack): Int {
require(self.length > 0, "No items in the stack to delete!");
// Note that we use the !! operator, as we know for sure that the value will be there
let lastItem: Int = self.m.get(self.length - 1)!!;
self.m.set(self.length - 1, null); // delete the entry
self.length -= 1; // decrease the length field
return lastItem;
}
// Extension function for returning the last value
extends fun peek(self: Stack): Int {
require(self.length > 0, "No items in the stack!");
// Note that we use the !! operator, as we know for sure that the value will be there
return self.m.get(self.length - 1)!!;
}
// Extension function for deleting all items in the Stack
extends mutates fun deleteAll(self: Stack) {
self.m = emptyMap();
self.length = 0;
}
// Global static function for creating an empty Stack
fun emptyStack(): Stack {
return Stack { m: emptyMap(), length: 0 }; // length defaults to 0
}
contract MapAsStack {
// Persistent state variables
stack: Stack; // our stack, which uses the map
// Constructor (initialization) function of the contract
init() {
self.stack = emptyStack();
}
// Internal message receiver, which responds to a `null` message body
// If used for deployment, forwards the remaining value back to the sender
receive() { cashback(sender()) }
// Internal message receiver, which responds to a String message "push"
receive("push") {
// Add a new item
self.stack.push(42);
}
// Internal message receiver, which responds to a String message "pop"
receive("pop") {
// Remove the last item and reply with it
self.reply(self.stack.pop().toCoinsString().asComment());
}
// Internal message receiver, which responds to a String message "peek"
receive("peek") {
// Reply back with the latest item in the map if it exists, or raise an error
self.reply(self.stack.peek().toCoinsString().asComment());
}
// Internal message receiver, which responds to a String message "delete_all"
receive("delete_all") {
self.stack.deleteAll();
}
// Getter function for obtaining the stack
get fun stack(): map {
return self.stack.m;
}
// Getter function for obtaining the current length of the stack
get fun length(): Int {
return self.stack.length;
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IFN0YWNrIHsKICAgIC8vIEEgc3RhY2sgb2YgSW50IHZhbHVlcyBhcyBhIG1hcCBvZiBJbnRzIHRvIEludHMsCiAgICAvLyB3aXRoIHNlcmlhbGl6YXRpb24gb2YgaXRzIGtleXMgdG8gdWludDE2IHRvIHNhdmUgc3BhY2UKICAgIG06IG1hcDxJbnQgYXMgdWludDE2LCBJbnQ%2BOwoKICAgIC8vIExlbmd0aCBvZiB0aGUgc3RhY2ssIGRlZmF1bHRzIHRvIDAKICAgIGxlbmd0aDogSW50ID0gMDsKfQoKLy8gQ29tcGlsZS10aW1lIGNvbnN0YW50IHVwcGVyIGJvdW5kIGZvciBvdXIgbWFwIHJlcHJlc2VudGluZyBhIHN0YWNrLgpjb25zdCBNYXhTdGFja1NpemU6IEludCA9IDVfMDAwOyAvLyA1LDAwMCBlbnRyaWVzIG1heCwgdG8gc3RheSByZWFzb25hYmx5IGZhciBmcm9tIGxpbWl0cwoKLy8gRXh0ZW5zaW9uIG11dGF0aW9uIGZ1bmN0aW9uIGZvciBhZGRpbmcgbmV3IGVudHJpZXMgdG8gdGhlIGVuZCBvZiB0aGUgc3RhY2sKZXh0ZW5kcyBtdXRhdGVzIGZ1biBwdXNoKHNlbGY6IFN0YWNrLCBpdGVtOiBJbnQpIHsKICAgIHJlcXVpcmUoc2VsZi5sZW5ndGggKyAxIDw9IE1heFN0YWNrU2l6ZSwgIk5vIHNwYWNlIGluIHRoZSBzdGFjayBsZWZ0IGZvciBuZXcgaXRlbXMhIik7CgogICAgc2VsZi5tLnNldChzZWxmLmxlbmd0aCwgaXRlbSk7IC8vIHNldCB0aGUgZW50cnkgKGtleS12YWx1ZSBwYWlyKQogICAgc2VsZi5sZW5ndGggKz0gMTsgLy8gaW5jcmVhc2UgdGhlIGxlbmd0aCBmaWVsZAp9CgovLyBFeHRlbnNpb24gbXV0YXRpb24gZnVuY3Rpb24gZm9yIGRlbGV0aW5nIHRoZSBsYXN0IGVudHJ5IGFuZCByZXR1cm5pbmcgaXRzIHZhbHVlCmV4dGVuZHMgbXV0YXRlcyBmdW4gcG9wKHNlbGY6IFN0YWNrKTogSW50IHsKICAgIHJlcXVpcmUoc2VsZi5sZW5ndGggPiAwLCAiTm8gaXRlbXMgaW4gdGhlIHN0YWNrIHRvIGRlbGV0ZSEiKTsKCiAgICAvLyBOb3RlIHRoYXQgd2UgdXNlIHRoZSAhISBvcGVyYXRvciwgYXMgd2Uga25vdyBmb3Igc3VyZSB0aGF0IHRoZSB2YWx1ZSB3aWxsIGJlIHRoZXJlCiAgICBsZXQgbGFzdEl0ZW06IEludCA9IHNlbGYubS5nZXQoc2VsZi5sZW5ndGggLSAxKSEhOwogICAgc2VsZi5tLnNldChzZWxmLmxlbmd0aCAtIDEsIG51bGwpOyAvLyBkZWxldGUgdGhlIGVudHJ5CiAgICBzZWxmLmxlbmd0aCAtPSAxOyAvLyBkZWNyZWFzZSB0aGUgbGVuZ3RoIGZpZWxkCgogICAgcmV0dXJuIGxhc3RJdGVtOwp9CgovLyBFeHRlbnNpb24gZnVuY3Rpb24gZm9yIHJldHVybmluZyB0aGUgbGFzdCB2YWx1ZQpleHRlbmRzIGZ1biBwZWVrKHNlbGY6IFN0YWNrKTogSW50IHsKICAgIHJlcXVpcmUoc2VsZi5sZW5ndGggPiAwLCAiTm8gaXRlbXMgaW4gdGhlIHN0YWNrISIpOwoKICAgIC8vIE5vdGUgdGhhdCB3ZSB1c2UgdGhlICEhIG9wZXJhdG9yLCBhcyB3ZSBrbm93IGZvciBzdXJlIHRoYXQgdGhlIHZhbHVlIHdpbGwgYmUgdGhlcmUKICAgIHJldHVybiBzZWxmLm0uZ2V0KHNlbGYubGVuZ3RoIC0gMSkhITsKfQoKLy8gRXh0ZW5zaW9uIGZ1bmN0aW9uIGZvciBkZWxldGluZyBhbGwgaXRlbXMgaW4gdGhlIFN0YWNrCmV4dGVuZHMgbXV0YXRlcyBmdW4gZGVsZXRlQWxsKHNlbGY6IFN0YWNrKSB7CiAgICBzZWxmLm0gPSBlbXB0eU1hcCgpOwogICAgc2VsZi5sZW5ndGggPSAwOwp9CgovLyBHbG9iYWwgc3RhdGljIGZ1bmN0aW9uIGZvciBjcmVhdGluZyBhbiBlbXB0eSBTdGFjawpmdW4gZW1wdHlTdGFjaygpOiBTdGFjayB7CiAgICByZXR1cm4gU3RhY2sgeyBtOiBlbXB0eU1hcCgpLCBsZW5ndGg6IDAgfTsgLy8gbGVuZ3RoIGRlZmF1bHRzIHRvIDAKfQoKY29udHJhY3QgTWFwQXNTdGFjayB7CiAgICAvLyBQZXJzaXN0ZW50IHN0YXRlIHZhcmlhYmxlcwogICAgc3RhY2s6IFN0YWNrOyAvLyBvdXIgc3RhY2ssIHdoaWNoIHVzZXMgdGhlIG1hcAoKICAgIC8vIENvbnN0cnVjdG9yIChpbml0aWFsaXphdGlvbikgZnVuY3Rpb24gb2YgdGhlIGNvbnRyYWN0CiAgICBpbml0KCkgewogICAgICAgIHNlbGYuc3RhY2sgPSBlbXB0eVN0YWNrKCk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBgbnVsbGAgbWVzc2FnZSBib2R5CiAgICAvLyBJZiB1c2VkIGZvciBkZXBsb3ltZW50LCBmb3J3YXJkcyB0aGUgcmVtYWluaW5nIHZhbHVlIGJhY2sgdG8gdGhlIHNlbmRlcgogICAgcmVjZWl2ZSgpIHsgY2FzaGJhY2soc2VuZGVyKCkpIH0KCiAgICAvLyBJbnRlcm5hbCBtZXNzYWdlIHJlY2VpdmVyLCB3aGljaCByZXNwb25kcyB0byBhIFN0cmluZyBtZXNzYWdlICJwdXNoIgogICAgcmVjZWl2ZSgicHVzaCIpIHsKICAgICAgICAvLyBBZGQgYSBuZXcgaXRlbQogICAgICAgIHNlbGYuc3RhY2sucHVzaCg0Mik7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAicG9wIgogICAgcmVjZWl2ZSgicG9wIikgewogICAgICAgIC8vIFJlbW92ZSB0aGUgbGFzdCBpdGVtIGFuZCByZXBseSB3aXRoIGl0CiAgICAgICAgc2VsZi5yZXBseShzZWxmLnN0YWNrLnBvcCgpLnRvQ29pbnNTdHJpbmcoKS5hc0NvbW1lbnQoKSk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAicGVlayIKICAgIHJlY2VpdmUoInBlZWsiKSB7CiAgICAgICAgLy8gUmVwbHkgYmFjayB3aXRoIHRoZSBsYXRlc3QgaXRlbSBpbiB0aGUgbWFwIGlmIGl0IGV4aXN0cywgb3IgcmFpc2UgYW4gZXJyb3IKICAgICAgICBzZWxmLnJlcGx5KHNlbGYuc3RhY2sucGVlaygpLnRvQ29pbnNTdHJpbmcoKS5hc0NvbW1lbnQoKSk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAiZGVsZXRlX2FsbCIKICAgIHJlY2VpdmUoImRlbGV0ZV9hbGwiKSB7CiAgICAgICAgc2VsZi5zdGFjay5kZWxldGVBbGwoKTsKICAgIH0KCiAgICAvLyBHZXR0ZXIgZnVuY3Rpb24gZm9yIG9idGFpbmluZyB0aGUgc3RhY2sKICAgIGdldCBmdW4gc3RhY2soKTogbWFwPEludCBhcyB1aW50MTYsIEludD4gewogICAgICAgIHJldHVybiBzZWxmLnN0YWNrLm07CiAgICB9CgogICAgLy8gR2V0dGVyIGZ1bmN0aW9uIGZvciBvYnRhaW5pbmcgdGhlIGN1cnJlbnQgbGVuZ3RoIG9mIHRoZSBzdGFjawogICAgZ2V0IGZ1biBsZW5ndGgoKTogSW50IHsKICAgICAgICByZXR1cm4gc2VsZi5zdGFjay5sZW5ndGg7CiAgICB9Cn0%3D)
## Circular buffer[](#circular-buffer)
A [circular buffer](https://en.wikipedia.org/wiki/Circular_buffer) (circular queue, cyclic buffer, or ring buffer) is a data structure that uses a single, fixed-size [buffer](https://en.wikipedia.org/wiki/Data_buffer) as if it were connected end-to-end.
The following example emulates a circular buffer using a [`map`](/book/maps) wrapped in a [struct](/book/structs-and-messages#structs), where `V` can be any of the [allowed value types](/book/maps#allowed-types) of the map:
```tact
struct CircularBuffer {
// A circular buffer of Int values as a map of Ints to Ints,
// with serialization of its keys to uint8 to save space
m: map;
// Length of the circular buffer; defaults to 0
length: Int = 0;
// Current index into the circular buffer; defaults to 0
start: Int = 0;
}
// Compile-time constant upper bound for our map representing a circular buffer.
const MaxCircularBufferSize: Int = 5;
// Extension mutation function for putting new items into the circular buffer
extends mutates fun put(self: CircularBuffer, item: Int) {
if (self.length < MaxCircularBufferSize) {
self.m.set(self.length, item); // store the item
self.length += 1; // increase the length field
} else {
self.m.set(self.start, item); // store the item, overriding previous entry
self.start = (self.start + 1) % MaxCircularBufferSize; // update starting position
}
}
// Extension mutation function for getting an item from the circular buffer
extends mutates fun getIdx(self: CircularBuffer, idx: Int): Int {
require(self.length > 0, "No items in the circular buffer!");
require(idx >= 0, "Index of the item cannot be negative!");
if (self.length < MaxCircularBufferSize) {
// Note that we use the !! operator as we know for sure that the value will be there
return self.m.get(idx % self.length)!!;
}
// Return the value rotating around the circular buffer, also guaranteed to be there
return self.m.get((self.start + idx) % MaxCircularBufferSize)!!;
}
// Extension function for iterating over all items in the circular buffer and dumping them to the console
extends fun printAll(self: CircularBuffer) {
let i: Int = self.start;
repeat (self.length) {
dump(self.m.get(i)!!); // !! tells the compiler this can't be null
i = (i + 1) % MaxCircularBufferSize;
}
}
// Extension function for deleting all items from the CircularBuffer
extends mutates fun deleteAll(self: CircularBuffer) {
self.m = emptyMap();
self.length = 0;
self.start = 0;
}
// Global static function for creating an empty CircularBuffer
fun emptyCircularBuffer(): CircularBuffer {
// Length and start default to 0
return CircularBuffer { m: emptyMap(), length: 0, start: 0 };
}
// This contract records the last 5 timestamps of when a "timer" message was received
contract MapAsCircularBuffer {
// Persistent state variables
cBuf: CircularBuffer; // our circular buffer, which uses a map
// Constructor (initialization) function of the contract
init() {
self.cBuf = emptyCircularBuffer();
}
// Internal message receiver, which responds to a `null` message body
// If used for deployment, forwards the remaining value back to the sender
receive() { cashback(sender()) }
// Internal message receiver, which responds to a String message "timer"
// and records the timestamp when it receives such a message
receive("timer") {
let timestamp: Int = now();
self.cBuf.put(timestamp);
}
// Internal message receiver, which responds to a String message "get_first"
// and replies with the first item of the circular buffer
receive("get_first") {
self.reply(self.cBuf.getIdx(0).toCoinsString().asComment());
}
// Internal message receiver, which responds to a String message "print_all"
receive("print_all") {
self.cBuf.printAll();
}
// Internal message receiver, which responds to a String message "delete_all"
receive("delete_all") {
self.cBuf.deleteAll();
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IENpcmN1bGFyQnVmZmVyIHsKICAgIC8vIEEgY2lyY3VsYXIgYnVmZmVyIG9mIEludCB2YWx1ZXMgYXMgYSBtYXAgb2YgSW50cyB0byBJbnRzLAogICAgLy8gd2l0aCBzZXJpYWxpemF0aW9uIG9mIGl0cyBrZXlzIHRvIHVpbnQ4IHRvIHNhdmUgc3BhY2UKICAgIG06IG1hcDxJbnQgYXMgdWludDgsIEludD47CgogICAgLy8gTGVuZ3RoIG9mIHRoZSBjaXJjdWxhciBidWZmZXI7IGRlZmF1bHRzIHRvIDAKICAgIGxlbmd0aDogSW50ID0gMDsKCiAgICAvLyBDdXJyZW50IGluZGV4IGludG8gdGhlIGNpcmN1bGFyIGJ1ZmZlcjsgZGVmYXVsdHMgdG8gMAogICAgc3RhcnQ6IEludCA9IDA7Cn0KCi8vIENvbXBpbGUtdGltZSBjb25zdGFudCB1cHBlciBib3VuZCBmb3Igb3VyIG1hcCByZXByZXNlbnRpbmcgYSBjaXJjdWxhciBidWZmZXIuCmNvbnN0IE1heENpcmN1bGFyQnVmZmVyU2l6ZTogSW50ID0gNTsKCi8vIEV4dGVuc2lvbiBtdXRhdGlvbiBmdW5jdGlvbiBmb3IgcHV0dGluZyBuZXcgaXRlbXMgaW50byB0aGUgY2lyY3VsYXIgYnVmZmVyCmV4dGVuZHMgbXV0YXRlcyBmdW4gcHV0KHNlbGY6IENpcmN1bGFyQnVmZmVyLCBpdGVtOiBJbnQpIHsKICAgIGlmIChzZWxmLmxlbmd0aCA8IE1heENpcmN1bGFyQnVmZmVyU2l6ZSkgewogICAgICAgIHNlbGYubS5zZXQoc2VsZi5sZW5ndGgsIGl0ZW0pOyAvLyBzdG9yZSB0aGUgaXRlbQogICAgICAgIHNlbGYubGVuZ3RoICs9IDE7IC8vIGluY3JlYXNlIHRoZSBsZW5ndGggZmllbGQKICAgIH0gZWxzZSB7CiAgICAgICAgc2VsZi5tLnNldChzZWxmLnN0YXJ0LCBpdGVtKTsgLy8gc3RvcmUgdGhlIGl0ZW0sIG92ZXJyaWRpbmcgcHJldmlvdXMgZW50cnkKICAgICAgICBzZWxmLnN0YXJ0ID0gKHNlbGYuc3RhcnQgKyAxKSAlIE1heENpcmN1bGFyQnVmZmVyU2l6ZTsgLy8gdXBkYXRlIHN0YXJ0aW5nIHBvc2l0aW9uCiAgICB9Cn0KCi8vIEV4dGVuc2lvbiBtdXRhdGlvbiBmdW5jdGlvbiBmb3IgZ2V0dGluZyBhbiBpdGVtIGZyb20gdGhlIGNpcmN1bGFyIGJ1ZmZlcgpleHRlbmRzIG11dGF0ZXMgZnVuIGdldElkeChzZWxmOiBDaXJjdWxhckJ1ZmZlciwgaWR4OiBJbnQpOiBJbnQgewogICAgcmVxdWlyZShzZWxmLmxlbmd0aCA%2BIDAsICJObyBpdGVtcyBpbiB0aGUgY2lyY3VsYXIgYnVmZmVyISIpOwogICAgcmVxdWlyZShpZHggPj0gMCwgIkluZGV4IG9mIHRoZSBpdGVtIGNhbm5vdCBiZSBuZWdhdGl2ZSEiKTsKCiAgICBpZiAoc2VsZi5sZW5ndGggPCBNYXhDaXJjdWxhckJ1ZmZlclNpemUpIHsKICAgICAgICAvLyBOb3RlIHRoYXQgd2UgdXNlIHRoZSAhISBvcGVyYXRvciBhcyB3ZSBrbm93IGZvciBzdXJlIHRoYXQgdGhlIHZhbHVlIHdpbGwgYmUgdGhlcmUKICAgICAgICByZXR1cm4gc2VsZi5tLmdldChpZHggJSBzZWxmLmxlbmd0aCkhITsKICAgIH0KCiAgICAvLyBSZXR1cm4gdGhlIHZhbHVlIHJvdGF0aW5nIGFyb3VuZCB0aGUgY2lyY3VsYXIgYnVmZmVyLCBhbHNvIGd1YXJhbnRlZWQgdG8gYmUgdGhlcmUKICAgIHJldHVybiBzZWxmLm0uZ2V0KChzZWxmLnN0YXJ0ICsgaWR4KSAlIE1heENpcmN1bGFyQnVmZmVyU2l6ZSkhITsKfQoKLy8gRXh0ZW5zaW9uIGZ1bmN0aW9uIGZvciBpdGVyYXRpbmcgb3ZlciBhbGwgaXRlbXMgaW4gdGhlIGNpcmN1bGFyIGJ1ZmZlciBhbmQgZHVtcGluZyB0aGVtIHRvIHRoZSBjb25zb2xlCmV4dGVuZHMgZnVuIHByaW50QWxsKHNlbGY6IENpcmN1bGFyQnVmZmVyKSB7CiAgICBsZXQgaTogSW50ID0gc2VsZi5zdGFydDsKICAgIHJlcGVhdCAoc2VsZi5sZW5ndGgpIHsKICAgICAgICBkdW1wKHNlbGYubS5nZXQoaSkhISk7IC8vICEhIHRlbGxzIHRoZSBjb21waWxlciB0aGlzIGNhbid0IGJlIG51bGwKICAgICAgICBpID0gKGkgKyAxKSAlIE1heENpcmN1bGFyQnVmZmVyU2l6ZTsKICAgIH0KfQoKLy8gRXh0ZW5zaW9uIGZ1bmN0aW9uIGZvciBkZWxldGluZyBhbGwgaXRlbXMgZnJvbSB0aGUgQ2lyY3VsYXJCdWZmZXIKZXh0ZW5kcyBtdXRhdGVzIGZ1biBkZWxldGVBbGwoc2VsZjogQ2lyY3VsYXJCdWZmZXIpIHsKICAgIHNlbGYubSA9IGVtcHR5TWFwKCk7CiAgICBzZWxmLmxlbmd0aCA9IDA7CiAgICBzZWxmLnN0YXJ0ID0gMDsKfQoKLy8gR2xvYmFsIHN0YXRpYyBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgYW4gZW1wdHkgQ2lyY3VsYXJCdWZmZXIKZnVuIGVtcHR5Q2lyY3VsYXJCdWZmZXIoKTogQ2lyY3VsYXJCdWZmZXIgewogICAgLy8gTGVuZ3RoIGFuZCBzdGFydCBkZWZhdWx0IHRvIDAKICAgIHJldHVybiBDaXJjdWxhckJ1ZmZlciB7IG06IGVtcHR5TWFwKCksIGxlbmd0aDogMCwgc3RhcnQ6IDAgfTsKfQoKLy8gVGhpcyBjb250cmFjdCByZWNvcmRzIHRoZSBsYXN0IDUgdGltZXN0YW1wcyBvZiB3aGVuIGEgInRpbWVyIiBtZXNzYWdlIHdhcyByZWNlaXZlZApjb250cmFjdCBNYXBBc0NpcmN1bGFyQnVmZmVyIHsKICAgIC8vIFBlcnNpc3RlbnQgc3RhdGUgdmFyaWFibGVzCiAgICBjQnVmOiBDaXJjdWxhckJ1ZmZlcjsgLy8gb3VyIGNpcmN1bGFyIGJ1ZmZlciwgd2hpY2ggdXNlcyBhIG1hcAoKICAgIC8vIENvbnN0cnVjdG9yIChpbml0aWFsaXphdGlvbikgZnVuY3Rpb24gb2YgdGhlIGNvbnRyYWN0CiAgICBpbml0KCkgewogICAgICAgIHNlbGYuY0J1ZiA9IGVtcHR5Q2lyY3VsYXJCdWZmZXIoKTsKICAgIH0KCiAgICAvLyBJbnRlcm5hbCBtZXNzYWdlIHJlY2VpdmVyLCB3aGljaCByZXNwb25kcyB0byBhIGBudWxsYCBtZXNzYWdlIGJvZHkKICAgIC8vIElmIHVzZWQgZm9yIGRlcGxveW1lbnQsIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIC8vIEludGVybmFsIG1lc3NhZ2UgcmVjZWl2ZXIsIHdoaWNoIHJlc3BvbmRzIHRvIGEgU3RyaW5nIG1lc3NhZ2UgInRpbWVyIgogICAgLy8gYW5kIHJlY29yZHMgdGhlIHRpbWVzdGFtcCB3aGVuIGl0IHJlY2VpdmVzIHN1Y2ggYSBtZXNzYWdlCiAgICByZWNlaXZlKCJ0aW1lciIpIHsKICAgICAgICBsZXQgdGltZXN0YW1wOiBJbnQgPSBub3coKTsKICAgICAgICBzZWxmLmNCdWYucHV0KHRpbWVzdGFtcCk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAiZ2V0X2ZpcnN0IgogICAgLy8gYW5kIHJlcGxpZXMgd2l0aCB0aGUgZmlyc3QgaXRlbSBvZiB0aGUgY2lyY3VsYXIgYnVmZmVyCiAgICByZWNlaXZlKCJnZXRfZmlyc3QiKSB7CiAgICAgICAgc2VsZi5yZXBseShzZWxmLmNCdWYuZ2V0SWR4KDApLnRvQ29pbnNTdHJpbmcoKS5hc0NvbW1lbnQoKSk7CiAgICB9CgogICAgLy8gSW50ZXJuYWwgbWVzc2FnZSByZWNlaXZlciwgd2hpY2ggcmVzcG9uZHMgdG8gYSBTdHJpbmcgbWVzc2FnZSAicHJpbnRfYWxsIgogICAgcmVjZWl2ZSgicHJpbnRfYWxsIikgewogICAgICAgIHNlbGYuY0J1Zi5wcmludEFsbCgpOwogICAgfQoKICAgIC8vIEludGVybmFsIG1lc3NhZ2UgcmVjZWl2ZXIsIHdoaWNoIHJlc3BvbmRzIHRvIGEgU3RyaW5nIG1lc3NhZ2UgImRlbGV0ZV9hbGwiCiAgICByZWNlaXZlKCJkZWxldGVfYWxsIikgewogICAgICAgIHNlbGYuY0J1Zi5kZWxldGVBbGwoKTsKICAgIH0KfQ%3D%3D)
Note
This example is adapted from the [Arrays page in Tact-By-Example](https://tact-by-example.org/04-arrays).
Hey there!
Didn’t find your favorite example of working with data structures? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# DeDust.io
> This page lists examples of working with DeDust, a decentralized exchange and automated market maker built natively on TON Blockchain and DeDust Protocol.
[DeDust](https://dedust.io) is a decentralized exchange (DEX) and automated market maker (AMM) built natively on [TON Blockchain](https://ton.org) and [DeDust Protocol 2.0](https://docs.dedust.io/reference/tlb-schemes). DeDust is designed with meticulous attention to user experience (UX), gas efficiency, and extensibility.
Before going further, familiarize yourself with the following:
* [Receiving messages](/book/receive/)
* [Sending messages](/book/send/)
* [Fungible Tokens (Jettons)](/cookbook/jettons/)
* [DeDust Docs: Concepts](https://docs.dedust.io/docs/concepts)
## Swaps[](#swaps)
Read more about swaps in the [DeDust documentation](https://docs.dedust.io/docs/swaps).
Caution
It is important to ensure that contracts are deployed. Sending funds to an inactive contract could result in irretrievable loss.
All kinds of swaps use the `SwapStep` and `SwapParams` structures:
```tact
/// https://docs.dedust.io/reference/tlb-schemes#swapstep
struct SwapStep {
// The pool that will perform the swap, e.g., pairs like TON/USDT or USDT/DUST
poolAddress: Address;
// The kind of swap to do: can only be 0 as of now
kind: Int as uint1 = 0;
// Minimum output of the swap
// If the actual value is less than specified, the swap will be rejected
limit: Int as coins = 0;
// Reference to the next step, which can be used for multi-hop swaps
// The type here is actually `SwapStep?`,
// but specifying recursive types isn't allowed in Tact yet
nextStep: Cell?;
}
/// https://docs.dedust.io/reference/tlb-schemes#swapparams
struct SwapParams {
// Specifies a deadline to reject the swap if it arrives at the pool late
// Accepts the number of seconds passed since the UNIX Epoch
// Defaults to 0, which removes the deadline
deadline: Int as uint32 = 0;
// Specifies an address where funds will be sent after the swap
// Defaults to `null`, causing the swap to use the sender's address
recipientAddress: Address? = null;
// Referral address required for the DeDust referral program
// Defaults to `null`
referralAddress: Address? = null;
// Custom payload that will be attached to the fund transfer upon a successful swap
// Defaults to `null`
fulfillPayload: Cell? = null;
// Custom payload that will be attached to the fund transfer upon a rejected swap
// Defaults to `null`
rejectPayload: Cell? = null;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZG9jcy5kZWR1c3QuaW8vcmVmZXJlbmNlL3RsYi1zY2hlbWVzI3N3YXBzdGVwCnN0cnVjdCBTd2FwU3RlcCB7CiAgICAvLyBUaGUgcG9vbCB0aGF0IHdpbGwgcGVyZm9ybSB0aGUgc3dhcCwgZS5nLiwgcGFpcnMgbGlrZSBUT04vVVNEVCBvciBVU0RUL0RVU1QKICAgIHBvb2xBZGRyZXNzOiBBZGRyZXNzOwoKICAgIC8vIFRoZSBraW5kIG9mIHN3YXAgdG8gZG86IGNhbiBvbmx5IGJlIDAgYXMgb2Ygbm93CiAgICBraW5kOiBJbnQgYXMgdWludDEgPSAwOwoKICAgIC8vIE1pbmltdW0gb3V0cHV0IG9mIHRoZSBzd2FwCiAgICAvLyBJZiB0aGUgYWN0dWFsIHZhbHVlIGlzIGxlc3MgdGhhbiBzcGVjaWZpZWQsIHRoZSBzd2FwIHdpbGwgYmUgcmVqZWN0ZWQKICAgIGxpbWl0OiBJbnQgYXMgY29pbnMgPSAwOwoKICAgIC8vIFJlZmVyZW5jZSB0byB0aGUgbmV4dCBzdGVwLCB3aGljaCBjYW4gYmUgdXNlZCBmb3IgbXVsdGktaG9wIHN3YXBzCiAgICAvLyBUaGUgdHlwZSBoZXJlIGlzIGFjdHVhbGx5IGBTd2FwU3RlcD9gLAogICAgLy8gYnV0IHNwZWNpZnlpbmcgcmVjdXJzaXZlIHR5cGVzIGlzbid0IGFsbG93ZWQgaW4gVGFjdCB5ZXQKICAgIG5leHRTdGVwOiBDZWxsPzsKfQoKLy8vIGh0dHBzOi8vZG9jcy5kZWR1c3QuaW8vcmVmZXJlbmNlL3RsYi1zY2hlbWVzI3N3YXBwYXJhbXMKc3RydWN0IFN3YXBQYXJhbXMgewogICAgLy8gU3BlY2lmaWVzIGEgZGVhZGxpbmUgdG8gcmVqZWN0IHRoZSBzd2FwIGlmIGl0IGFycml2ZXMgYXQgdGhlIHBvb2wgbGF0ZQogICAgLy8gQWNjZXB0cyB0aGUgbnVtYmVyIG9mIHNlY29uZHMgcGFzc2VkIHNpbmNlIHRoZSBVTklYIEVwb2NoCiAgICAvLyBEZWZhdWx0cyB0byAwLCB3aGljaCByZW1vdmVzIHRoZSBkZWFkbGluZQogICAgZGVhZGxpbmU6IEludCBhcyB1aW50MzIgPSAwOwoKICAgIC8vIFNwZWNpZmllcyBhbiBhZGRyZXNzIHdoZXJlIGZ1bmRzIHdpbGwgYmUgc2VudCBhZnRlciB0aGUgc3dhcAogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgLCBjYXVzaW5nIHRoZSBzd2FwIHRvIHVzZSB0aGUgc2VuZGVyJ3MgYWRkcmVzcwogICAgcmVjaXBpZW50QWRkcmVzczogQWRkcmVzcz8gPSBudWxsOwoKICAgIC8vIFJlZmVycmFsIGFkZHJlc3MgcmVxdWlyZWQgZm9yIHRoZSBEZUR1c3QgcmVmZXJyYWwgcHJvZ3JhbQogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgCiAgICByZWZlcnJhbEFkZHJlc3M6IEFkZHJlc3M%2FID0gbnVsbDsKCiAgICAvLyBDdXN0b20gcGF5bG9hZCB0aGF0IHdpbGwgYmUgYXR0YWNoZWQgdG8gdGhlIGZ1bmQgdHJhbnNmZXIgdXBvbiBhIHN1Y2Nlc3NmdWwgc3dhcAogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgCiAgICBmdWxmaWxsUGF5bG9hZDogQ2VsbD8gPSBudWxsOwoKICAgIC8vIEN1c3RvbSBwYXlsb2FkIHRoYXQgd2lsbCBiZSBhdHRhY2hlZCB0byB0aGUgZnVuZCB0cmFuc2ZlciB1cG9uIGEgcmVqZWN0ZWQgc3dhcAogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgCiAgICByZWplY3RQYXlsb2FkOiBDZWxsPyA9IG51bGw7Cn0%3D)
### Swap Toncoin for any Jetton[](#swap-toncoin-for-any-jetton)
Note
The guides below use the [Jetton vault](https://docs.dedust.io/docs/concepts#vault). To obtain its address for your Jetton, refer to [this guide](https://docs.dedust.io/docs/swaps#step-1-find-the-vault-scale).
```tact
/// https://docs.dedust.io/reference/tlb-schemes#message-swap
message(0xea06185d) NativeSwap {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means we don't mark messages to trace their chains
queryId: Int as uint64 = 0;
// Toncoin amount for the swap
amount: Int as coins;
// Inlined fields of SwapStep struct
poolAddress: Address;
kind: Int as uint1 = 0;
limit: Int as coins = 0;
nextStep: SwapStep? = null;
// Set of parameters relevant for the whole swap
swapParams: SwapParams;
}
// Let's say `swapAmount` is `ton("0.1")`, which is 10000000 nanoToncoins
fun swapToncoinForUSDT(swapAmount: Int) {
send(SendParameters {
// Address of the TON vault to send the message to
to: address("EQDa4VOnTYlLvDJ0gZjNYm5PXfSmmtL6Vs6A_CZEtXCNICq_"),
// Amount to swap plus a trade fee
value: swapAmount + ton("0.2"),
body: NativeSwap {
amount: swapAmount,
// Address of the swap pool, which is the TON/USDT pair in this case
poolAddress: address("EQA-X_yo3fzzbDbJ_0bzFWKqtRuZFIRa1sJsveZJ1YpViO3r"),
// Set of parameters relevant for the whole swap
swapParams: SwapParams {}, // use defaults
}.toCell(),
});
}
//
// Helper structs described earlier on this page
//
struct SwapStep {
poolAddress: Address;
kind: Int as uint1 = 0;
limit: Int as coins = 0;
nextStep: Cell?;
}
struct SwapParams {
deadline: Int as uint32 = 0;
recipientAddress: Address? = null;
referralAddress: Address? = null;
fulfillPayload: Cell? = null;
rejectPayload: Cell? = null;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZG9jcy5kZWR1c3QuaW8vcmVmZXJlbmNlL3RsYi1zY2hlbWVzI21lc3NhZ2Utc3dhcAptZXNzYWdlKDB4ZWEwNjE4NWQpIE5hdGl2ZVN3YXAgewogICAgLy8gVW5pcXVlIGlkZW50aWZpZXIgdXNlZCB0byB0cmFjZSB0cmFuc2FjdGlvbnMgYWNyb3NzIG11bHRpcGxlIGNvbnRyYWN0cwogICAgLy8gRGVmYXVsdHMgdG8gMCwgd2hpY2ggbWVhbnMgd2UgZG9uJ3QgbWFyayBtZXNzYWdlcyB0byB0cmFjZSB0aGVpciBjaGFpbnMKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQgPSAwOwoKICAgIC8vIFRvbmNvaW4gYW1vdW50IGZvciB0aGUgc3dhcAogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7CgogICAgLy8gSW5saW5lZCBmaWVsZHMgb2YgU3dhcFN0ZXAgc3RydWN0CiAgICBwb29sQWRkcmVzczogQWRkcmVzczsKICAgIGtpbmQ6IEludCBhcyB1aW50MSA9IDA7CiAgICBsaW1pdDogSW50IGFzIGNvaW5zID0gMDsKICAgIG5leHRTdGVwOiBTd2FwU3RlcD8gPSBudWxsOwoKICAgIC8vIFNldCBvZiBwYXJhbWV0ZXJzIHJlbGV2YW50IGZvciB0aGUgd2hvbGUgc3dhcAogICAgc3dhcFBhcmFtczogU3dhcFBhcmFtczsKfQoKLy8gTGV0J3Mgc2F5IGBzd2FwQW1vdW50YCBpcyBgdG9uKCIwLjEiKWAsIHdoaWNoIGlzIDEwMDAwMDAwIG5hbm9Ub25jb2lucwpmdW4gc3dhcFRvbmNvaW5Gb3JVU0RUKHN3YXBBbW91bnQ6IEludCkgewogICAgc2VuZChTZW5kUGFyYW1ldGVycyB7CiAgICAgICAgLy8gQWRkcmVzcyBvZiB0aGUgVE9OIHZhdWx0IHRvIHNlbmQgdGhlIG1lc3NhZ2UgdG8KICAgICAgICB0bzogYWRkcmVzcygiRVFEYTRWT25UWWxMdkRKMGdaak5ZbTVQWGZTbW10TDZWczZBX0NaRXRYQ05JQ3FfIiksCiAgICAgICAgLy8gQW1vdW50IHRvIHN3YXAgcGx1cyBhIHRyYWRlIGZlZQogICAgICAgIHZhbHVlOiBzd2FwQW1vdW50ICsgdG9uKCIwLjIiKSwKICAgICAgICBib2R5OiBOYXRpdmVTd2FwIHsKICAgICAgICAgICAgYW1vdW50OiBzd2FwQW1vdW50LAogICAgICAgICAgICAvLyBBZGRyZXNzIG9mIHRoZSBzd2FwIHBvb2wsIHdoaWNoIGlzIHRoZSBUT04vVVNEVCBwYWlyIGluIHRoaXMgY2FzZQogICAgICAgICAgICBwb29sQWRkcmVzczogYWRkcmVzcygiRVFBLVhfeW8zZnp6YkRiSl8wYnpGV0txdFJ1WkZJUmExc0pzdmVaSjFZcFZpTzNyIiksCiAgICAgICAgICAgIC8vIFNldCBvZiBwYXJhbWV0ZXJzIHJlbGV2YW50IGZvciB0aGUgd2hvbGUgc3dhcAogICAgICAgICAgICBzd2FwUGFyYW1zOiBTd2FwUGFyYW1zIHt9LCAvLyB1c2UgZGVmYXVsdHMKICAgICAgICB9LnRvQ2VsbCgpLAogICAgfSk7Cn0KCi8vCi8vIEhlbHBlciBzdHJ1Y3RzIGRlc2NyaWJlZCBlYXJsaWVyIG9uIHRoaXMgcGFnZQovLwoKc3RydWN0IFN3YXBTdGVwIHsKICAgIHBvb2xBZGRyZXNzOiBBZGRyZXNzOwogICAga2luZDogSW50IGFzIHVpbnQxID0gMDsKICAgIGxpbWl0OiBJbnQgYXMgY29pbnMgPSAwOwogICAgbmV4dFN0ZXA6IENlbGw%2FOwp9CgpzdHJ1Y3QgU3dhcFBhcmFtcyB7CiAgICBkZWFkbGluZTogSW50IGFzIHVpbnQzMiA9IDA7CiAgICByZWNpcGllbnRBZGRyZXNzOiBBZGRyZXNzPyA9IG51bGw7CiAgICByZWZlcnJhbEFkZHJlc3M6IEFkZHJlc3M%2FID0gbnVsbDsKICAgIGZ1bGZpbGxQYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICByZWplY3RQYXlsb2FkOiBDZWxsPyA9IG51bGw7Cn0%3D)
### Swap a Jetton for another Jetton or Toncoin[](#swap-a-jetton-for-another-jetton-or-toncoin)
```tact
/// https://docs.dedust.io/reference/tlb-schemes#message-swap-1
message(0xe3a0d482) JettonSwapPayload {
// Inlined fields of SwapStep struct
poolAddress: Address;
kind: Int as uint1 = 0;
limit: Int as coins = 0;
nextStep: SwapStep? = null;
// Set of parameters relevant for the entire swap
swapParams: SwapParams;
}
/// NOTE: To calculate and provide the Jetton wallet address for the target user,
/// make sure to check the links after this code snippet.
fun swapJetton(targetJettonWalletAddress: Address) {
send(SendParameters {
to: targetJettonWalletAddress,
value: ton("0.3"),
body: JettonTransfer {
// Unique identifier used to trace transactions across multiple contracts.
// Set to 0, which means we don't mark messages to trace their chains.
queryId: 0,
// Jetton amount for the swap.
amount: 10, // NOTE: change to your amount
// Address of the Jetton vault to send the message to.
destination: address("EQAYqo4u7VF0fa4DPAebk4g9lBytj2VFny7pzXR0trjtXQaO"),
// Address to return any exceeding funds.
responseDestination: myAddress(),
forwardTonAmount: ton("0.25"),
forwardPayload: JettonSwapPayload {
// Address of the swap pool, which is the TON/USDT pair in this case.
poolAddress: address("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"),
// Set of parameters relevant for the entire swap.
swapParams: SwapParams {}, // use defaults
}.toCell(),
}.toCell(),
});
}
//
// Helper structs described earlier on this page
//
struct SwapStep {
poolAddress: Address;
kind: Int as uint1 = 0;
limit: Int as coins = 0;
nextStep: Cell?;
}
struct SwapParams {
deadline: Int as uint32 = 0;
recipientAddress: Address? = null;
referralAddress: Address? = null;
fulfillPayload: Cell? = null;
rejectPayload: Cell? = null;
}
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZG9jcy5kZWR1c3QuaW8vcmVmZXJlbmNlL3RsYi1zY2hlbWVzI21lc3NhZ2Utc3dhcC0xCm1lc3NhZ2UoMHhlM2EwZDQ4MikgSmV0dG9uU3dhcFBheWxvYWQgewogICAgLy8gSW5saW5lZCBmaWVsZHMgb2YgU3dhcFN0ZXAgc3RydWN0CiAgICBwb29sQWRkcmVzczogQWRkcmVzczsKICAgIGtpbmQ6IEludCBhcyB1aW50MSA9IDA7CiAgICBsaW1pdDogSW50IGFzIGNvaW5zID0gMDsKICAgIG5leHRTdGVwOiBTd2FwU3RlcD8gPSBudWxsOwoKICAgIC8vIFNldCBvZiBwYXJhbWV0ZXJzIHJlbGV2YW50IGZvciB0aGUgZW50aXJlIHN3YXAKICAgIHN3YXBQYXJhbXM6IFN3YXBQYXJhbXM7Cn0KCi8vLyBOT1RFOiBUbyBjYWxjdWxhdGUgYW5kIHByb3ZpZGUgdGhlIEpldHRvbiB3YWxsZXQgYWRkcmVzcyBmb3IgdGhlIHRhcmdldCB1c2VyLAovLy8gICAgICAgbWFrZSBzdXJlIHRvIGNoZWNrIHRoZSBsaW5rcyBhZnRlciB0aGlzIGNvZGUgc25pcHBldC4KZnVuIHN3YXBKZXR0b24odGFyZ2V0SmV0dG9uV2FsbGV0QWRkcmVzczogQWRkcmVzcykgewogICAgc2VuZChTZW5kUGFyYW1ldGVycyB7CiAgICAgICAgdG86IHRhcmdldEpldHRvbldhbGxldEFkZHJlc3MsCiAgICAgICAgdmFsdWU6IHRvbigiMC4zIiksCiAgICAgICAgYm9keTogSmV0dG9uVHJhbnNmZXIgewogICAgICAgICAgICAvLyBVbmlxdWUgaWRlbnRpZmllciB1c2VkIHRvIHRyYWNlIHRyYW5zYWN0aW9ucyBhY3Jvc3MgbXVsdGlwbGUgY29udHJhY3RzLgogICAgICAgICAgICAvLyBTZXQgdG8gMCwgd2hpY2ggbWVhbnMgd2UgZG9uJ3QgbWFyayBtZXNzYWdlcyB0byB0cmFjZSB0aGVpciBjaGFpbnMuCiAgICAgICAgICAgIHF1ZXJ5SWQ6IDAsCiAgICAgICAgICAgIC8vIEpldHRvbiBhbW91bnQgZm9yIHRoZSBzd2FwLgogICAgICAgICAgICBhbW91bnQ6IDEwLCAvLyBOT1RFOiBjaGFuZ2UgdG8geW91ciBhbW91bnQKICAgICAgICAgICAgLy8gQWRkcmVzcyBvZiB0aGUgSmV0dG9uIHZhdWx0IHRvIHNlbmQgdGhlIG1lc3NhZ2UgdG8uCiAgICAgICAgICAgIGRlc3RpbmF0aW9uOiBhZGRyZXNzKCJFUUFZcW80dTdWRjBmYTREUEFlYms0ZzlsQnl0ajJWRm55N3B6WFIwdHJqdFhRYU8iKSwKICAgICAgICAgICAgLy8gQWRkcmVzcyB0byByZXR1cm4gYW55IGV4Y2VlZGluZyBmdW5kcy4KICAgICAgICAgICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogbXlBZGRyZXNzKCksCiAgICAgICAgICAgIGZvcndhcmRUb25BbW91bnQ6IHRvbigiMC4yNSIpLAogICAgICAgICAgICBmb3J3YXJkUGF5bG9hZDogSmV0dG9uU3dhcFBheWxvYWQgewogICAgICAgICAgICAgICAgLy8gQWRkcmVzcyBvZiB0aGUgc3dhcCBwb29sLCB3aGljaCBpcyB0aGUgVE9OL1VTRFQgcGFpciBpbiB0aGlzIGNhc2UuCiAgICAgICAgICAgICAgICBwb29sQWRkcmVzczogYWRkcmVzcygiRVFDeEU2bVV0UUpLRm5HZmFST1RLT3QxbFpiRGlpWDFrQ2l4UnY3TncySWRfc0RzIiksCiAgICAgICAgICAgICAgICAvLyBTZXQgb2YgcGFyYW1ldGVycyByZWxldmFudCBmb3IgdGhlIGVudGlyZSBzd2FwLgogICAgICAgICAgICAgICAgc3dhcFBhcmFtczogU3dhcFBhcmFtcyB7fSwgLy8gdXNlIGRlZmF1bHRzCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfS50b0NlbGwoKSwKICAgIH0pOwp9CgovLwovLyBIZWxwZXIgc3RydWN0cyBkZXNjcmliZWQgZWFybGllciBvbiB0aGlzIHBhZ2UKLy8KCnN0cnVjdCBTd2FwU3RlcCB7CiAgICBwb29sQWRkcmVzczogQWRkcmVzczsKICAgIGtpbmQ6IEludCBhcyB1aW50MSA9IDA7CiAgICBsaW1pdDogSW50IGFzIGNvaW5zID0gMDsKICAgIG5leHRTdGVwOiBDZWxsPzsKfQoKc3RydWN0IFN3YXBQYXJhbXMgewogICAgZGVhZGxpbmU6IEludCBhcyB1aW50MzIgPSAwOwogICAgcmVjaXBpZW50QWRkcmVzczogQWRkcmVzcz8gPSBudWxsOwogICAgcmVmZXJyYWxBZGRyZXNzOiBBZGRyZXNzPyA9IG51bGw7CiAgICBmdWxmaWxsUGF5bG9hZDogQ2VsbD8gPSBudWxsOwogICAgcmVqZWN0UGF5bG9hZDogQ2VsbD8gPSBudWxsOwp9CgovLwovLyBNZXNzYWdlcyBmcm9tIHRoZSBKZXR0b24gc3RhbmRhcmQKLy8KCm1lc3NhZ2UoMHhmOGE3ZWE1KSBKZXR0b25UcmFuc2ZlciB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBkZXN0aW5hdGlvbjogQWRkcmVzczsKICAgIHJlc3BvbnNlRGVzdGluYXRpb246IEFkZHJlc3M7CiAgICBjdXN0b21QYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICBmb3J3YXJkVG9uQW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBmb3J3YXJkUGF5bG9hZDogQ2VsbD87IC8vIHNsaWdodGx5IGFkanVzdGVkCn0%3D)
Useful links:
[Retrieving Jetton wallet address in TON Docs](https://docs.ton.org/develop/dapps/asset-processing/jettons#retrieving-jetton-wallet-addresses-for-a-given-user)\
[How to calculate user’s Jetton wallet address (offline)?](https://docs.ton.org/v3/guidelines/dapps/cookbook#how-to-calculate-users-jetton-wallet-address-offline)
## Liquidity Provisioning[](#liquidity-provisioning)
To provide liquidity to a particular DeDust pool, you must provide both assets. The pool will then issue special *LP tokens* to the depositor’s address.
Read more about liquidity provisioning in the [DeDust documentation](https://docs.dedust.io/docs/liquidity-provisioning).
```tact
/// https://docs.dedust.io/reference/tlb-schemes#message-deposit_liquidity-1
message(0x40e108d6) JettonDepositLiquidity {
// Pool type: 0 for volatile, 1 for stable
// A volatile pool is based on the "Constant Product" formula
// A stable-swap pool is optimized for assets of near-equal value,
// e.g., USDT/USDC, TON/stTON, etc.
poolType: Int as uint1;
// Provided assets
asset0: Asset;
asset1: Asset;
// Minimal amount of LP tokens to be received
// If less liquidity is provided, the provisioning will be rejected
// Defaults to 0, making this value ignored
minimalLpAmount: Int as coins = 0;
// Target amount of the first asset
targetBalances0: Int as coins;
// Target amount of the second asset
targetBalances1: Int as coins;
// Custom payload attached to the transaction if the provisioning is successful
// Defaults to `null`, which means no payload
fulfillPayload: Cell? = null;
// Custom payload attached to the transaction if the provisioning is rejected
// Defaults to `null`, which means no payload
rejectPayload: Cell? = null;
}
/// https://docs.dedust.io/reference/tlb-schemes#message-deposit_liquidity
message(0xd55e4686) NativeDepositLiquidity {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means messages are not marked to trace their chains
queryId: Int as uint64 = 0;
// Toncoin amount for the deposit
amount: Int as coins;
// Inlined fields of JettonDepositLiquidity message without the opcode prefix
poolType: Int as uint1;
asset0: Asset;
asset1: Asset;
minimalLpAmount: Int as coins = 0;
targetBalances0: Int as coins;
targetBalances1: Int as coins;
fulfillPayload: Cell? = null;
rejectPayload: Cell? = null;
}
/// https://docs.dedust.io/reference/tlb-schemes#asset
struct Asset {
// Specify 0 for native (TON) and omit all following fields
// Specify 1 for Jetton, then you must set non-null values for the following fields
type: Int as uint4;
workchain: Int as uint8 = 0; // Both these zeros will be removed during the .build() function. Only type will remain.
address: Int as uint256 = 0;
}
const PoolTypeVolatile: Int = 0;
const PoolTypeStable: Int = 1;
const AssetTypeNative: Int = 0b0000;
const AssetTypeJetton: Int = 0b0001;
const JettonProvideLpGas: Int = ton("0.5");
const JettonProvideLpGasFwd: Int = ton("0.4");
const TonProvideLpGas: Int = ton("0.15");
// This example directly uses the provided `myJettonWalletAddress`.
// In real-world scenarios, it's more reliable to calculate this address on-chain or save it during initialization to prevent any issues.
fun provideLiquidity(myJettonWalletAddress: Address) {
let jettonMasterRaw = parseStdAddress(
address("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs").asSlice(),
);
// Step 1. Prepare input
let jettonAmount = ton("1");
let tonAmount = ton("1");
let asset0 = Asset {
type: AssetTypeNative,
};
let asset1 = Asset {
type: AssetTypeJetton,
workchain: jettonMasterRaw.workchain,
address: jettonMasterRaw.address,
};
// Step 2. Deposit Jetton to Vault
let jettonDepositBody = JettonDepositLiquidity {
poolType: PoolTypeVolatile,
asset0,
asset1,
targetBalances0: tonAmount,
targetBalances1: jettonAmount,
}.build();
// Notice .build() instead of .toCell(),
// since we want some custom serialization logic.
send(SendParameters {
to: myJettonWalletAddress,
value: JettonProvideLpGas,
body: JettonTransfer {
queryId: 42,
amount: jettonAmount,
// Jetton Vault
destination: address("EQAYqo4u7VF0fa4DPAebk4g9lBytj2VFny7pzXR0trjtXQaO"),
responseDestination: myAddress(),
forwardTonAmount: JettonProvideLpGasFwd,
forwardPayload: jettonDepositBody,
}.toCell(),
});
// Step 3. Deposit TON to Vault
let nativeDepositBody = NativeDepositLiquidity {
queryId: 42,
amount: tonAmount,
poolType: PoolTypeVolatile,
asset0,
asset1,
targetBalances0: tonAmount,
targetBalances1: jettonAmount,
}.build();
// Notice .build() instead of .toCell(),
// since we want some custom serialization logic.
send(SendParameters {
to: address("EQDa4VOnTYlLvDJ0gZjNYm5PXfSmmtL6Vs6A_CZEtXCNICq_"),
value: tonAmount + TonProvideLpGas,
body: nativeDepositBody,
});
}
//
// Helper extension functions to build respective structures and messages
//
extends fun build(self: Asset): Cell {
let assetBuilder = beginCell().storeUint(self.type, 4);
if (self.type == AssetTypeNative) {
return assetBuilder.endCell();
}
if (self.type == AssetTypeJetton) {
return assetBuilder
.storeUint(self.workchain, 8)
.storeUint(self.address, 256)
.endCell();
}
// Unknown asset type
return beginCell().endCell();
}
extends fun build(self: JettonDepositLiquidity): Cell {
return beginCell()
.storeUint(0x40e108d6, 32)
.storeUint(self.poolType, 1)
.storeSlice(self.asset0.build().asSlice())
.storeSlice(self.asset1.build().asSlice())
.storeCoins(self.minimalLpAmount)
.storeCoins(self.targetBalances0)
.storeCoins(self.targetBalances1)
.storeMaybeRef(self.fulfillPayload)
.storeMaybeRef(self.rejectPayload)
.endCell();
}
extends fun build(self: NativeDepositLiquidity): Cell {
return beginCell()
.storeUint(0xd55e4686, 32)
.storeUint(self.queryId, 64)
.storeCoins(self.amount)
.storeUint(self.poolType, 1)
.storeSlice(self.asset0.build().asSlice())
.storeSlice(self.asset1.build().asSlice())
.storeRef(
beginCell()
.storeCoins(self.minimalLpAmount)
.storeCoins(self.targetBalances0)
.storeCoins(self.targetBalances1)
.endCell(),
)
.storeMaybeRef(self.fulfillPayload)
.storeMaybeRef(self.rejectPayload)
.endCell();
}
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // Slightly adjusted
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZG9jcy5kZWR1c3QuaW8vcmVmZXJlbmNlL3RsYi1zY2hlbWVzI21lc3NhZ2UtZGVwb3NpdF9saXF1aWRpdHktMQptZXNzYWdlKDB4NDBlMTA4ZDYpIEpldHRvbkRlcG9zaXRMaXF1aWRpdHkgewogICAgLy8gUG9vbCB0eXBlOiAwIGZvciB2b2xhdGlsZSwgMSBmb3Igc3RhYmxlCiAgICAvLyBBIHZvbGF0aWxlIHBvb2wgaXMgYmFzZWQgb24gdGhlICJDb25zdGFudCBQcm9kdWN0IiBmb3JtdWxhCiAgICAvLyBBIHN0YWJsZS1zd2FwIHBvb2wgaXMgb3B0aW1pemVkIGZvciBhc3NldHMgb2YgbmVhci1lcXVhbCB2YWx1ZSwKICAgIC8vIGUuZy4sIFVTRFQvVVNEQywgVE9OL3N0VE9OLCBldGMuCiAgICBwb29sVHlwZTogSW50IGFzIHVpbnQxOwoKICAgIC8vIFByb3ZpZGVkIGFzc2V0cwogICAgYXNzZXQwOiBBc3NldDsKICAgIGFzc2V0MTogQXNzZXQ7CgogICAgLy8gTWluaW1hbCBhbW91bnQgb2YgTFAgdG9rZW5zIHRvIGJlIHJlY2VpdmVkCiAgICAvLyBJZiBsZXNzIGxpcXVpZGl0eSBpcyBwcm92aWRlZCwgdGhlIHByb3Zpc2lvbmluZyB3aWxsIGJlIHJlamVjdGVkCiAgICAvLyBEZWZhdWx0cyB0byAwLCBtYWtpbmcgdGhpcyB2YWx1ZSBpZ25vcmVkCiAgICBtaW5pbWFsTHBBbW91bnQ6IEludCBhcyBjb2lucyA9IDA7CgogICAgLy8gVGFyZ2V0IGFtb3VudCBvZiB0aGUgZmlyc3QgYXNzZXQKICAgIHRhcmdldEJhbGFuY2VzMDogSW50IGFzIGNvaW5zOwoKICAgIC8vIFRhcmdldCBhbW91bnQgb2YgdGhlIHNlY29uZCBhc3NldAogICAgdGFyZ2V0QmFsYW5jZXMxOiBJbnQgYXMgY29pbnM7CgogICAgLy8gQ3VzdG9tIHBheWxvYWQgYXR0YWNoZWQgdG8gdGhlIHRyYW5zYWN0aW9uIGlmIHRoZSBwcm92aXNpb25pbmcgaXMgc3VjY2Vzc2Z1bAogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgLCB3aGljaCBtZWFucyBubyBwYXlsb2FkCiAgICBmdWxmaWxsUGF5bG9hZDogQ2VsbD8gPSBudWxsOwoKICAgIC8vIEN1c3RvbSBwYXlsb2FkIGF0dGFjaGVkIHRvIHRoZSB0cmFuc2FjdGlvbiBpZiB0aGUgcHJvdmlzaW9uaW5nIGlzIHJlamVjdGVkCiAgICAvLyBEZWZhdWx0cyB0byBgbnVsbGAsIHdoaWNoIG1lYW5zIG5vIHBheWxvYWQKICAgIHJlamVjdFBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKfQoKLy8vIGh0dHBzOi8vZG9jcy5kZWR1c3QuaW8vcmVmZXJlbmNlL3RsYi1zY2hlbWVzI21lc3NhZ2UtZGVwb3NpdF9saXF1aWRpdHkKbWVzc2FnZSgweGQ1NWU0Njg2KSBOYXRpdmVEZXBvc2l0TGlxdWlkaXR5IHsKICAgIC8vIFVuaXF1ZSBpZGVudGlmaWVyIHVzZWQgdG8gdHJhY2UgdHJhbnNhY3Rpb25zIGFjcm9zcyBtdWx0aXBsZSBjb250cmFjdHMKICAgIC8vIERlZmF1bHRzIHRvIDAsIHdoaWNoIG1lYW5zIG1lc3NhZ2VzIGFyZSBub3QgbWFya2VkIHRvIHRyYWNlIHRoZWlyIGNoYWlucwogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NCA9IDA7CgogICAgLy8gVG9uY29pbiBhbW91bnQgZm9yIHRoZSBkZXBvc2l0CiAgICBhbW91bnQ6IEludCBhcyBjb2luczsKCiAgICAvLyBJbmxpbmVkIGZpZWxkcyBvZiBKZXR0b25EZXBvc2l0TGlxdWlkaXR5IG1lc3NhZ2Ugd2l0aG91dCB0aGUgb3Bjb2RlIHByZWZpeAogICAgcG9vbFR5cGU6IEludCBhcyB1aW50MTsKICAgIGFzc2V0MDogQXNzZXQ7CiAgICBhc3NldDE6IEFzc2V0OwogICAgbWluaW1hbExwQW1vdW50OiBJbnQgYXMgY29pbnMgPSAwOwogICAgdGFyZ2V0QmFsYW5jZXMwOiBJbnQgYXMgY29pbnM7CiAgICB0YXJnZXRCYWxhbmNlczE6IEludCBhcyBjb2luczsKICAgIGZ1bGZpbGxQYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICByZWplY3RQYXlsb2FkOiBDZWxsPyA9IG51bGw7Cn0KCi8vLyBodHRwczovL2RvY3MuZGVkdXN0LmlvL3JlZmVyZW5jZS90bGItc2NoZW1lcyNhc3NldApzdHJ1Y3QgQXNzZXQgewogICAgLy8gU3BlY2lmeSAwIGZvciBuYXRpdmUgKFRPTikgYW5kIG9taXQgYWxsIGZvbGxvd2luZyBmaWVsZHMKICAgIC8vIFNwZWNpZnkgMSBmb3IgSmV0dG9uLCB0aGVuIHlvdSBtdXN0IHNldCBub24tbnVsbCB2YWx1ZXMgZm9yIHRoZSBmb2xsb3dpbmcgZmllbGRzCiAgICB0eXBlOiBJbnQgYXMgdWludDQ7CgogICAgd29ya2NoYWluOiBJbnQgYXMgdWludDggPSAwOyAvLyBCb3RoIHRoZXNlIHplcm9zIHdpbGwgYmUgcmVtb3ZlZCBkdXJpbmcgdGhlIC5idWlsZCgpIGZ1bmN0aW9uLiBPbmx5IHR5cGUgd2lsbCByZW1haW4uCiAgICBhZGRyZXNzOiBJbnQgYXMgdWludDI1NiA9IDA7Cn0KCmNvbnN0IFBvb2xUeXBlVm9sYXRpbGU6IEludCA9IDA7CmNvbnN0IFBvb2xUeXBlU3RhYmxlOiBJbnQgPSAxOwoKY29uc3QgQXNzZXRUeXBlTmF0aXZlOiBJbnQgPSAwYjAwMDA7CmNvbnN0IEFzc2V0VHlwZUpldHRvbjogSW50ID0gMGIwMDAxOwoKY29uc3QgSmV0dG9uUHJvdmlkZUxwR2FzOiBJbnQgPSB0b24oIjAuNSIpOwpjb25zdCBKZXR0b25Qcm92aWRlTHBHYXNGd2Q6IEludCA9IHRvbigiMC40Iik7CmNvbnN0IFRvblByb3ZpZGVMcEdhczogSW50ID0gdG9uKCIwLjE1Iik7CgovLyBUaGlzIGV4YW1wbGUgZGlyZWN0bHkgdXNlcyB0aGUgcHJvdmlkZWQgYG15SmV0dG9uV2FsbGV0QWRkcmVzc2AuCi8vIEluIHJlYWwtd29ybGQgc2NlbmFyaW9zLCBpdCdzIG1vcmUgcmVsaWFibGUgdG8gY2FsY3VsYXRlIHRoaXMgYWRkcmVzcyBvbi1jaGFpbiBvciBzYXZlIGl0IGR1cmluZyBpbml0aWFsaXphdGlvbiB0byBwcmV2ZW50IGFueSBpc3N1ZXMuCmZ1biBwcm92aWRlTGlxdWlkaXR5KG15SmV0dG9uV2FsbGV0QWRkcmVzczogQWRkcmVzcykgewogICAgbGV0IGpldHRvbk1hc3RlclJhdyA9IHBhcnNlU3RkQWRkcmVzcygKICAgICAgICBhZGRyZXNzKCJFUUN4RTZtVXRRSktGbkdmYVJPVEtPdDFsWmJEaWlYMWtDaXhSdjdOdzJJZF9zRHMiKS5hc1NsaWNlKCksCiAgICApOwoKICAgIC8vIFN0ZXAgMS4gUHJlcGFyZSBpbnB1dAogICAgbGV0IGpldHRvbkFtb3VudCA9IHRvbigiMSIpOwogICAgbGV0IHRvbkFtb3VudCA9IHRvbigiMSIpOwoKICAgIGxldCBhc3NldDAgPSBBc3NldCB7CiAgICAgICAgdHlwZTogQXNzZXRUeXBlTmF0aXZlLAogICAgfTsKICAgIGxldCBhc3NldDEgPSBBc3NldCB7CiAgICAgICAgdHlwZTogQXNzZXRUeXBlSmV0dG9uLAogICAgICAgIHdvcmtjaGFpbjogamV0dG9uTWFzdGVyUmF3LndvcmtjaGFpbiwKICAgICAgICBhZGRyZXNzOiBqZXR0b25NYXN0ZXJSYXcuYWRkcmVzcywKICAgIH07CgogICAgLy8gU3RlcCAyLiBEZXBvc2l0IEpldHRvbiB0byBWYXVsdAogICAgbGV0IGpldHRvbkRlcG9zaXRCb2R5ID0gSmV0dG9uRGVwb3NpdExpcXVpZGl0eSB7CiAgICAgICAgcG9vbFR5cGU6IFBvb2xUeXBlVm9sYXRpbGUsCiAgICAgICAgYXNzZXQwLAogICAgICAgIGFzc2V0MSwKICAgICAgICB0YXJnZXRCYWxhbmNlczA6IHRvbkFtb3VudCwKICAgICAgICB0YXJnZXRCYWxhbmNlczE6IGpldHRvbkFtb3VudCwKICAgIH0uYnVpbGQoKTsKICAgIC8vIE5vdGljZSAuYnVpbGQoKSBpbnN0ZWFkIG9mIC50b0NlbGwoKSwKICAgIC8vIHNpbmNlIHdlIHdhbnQgc29tZSBjdXN0b20gc2VyaWFsaXphdGlvbiBsb2dpYy4KCiAgICBzZW5kKFNlbmRQYXJhbWV0ZXJzIHsKICAgICAgICB0bzogbXlKZXR0b25XYWxsZXRBZGRyZXNzLAogICAgICAgIHZhbHVlOiBKZXR0b25Qcm92aWRlTHBHYXMsCiAgICAgICAgYm9keTogSmV0dG9uVHJhbnNmZXIgewogICAgICAgICAgICBxdWVyeUlkOiA0MiwKICAgICAgICAgICAgYW1vdW50OiBqZXR0b25BbW91bnQsCiAgICAgICAgICAgIC8vIEpldHRvbiBWYXVsdAogICAgICAgICAgICBkZXN0aW5hdGlvbjogYWRkcmVzcygiRVFBWXFvNHU3VkYwZmE0RFBBZWJrNGc5bEJ5dGoyVkZueTdwelhSMHRyanRYUWFPIiksCiAgICAgICAgICAgIHJlc3BvbnNlRGVzdGluYXRpb246IG15QWRkcmVzcygpLAogICAgICAgICAgICBmb3J3YXJkVG9uQW1vdW50OiBKZXR0b25Qcm92aWRlTHBHYXNGd2QsCiAgICAgICAgICAgIGZvcndhcmRQYXlsb2FkOiBqZXR0b25EZXBvc2l0Qm9keSwKICAgICAgICB9LnRvQ2VsbCgpLAogICAgfSk7CgogICAgLy8gU3RlcCAzLiBEZXBvc2l0IFRPTiB0byBWYXVsdAogICAgbGV0IG5hdGl2ZURlcG9zaXRCb2R5ID0gTmF0aXZlRGVwb3NpdExpcXVpZGl0eSB7CiAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgYW1vdW50OiB0b25BbW91bnQsCiAgICAgICAgcG9vbFR5cGU6IFBvb2xUeXBlVm9sYXRpbGUsCiAgICAgICAgYXNzZXQwLAogICAgICAgIGFzc2V0MSwKICAgICAgICB0YXJnZXRCYWxhbmNlczA6IHRvbkFtb3VudCwKICAgICAgICB0YXJnZXRCYWxhbmNlczE6IGpldHRvbkFtb3VudCwKICAgIH0uYnVpbGQoKTsKICAgIC8vIE5vdGljZSAuYnVpbGQoKSBpbnN0ZWFkIG9mIC50b0NlbGwoKSwKICAgIC8vIHNpbmNlIHdlIHdhbnQgc29tZSBjdXN0b20gc2VyaWFsaXphdGlvbiBsb2dpYy4KCiAgICBzZW5kKFNlbmRQYXJhbWV0ZXJzIHsKICAgICAgICB0bzogYWRkcmVzcygiRVFEYTRWT25UWWxMdkRKMGdaak5ZbTVQWGZTbW10TDZWczZBX0NaRXRYQ05JQ3FfIiksCiAgICAgICAgdmFsdWU6IHRvbkFtb3VudCArIFRvblByb3ZpZGVMcEdhcywKICAgICAgICBib2R5OiBuYXRpdmVEZXBvc2l0Qm9keSwKICAgIH0pOwp9CgovLwovLyBIZWxwZXIgZXh0ZW5zaW9uIGZ1bmN0aW9ucyB0byBidWlsZCByZXNwZWN0aXZlIHN0cnVjdHVyZXMgYW5kIG1lc3NhZ2VzCi8vCgpleHRlbmRzIGZ1biBidWlsZChzZWxmOiBBc3NldCk6IENlbGwgewogICAgbGV0IGFzc2V0QnVpbGRlciA9IGJlZ2luQ2VsbCgpLnN0b3JlVWludChzZWxmLnR5cGUsIDQpOwoKICAgIGlmIChzZWxmLnR5cGUgPT0gQXNzZXRUeXBlTmF0aXZlKSB7CiAgICAgICAgcmV0dXJuIGFzc2V0QnVpbGRlci5lbmRDZWxsKCk7CiAgICB9CgogICAgaWYgKHNlbGYudHlwZSA9PSBBc3NldFR5cGVKZXR0b24pIHsKICAgICAgICByZXR1cm4gYXNzZXRCdWlsZGVyCiAgICAgICAgICAgIC5zdG9yZVVpbnQoc2VsZi53b3JrY2hhaW4sIDgpCiAgICAgICAgICAgIC5zdG9yZVVpbnQoc2VsZi5hZGRyZXNzLCAyNTYpCiAgICAgICAgICAgIC5lbmRDZWxsKCk7CiAgICB9CgogICAgLy8gVW5rbm93biBhc3NldCB0eXBlCiAgICByZXR1cm4gYmVnaW5DZWxsKCkuZW5kQ2VsbCgpOwp9CgpleHRlbmRzIGZ1biBidWlsZChzZWxmOiBKZXR0b25EZXBvc2l0TGlxdWlkaXR5KTogQ2VsbCB7CiAgICByZXR1cm4gYmVnaW5DZWxsKCkKICAgICAgICAuc3RvcmVVaW50KDB4NDBlMTA4ZDYsIDMyKQogICAgICAgIC5zdG9yZVVpbnQoc2VsZi5wb29sVHlwZSwgMSkKICAgICAgICAuc3RvcmVTbGljZShzZWxmLmFzc2V0MC5idWlsZCgpLmFzU2xpY2UoKSkKICAgICAgICAuc3RvcmVTbGljZShzZWxmLmFzc2V0MS5idWlsZCgpLmFzU2xpY2UoKSkKICAgICAgICAuc3RvcmVDb2lucyhzZWxmLm1pbmltYWxMcEFtb3VudCkKICAgICAgICAuc3RvcmVDb2lucyhzZWxmLnRhcmdldEJhbGFuY2VzMCkKICAgICAgICAuc3RvcmVDb2lucyhzZWxmLnRhcmdldEJhbGFuY2VzMSkKICAgICAgICAuc3RvcmVNYXliZVJlZihzZWxmLmZ1bGZpbGxQYXlsb2FkKQogICAgICAgIC5zdG9yZU1heWJlUmVmKHNlbGYucmVqZWN0UGF5bG9hZCkKICAgICAgICAuZW5kQ2VsbCgpOwp9CgpleHRlbmRzIGZ1biBidWlsZChzZWxmOiBOYXRpdmVEZXBvc2l0TGlxdWlkaXR5KTogQ2VsbCB7CiAgICByZXR1cm4gYmVnaW5DZWxsKCkKICAgICAgICAuc3RvcmVVaW50KDB4ZDU1ZTQ2ODYsIDMyKQogICAgICAgIC5zdG9yZVVpbnQoc2VsZi5xdWVyeUlkLCA2NCkKICAgICAgICAuc3RvcmVDb2lucyhzZWxmLmFtb3VudCkKICAgICAgICAuc3RvcmVVaW50KHNlbGYucG9vbFR5cGUsIDEpCiAgICAgICAgLnN0b3JlU2xpY2Uoc2VsZi5hc3NldDAuYnVpbGQoKS5hc1NsaWNlKCkpCiAgICAgICAgLnN0b3JlU2xpY2Uoc2VsZi5hc3NldDEuYnVpbGQoKS5hc1NsaWNlKCkpCiAgICAgICAgLnN0b3JlUmVmKAogICAgICAgICAgICBiZWdpbkNlbGwoKQogICAgICAgICAgICAgICAgLnN0b3JlQ29pbnMoc2VsZi5taW5pbWFsTHBBbW91bnQpCiAgICAgICAgICAgICAgICAuc3RvcmVDb2lucyhzZWxmLnRhcmdldEJhbGFuY2VzMCkKICAgICAgICAgICAgICAgIC5zdG9yZUNvaW5zKHNlbGYudGFyZ2V0QmFsYW5jZXMxKQogICAgICAgICAgICAgICAgLmVuZENlbGwoKSwKICAgICAgICApCiAgICAgICAgLnN0b3JlTWF5YmVSZWYoc2VsZi5mdWxmaWxsUGF5bG9hZCkKICAgICAgICAuc3RvcmVNYXliZVJlZihzZWxmLnJlamVjdFBheWxvYWQpCiAgICAgICAgLmVuZENlbGwoKTsKfQoKLy8KLy8gTWVzc2FnZXMgZnJvbSB0aGUgSmV0dG9uIHN0YW5kYXJkCi8vCgptZXNzYWdlKDB4ZjhhN2VhNSkgSmV0dG9uVHJhbnNmZXIgewogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NDsKICAgIGFtb3VudDogSW50IGFzIGNvaW5zOwogICAgZGVzdGluYXRpb246IEFkZHJlc3M7CiAgICByZXNwb25zZURlc3RpbmF0aW9uOiBBZGRyZXNzPzsKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIGZvcndhcmRUb25BbW91bnQ6IEludCBhcyBjb2luczsKICAgIGZvcndhcmRQYXlsb2FkOiBDZWxsPzsgLy8gU2xpZ2h0bHkgYWRqdXN0ZWQKfQ%3D%3D)
### Withdraw liquidity[](#withdraw-liquidity)
To withdraw liquidity, burning LP tokens is required. You can refer to examples of Jetton burning in the [respective section of the Jettons Cookbook page](/cookbook/jettons#burning-jetton). However, more Toncoin should be added than for a normal burn, since adding too few may result in LP tokens being burned but no liquidity (or only partial liquidity) being sent from the pool. Therefore, consider attaching at least 0.5 Toncoin — the excess amount will be returned.
Hey there!
Didn’t find your favorite example of DeDust interaction? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# STON.fi
> This page lists examples of working with STON.fi, a decentralized automated market maker built on TON Blockchain.
[STON.fi](https://ston.fi) is a decentralized automated market maker (AMM) built on [TON blockchain](https://ton.org), providing virtually zero fees, low slippage, an extremely easy interface, and direct integration with TON wallets.
Caution
The examples on this page use STON.fi’s API v2, which is currently under development. Thus, all addresses are given in [testnet](https://docs.ton.org/v3/documentation/smart-contracts/getting-started/testnet).
Proceed with caution and vigilance — do not attempt to send funds from the mainnet to the testnet and vice versa.
Before going further, familiarize yourself with the following:
* [Receiving messages](/book/receive/)
* [Sending messages](/book/send/)
* [Fungible Tokens (Jettons)](/cookbook/jettons/)
* [STON.fi Docs: Glossary](https://docs.ston.fi/docs/user-section/glossary)
* [STON.fi Docs: Architecture](https://docs.ston.fi/docs/developer-section/architecture)
## Swaps[](#swaps)
Read more about swaps in the [STON.fi documentation](https://docs.ston.fi/docs/developer-section/api-reference-v2/example_swap).
Swaps use the `StonfiSwap` [Message](/book/structs-and-messages#messages) and the `SwapAdditionalData` [struct](/book/structs-and-messages#structs):
```tact
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#swap-0x6664de2a
message(0x6664de2a) StonfiSwap {
// Address of the other Router token wallet
otherTokenWallet: Address;
// Where to send refunds upon a failed swap
refundAddress: Address;
// Where to send excesses upon a successful swap
excessesAddress: Address;
// UNIX timestamp of execution deadline for the swap
deadline: Int as uint64;
// Reference to another Cell with additional data,
// using Tact's greedy auto-layout mechanism
additionalData: SwapAdditionalData;
}
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#additional_data-body
struct SwapAdditionalData {
// Minimum required amount of tokens to receive
// Defaults to 1, which causes the swap to fail
// only if no tokens are received
minOut: Int as coins = 1;
// Where to send tokens upon a successful swap
receiverAddress: Address;
// Forward fees for the `customPayload` if it's not `null`
// Defaults to 0
fwdGas: Int as coins = 0;
// Custom payload that will be sent upon a successful swap
// Defaults to `null`, which means no payload
customPayload: Cell? = null;
// Forward fees for `refundPayload` if it's not `null`
// Defaults to 0
refundFwdGas: Int as coins = 0;
// Custom payload that will be sent upon a failed swap
// Defaults to `null`, which means no payload
refundPayload: Cell? = null;
// Referral fee, between 0 (no fee) and 100 (1%)
// Defaults to 10, which means 0.1% fee
refFee: Int as uint16 = 10;
// Address of the referral
// Defaults to `null`
referralAddress: Address? = null;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZG9jcy5zdG9uLmZpL2RvY3MvZGV2ZWxvcGVyLXNlY3Rpb24vYXBpLXJlZmVyZW5jZS12Mi9yb3V0ZXIjc3dhcC0weDY2NjRkZTJhCm1lc3NhZ2UoMHg2NjY0ZGUyYSkgU3RvbmZpU3dhcCB7CiAgICAvLyBBZGRyZXNzIG9mIHRoZSBvdGhlciBSb3V0ZXIgdG9rZW4gd2FsbGV0CiAgICBvdGhlclRva2VuV2FsbGV0OiBBZGRyZXNzOwoKICAgIC8vIFdoZXJlIHRvIHNlbmQgcmVmdW5kcyB1cG9uIGEgZmFpbGVkIHN3YXAKICAgIHJlZnVuZEFkZHJlc3M6IEFkZHJlc3M7CgogICAgLy8gV2hlcmUgdG8gc2VuZCBleGNlc3NlcyB1cG9uIGEgc3VjY2Vzc2Z1bCBzd2FwCiAgICBleGNlc3Nlc0FkZHJlc3M6IEFkZHJlc3M7CgogICAgLy8gVU5JWCB0aW1lc3RhbXAgb2YgZXhlY3V0aW9uIGRlYWRsaW5lIGZvciB0aGUgc3dhcAogICAgZGVhZGxpbmU6IEludCBhcyB1aW50NjQ7CgogICAgLy8gUmVmZXJlbmNlIHRvIGFub3RoZXIgQ2VsbCB3aXRoIGFkZGl0aW9uYWwgZGF0YSwKICAgIC8vIHVzaW5nIFRhY3QncyBncmVlZHkgYXV0by1sYXlvdXQgbWVjaGFuaXNtCiAgICBhZGRpdGlvbmFsRGF0YTogU3dhcEFkZGl0aW9uYWxEYXRhOwp9CgovLy8gaHR0cHM6Ly9kb2NzLnN0b24uZmkvZG9jcy9kZXZlbG9wZXItc2VjdGlvbi9hcGktcmVmZXJlbmNlLXYyL3JvdXRlciNhZGRpdGlvbmFsX2RhdGEtYm9keQpzdHJ1Y3QgU3dhcEFkZGl0aW9uYWxEYXRhIHsKICAgIC8vIE1pbmltdW0gcmVxdWlyZWQgYW1vdW50IG9mIHRva2VucyB0byByZWNlaXZlCiAgICAvLyBEZWZhdWx0cyB0byAxLCB3aGljaCBjYXVzZXMgdGhlIHN3YXAgdG8gZmFpbAogICAgLy8gICAgICAgICAgICAgICAgb25seSBpZiBubyB0b2tlbnMgYXJlIHJlY2VpdmVkCiAgICBtaW5PdXQ6IEludCBhcyBjb2lucyA9IDE7CgogICAgLy8gV2hlcmUgdG8gc2VuZCB0b2tlbnMgdXBvbiBhIHN1Y2Nlc3NmdWwgc3dhcAogICAgcmVjZWl2ZXJBZGRyZXNzOiBBZGRyZXNzOwoKICAgIC8vIEZvcndhcmQgZmVlcyBmb3IgdGhlIGBjdXN0b21QYXlsb2FkYCBpZiBpdCdzIG5vdCBgbnVsbGAKICAgIC8vIERlZmF1bHRzIHRvIDAKICAgIGZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKCiAgICAvLyBDdXN0b20gcGF5bG9hZCB0aGF0IHdpbGwgYmUgc2VudCB1cG9uIGEgc3VjY2Vzc2Z1bCBzd2FwCiAgICAvLyBEZWZhdWx0cyB0byBgbnVsbGAsIHdoaWNoIG1lYW5zIG5vIHBheWxvYWQKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKCiAgICAvLyBGb3J3YXJkIGZlZXMgZm9yIGByZWZ1bmRQYXlsb2FkYCBpZiBpdCdzIG5vdCBgbnVsbGAKICAgIC8vIERlZmF1bHRzIHRvIDAKICAgIHJlZnVuZEZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKCiAgICAvLyBDdXN0b20gcGF5bG9hZCB0aGF0IHdpbGwgYmUgc2VudCB1cG9uIGEgZmFpbGVkIHN3YXAKICAgIC8vIERlZmF1bHRzIHRvIGBudWxsYCwgd2hpY2ggbWVhbnMgbm8gcGF5bG9hZAogICAgcmVmdW5kUGF5bG9hZDogQ2VsbD8gPSBudWxsOwoKICAgIC8vIFJlZmVycmFsIGZlZSwgYmV0d2VlbiAwIChubyBmZWUpIGFuZCAxMDAgKDElKQogICAgLy8gRGVmYXVsdHMgdG8gMTAsIHdoaWNoIG1lYW5zIDAuMSUgZmVlCiAgICByZWZGZWU6IEludCBhcyB1aW50MTYgPSAxMDsKCiAgICAvLyBBZGRyZXNzIG9mIHRoZSByZWZlcnJhbAogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgCiAgICByZWZlcnJhbEFkZHJlc3M6IEFkZHJlc3M%2FID0gbnVsbDsKfQ%3D%3D)
The [STON.fi SDK](https://github.com/ston-fi/sdk) defines some [constants to deal with fees](https://github.com/ston-fi/sdk/blob/786ece758794bd5c575db8b38f5e5de19f43f0d1/packages/sdk/src/contracts/dex/v2_1/router/BaseRouterV2_1.ts). Note that these are hardcoded values, but the best practice is to [calculate fees dynamically using current config params](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation) instead.
```tact
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToJetton: Int = ton("0.3");
/// Hardcoded fee value to pay forward fees from the Jetton wallet
const FeeSwapJettonToJettonFwd: Int = ton("0.24");
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToToncoin: Int = ton("0.3");
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToToncoinFwd: Int = ton("0.24");
/// Hardcoded fee value to pay for sending a message and subsequent forwarding
const FeeSwapToncoinToJetton: Int = ton("0.01") + ton("0.3");
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIEhhcmRjb2RlZCBmZWUgdmFsdWUgdG8gcGF5IGZvciBzZW5kaW5nIGEgbWVzc2FnZSB0byB0aGUgSmV0dG9uIHdhbGxldApjb25zdCBGZWVTd2FwSmV0dG9uVG9KZXR0b246IEludCA9IHRvbigiMC4zIik7Ci8vLyBIYXJkY29kZWQgZmVlIHZhbHVlIHRvIHBheSBmb3J3YXJkIGZlZXMgZnJvbSB0aGUgSmV0dG9uIHdhbGxldApjb25zdCBGZWVTd2FwSmV0dG9uVG9KZXR0b25Gd2Q6IEludCA9IHRvbigiMC4yNCIpOwoKLy8vIEhhcmRjb2RlZCBmZWUgdmFsdWUgdG8gcGF5IGZvciBzZW5kaW5nIGEgbWVzc2FnZSB0byB0aGUgSmV0dG9uIHdhbGxldApjb25zdCBGZWVTd2FwSmV0dG9uVG9Ub25jb2luOiBJbnQgPSB0b24oIjAuMyIpOwovLy8gSGFyZGNvZGVkIGZlZSB2YWx1ZSB0byBwYXkgZm9yIHNlbmRpbmcgYSBtZXNzYWdlIHRvIHRoZSBKZXR0b24gd2FsbGV0CmNvbnN0IEZlZVN3YXBKZXR0b25Ub1RvbmNvaW5Gd2Q6IEludCA9IHRvbigiMC4yNCIpOwoKLy8vIEhhcmRjb2RlZCBmZWUgdmFsdWUgdG8gcGF5IGZvciBzZW5kaW5nIGEgbWVzc2FnZSBhbmQgc3Vic2VxdWVudCBmb3J3YXJkaW5nCmNvbnN0IEZlZVN3YXBUb25jb2luVG9KZXR0b246IEludCA9IHRvbigiMC4wMSIpICsgdG9uKCIwLjMiKTs%3D)
Useful links:
[Fees Calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation)
### Jetton to Jetton[](#swaps-jetton-to-jetton)
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in [testnet](https://docs.ton.org/v3/documentation/smart-contracts/getting-started/testnet).
In addition, some variables such as `offerAmount` are hardcoded for demonstration purposes. Don’t forget to change them in real-life scenarios.
```tact
// CPI Router v2.1.0
const RouterAddress: Address = address("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v");
// Router Jetton Wallet address
const RouterJettonWallet: Address = address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
/// NOTE: To calculate and provide the Jetton wallet address for the target user,
/// make sure to check the links after this code snippet.
fun jettonToJetton(myJettonWalletAddress: Address) {
// Amount of Jettons to swap
let offerAmount: Int = 100_000;
// Prepare the payload
let forwardPayload = StonfiSwap {
otherTokenWallet: RouterJettonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 10,000 seconds from now
deadline: now() + 10_000,
additionalData: SwapAdditionalData { receiverAddress: myAddress() },
};
// Start a swap with the message to the Jetton wallet
send(SendParameters {
to: myJettonWalletAddress,
value: FeeSwapJettonToJetton,
body: JettonTransfer {
queryId: 42,
amount: offerAmount,
destination: RouterAddress,
responseDestination: myAddress(),
forwardTonAmount: FeeSwapJettonToJettonFwd,
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper structures and constants described earlier on this page
//
message(0x6664de2a) StonfiSwap {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: SwapAdditionalData;
}
struct SwapAdditionalData {
minOut: Int as coins = 1;
receiverAddress: Address;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
refundFwdGas: Int as coins = 0;
refundPayload: Cell? = null;
refFee: Int as uint16 = 10;
referralAddress: Address? = null;
}
const FeeSwapJettonToJetton: Int = ton("0.3");
const FeeSwapJettonToJettonFwd: Int = ton("0.24");
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gQ1BJIFJvdXRlciB2Mi4xLjAKY29uc3QgUm91dGVyQWRkcmVzczogQWRkcmVzcyA9IGFkZHJlc3MoImtRQUxoLUpCQklLSzdncjBvNEFWZjlKWm5Fc0ZuZHFPMHFUQ3lULUQteUJzV2swdiIpOwoKLy8gUm91dGVyIEpldHRvbiBXYWxsZXQgYWRkcmVzcwpjb25zdCBSb3V0ZXJKZXR0b25XYWxsZXQ6IEFkZHJlc3MgPSBhZGRyZXNzKCJrUUF0WDN4MnMtd010WVR6OENmbUF5bG9IQUI3M3ZPTnpKTTVTMmlkcVhsLV81eEsiKTsKCi8vLyBOT1RFOiBUbyBjYWxjdWxhdGUgYW5kIHByb3ZpZGUgdGhlIEpldHRvbiB3YWxsZXQgYWRkcmVzcyBmb3IgdGhlIHRhcmdldCB1c2VyLAovLy8gICAgICAgbWFrZSBzdXJlIHRvIGNoZWNrIHRoZSBsaW5rcyBhZnRlciB0aGlzIGNvZGUgc25pcHBldC4KZnVuIGpldHRvblRvSmV0dG9uKG15SmV0dG9uV2FsbGV0QWRkcmVzczogQWRkcmVzcykgewogICAgLy8gQW1vdW50IG9mIEpldHRvbnMgdG8gc3dhcAogICAgbGV0IG9mZmVyQW1vdW50OiBJbnQgPSAxMDBfMDAwOwoKICAgIC8vIFByZXBhcmUgdGhlIHBheWxvYWQKICAgIGxldCBmb3J3YXJkUGF5bG9hZCA9IFN0b25maVN3YXAgewogICAgICAgIG90aGVyVG9rZW5XYWxsZXQ6IFJvdXRlckpldHRvbldhbGxldCwKICAgICAgICByZWZ1bmRBZGRyZXNzOiBteUFkZHJlc3MoKSwKICAgICAgICBleGNlc3Nlc0FkZHJlc3M6IG15QWRkcmVzcygpLAogICAgICAgIC8vIERlYWRsaW5lIGlzIHNldCB0byAxMCwwMDAgc2Vjb25kcyBmcm9tIG5vdwogICAgICAgIGRlYWRsaW5lOiBub3coKSArIDEwXzAwMCwKICAgICAgICBhZGRpdGlvbmFsRGF0YTogU3dhcEFkZGl0aW9uYWxEYXRhIHsgcmVjZWl2ZXJBZGRyZXNzOiBteUFkZHJlc3MoKSB9LAogICAgfTsKCiAgICAvLyBTdGFydCBhIHN3YXAgd2l0aCB0aGUgbWVzc2FnZSB0byB0aGUgSmV0dG9uIHdhbGxldAogICAgc2VuZChTZW5kUGFyYW1ldGVycyB7CiAgICAgICAgdG86IG15SmV0dG9uV2FsbGV0QWRkcmVzcywKICAgICAgICB2YWx1ZTogRmVlU3dhcEpldHRvblRvSmV0dG9uLAogICAgICAgIGJvZHk6IEpldHRvblRyYW5zZmVyIHsKICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgIGFtb3VudDogb2ZmZXJBbW91bnQsCiAgICAgICAgICAgIGRlc3RpbmF0aW9uOiBSb3V0ZXJBZGRyZXNzLAogICAgICAgICAgICByZXNwb25zZURlc3RpbmF0aW9uOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgZm9yd2FyZFRvbkFtb3VudDogRmVlU3dhcEpldHRvblRvSmV0dG9uRndkLAogICAgICAgICAgICBmb3J3YXJkUGF5bG9hZDogZm9yd2FyZFBheWxvYWQudG9DZWxsKCksCiAgICAgICAgfS50b0NlbGwoKSwKICAgIH0pOwp9CgovLwovLyBIZWxwZXIgc3RydWN0dXJlcyBhbmQgY29uc3RhbnRzIGRlc2NyaWJlZCBlYXJsaWVyIG9uIHRoaXMgcGFnZQovLwoKbWVzc2FnZSgweDY2NjRkZTJhKSBTdG9uZmlTd2FwIHsKICAgIG90aGVyVG9rZW5XYWxsZXQ6IEFkZHJlc3M7CiAgICByZWZ1bmRBZGRyZXNzOiBBZGRyZXNzOwogICAgZXhjZXNzZXNBZGRyZXNzOiBBZGRyZXNzOwogICAgZGVhZGxpbmU6IEludCBhcyB1aW50NjQ7CiAgICBhZGRpdGlvbmFsRGF0YTogU3dhcEFkZGl0aW9uYWxEYXRhOwp9CgpzdHJ1Y3QgU3dhcEFkZGl0aW9uYWxEYXRhIHsKICAgIG1pbk91dDogSW50IGFzIGNvaW5zID0gMTsKICAgIHJlY2VpdmVyQWRkcmVzczogQWRkcmVzczsKICAgIGZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIHJlZnVuZEZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKICAgIHJlZnVuZFBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIHJlZkZlZTogSW50IGFzIHVpbnQxNiA9IDEwOwogICAgcmVmZXJyYWxBZGRyZXNzOiBBZGRyZXNzPyA9IG51bGw7Cn0KCmNvbnN0IEZlZVN3YXBKZXR0b25Ub0pldHRvbjogSW50ID0gdG9uKCIwLjMiKTsKY29uc3QgRmVlU3dhcEpldHRvblRvSmV0dG9uRndkOiBJbnQgPSB0b24oIjAuMjQiKTsKCi8vCi8vIE1lc3NhZ2VzIGZyb20gdGhlIEpldHRvbiBzdGFuZGFyZAovLwoKbWVzc2FnZSgweGY4YTdlYTUpIEpldHRvblRyYW5zZmVyIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7CiAgICBhbW91bnQ6IEludCBhcyBjb2luczsKICAgIGRlc3RpbmF0aW9uOiBBZGRyZXNzOwogICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogQWRkcmVzcz87CiAgICBjdXN0b21QYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICBmb3J3YXJkVG9uQW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBmb3J3YXJkUGF5bG9hZDogQ2VsbD87IC8vIHNsaWdodGx5IGFkanVzdGVkCn0%3D)
Useful links:
[Retrieving Jetton wallet address in TON Docs](https://docs.ton.org/develop/dapps/asset-processing/jettons#retrieving-jetton-wallet-addresses-for-a-given-user)\
[How to calculate user’s Jetton wallet address (offline)?](https://docs.ton.org/v3/guidelines/dapps/cookbook#how-to-calculate-users-jetton-wallet-address-offline)\
[Discoverable Jetton wallets](https://github.com/ton-blockchain/TEPs/blob/master/text/0089-jetton-wallet-discovery.md)\
[Fees Calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation)
### Jetton to Toncoin[](#swaps-jetton-to-toncoin)
A Jetton to Toncoin swap is very similar to a [Jetton to Jetton swap](#swaps-jetton-to-jetton), with the only difference being that the `RouterJettonWallet` address is replaced with `RouterProxyTonWallet`.
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in [testnet](https://docs.ton.org/v3/documentation/smart-contracts/getting-started/testnet).
In addition, some variables, such as `offerAmount`, are hardcoded for demonstration purposes. Don’t forget to change them in real-life scenarios.
```tact
// CPI Router v2.1.0
const RouterAddress: Address = address("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v");
// Router's pTON address
const RouterProxyTonWallet: Address = address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
/// NOTE: To calculate and provide the Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonToToncoin(myJettonWalletAddress: Address) {
// Amount of Jettons to swap
let offerAmount: Int = 100_000;
// Prepare the payload
let forwardPayload = StonfiSwap {
otherTokenWallet: RouterProxyTonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 10,000 seconds from now
deadline: now() + 10_000,
additionalData: SwapAdditionalData { receiverAddress: myAddress() },
};
// Start a swap with the message to the Jetton wallet
send(SendParameters {
to: myJettonWalletAddress,
value: FeeSwapJettonToToncoin,
body: JettonTransfer {
queryId: 42,
amount: offerAmount,
destination: RouterAddress,
responseDestination: myAddress(),
forwardTonAmount: FeeSwapJettonToToncoinFwd,
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper messages, structs, and constants described earlier on this page
//
message(0x6664de2a) StonfiSwap {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: SwapAdditionalData;
}
struct SwapAdditionalData {
minOut: Int as coins = 1;
receiverAddress: Address;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
refundFwdGas: Int as coins = 0;
refundPayload: Cell? = null;
refFee: Int as uint16 = 10;
referralAddress: Address? = null;
}
const FeeSwapJettonToToncoin: Int = ton("0.3");
const FeeSwapJettonToToncoinFwd: Int = ton("0.24");
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gQ1BJIFJvdXRlciB2Mi4xLjAKY29uc3QgUm91dGVyQWRkcmVzczogQWRkcmVzcyA9IGFkZHJlc3MoImtRQUxoLUpCQklLSzdncjBvNEFWZjlKWm5Fc0ZuZHFPMHFUQ3lULUQteUJzV2swdiIpOwoKLy8gUm91dGVyJ3MgcFRPTiBhZGRyZXNzCmNvbnN0IFJvdXRlclByb3h5VG9uV2FsbGV0OiBBZGRyZXNzID0gYWRkcmVzcygia1FCYkpqbmFoQk1HYk1VSndoQVhMbjhCaWlnY0dYTUpoU0MwbDdEQmhkWUFCaEc3Iik7CgovLy8gTk9URTogVG8gY2FsY3VsYXRlIGFuZCBwcm92aWRlIHRoZSBKZXR0b24gd2FsbGV0IGFkZHJlc3MgZm9yIHRoZSB0YXJnZXQgdXNlciwKLy8vICAgICAgIG1ha2Ugc3VyZSB0byBjaGVjayBsaW5rcyBhZnRlciB0aGlzIGNvZGUgc25pcHBldApmdW4gamV0dG9uVG9Ub25jb2luKG15SmV0dG9uV2FsbGV0QWRkcmVzczogQWRkcmVzcykgewogICAgLy8gQW1vdW50IG9mIEpldHRvbnMgdG8gc3dhcAogICAgbGV0IG9mZmVyQW1vdW50OiBJbnQgPSAxMDBfMDAwOwoKICAgIC8vIFByZXBhcmUgdGhlIHBheWxvYWQKICAgIGxldCBmb3J3YXJkUGF5bG9hZCA9IFN0b25maVN3YXAgewogICAgICAgIG90aGVyVG9rZW5XYWxsZXQ6IFJvdXRlclByb3h5VG9uV2FsbGV0LAogICAgICAgIHJlZnVuZEFkZHJlc3M6IG15QWRkcmVzcygpLAogICAgICAgIGV4Y2Vzc2VzQWRkcmVzczogbXlBZGRyZXNzKCksCiAgICAgICAgLy8gRGVhZGxpbmUgaXMgc2V0IHRvIDEwLDAwMCBzZWNvbmRzIGZyb20gbm93CiAgICAgICAgZGVhZGxpbmU6IG5vdygpICsgMTBfMDAwLAogICAgICAgIGFkZGl0aW9uYWxEYXRhOiBTd2FwQWRkaXRpb25hbERhdGEgeyByZWNlaXZlckFkZHJlc3M6IG15QWRkcmVzcygpIH0sCiAgICB9OwoKICAgIC8vIFN0YXJ0IGEgc3dhcCB3aXRoIHRoZSBtZXNzYWdlIHRvIHRoZSBKZXR0b24gd2FsbGV0CiAgICBzZW5kKFNlbmRQYXJhbWV0ZXJzIHsKICAgICAgICB0bzogbXlKZXR0b25XYWxsZXRBZGRyZXNzLAogICAgICAgIHZhbHVlOiBGZWVTd2FwSmV0dG9uVG9Ub25jb2luLAogICAgICAgIGJvZHk6IEpldHRvblRyYW5zZmVyIHsKICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgIGFtb3VudDogb2ZmZXJBbW91bnQsCiAgICAgICAgICAgIGRlc3RpbmF0aW9uOiBSb3V0ZXJBZGRyZXNzLAogICAgICAgICAgICByZXNwb25zZURlc3RpbmF0aW9uOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgZm9yd2FyZFRvbkFtb3VudDogRmVlU3dhcEpldHRvblRvVG9uY29pbkZ3ZCwKICAgICAgICAgICAgZm9yd2FyZFBheWxvYWQ6IGZvcndhcmRQYXlsb2FkLnRvQ2VsbCgpLAogICAgICAgIH0udG9DZWxsKCksCiAgICB9KTsKfQoKLy8KLy8gSGVscGVyIG1lc3NhZ2VzLCBzdHJ1Y3RzLCBhbmQgY29uc3RhbnRzIGRlc2NyaWJlZCBlYXJsaWVyIG9uIHRoaXMgcGFnZQovLwoKbWVzc2FnZSgweDY2NjRkZTJhKSBTdG9uZmlTd2FwIHsKICAgIG90aGVyVG9rZW5XYWxsZXQ6IEFkZHJlc3M7CiAgICByZWZ1bmRBZGRyZXNzOiBBZGRyZXNzOwogICAgZXhjZXNzZXNBZGRyZXNzOiBBZGRyZXNzOwogICAgZGVhZGxpbmU6IEludCBhcyB1aW50NjQ7CiAgICBhZGRpdGlvbmFsRGF0YTogU3dhcEFkZGl0aW9uYWxEYXRhOwp9CgpzdHJ1Y3QgU3dhcEFkZGl0aW9uYWxEYXRhIHsKICAgIG1pbk91dDogSW50IGFzIGNvaW5zID0gMTsKICAgIHJlY2VpdmVyQWRkcmVzczogQWRkcmVzczsKICAgIGZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIHJlZnVuZEZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKICAgIHJlZnVuZFBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIHJlZkZlZTogSW50IGFzIHVpbnQxNiA9IDEwOwogICAgcmVmZXJyYWxBZGRyZXNzOiBBZGRyZXNzPyA9IG51bGw7Cn0KCmNvbnN0IEZlZVN3YXBKZXR0b25Ub1RvbmNvaW46IEludCA9IHRvbigiMC4zIik7CmNvbnN0IEZlZVN3YXBKZXR0b25Ub1RvbmNvaW5Gd2Q6IEludCA9IHRvbigiMC4yNCIpOwoKLy8KLy8gTWVzc2FnZXMgZnJvbSB0aGUgSmV0dG9uIHN0YW5kYXJkCi8vCgptZXNzYWdlKDB4ZjhhN2VhNSkgSmV0dG9uVHJhbnNmZXIgewogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NDsKICAgIGFtb3VudDogSW50IGFzIGNvaW5zOwogICAgZGVzdGluYXRpb246IEFkZHJlc3M7CiAgICByZXNwb25zZURlc3RpbmF0aW9uOiBBZGRyZXNzPzsKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIGZvcndhcmRUb25BbW91bnQ6IEludCBhcyBjb2luczsKICAgIGZvcndhcmRQYXlsb2FkOiBDZWxsPzsgLy8gc2xpZ2h0bHkgYWRqdXN0ZWQKfQ%3D%3D)
Useful links:
[Retrieving Jetton wallet address in TON Docs](https://docs.ton.org/develop/dapps/asset-processing/jettons#retrieving-jetton-wallet-addresses-for-a-given-user)\
[How to calculate user’s Jetton wallet address (offline)?](https://docs.ton.org/v3/guidelines/dapps/cookbook#how-to-calculate-users-jetton-wallet-address-offline)\
[Discoverable Jetton wallets](https://github.com/ton-blockchain/TEPs/blob/master/text/0089-jetton-wallet-discovery.md)\
[Fees Calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation)
### Toncoin to Jetton[](#swaps-jetton-to-toncoin)
To swap Toncoin to Jetton, STON.fi requires the use of a so-called proxy Toncoin wallet (or pTON for short). To interact with it properly, we need to introduce a `ProxyToncoinTransfer` [Message](/book/structs-and-messages#messages):
```tact
/// https://github.com/ston-fi/sdk/blob/786ece758794bd5c575db8b38f5e5de19f43f0d1/packages/sdk/src/contracts/pTON/v2_1/PtonV2_1.ts
message(0x01f3835d) ProxyToncoinTransfer {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means we don't mark messages to trace their chains
queryId: Int as uint64 = 0;
// Toncoin amount for the swap
tonAmount: Int as coins;
// Address to send refunds to upon a failed swap
refundAddress: Address;
// Optional custom payload to attach to the swap
// Defaults to `null`
forwardPayload: Cell?;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZ2l0aHViLmNvbS9zdG9uLWZpL3Nkay9ibG9iLzc4NmVjZTc1ODc5NGJkNWM1NzVkYjhiMzhmNWU1ZGUxOWY0M2YwZDEvcGFja2FnZXMvc2RrL3NyYy9jb250cmFjdHMvcFRPTi92Ml8xL1B0b25WMl8xLnRzCm1lc3NhZ2UoMHgwMWYzODM1ZCkgUHJveHlUb25jb2luVHJhbnNmZXIgewogICAgLy8gVW5pcXVlIGlkZW50aWZpZXIgdXNlZCB0byB0cmFjZSB0cmFuc2FjdGlvbnMgYWNyb3NzIG11bHRpcGxlIGNvbnRyYWN0cwogICAgLy8gRGVmYXVsdHMgdG8gMCwgd2hpY2ggbWVhbnMgd2UgZG9uJ3QgbWFyayBtZXNzYWdlcyB0byB0cmFjZSB0aGVpciBjaGFpbnMKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQgPSAwOwoKICAgIC8vIFRvbmNvaW4gYW1vdW50IGZvciB0aGUgc3dhcAogICAgdG9uQW1vdW50OiBJbnQgYXMgY29pbnM7CgogICAgLy8gQWRkcmVzcyB0byBzZW5kIHJlZnVuZHMgdG8gdXBvbiBhIGZhaWxlZCBzd2FwCiAgICByZWZ1bmRBZGRyZXNzOiBBZGRyZXNzOwoKICAgIC8vIE9wdGlvbmFsIGN1c3RvbSBwYXlsb2FkIHRvIGF0dGFjaCB0byB0aGUgc3dhcAogICAgLy8gRGVmYXVsdHMgdG8gYG51bGxgCiAgICBmb3J3YXJkUGF5bG9hZDogQ2VsbD87Cn0%3D)
Notice that `ProxyToncoinTransfer` is quite similar to `JettonTransfer`, except that it doesn’t require any addresses other than the refund address, nor does it require any forward amounts to be specified.
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in [testnet](https://docs.ton.org/v3/documentation/smart-contracts/getting-started/testnet).
In addition, some variables such as `offerAmount` are hardcoded for demonstration purposes. Don’t forget to change them in real-life scenarios.
```tact
// Router's pTON wallet address
const RouterProxyTonWallet: Address = address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
// Router's Jetton wallet address
const RouterJettonWallet: Address = address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
fun toncoinToJetton() {
// Amount of Toncoin to swap
let offerAmount: Int = 1_000;
// Prepare the payload
let forwardPayload = StonfiSwap {
otherTokenWallet: RouterJettonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 10,000 seconds from now
deadline: now() + 10_000,
additionalData: SwapAdditionalData { receiverAddress: myAddress() },
};
// Start a swap with the message to the proxy Toncoin wallet
send(SendParameters {
to: RouterProxyTonWallet,
value: FeeSwapToncoinToJetton + offerAmount,
body: ProxyToncoinTransfer {
tonAmount: offerAmount,
refundAddress: myAddress(),
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper structures and constants described earlier on this page
//
message(0x01f3835d) ProxyToncoinTransfer {
queryId: Int as uint64 = 0;
tonAmount: Int as coins;
refundAddress: Address;
forwardPayload: Cell?;
}
message(0x6664de2a) StonfiSwap {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: SwapAdditionalData;
}
struct SwapAdditionalData {
minOut: Int as coins = 1;
receiverAddress: Address;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
refundFwdGas: Int as coins = 0;
refundPayload: Cell? = null;
refFee: Int as uint16 = 10;
referralAddress: Address? = null;
}
const FeeSwapToncoinToJetton: Int = ton("0.3");
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gUm91dGVyJ3MgcFRPTiB3YWxsZXQgYWRkcmVzcwpjb25zdCBSb3V0ZXJQcm94eVRvbldhbGxldDogQWRkcmVzcyA9IGFkZHJlc3MoImtRQmJKam5haEJNR2JNVUp3aEFYTG44QmlpZ2NHWE1KaFNDMGw3REJoZFlBQmhHNyIpOwoKLy8gUm91dGVyJ3MgSmV0dG9uIHdhbGxldCBhZGRyZXNzCmNvbnN0IFJvdXRlckpldHRvbldhbGxldDogQWRkcmVzcyA9IGFkZHJlc3MoImtRQXRYM3gycy13TXRZVHo4Q2ZtQXlsb0hBQjczdk9OekpNNVMyaWRxWGwtXzV4SyIpOwoKZnVuIHRvbmNvaW5Ub0pldHRvbigpIHsKICAgIC8vIEFtb3VudCBvZiBUb25jb2luIHRvIHN3YXAKICAgIGxldCBvZmZlckFtb3VudDogSW50ID0gMV8wMDA7CgogICAgLy8gUHJlcGFyZSB0aGUgcGF5bG9hZAogICAgbGV0IGZvcndhcmRQYXlsb2FkID0gU3RvbmZpU3dhcCB7CiAgICAgICAgb3RoZXJUb2tlbldhbGxldDogUm91dGVySmV0dG9uV2FsbGV0LAogICAgICAgIHJlZnVuZEFkZHJlc3M6IG15QWRkcmVzcygpLAogICAgICAgIGV4Y2Vzc2VzQWRkcmVzczogbXlBZGRyZXNzKCksCiAgICAgICAgLy8gRGVhZGxpbmUgaXMgc2V0IHRvIDEwLDAwMCBzZWNvbmRzIGZyb20gbm93CiAgICAgICAgZGVhZGxpbmU6IG5vdygpICsgMTBfMDAwLAogICAgICAgIGFkZGl0aW9uYWxEYXRhOiBTd2FwQWRkaXRpb25hbERhdGEgeyByZWNlaXZlckFkZHJlc3M6IG15QWRkcmVzcygpIH0sCiAgICB9OwoKICAgIC8vIFN0YXJ0IGEgc3dhcCB3aXRoIHRoZSBtZXNzYWdlIHRvIHRoZSBwcm94eSBUb25jb2luIHdhbGxldAogICAgc2VuZChTZW5kUGFyYW1ldGVycyB7CiAgICAgICAgdG86IFJvdXRlclByb3h5VG9uV2FsbGV0LAogICAgICAgIHZhbHVlOiBGZWVTd2FwVG9uY29pblRvSmV0dG9uICsgb2ZmZXJBbW91bnQsCiAgICAgICAgYm9keTogUHJveHlUb25jb2luVHJhbnNmZXIgewogICAgICAgICAgICB0b25BbW91bnQ6IG9mZmVyQW1vdW50LAogICAgICAgICAgICByZWZ1bmRBZGRyZXNzOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgZm9yd2FyZFBheWxvYWQ6IGZvcndhcmRQYXlsb2FkLnRvQ2VsbCgpLAogICAgICAgIH0udG9DZWxsKCksCiAgICB9KTsKfQoKLy8KLy8gSGVscGVyIHN0cnVjdHVyZXMgYW5kIGNvbnN0YW50cyBkZXNjcmliZWQgZWFybGllciBvbiB0aGlzIHBhZ2UKLy8KCm1lc3NhZ2UoMHgwMWYzODM1ZCkgUHJveHlUb25jb2luVHJhbnNmZXIgewogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NCA9IDA7CiAgICB0b25BbW91bnQ6IEludCBhcyBjb2luczsKICAgIHJlZnVuZEFkZHJlc3M6IEFkZHJlc3M7CiAgICBmb3J3YXJkUGF5bG9hZDogQ2VsbD87Cn0KCm1lc3NhZ2UoMHg2NjY0ZGUyYSkgU3RvbmZpU3dhcCB7CiAgICBvdGhlclRva2VuV2FsbGV0OiBBZGRyZXNzOwogICAgcmVmdW5kQWRkcmVzczogQWRkcmVzczsKICAgIGV4Y2Vzc2VzQWRkcmVzczogQWRkcmVzczsKICAgIGRlYWRsaW5lOiBJbnQgYXMgdWludDY0OwogICAgYWRkaXRpb25hbERhdGE6IFN3YXBBZGRpdGlvbmFsRGF0YTsKfQoKc3RydWN0IFN3YXBBZGRpdGlvbmFsRGF0YSB7CiAgICBtaW5PdXQ6IEludCBhcyBjb2lucyA9IDE7CiAgICByZWNlaXZlckFkZHJlc3M6IEFkZHJlc3M7CiAgICBmd2RHYXM6IEludCBhcyBjb2lucyA9IDA7CiAgICBjdXN0b21QYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICByZWZ1bmRGd2RHYXM6IEludCBhcyBjb2lucyA9IDA7CiAgICByZWZ1bmRQYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICByZWZGZWU6IEludCBhcyB1aW50MTYgPSAxMDsKICAgIHJlZmVycmFsQWRkcmVzczogQWRkcmVzcz8gPSBudWxsOwp9Cgpjb25zdCBGZWVTd2FwVG9uY29pblRvSmV0dG9uOiBJbnQgPSB0b24oIjAuMyIpOw%3D%3D)
Useful links:
[Fees Calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation)
## Liquidity provision[](#liquidity-provision)
Read more about liquidity provision in the [STON.fi documentation](https://docs.ston.fi/docs/developer-section/api-reference-v2/example_lp_provide).
STON.fi allows you to deposit liquidity by specifying only one type of token. The pool will automatically perform the swap and mint liquidity provider (LP) tokens. To do this, you need to set the `bothPositive` field of the `ProvideLiquidity` [Message](/book/structs-and-messages#messages) to `false`.
Liquidity deposits use the `ProvideLiquidity` [Message](/book/structs-and-messages#messages) and `ProvideLiquidityAdditionalData` [struct](/book/structs-and-messages#structs):
```tact
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#provide_lp-0x37c096df
message(0x37c096df) ProvideLiquidity {
// Address of the other Router token wallet
otherTokenWallet: Address;
// Where to send refunds if provisioning fails
refundAddress: Address;
// Where to send excesses if provisioning succeeds
excessesAddress: Address;
// UNIX timestamp of execution deadline for the provisioning
deadline: Int as uint64;
// Reference to another Cell with additional data,
// using Tact's greedy auto-layout mechanism
additionalData: ProvideLiquidityAdditionalData;
}
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#additional_data-body-1
struct ProvideLiquidityAdditionalData {
// Minimum required amount of LP tokens to receive
// Defaults to 1, which causes the provisioning to fail
// only if no tokens are received
minLpOut: Int as coins = 1;
// Where to send LP tokens if provisioning succeeds
receiverAddress: Address;
// Should both tokens in a pair have a positive quantity?
// If not, then the pool will perform an additional swap for the lacking token.
// Defaults to `true`, meaning the deposit will only go through
// when both token amounts are non-zero.
bothPositive: Bool = true;
// Forward fees for the `customPayload` if it is not `null`
// Defaults to 0
fwdGas: Int as coins = 0;
// Custom payload that will be sent if provisioning succeeds
// Defaults to `null`, meaning no payload
customPayload: Cell? = null;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZG9jcy5zdG9uLmZpL2RvY3MvZGV2ZWxvcGVyLXNlY3Rpb24vYXBpLXJlZmVyZW5jZS12Mi9yb3V0ZXIjcHJvdmlkZV9scC0weDM3YzA5NmRmCm1lc3NhZ2UoMHgzN2MwOTZkZikgUHJvdmlkZUxpcXVpZGl0eSB7CiAgICAvLyBBZGRyZXNzIG9mIHRoZSBvdGhlciBSb3V0ZXIgdG9rZW4gd2FsbGV0CiAgICBvdGhlclRva2VuV2FsbGV0OiBBZGRyZXNzOwoKICAgIC8vIFdoZXJlIHRvIHNlbmQgcmVmdW5kcyBpZiBwcm92aXNpb25pbmcgZmFpbHMKICAgIHJlZnVuZEFkZHJlc3M6IEFkZHJlc3M7CgogICAgLy8gV2hlcmUgdG8gc2VuZCBleGNlc3NlcyBpZiBwcm92aXNpb25pbmcgc3VjY2VlZHMKICAgIGV4Y2Vzc2VzQWRkcmVzczogQWRkcmVzczsKCiAgICAvLyBVTklYIHRpbWVzdGFtcCBvZiBleGVjdXRpb24gZGVhZGxpbmUgZm9yIHRoZSBwcm92aXNpb25pbmcKICAgIGRlYWRsaW5lOiBJbnQgYXMgdWludDY0OwoKICAgIC8vIFJlZmVyZW5jZSB0byBhbm90aGVyIENlbGwgd2l0aCBhZGRpdGlvbmFsIGRhdGEsCiAgICAvLyB1c2luZyBUYWN0J3MgZ3JlZWR5IGF1dG8tbGF5b3V0IG1lY2hhbmlzbQogICAgYWRkaXRpb25hbERhdGE6IFByb3ZpZGVMaXF1aWRpdHlBZGRpdGlvbmFsRGF0YTsKfQoKLy8vIGh0dHBzOi8vZG9jcy5zdG9uLmZpL2RvY3MvZGV2ZWxvcGVyLXNlY3Rpb24vYXBpLXJlZmVyZW5jZS12Mi9yb3V0ZXIjYWRkaXRpb25hbF9kYXRhLWJvZHktMQpzdHJ1Y3QgUHJvdmlkZUxpcXVpZGl0eUFkZGl0aW9uYWxEYXRhIHsKICAgIC8vIE1pbmltdW0gcmVxdWlyZWQgYW1vdW50IG9mIExQIHRva2VucyB0byByZWNlaXZlCiAgICAvLyBEZWZhdWx0cyB0byAxLCB3aGljaCBjYXVzZXMgdGhlIHByb3Zpc2lvbmluZyB0byBmYWlsCiAgICAvLyAgICAgICAgICAgICAgICBvbmx5IGlmIG5vIHRva2VucyBhcmUgcmVjZWl2ZWQKICAgIG1pbkxwT3V0OiBJbnQgYXMgY29pbnMgPSAxOwoKICAgIC8vIFdoZXJlIHRvIHNlbmQgTFAgdG9rZW5zIGlmIHByb3Zpc2lvbmluZyBzdWNjZWVkcwogICAgcmVjZWl2ZXJBZGRyZXNzOiBBZGRyZXNzOwoKICAgIC8vIFNob3VsZCBib3RoIHRva2VucyBpbiBhIHBhaXIgaGF2ZSBhIHBvc2l0aXZlIHF1YW50aXR5PwogICAgLy8gSWYgbm90LCB0aGVuIHRoZSBwb29sIHdpbGwgcGVyZm9ybSBhbiBhZGRpdGlvbmFsIHN3YXAgZm9yIHRoZSBsYWNraW5nIHRva2VuLgogICAgLy8gRGVmYXVsdHMgdG8gYHRydWVgLCBtZWFuaW5nIHRoZSBkZXBvc2l0IHdpbGwgb25seSBnbyB0aHJvdWdoCiAgICAvLyB3aGVuIGJvdGggdG9rZW4gYW1vdW50cyBhcmUgbm9uLXplcm8uCiAgICBib3RoUG9zaXRpdmU6IEJvb2wgPSB0cnVlOwoKICAgIC8vIEZvcndhcmQgZmVlcyBmb3IgdGhlIGBjdXN0b21QYXlsb2FkYCBpZiBpdCBpcyBub3QgYG51bGxgCiAgICAvLyBEZWZhdWx0cyB0byAwCiAgICBmd2RHYXM6IEludCBhcyBjb2lucyA9IDA7CgogICAgLy8gQ3VzdG9tIHBheWxvYWQgdGhhdCB3aWxsIGJlIHNlbnQgaWYgcHJvdmlzaW9uaW5nIHN1Y2NlZWRzCiAgICAvLyBEZWZhdWx0cyB0byBgbnVsbGAsIG1lYW5pbmcgbm8gcGF5bG9hZAogICAgY3VzdG9tUGF5bG9hZDogQ2VsbD8gPSBudWxsOwp9)
The [STON.fi SDK](https://github.com/ston-fi/sdk) defines some [constants to deal with fees](https://github.com/ston-fi/sdk/blob/786ece758794bd5c575db8b38f5e5de19f43f0d1/packages/sdk/src/contracts/dex/v2_1/router/BaseRouterV2_1.ts). Note that these are hardcoded values, but the best practice is to [calculate fees dynamically using current config parameters](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation) instead.
```tact
/// Hardcoded fee value to pay for sending a liquidity provisioning message
/// when depositing a certain amount of Jettons
const FeeSingleSideProvideLpJetton: Int = ton("1");
/// Hardcoded fee value to pay forward fees of subsequent messages for liquidity provisioning
const FeeSingleSideProvideLpJettonFwd: Int = ton("0.8");
/// Hardcoded fee value to pay for sending a liquidity provisioning message
/// when depositing a certain amount of Toncoins
const FeeSingleSideProvideLpToncoin: Int = ton("0.01") + ton("0.8");
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIEhhcmRjb2RlZCBmZWUgdmFsdWUgdG8gcGF5IGZvciBzZW5kaW5nIGEgbGlxdWlkaXR5IHByb3Zpc2lvbmluZyBtZXNzYWdlCi8vLyB3aGVuIGRlcG9zaXRpbmcgYSBjZXJ0YWluIGFtb3VudCBvZiBKZXR0b25zCmNvbnN0IEZlZVNpbmdsZVNpZGVQcm92aWRlTHBKZXR0b246IEludCA9IHRvbigiMSIpOwoKLy8vIEhhcmRjb2RlZCBmZWUgdmFsdWUgdG8gcGF5IGZvcndhcmQgZmVlcyBvZiBzdWJzZXF1ZW50IG1lc3NhZ2VzIGZvciBsaXF1aWRpdHkgcHJvdmlzaW9uaW5nCmNvbnN0IEZlZVNpbmdsZVNpZGVQcm92aWRlTHBKZXR0b25Gd2Q6IEludCA9IHRvbigiMC44Iik7CgovLy8gSGFyZGNvZGVkIGZlZSB2YWx1ZSB0byBwYXkgZm9yIHNlbmRpbmcgYSBsaXF1aWRpdHkgcHJvdmlzaW9uaW5nIG1lc3NhZ2UKLy8vIHdoZW4gZGVwb3NpdGluZyBhIGNlcnRhaW4gYW1vdW50IG9mIFRvbmNvaW5zCmNvbnN0IEZlZVNpbmdsZVNpZGVQcm92aWRlTHBUb25jb2luOiBJbnQgPSB0b24oIjAuMDEiKSArIHRvbigiMC44Iik7)
Useful links:
[Fees Calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation)
### Jetton deposit[](#jetton-deposit)
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in [testnet](https://docs.ton.org/v3/documentation/smart-contracts/getting-started/testnet).
In addition, some variables such as `offerAmount` are hardcoded for demonstration purposes. Don’t forget to change them in real-life scenarios.
```tact
// CPI Router v2.1.0
const RouterAddress: Address = address("kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v");
// Router's pTON wallet address
const RouterProxyTonWallet: Address = address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
// Router's Jetton wallet address
const RouterJettonWallet: Address = address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
/// NOTE: To calculate and provide the Jetton wallet address for the target user,
/// make sure to check the links after this code snippet.
fun jettonDeposit(myJettonWalletAddress: Address) {
// Amount of Jettons for liquidity provisioning
let offerAmount = 100_000;
// Prepare the payload
let forwardPayload = ProvideLiquidity {
otherTokenWallet: RouterProxyTonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
// Deadline is set to 1,000 seconds from now
deadline: now() + 1_000,
additionalData: ProvideLiquidityAdditionalData {
receiverAddress: myAddress(),
bothPositive: false, // i.e., single side
},
};
send(SendParameters {
to: myJettonWalletAddress,
value: FeeSingleSideProvideLpJetton,
body: JettonTransfer {
queryId: 42,
amount: offerAmount,
destination: RouterAddress,
responseDestination: myAddress(),
forwardTonAmount: FeeSingleSideProvideLpJettonFwd,
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper structures and constants described earlier on this page
//
message(0x37c096df) ProvideLiquidity {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: ProvideLiquidityAdditionalData;
}
struct ProvideLiquidityAdditionalData {
minLpOut: Int as coins = 1;
receiverAddress: Address;
bothPositive: Bool = true;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
}
const FeeSingleSideProvideLpJetton: Int = ton("1");
const FeeSingleSideProvideLpJettonFwd: Int = ton("0.8");
//
// Messages from the Jetton standard
//
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Cell?; // slightly adjusted
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gQ1BJIFJvdXRlciB2Mi4xLjAKY29uc3QgUm91dGVyQWRkcmVzczogQWRkcmVzcyA9IGFkZHJlc3MoImtRQUxoLUpCQklLSzdncjBvNEFWZjlKWm5Fc0ZuZHFPMHFUQ3lULUQteUJzV2swdiIpOwoKLy8gUm91dGVyJ3MgcFRPTiB3YWxsZXQgYWRkcmVzcwpjb25zdCBSb3V0ZXJQcm94eVRvbldhbGxldDogQWRkcmVzcyA9IGFkZHJlc3MoImtRQmJKam5haEJNR2JNVUp3aEFYTG44QmlpZ2NHWE1KaFNDMGw3REJoZFlBQmhHNyIpOwoKLy8gUm91dGVyJ3MgSmV0dG9uIHdhbGxldCBhZGRyZXNzCmNvbnN0IFJvdXRlckpldHRvbldhbGxldDogQWRkcmVzcyA9IGFkZHJlc3MoImtRQXRYM3gycy13TXRZVHo4Q2ZtQXlsb0hBQjczdk9OekpNNVMyaWRxWGwtXzV4SyIpOwoKLy8vIE5PVEU6IFRvIGNhbGN1bGF0ZSBhbmQgcHJvdmlkZSB0aGUgSmV0dG9uIHdhbGxldCBhZGRyZXNzIGZvciB0aGUgdGFyZ2V0IHVzZXIsCi8vLyAgICAgICBtYWtlIHN1cmUgdG8gY2hlY2sgdGhlIGxpbmtzIGFmdGVyIHRoaXMgY29kZSBzbmlwcGV0LgpmdW4gamV0dG9uRGVwb3NpdChteUpldHRvbldhbGxldEFkZHJlc3M6IEFkZHJlc3MpIHsKICAgIC8vIEFtb3VudCBvZiBKZXR0b25zIGZvciBsaXF1aWRpdHkgcHJvdmlzaW9uaW5nCiAgICBsZXQgb2ZmZXJBbW91bnQgPSAxMDBfMDAwOwoKICAgIC8vIFByZXBhcmUgdGhlIHBheWxvYWQKICAgIGxldCBmb3J3YXJkUGF5bG9hZCA9IFByb3ZpZGVMaXF1aWRpdHkgewogICAgICAgIG90aGVyVG9rZW5XYWxsZXQ6IFJvdXRlclByb3h5VG9uV2FsbGV0LAogICAgICAgIHJlZnVuZEFkZHJlc3M6IG15QWRkcmVzcygpLAogICAgICAgIGV4Y2Vzc2VzQWRkcmVzczogbXlBZGRyZXNzKCksCiAgICAgICAgLy8gRGVhZGxpbmUgaXMgc2V0IHRvIDEsMDAwIHNlY29uZHMgZnJvbSBub3cKICAgICAgICBkZWFkbGluZTogbm93KCkgKyAxXzAwMCwKICAgICAgICBhZGRpdGlvbmFsRGF0YTogUHJvdmlkZUxpcXVpZGl0eUFkZGl0aW9uYWxEYXRhIHsKICAgICAgICAgICAgcmVjZWl2ZXJBZGRyZXNzOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgYm90aFBvc2l0aXZlOiBmYWxzZSwgLy8gaS5lLiwgc2luZ2xlIHNpZGUKICAgICAgICB9LAogICAgfTsKCiAgICBzZW5kKFNlbmRQYXJhbWV0ZXJzIHsKICAgICAgICB0bzogbXlKZXR0b25XYWxsZXRBZGRyZXNzLAogICAgICAgIHZhbHVlOiBGZWVTaW5nbGVTaWRlUHJvdmlkZUxwSmV0dG9uLAogICAgICAgIGJvZHk6IEpldHRvblRyYW5zZmVyIHsKICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgIGFtb3VudDogb2ZmZXJBbW91bnQsCiAgICAgICAgICAgIGRlc3RpbmF0aW9uOiBSb3V0ZXJBZGRyZXNzLAogICAgICAgICAgICByZXNwb25zZURlc3RpbmF0aW9uOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgZm9yd2FyZFRvbkFtb3VudDogRmVlU2luZ2xlU2lkZVByb3ZpZGVMcEpldHRvbkZ3ZCwKICAgICAgICAgICAgZm9yd2FyZFBheWxvYWQ6IGZvcndhcmRQYXlsb2FkLnRvQ2VsbCgpLAogICAgICAgIH0udG9DZWxsKCksCiAgICB9KTsKfQoKLy8KLy8gSGVscGVyIHN0cnVjdHVyZXMgYW5kIGNvbnN0YW50cyBkZXNjcmliZWQgZWFybGllciBvbiB0aGlzIHBhZ2UKLy8KCm1lc3NhZ2UoMHgzN2MwOTZkZikgUHJvdmlkZUxpcXVpZGl0eSB7CiAgICBvdGhlclRva2VuV2FsbGV0OiBBZGRyZXNzOwogICAgcmVmdW5kQWRkcmVzczogQWRkcmVzczsKICAgIGV4Y2Vzc2VzQWRkcmVzczogQWRkcmVzczsKICAgIGRlYWRsaW5lOiBJbnQgYXMgdWludDY0OwogICAgYWRkaXRpb25hbERhdGE6IFByb3ZpZGVMaXF1aWRpdHlBZGRpdGlvbmFsRGF0YTsKfQoKc3RydWN0IFByb3ZpZGVMaXF1aWRpdHlBZGRpdGlvbmFsRGF0YSB7CiAgICBtaW5McE91dDogSW50IGFzIGNvaW5zID0gMTsKICAgIHJlY2VpdmVyQWRkcmVzczogQWRkcmVzczsKICAgIGJvdGhQb3NpdGl2ZTogQm9vbCA9IHRydWU7CiAgICBmd2RHYXM6IEludCBhcyBjb2lucyA9IDA7CiAgICBjdXN0b21QYXlsb2FkOiBDZWxsPyA9IG51bGw7Cn0KCmNvbnN0IEZlZVNpbmdsZVNpZGVQcm92aWRlTHBKZXR0b246IEludCA9IHRvbigiMSIpOwpjb25zdCBGZWVTaW5nbGVTaWRlUHJvdmlkZUxwSmV0dG9uRndkOiBJbnQgPSB0b24oIjAuOCIpOwoKLy8KLy8gTWVzc2FnZXMgZnJvbSB0aGUgSmV0dG9uIHN0YW5kYXJkCi8vCgptZXNzYWdlKDB4ZjhhN2VhNSkgSmV0dG9uVHJhbnNmZXIgewogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NDsKICAgIGFtb3VudDogSW50IGFzIGNvaW5zOwogICAgZGVzdGluYXRpb246IEFkZHJlc3M7CiAgICByZXNwb25zZURlc3RpbmF0aW9uOiBBZGRyZXNzPzsKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKICAgIGZvcndhcmRUb25BbW91bnQ6IEludCBhcyBjb2luczsKICAgIGZvcndhcmRQYXlsb2FkOiBDZWxsPzsgLy8gc2xpZ2h0bHkgYWRqdXN0ZWQKfQ%3D%3D)
### Toncoin deposit[](#toncoin-deposit)
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given on [testnet](https://docs.ton.org/v3/documentation/smart-contracts/getting-started/testnet).
In addition, some variables, such as `offerAmount`, are hardcoded for demonstration purposes. Don’t forget to change them in real-life scenarios.
```tact
// Router's pTON wallet address
const RouterProxyTonWallet: Address = address("kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7");
// Router's Jetton wallet address
const RouterJettonWallet: Address = address("kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK");
fun toncoinDeposit() {
// Amount of Jettons for liquidity provisioning
let offerAmount = 100_000;
// Prepare the payload
let forwardPayload = ProvideLiquidity {
otherTokenWallet: RouterJettonWallet,
refundAddress: myAddress(),
excessesAddress: myAddress(),
deadline: now() + 1000,
additionalData: ProvideLiquidityAdditionalData {
receiverAddress: myAddress(),
bothPositive: false, // i.e. single side
},
};
send(SendParameters {
to: RouterProxyTonWallet,
value: FeeSingleSideProvideLpToncoin + offerAmount,
body: ProxyToncoinTransfer {
queryId: 42,
tonAmount: offerAmount,
refundAddress: myAddress(),
forwardPayload: forwardPayload.toCell(),
}.toCell(),
});
}
//
// Helper messages, structs, and constants described earlier on this page
//
message(0x01f3835d) ProxyToncoinTransfer {
queryId: Int as uint64 = 0;
tonAmount: Int as coins;
refundAddress: Address;
forwardPayload: Cell?;
}
message(0x37c096df) ProvideLiquidity {
otherTokenWallet: Address;
refundAddress: Address;
excessesAddress: Address;
deadline: Int as uint64;
additionalData: ProvideLiquidityAdditionalData;
}
struct ProvideLiquidityAdditionalData {
minLpOut: Int as coins = 1;
receiverAddress: Address;
bothPositive: Bool = true;
fwdGas: Int as coins = 0;
customPayload: Cell? = null;
}
const FeeSingleSideProvideLpToncoin: Int = ton("0.01") + ton("0.8");
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gUm91dGVyJ3MgcFRPTiB3YWxsZXQgYWRkcmVzcwpjb25zdCBSb3V0ZXJQcm94eVRvbldhbGxldDogQWRkcmVzcyA9IGFkZHJlc3MoImtRQmJKam5haEJNR2JNVUp3aEFYTG44QmlpZ2NHWE1KaFNDMGw3REJoZFlBQmhHNyIpOwoKLy8gUm91dGVyJ3MgSmV0dG9uIHdhbGxldCBhZGRyZXNzCmNvbnN0IFJvdXRlckpldHRvbldhbGxldDogQWRkcmVzcyA9IGFkZHJlc3MoImtRQXRYM3gycy13TXRZVHo4Q2ZtQXlsb0hBQjczdk9OekpNNVMyaWRxWGwtXzV4SyIpOwoKZnVuIHRvbmNvaW5EZXBvc2l0KCkgewogICAgLy8gQW1vdW50IG9mIEpldHRvbnMgZm9yIGxpcXVpZGl0eSBwcm92aXNpb25pbmcKICAgIGxldCBvZmZlckFtb3VudCA9IDEwMF8wMDA7CgogICAgLy8gUHJlcGFyZSB0aGUgcGF5bG9hZAogICAgbGV0IGZvcndhcmRQYXlsb2FkID0gUHJvdmlkZUxpcXVpZGl0eSB7CiAgICAgICAgb3RoZXJUb2tlbldhbGxldDogUm91dGVySmV0dG9uV2FsbGV0LAogICAgICAgIHJlZnVuZEFkZHJlc3M6IG15QWRkcmVzcygpLAogICAgICAgIGV4Y2Vzc2VzQWRkcmVzczogbXlBZGRyZXNzKCksCiAgICAgICAgZGVhZGxpbmU6IG5vdygpICsgMTAwMCwKICAgICAgICBhZGRpdGlvbmFsRGF0YTogUHJvdmlkZUxpcXVpZGl0eUFkZGl0aW9uYWxEYXRhIHsKICAgICAgICAgICAgcmVjZWl2ZXJBZGRyZXNzOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgYm90aFBvc2l0aXZlOiBmYWxzZSwgLy8gaS5lLiBzaW5nbGUgc2lkZQogICAgICAgIH0sCiAgICB9OwoKICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgIHRvOiBSb3V0ZXJQcm94eVRvbldhbGxldCwKICAgICAgICB2YWx1ZTogRmVlU2luZ2xlU2lkZVByb3ZpZGVMcFRvbmNvaW4gKyBvZmZlckFtb3VudCwKICAgICAgICBib2R5OiBQcm94eVRvbmNvaW5UcmFuc2ZlciB7CiAgICAgICAgICAgIHF1ZXJ5SWQ6IDQyLAogICAgICAgICAgICB0b25BbW91bnQ6IG9mZmVyQW1vdW50LAogICAgICAgICAgICByZWZ1bmRBZGRyZXNzOiBteUFkZHJlc3MoKSwKICAgICAgICAgICAgZm9yd2FyZFBheWxvYWQ6IGZvcndhcmRQYXlsb2FkLnRvQ2VsbCgpLAogICAgICAgIH0udG9DZWxsKCksCiAgICB9KTsKfQoKLy8KLy8gSGVscGVyIG1lc3NhZ2VzLCBzdHJ1Y3RzLCBhbmQgY29uc3RhbnRzIGRlc2NyaWJlZCBlYXJsaWVyIG9uIHRoaXMgcGFnZQovLwoKbWVzc2FnZSgweDAxZjM4MzVkKSBQcm94eVRvbmNvaW5UcmFuc2ZlciB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0ID0gMDsKICAgIHRvbkFtb3VudDogSW50IGFzIGNvaW5zOwogICAgcmVmdW5kQWRkcmVzczogQWRkcmVzczsKICAgIGZvcndhcmRQYXlsb2FkOiBDZWxsPzsKfQoKbWVzc2FnZSgweDM3YzA5NmRmKSBQcm92aWRlTGlxdWlkaXR5IHsKICAgIG90aGVyVG9rZW5XYWxsZXQ6IEFkZHJlc3M7CiAgICByZWZ1bmRBZGRyZXNzOiBBZGRyZXNzOwogICAgZXhjZXNzZXNBZGRyZXNzOiBBZGRyZXNzOwogICAgZGVhZGxpbmU6IEludCBhcyB1aW50NjQ7CiAgICBhZGRpdGlvbmFsRGF0YTogUHJvdmlkZUxpcXVpZGl0eUFkZGl0aW9uYWxEYXRhOwp9CgpzdHJ1Y3QgUHJvdmlkZUxpcXVpZGl0eUFkZGl0aW9uYWxEYXRhIHsKICAgIG1pbkxwT3V0OiBJbnQgYXMgY29pbnMgPSAxOwogICAgcmVjZWl2ZXJBZGRyZXNzOiBBZGRyZXNzOwogICAgYm90aFBvc2l0aXZlOiBCb29sID0gdHJ1ZTsKICAgIGZ3ZEdhczogSW50IGFzIGNvaW5zID0gMDsKICAgIGN1c3RvbVBheWxvYWQ6IENlbGw%2FID0gbnVsbDsKfQoKY29uc3QgRmVlU2luZ2xlU2lkZVByb3ZpZGVMcFRvbmNvaW46IEludCA9IHRvbigiMC4wMSIpICsgdG9uKCIwLjgiKTs%3D)
### Withdraw liquidity[](#withdraw-liquidity)
To withdraw liquidity, burning LP tokens is required. You can refer to examples of Jetton burning in the [respective section of the Jettons Cookbook page](/cookbook/jettons#burning-jetton). However, more Toncoin should be added than for a normal burn, since adding too little may result in LP tokens being burned but no (or only partial) liquidity being sent from the pool. Therefore, consider attaching at least 0.5 Toncoin — any excess amount will be returned.
Hey there!
Didn’t find your favorite example of STON.fi interaction? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Cookbook overview
> The Cookbook section focuses on everyday tasks that every Tact developer resolves during the development of smart contracts.
The main reason for creating the Tact Cookbook is to gather all the experiences of Tact developers in one place so that future developers can use it. This section of the documentation focuses on everyday tasks that every Tact developer resolves during the development of smart contracts.
Use it as a recipe book for cooking up delightful smart contracts on TON Blockchain without reinventing the wheel in the process.
For DeFi-specific elaborate recipes that include smart contracts, auxiliary scripts, and testing suites, see the [Tact’s DeFi Cookbook on GitHub](https://github.com/tact-lang/defi-cookbook).
1. #### Single contract[](#single-contract)
The following pages focus on single-contract examples and cover a wide range of topics:
[1️⃣ Single-contract communication ](/cookbook/single-communication)
[⚙️ Type conversion ](/cookbook/type-conversion)
[📦 Data structures ](/cookbook/data-structures)
[🤖 Algorithms ](/cookbook/algo)
[📆 Time and date ](/cookbook/time)
[⚠️ Access control ](/cookbook/access)
[✨ Randomness ](/cookbook/random)
[🔄 Code upgrades ](/cookbook/upgrades)
[🤔 Miscellaneous ](/cookbook/misc)
2. #### Multiple contracts[](#multiple-contracts)
The following pages focus on multi-contract examples, exploring the scalable nature of TON Blockchain:
[🧮 Multi-contract communication ](/cookbook/multi-communication)
[💎 Fungible Tokens (Jettons) ](/cookbook/jettons)
[🖼️ Non-Fungible Tokens (NFTs) ](/cookbook/nfts)
Additionally, there are examples of working with popular TON DEXes (Decentralized EXchanges), which often require many contracts and complex logic:
[DeDust.io ](/cookbook/dexes/dedust)
[STON.fi ](/cookbook/dexes/stonfi)
3. #### DeFi Cookbook on GitHub[](#defi-cookbook)
As an extension of this Cookbook, we’ve made a special GitHub repository for elaborate recipes that include smart contracts, auxiliary scripts, and testing suites. Here are some of the recipes of the [Tact’s DeFi Cookbook on GitHub](https://github.com/tact-lang/defi-cookbook):
[Receive Jettons ](https://github.com/tact-lang/defi-cookbook/tree/main/jettons/receive-jettons)
[Receive USDT ](https://github.com/tact-lang/defi-cookbook/tree/main/jettons/receive-usdt)
[Send Jettons ](https://github.com/tact-lang/defi-cookbook/tree/main/jettons/send-jettons)
[Send USDT ](https://github.com/tact-lang/defi-cookbook/tree/main/jettons/send-usdt)
[Mint USDT ](https://github.com/tact-lang/defi-cookbook/tree/main/jettons/mint-usdt)
[Onchain API ](https://github.com/tact-lang/defi-cookbook/tree/main/jettons/onchain-api)
---
# Fungible Tokens (Jettons)
> Common examples of working with Fungible Tokens (Jettons) in Tact
This page lists common examples of working with [Fungible Tokens (Jettons)](https://docs.ton.org/develop/dapps/asset-processing/jettons).
Jettons are token standards on the TON Blockchain, designed to create fungible tokens (similar to ERC-20 on Ethereum) using a decentralized approach. They are implemented as a pair of smart contracts, typically consisting of two core components:
* Jetton Master Contract (Jetton master)
* Jetton Wallet Contract (Jetton wallet)
These contracts interact with each other to manage token supply, distribution, transfers, and other operations related to the Jetton.
## Jetton Master Contract[](#jetton-master-contract)
The Jetton Master Contract serves as the central entity for a given Jetton. It maintains critical information about the Jetton itself. Key responsibilities and data stored in the Jetton Master Contract include:
* Jetton metadata: Information such as the token’s name, symbol, total supply, and decimals.
* Minting and burning: When new Jettons are minted (created), the Jetton Master manages the creation process and distributes them to the appropriate wallets. It also manages the burning (destruction) of tokens as needed.
* Supply management: The Jetton Master keeps track of the total supply of Jettons and ensures proper accounting of all issued Jettons.
## Jetton Wallet Contract[](#jetton-wallet-contract)
The Jetton Wallet Contract represents an individual holder’s token wallet and is responsible for managing the balance and token-related operations for a specific user. Each user or entity holding Jettons will have its own unique Jetton Wallet Contract. Key features of the Jetton Wallet Contract include:
* Balance tracking: The wallet contract stores the user’s token balance.
* Token transfers: The wallet is responsible for handling token transfers between users. When a user sends Jettons, the Jetton Wallet Contract ensures proper transfer and communication with the recipient’s wallet. The Jetton Master is not involved in this activity and does not create a bottleneck. Wallets can effectively utilize TON’s sharding capability.
* Token burning: The Jetton Wallet interacts with the Jetton Master to burn tokens.
* Owner control: The wallet contract is owned and controlled by a specific user, meaning that only the owner of the wallet can initiate transfers or other token operations.
## Examples[](#examples)
The following are common examples of working with Jettons.
For larger Jetton recipes that include smart contracts, auxiliary scripts, and testing suites, see the [Tact’s DeFi Cookbook on GitHub](https://github.com/tact-lang/defi-cookbook).
### Accepting Jetton transfer[](#accepting-jetton-transfer)
The transfer notification message has the following structure:
```tact
message(0x7362d09c) JettonTransferNotification {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means we don't mark messages to trace their chains
queryId: Int as uint64 = 0;
// Amount of Jettons transferred
amount: Int as coins;
// Address of the sender of the Jettons
sender: Address;
// Optional custom payload
forwardPayload: Slice as remaining;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDczNjJkMDljKSBKZXR0b25UcmFuc2Zlck5vdGlmaWNhdGlvbiB7CiAgICAvLyBVbmlxdWUgaWRlbnRpZmllciB1c2VkIHRvIHRyYWNlIHRyYW5zYWN0aW9ucyBhY3Jvc3MgbXVsdGlwbGUgY29udHJhY3RzCiAgICAvLyBEZWZhdWx0cyB0byAwLCB3aGljaCBtZWFucyB3ZSBkb24ndCBtYXJrIG1lc3NhZ2VzIHRvIHRyYWNlIHRoZWlyIGNoYWlucwogICAgcXVlcnlJZDogSW50IGFzIHVpbnQ2NCA9IDA7CgogICAgLy8gQW1vdW50IG9mIEpldHRvbnMgdHJhbnNmZXJyZWQKICAgIGFtb3VudDogSW50IGFzIGNvaW5zOwoKICAgIC8vIEFkZHJlc3Mgb2YgdGhlIHNlbmRlciBvZiB0aGUgSmV0dG9ucwogICAgc2VuZGVyOiBBZGRyZXNzOwoKICAgIC8vIE9wdGlvbmFsIGN1c3RvbSBwYXlsb2FkCiAgICBmb3J3YXJkUGF5bG9hZDogU2xpY2UgYXMgcmVtYWluaW5nOwp9)
Use the [receiver](/book/receive) function to accept token notification messages.
Caution
The sender of transfer notifications must be validated!
The sender of a transfer notification must be validated because malicious actors could attempt to spoof notifications from an unauthorized account. If this validation is not performed, the contract may accept unauthorized transactions, leading to potential security vulnerabilities.
Validation is performed using the Jetton address from the contract:
1. Sender sends a message with `0xf8a7ea5` as its 32-bit header (opcode) to their Jetton wallet.
2. The Jetton wallet transfers funds to the contract’s Jetton wallet.
3. After successfully accepting the transfer, the contract’s Jetton wallet sends a transfer notification to its owner contract.
4. The contract validates the Jetton message.
You may obtain the contract’s Jetton wallet address using the [`contractAddress()`](/ref/core-addresses#contractaddress) function or calculating this address offchain.
To obtain the Jetton wallet’s state init, you need the wallet’s data and code. While there is a common structure for the initial data layout, it may differ in some cases, such as with [USDT](#usdt-jetton-operations).
Since notifications originate from your contract’s Jetton wallet, the function [`myAddress()`](/ref/core-contextstate#myaddress) should be used in the `ownerAddress` field.
Caution
Notifications are not always guaranteed to be sent. By default, the implementation does not send a notification if the `forwardAmount` is set to zero. Therefore, in such cases, you cannot rely on notifications being sent.
```tact
struct JettonWalletData {
balance: Int as coins;
ownerAddress: Address;
jettonMasterAddress: Address;
jettonWalletCode: Cell;
}
fun calculateJettonWalletAddress(
ownerAddress: Address,
jettonMasterAddress: Address,
jettonWalletCode: Cell,
): Address {
let initData = JettonWalletData {
balance: 0,
ownerAddress,
jettonMasterAddress,
jettonWalletCode,
};
return contractAddress(StateInit {
code: jettonWalletCode,
data: initData.toCell(),
});
}
message(0x7362d09c) JettonTransferNotification {
queryId: Int as uint64;
amount: Int as coins;
sender: Address;
forwardPayload: Slice as remaining;
}
contract Example {
myJettonWalletAddress: Address;
myJettonAmount: Int as coins = 0;
init(jettonWalletCode: Cell, jettonMasterAddress: Address) {
self.myJettonWalletAddress = calculateJettonWalletAddress(
myAddress(),
jettonMasterAddress,
jettonWalletCode,
);
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
receive(msg: JettonTransferNotification) {
require(
sender() == self.myJettonWalletAddress,
"Notification not from your jetton wallet!",
);
self.myJettonAmount += msg.amount;
// Forward excesses
self.forward(msg.sender, null, false, null);
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IEpldHRvbldhbGxldERhdGEgewogICAgYmFsYW5jZTogSW50IGFzIGNvaW5zOwogICAgb3duZXJBZGRyZXNzOiBBZGRyZXNzOwogICAgamV0dG9uTWFzdGVyQWRkcmVzczogQWRkcmVzczsKICAgIGpldHRvbldhbGxldENvZGU6IENlbGw7Cn0KCmZ1biBjYWxjdWxhdGVKZXR0b25XYWxsZXRBZGRyZXNzKAogICAgb3duZXJBZGRyZXNzOiBBZGRyZXNzLAogICAgamV0dG9uTWFzdGVyQWRkcmVzczogQWRkcmVzcywKICAgIGpldHRvbldhbGxldENvZGU6IENlbGwsCik6IEFkZHJlc3MgewogICAgbGV0IGluaXREYXRhID0gSmV0dG9uV2FsbGV0RGF0YSB7CiAgICAgICAgYmFsYW5jZTogMCwKICAgICAgICBvd25lckFkZHJlc3MsCiAgICAgICAgamV0dG9uTWFzdGVyQWRkcmVzcywKICAgICAgICBqZXR0b25XYWxsZXRDb2RlLAogICAgfTsKCiAgICByZXR1cm4gY29udHJhY3RBZGRyZXNzKFN0YXRlSW5pdCB7CiAgICAgICAgY29kZTogamV0dG9uV2FsbGV0Q29kZSwKICAgICAgICBkYXRhOiBpbml0RGF0YS50b0NlbGwoKSwKICAgIH0pOwp9CgptZXNzYWdlKDB4NzM2MmQwOWMpIEpldHRvblRyYW5zZmVyTm90aWZpY2F0aW9uIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7CiAgICBhbW91bnQ6IEludCBhcyBjb2luczsKICAgIHNlbmRlcjogQWRkcmVzczsKICAgIGZvcndhcmRQYXlsb2FkOiBTbGljZSBhcyByZW1haW5pbmc7Cn0KCmNvbnRyYWN0IEV4YW1wbGUgewogICAgbXlKZXR0b25XYWxsZXRBZGRyZXNzOiBBZGRyZXNzOwogICAgbXlKZXR0b25BbW91bnQ6IEludCBhcyBjb2lucyA9IDA7CgogICAgaW5pdChqZXR0b25XYWxsZXRDb2RlOiBDZWxsLCBqZXR0b25NYXN0ZXJBZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5teUpldHRvbldhbGxldEFkZHJlc3MgPSBjYWxjdWxhdGVKZXR0b25XYWxsZXRBZGRyZXNzKAogICAgICAgICAgICBteUFkZHJlc3MoKSwKICAgICAgICAgICAgamV0dG9uTWFzdGVyQWRkcmVzcywKICAgICAgICAgICAgamV0dG9uV2FsbGV0Q29kZSwKICAgICAgICApOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIHJlY2VpdmUobXNnOiBKZXR0b25UcmFuc2Zlck5vdGlmaWNhdGlvbikgewogICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgIHNlbmRlcigpID09IHNlbGYubXlKZXR0b25XYWxsZXRBZGRyZXNzLAogICAgICAgICAgICAiTm90aWZpY2F0aW9uIG5vdCBmcm9tIHlvdXIgamV0dG9uIHdhbGxldCEiLAogICAgICAgICk7CgogICAgICAgIHNlbGYubXlKZXR0b25BbW91bnQgKz0gbXNnLmFtb3VudDsKCiAgICAgICAgLy8gRm9yd2FyZCBleGNlc3NlcwogICAgICAgIHNlbGYuZm9yd2FyZChtc2cuc2VuZGVyLCBudWxsLCBmYWxzZSwgbnVsbCk7CiAgICB9Cn0%3D)
### Sending Jetton transfer[](#sending-jetton-transfer)
A Jetton transfer is the process of sending a specified amount of Jettons from one wallet (contract) to another.
To send a Jetton transfer, use the [`send()`](/book/send) function.
```tact
message(0xf8a7ea5) JettonTransfer {
queryId: Int as uint64;
amount: Int as coins;
destination: Address;
responseDestination: Address?;
customPayload: Cell? = null;
forwardTonAmount: Int as coins;
forwardPayload: Slice as remaining;
}
const JettonTransferGas: Int = ton("0.05");
struct JettonWalletData {
balance: Int as coins;
ownerAddress: Address;
jettonMasterAddress: Address;
jettonWalletCode: Cell;
}
fun calculateJettonWalletAddress(
ownerAddress: Address,
jettonMasterAddress: Address,
jettonWalletCode: Cell,
): Address {
let initData = JettonWalletData {
balance: 0,
ownerAddress,
jettonMasterAddress,
jettonWalletCode,
};
return contractAddress(StateInit {
code: jettonWalletCode,
data: initData.toCell(),
});
}
message Withdraw {
amount: Int as coins;
}
contract Example {
myJettonWalletAddress: Address;
myJettonAmount: Int as coins = 0;
init(jettonWalletCode: Cell, jettonMasterAddress: Address) {
self.myJettonWalletAddress = calculateJettonWalletAddress(
myAddress(),
jettonMasterAddress,
jettonWalletCode,
);
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
receive(msg: Withdraw) {
require(
msg.amount <= self.myJettonAmount,
"Not enough funds to withdraw",
);
send(SendParameters {
to: self.myJettonWalletAddress,
value: JettonTransferGas,
body: JettonTransfer {
// Unique identifier used to trace transactions across multiple contracts
queryId: 42,
// Jetton amount to transfer
amount: msg.amount,
// Where to transfer Jettons:
// this is the address of the Jetton wallet
// owner and not the Jetton wallet itself
destination: sender(),
// Where to send a confirmation notice of a successful transfer
// and the remainder of the incoming message value
responseDestination: sender(),
// Can be used for custom logic of the Jettons themselves,
// or set to null otherwise
customPayload: null,
// Amount to transfer with JettonTransferNotification,
// which is needed for the execution of custom logic
forwardTonAmount: 1, // if it's 0, the notification won't be sent!
// Compile-time way of expressing:
// beginCell().storeUint(0xF, 4).endCell().beginParse()
// For more complicated transfers, adjust accordingly
forwardPayload: rawSlice("F"),
}.toCell(),
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweGY4YTdlYTUpIEpldHRvblRyYW5zZmVyIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7CiAgICBhbW91bnQ6IEludCBhcyBjb2luczsKICAgIGRlc3RpbmF0aW9uOiBBZGRyZXNzOwogICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogQWRkcmVzcz87CiAgICBjdXN0b21QYXlsb2FkOiBDZWxsPyA9IG51bGw7CiAgICBmb3J3YXJkVG9uQW1vdW50OiBJbnQgYXMgY29pbnM7CiAgICBmb3J3YXJkUGF5bG9hZDogU2xpY2UgYXMgcmVtYWluaW5nOwp9Cgpjb25zdCBKZXR0b25UcmFuc2ZlckdhczogSW50ID0gdG9uKCIwLjA1Iik7CgpzdHJ1Y3QgSmV0dG9uV2FsbGV0RGF0YSB7CiAgICBiYWxhbmNlOiBJbnQgYXMgY29pbnM7CiAgICBvd25lckFkZHJlc3M6IEFkZHJlc3M7CiAgICBqZXR0b25NYXN0ZXJBZGRyZXNzOiBBZGRyZXNzOwogICAgamV0dG9uV2FsbGV0Q29kZTogQ2VsbDsKfQoKZnVuIGNhbGN1bGF0ZUpldHRvbldhbGxldEFkZHJlc3MoCiAgICBvd25lckFkZHJlc3M6IEFkZHJlc3MsCiAgICBqZXR0b25NYXN0ZXJBZGRyZXNzOiBBZGRyZXNzLAogICAgamV0dG9uV2FsbGV0Q29kZTogQ2VsbCwKKTogQWRkcmVzcyB7CiAgICBsZXQgaW5pdERhdGEgPSBKZXR0b25XYWxsZXREYXRhIHsKICAgICAgICBiYWxhbmNlOiAwLAogICAgICAgIG93bmVyQWRkcmVzcywKICAgICAgICBqZXR0b25NYXN0ZXJBZGRyZXNzLAogICAgICAgIGpldHRvbldhbGxldENvZGUsCiAgICB9OwoKICAgIHJldHVybiBjb250cmFjdEFkZHJlc3MoU3RhdGVJbml0IHsKICAgICAgICBjb2RlOiBqZXR0b25XYWxsZXRDb2RlLAogICAgICAgIGRhdGE6IGluaXREYXRhLnRvQ2VsbCgpLAogICAgfSk7Cn0KCm1lc3NhZ2UgV2l0aGRyYXcgewogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7Cn0KCmNvbnRyYWN0IEV4YW1wbGUgewogICAgbXlKZXR0b25XYWxsZXRBZGRyZXNzOiBBZGRyZXNzOwogICAgbXlKZXR0b25BbW91bnQ6IEludCBhcyBjb2lucyA9IDA7CgogICAgaW5pdChqZXR0b25XYWxsZXRDb2RlOiBDZWxsLCBqZXR0b25NYXN0ZXJBZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5teUpldHRvbldhbGxldEFkZHJlc3MgPSBjYWxjdWxhdGVKZXR0b25XYWxsZXRBZGRyZXNzKAogICAgICAgICAgICBteUFkZHJlc3MoKSwKICAgICAgICAgICAgamV0dG9uTWFzdGVyQWRkcmVzcywKICAgICAgICAgICAgamV0dG9uV2FsbGV0Q29kZSwKICAgICAgICApOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIHJlY2VpdmUobXNnOiBXaXRoZHJhdykgewogICAgICAgIHJlcXVpcmUoCiAgICAgICAgICAgIG1zZy5hbW91bnQgPD0gc2VsZi5teUpldHRvbkFtb3VudCwKICAgICAgICAgICAgIk5vdCBlbm91Z2ggZnVuZHMgdG8gd2l0aGRyYXciLAogICAgICAgICk7CgogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VsZi5teUpldHRvbldhbGxldEFkZHJlc3MsCiAgICAgICAgICAgIHZhbHVlOiBKZXR0b25UcmFuc2ZlckdhcywKICAgICAgICAgICAgYm9keTogSmV0dG9uVHJhbnNmZXIgewogICAgICAgICAgICAgICAgLy8gVW5pcXVlIGlkZW50aWZpZXIgdXNlZCB0byB0cmFjZSB0cmFuc2FjdGlvbnMgYWNyb3NzIG11bHRpcGxlIGNvbnRyYWN0cwogICAgICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgICAgICAvLyBKZXR0b24gYW1vdW50IHRvIHRyYW5zZmVyCiAgICAgICAgICAgICAgICBhbW91bnQ6IG1zZy5hbW91bnQsCiAgICAgICAgICAgICAgICAvLyBXaGVyZSB0byB0cmFuc2ZlciBKZXR0b25zOgogICAgICAgICAgICAgICAgLy8gdGhpcyBpcyB0aGUgYWRkcmVzcyBvZiB0aGUgSmV0dG9uIHdhbGxldAogICAgICAgICAgICAgICAgLy8gb3duZXIgYW5kIG5vdCB0aGUgSmV0dG9uIHdhbGxldCBpdHNlbGYKICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uOiBzZW5kZXIoKSwKICAgICAgICAgICAgICAgIC8vIFdoZXJlIHRvIHNlbmQgYSBjb25maXJtYXRpb24gbm90aWNlIG9mIGEgc3VjY2Vzc2Z1bCB0cmFuc2ZlcgogICAgICAgICAgICAgICAgLy8gYW5kIHRoZSByZW1haW5kZXIgb2YgdGhlIGluY29taW5nIG1lc3NhZ2UgdmFsdWUKICAgICAgICAgICAgICAgIHJlc3BvbnNlRGVzdGluYXRpb246IHNlbmRlcigpLAogICAgICAgICAgICAgICAgLy8gQ2FuIGJlIHVzZWQgZm9yIGN1c3RvbSBsb2dpYyBvZiB0aGUgSmV0dG9ucyB0aGVtc2VsdmVzLAogICAgICAgICAgICAgICAgLy8gb3Igc2V0IHRvIG51bGwgb3RoZXJ3aXNlCiAgICAgICAgICAgICAgICBjdXN0b21QYXlsb2FkOiBudWxsLAogICAgICAgICAgICAgICAgLy8gQW1vdW50IHRvIHRyYW5zZmVyIHdpdGggSmV0dG9uVHJhbnNmZXJOb3RpZmljYXRpb24sCiAgICAgICAgICAgICAgICAvLyB3aGljaCBpcyBuZWVkZWQgZm9yIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljCiAgICAgICAgICAgICAgICBmb3J3YXJkVG9uQW1vdW50OiAxLCAvLyBpZiBpdCdzIDAsIHRoZSBub3RpZmljYXRpb24gd29uJ3QgYmUgc2VudCEKICAgICAgICAgICAgICAgIC8vIENvbXBpbGUtdGltZSB3YXkgb2YgZXhwcmVzc2luZzoKICAgICAgICAgICAgICAgIC8vICAgICBiZWdpbkNlbGwoKS5zdG9yZVVpbnQoMHhGLCA0KS5lbmRDZWxsKCkuYmVnaW5QYXJzZSgpCiAgICAgICAgICAgICAgICAvLyBGb3IgbW9yZSBjb21wbGljYXRlZCB0cmFuc2ZlcnMsIGFkanVzdCBhY2NvcmRpbmdseQogICAgICAgICAgICAgICAgZm9yd2FyZFBheWxvYWQ6IHJhd1NsaWNlKCJGIiksCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9Cn0%3D)
### Burning Jetton[](#burning-jetton)
Jetton burning is the process of permanently removing a specified amount of Jettons from circulation, with no possibility of recovery.
```tact
message(0x595f07bc) JettonBurn {
queryId: Int as uint64;
amount: Int as coins;
responseDestination: Address?;
customPayload: Cell? = null;
}
const JettonBurnGas: Int = ton("0.05");
struct JettonWalletData {
balance: Int as coins;
ownerAddress: Address;
jettonMasterAddress: Address;
jettonWalletCode: Cell;
}
fun calculateJettonWalletAddress(
ownerAddress: Address,
jettonMasterAddress: Address,
jettonWalletCode: Cell,
): Address {
let initData = JettonWalletData {
balance: 0,
ownerAddress,
jettonMasterAddress,
jettonWalletCode,
};
return contractAddress(StateInit {
code: jettonWalletCode,
data: initData.toCell(),
});
}
message ThrowAway {
amount: Int as coins;
}
contract Example {
myJettonWalletAddress: Address;
myJettonAmount: Int as coins = 0;
init(jettonWalletCode: Cell, jettonMasterAddress: Address) {
self.myJettonWalletAddress = calculateJettonWalletAddress(
myAddress(),
jettonMasterAddress,
jettonWalletCode,
);
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
receive(msg: ThrowAway) {
require(
msg.amount <= self.myJettonAmount,
"Not enough funds to throw away",
);
send(SendParameters {
to: self.myJettonWalletAddress,
value: JettonBurnGas,
body: JettonBurn {
// Unique identifier used to trace transactions across multiple contracts
queryId: 42,
// Jetton amount you want to burn
amount: msg.amount,
// Destination address for a confirmation notice of a successful burn
// and the remainder of the incoming message value
responseDestination: sender(),
// Can be used for custom logic of Jettons;
// if unused, it can be set to null
customPayload: null,
}.toCell(),
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDU5NWYwN2JjKSBKZXR0b25CdXJuIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7CiAgICBhbW91bnQ6IEludCBhcyBjb2luczsKICAgIHJlc3BvbnNlRGVzdGluYXRpb246IEFkZHJlc3M%2FOwogICAgY3VzdG9tUGF5bG9hZDogQ2VsbD8gPSBudWxsOwp9Cgpjb25zdCBKZXR0b25CdXJuR2FzOiBJbnQgPSB0b24oIjAuMDUiKTsKCnN0cnVjdCBKZXR0b25XYWxsZXREYXRhIHsKICAgIGJhbGFuY2U6IEludCBhcyBjb2luczsKICAgIG93bmVyQWRkcmVzczogQWRkcmVzczsKICAgIGpldHRvbk1hc3RlckFkZHJlc3M6IEFkZHJlc3M7CiAgICBqZXR0b25XYWxsZXRDb2RlOiBDZWxsOwp9CgpmdW4gY2FsY3VsYXRlSmV0dG9uV2FsbGV0QWRkcmVzcygKICAgIG93bmVyQWRkcmVzczogQWRkcmVzcywKICAgIGpldHRvbk1hc3RlckFkZHJlc3M6IEFkZHJlc3MsCiAgICBqZXR0b25XYWxsZXRDb2RlOiBDZWxsLAopOiBBZGRyZXNzIHsKICAgIGxldCBpbml0RGF0YSA9IEpldHRvbldhbGxldERhdGEgewogICAgICAgIGJhbGFuY2U6IDAsCiAgICAgICAgb3duZXJBZGRyZXNzLAogICAgICAgIGpldHRvbk1hc3RlckFkZHJlc3MsCiAgICAgICAgamV0dG9uV2FsbGV0Q29kZSwKICAgIH07CgogICAgcmV0dXJuIGNvbnRyYWN0QWRkcmVzcyhTdGF0ZUluaXQgewogICAgICAgIGNvZGU6IGpldHRvbldhbGxldENvZGUsCiAgICAgICAgZGF0YTogaW5pdERhdGEudG9DZWxsKCksCiAgICB9KTsKfQoKbWVzc2FnZSBUaHJvd0F3YXkgewogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7Cn0KCmNvbnRyYWN0IEV4YW1wbGUgewogICAgbXlKZXR0b25XYWxsZXRBZGRyZXNzOiBBZGRyZXNzOwogICAgbXlKZXR0b25BbW91bnQ6IEludCBhcyBjb2lucyA9IDA7CgogICAgaW5pdChqZXR0b25XYWxsZXRDb2RlOiBDZWxsLCBqZXR0b25NYXN0ZXJBZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5teUpldHRvbldhbGxldEFkZHJlc3MgPSBjYWxjdWxhdGVKZXR0b25XYWxsZXRBZGRyZXNzKAogICAgICAgICAgICBteUFkZHJlc3MoKSwKICAgICAgICAgICAgamV0dG9uTWFzdGVyQWRkcmVzcywKICAgICAgICAgICAgamV0dG9uV2FsbGV0Q29kZSwKICAgICAgICApOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIHJlY2VpdmUobXNnOiBUaHJvd0F3YXkpIHsKICAgICAgICByZXF1aXJlKAogICAgICAgICAgICBtc2cuYW1vdW50IDw9IHNlbGYubXlKZXR0b25BbW91bnQsCiAgICAgICAgICAgICJOb3QgZW5vdWdoIGZ1bmRzIHRvIHRocm93IGF3YXkiLAogICAgICAgICk7CgogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VsZi5teUpldHRvbldhbGxldEFkZHJlc3MsCiAgICAgICAgICAgIHZhbHVlOiBKZXR0b25CdXJuR2FzLAogICAgICAgICAgICBib2R5OiBKZXR0b25CdXJuIHsKICAgICAgICAgICAgICAgIC8vIFVuaXF1ZSBpZGVudGlmaWVyIHVzZWQgdG8gdHJhY2UgdHJhbnNhY3Rpb25zIGFjcm9zcyBtdWx0aXBsZSBjb250cmFjdHMKICAgICAgICAgICAgICAgIHF1ZXJ5SWQ6IDQyLAogICAgICAgICAgICAgICAgLy8gSmV0dG9uIGFtb3VudCB5b3Ugd2FudCB0byBidXJuCiAgICAgICAgICAgICAgICBhbW91bnQ6IG1zZy5hbW91bnQsCiAgICAgICAgICAgICAgICAvLyBEZXN0aW5hdGlvbiBhZGRyZXNzIGZvciBhIGNvbmZpcm1hdGlvbiBub3RpY2Ugb2YgYSBzdWNjZXNzZnVsIGJ1cm4KICAgICAgICAgICAgICAgIC8vIGFuZCB0aGUgcmVtYWluZGVyIG9mIHRoZSBpbmNvbWluZyBtZXNzYWdlIHZhbHVlCiAgICAgICAgICAgICAgICByZXNwb25zZURlc3RpbmF0aW9uOiBzZW5kZXIoKSwKICAgICAgICAgICAgICAgIC8vIENhbiBiZSB1c2VkIGZvciBjdXN0b20gbG9naWMgb2YgSmV0dG9uczsKICAgICAgICAgICAgICAgIC8vIGlmIHVudXNlZCwgaXQgY2FuIGJlIHNldCB0byBudWxsCiAgICAgICAgICAgICAgICBjdXN0b21QYXlsb2FkOiBudWxsLAogICAgICAgICAgICB9LnRvQ2VsbCgpLAogICAgICAgIH0pOwogICAgfQp9)
### USDT Jetton operations[](#usdt-jetton-operations)
Operations with USDT (on TON) remain the same, except that `JettonWalletData` will have the following structure:
```tact
struct JettonWalletData {
status: Int as uint4;
balance: Int as coins;
ownerAddress: Address;
jettonMasterAddress: Address;
}
// The function to calculate the wallet address may look like this:
fun calculateJettonWalletAddress(
ownerAddress: Address,
jettonMasterAddress: Address,
jettonWalletCode: Cell,
): Address {
let initData = JettonWalletData {
status: 0,
balance: 0,
ownerAddress,
jettonMasterAddress,
};
return contractAddress(StateInit {
code: jettonWalletCode,
data: initData.toCell(),
});
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IEpldHRvbldhbGxldERhdGEgewogICAgc3RhdHVzOiBJbnQgYXMgdWludDQ7CiAgICBiYWxhbmNlOiBJbnQgYXMgY29pbnM7CiAgICBvd25lckFkZHJlc3M6IEFkZHJlc3M7CiAgICBqZXR0b25NYXN0ZXJBZGRyZXNzOiBBZGRyZXNzOwp9CgovLyBUaGUgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSB3YWxsZXQgYWRkcmVzcyBtYXkgbG9vayBsaWtlIHRoaXM6CmZ1biBjYWxjdWxhdGVKZXR0b25XYWxsZXRBZGRyZXNzKAogICAgb3duZXJBZGRyZXNzOiBBZGRyZXNzLAogICAgamV0dG9uTWFzdGVyQWRkcmVzczogQWRkcmVzcywKICAgIGpldHRvbldhbGxldENvZGU6IENlbGwsCik6IEFkZHJlc3MgewogICAgbGV0IGluaXREYXRhID0gSmV0dG9uV2FsbGV0RGF0YSB7CiAgICAgICAgc3RhdHVzOiAwLAogICAgICAgIGJhbGFuY2U6IDAsCiAgICAgICAgb3duZXJBZGRyZXNzLAogICAgICAgIGpldHRvbk1hc3RlckFkZHJlc3MsCiAgICB9OwoKICAgIHJldHVybiBjb250cmFjdEFkZHJlc3MoU3RhdGVJbml0IHsKICAgICAgICBjb2RlOiBqZXR0b25XYWxsZXRDb2RlLAogICAgICAgIGRhdGE6IGluaXREYXRhLnRvQ2VsbCgpLAogICAgfSk7Cn0%3D)
### Onchain metadata creation[](#onchain-metadata-creation)
```tact
/// https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#jetton-metadata-example-offchain
fun composeJettonMetadata(
// Full name
name: String,
// Text description of the Jetton
description: String,
// "Stock ticker" symbol without the $ prefix, like USDT or SCALE
symbol: String,
// Link to the image
image: String,
// There could be other data, see:
// https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#jetton-metadata-attributes
): Cell {
let dict: map = emptyMap();
dict.set(sha256("name"), name.asMetadataCell());
dict.set(sha256("description"), description.asMetadataCell());
dict.set(sha256("symbol"), symbol.asMetadataCell());
dict.set(sha256("image"), image.asMetadataCell());
return beginCell()
.storeUint(0, 8) // a null byte prefix
.storeMaybeRef(dict.asCell()!!) // 1 as a single bit, then a reference
.endCell();
}
// Taking flight!
fun poorMansLaunchPad() {
let jettonMetadata = composeJettonMetadata(
"Best Jetton",
"A very descriptive description describing the Jetton descriptively",
"JETTON",
"...link to ipfs or somewhere trusted...",
);
}
// Prefixes the String with a single null byte and converts it to a Cell
// The null byte prefix is used to express metadata in various standards, like NFT or Jetton
inline extends fun asMetadataCell(self: String): Cell {
return beginTailString().concat(self).toCell();
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZ2l0aHViLmNvbS90b24tYmxvY2tjaGFpbi9URVBzL2Jsb2IvbWFzdGVyL3RleHQvMDA2NC10b2tlbi1kYXRhLXN0YW5kYXJkLm1kI2pldHRvbi1tZXRhZGF0YS1leGFtcGxlLW9mZmNoYWluCmZ1biBjb21wb3NlSmV0dG9uTWV0YWRhdGEoCiAgICAvLyBGdWxsIG5hbWUKICAgIG5hbWU6IFN0cmluZywKCiAgICAvLyBUZXh0IGRlc2NyaXB0aW9uIG9mIHRoZSBKZXR0b24KICAgIGRlc2NyaXB0aW9uOiBTdHJpbmcsCgogICAgLy8gIlN0b2NrIHRpY2tlciIgc3ltYm9sIHdpdGhvdXQgdGhlICQgcHJlZml4LCBsaWtlIFVTRFQgb3IgU0NBTEUKICAgIHN5bWJvbDogU3RyaW5nLAoKICAgIC8vIExpbmsgdG8gdGhlIGltYWdlCiAgICBpbWFnZTogU3RyaW5nLAoKICAgIC8vIFRoZXJlIGNvdWxkIGJlIG90aGVyIGRhdGEsIHNlZToKICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS90b24tYmxvY2tjaGFpbi9URVBzL2Jsb2IvbWFzdGVyL3RleHQvMDA2NC10b2tlbi1kYXRhLXN0YW5kYXJkLm1kI2pldHRvbi1tZXRhZGF0YS1hdHRyaWJ1dGVzCik6IENlbGwgewogICAgbGV0IGRpY3Q6IG1hcDxJbnQgYXMgdWludDI1NiwgQ2VsbD4gPSBlbXB0eU1hcCgpOwogICAgZGljdC5zZXQoc2hhMjU2KCJuYW1lIiksIG5hbWUuYXNNZXRhZGF0YUNlbGwoKSk7CiAgICBkaWN0LnNldChzaGEyNTYoImRlc2NyaXB0aW9uIiksIGRlc2NyaXB0aW9uLmFzTWV0YWRhdGFDZWxsKCkpOwogICAgZGljdC5zZXQoc2hhMjU2KCJzeW1ib2wiKSwgc3ltYm9sLmFzTWV0YWRhdGFDZWxsKCkpOwogICAgZGljdC5zZXQoc2hhMjU2KCJpbWFnZSIpLCBpbWFnZS5hc01ldGFkYXRhQ2VsbCgpKTsKCiAgICByZXR1cm4gYmVnaW5DZWxsKCkKICAgICAgICAuc3RvcmVVaW50KDAsIDgpIC8vICAgICAgICAgICAgICAgIGEgbnVsbCBieXRlIHByZWZpeAogICAgICAgIC5zdG9yZU1heWJlUmVmKGRpY3QuYXNDZWxsKCkhISkgLy8gMSBhcyBhIHNpbmdsZSBiaXQsIHRoZW4gYSByZWZlcmVuY2UKICAgICAgICAuZW5kQ2VsbCgpOwp9CgovLyBUYWtpbmcgZmxpZ2h0IQpmdW4gcG9vck1hbnNMYXVuY2hQYWQoKSB7CiAgICBsZXQgamV0dG9uTWV0YWRhdGEgPSBjb21wb3NlSmV0dG9uTWV0YWRhdGEoCiAgICAgICAgIkJlc3QgSmV0dG9uIiwKICAgICAgICAiQSB2ZXJ5IGRlc2NyaXB0aXZlIGRlc2NyaXB0aW9uIGRlc2NyaWJpbmcgdGhlIEpldHRvbiBkZXNjcmlwdGl2ZWx5IiwKICAgICAgICAiSkVUVE9OIiwKICAgICAgICAiLi4ubGluayB0byBpcGZzIG9yIHNvbWV3aGVyZSB0cnVzdGVkLi4uIiwKICAgICk7Cn0KCi8vIFByZWZpeGVzIHRoZSBTdHJpbmcgd2l0aCBhIHNpbmdsZSBudWxsIGJ5dGUgYW5kIGNvbnZlcnRzIGl0IHRvIGEgQ2VsbAovLyBUaGUgbnVsbCBieXRlIHByZWZpeCBpcyB1c2VkIHRvIGV4cHJlc3MgbWV0YWRhdGEgaW4gdmFyaW91cyBzdGFuZGFyZHMsIGxpa2UgTkZUIG9yIEpldHRvbgppbmxpbmUgZXh0ZW5kcyBmdW4gYXNNZXRhZGF0YUNlbGwoc2VsZjogU3RyaW5nKTogQ2VsbCB7CiAgICByZXR1cm4gYmVnaW5UYWlsU3RyaW5nKCkuY29uY2F0KHNlbGYpLnRvQ2VsbCgpOwp9)
Useful links:
[Token Data Standard in TEPs](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#jetton-metadata-attributes)
Hey there!
Didn’t find your favorite example of Jetton usage? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
For complete and exhaustive Jetton recipes that include smart contracts, auxiliary scripts, and testing suites, see the [Tact’s DeFi Cookbook on GitHub](https://github.com/tact-lang/defi-cookbook).
---
# Miscellaneous
> Various niche examples which don't yet have a dedicated page but are useful and interesting nonetheless.
Various niche examples which don’t yet have a dedicated page but are useful and interesting nonetheless.
## How to throw errors[](#how-to-throw-errors)
The `throw()` function in a contract is useful when we don’t know how often to perform a specific action.
It allows intentional exception or error handling, which leads to the termination of the current transaction and reverts any state changes made during that transaction.
```tact
let number: Int = 198;
// the error will be triggered anyway
try {
throw(36);
} catch (exitCode) {}
// the error will be triggered only if the number is greater than 50
try {
throwIf(35, number > 50);
} catch (exitCode) {}
// the error will be triggered only if the number is NOT EQUAL to 198
try {
throwUnless(39, number == 198);
} catch (exitCode) {}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIGZyb21UYWN0RG9jcygpIHsKICAgIGxldCBudW1iZXI6IEludCA9IDE5ODsKICAgIAogICAgLy8gdGhlIGVycm9yIHdpbGwgYmUgdHJpZ2dlcmVkIGFueXdheQogICAgdHJ5IHsKICAgICAgICB0aHJvdygzNik7CiAgICB9IGNhdGNoIChleGl0Q29kZSkge30KICAgIAogICAgLy8gdGhlIGVycm9yIHdpbGwgYmUgdHJpZ2dlcmVkIG9ubHkgaWYgdGhlIG51bWJlciBpcyBncmVhdGVyIHRoYW4gNTAKICAgIHRyeSB7CiAgICAgICAgdGhyb3dJZigzNSwgbnVtYmVyID4gNTApOwogICAgfSBjYXRjaCAoZXhpdENvZGUpIHt9CiAgICAKICAgIC8vIHRoZSBlcnJvciB3aWxsIGJlIHRyaWdnZXJlZCBvbmx5IGlmIHRoZSBudW1iZXIgaXMgTk9UIEVRVUFMIHRvIDE5OAogICAgdHJ5IHsKICAgICAgICB0aHJvd1VubGVzcygzOSwgbnVtYmVyID09IDE5OCk7CiAgICB9IGNhdGNoIChleGl0Q29kZSkge30KfQ%3D%3D)
Useful links:
[`throw()` in Core library](/ref/core-debug#throw)\
[Errors in Tact-By-Example](https://tact-by-example.org/03-errors)
Hey there!
Didn’t find your favorite example of working with something niche? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Multi-contract communication
> Common examples of communication between multiple deployed contracts on the blockchain
Not implemented
This page is a stub. [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Non-Fungible Tokens (NFTs)
> Common examples of working with Non-Fungible Tokens (NFTs) in Tact
This page lists common examples of working with [NFTs](https://docs.ton.org/develop/dapps/asset-processing/nfts).
## Accepting NFT ownership assignment[](#accepting-nft-ownership-assignment)
The notification message of assigned NFT ownership has the following structure:
```tact
message(0x05138d91) NFTOwnershipAssigned {
queryId: Int as uint64;
previousOwner: Address;
forwardPayload: Slice as remaining;
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDA1MTM4ZDkxKSBORlRPd25lcnNoaXBBc3NpZ25lZCB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgcHJldmlvdXNPd25lcjogQWRkcmVzczsKICAgIGZvcndhcmRQYXlsb2FkOiBTbGljZSBhcyByZW1haW5pbmc7Cn0%3D)
Use the [receiver](/book/receive) function to accept the notification message.
Caution
The sender of the notification must be validated!
Validation can be done in two ways:
1. Directly store the NFT item address and validate against it.
```tact
message(0x05138d91) NFTOwnershipAssigned {
queryId: Int as uint64;
previousOwner: Address;
forwardPayload: Slice as remaining;
}
contract SingleNft {
nftItemAddress: Address;
init(nftItemAddress: Address) {
self.nftItemAddress = nftItemAddress;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
receive(msg: NFTOwnershipAssigned) {
require(self.nftItemAddress == sender(), "NFT contract is not the sender");
// your logic of processing NFT ownership assignment notification
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDA1MTM4ZDkxKSBORlRPd25lcnNoaXBBc3NpZ25lZCB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgcHJldmlvdXNPd25lcjogQWRkcmVzczsKICAgIGZvcndhcmRQYXlsb2FkOiBTbGljZSBhcyByZW1haW5pbmc7Cn0KCmNvbnRyYWN0IFNpbmdsZU5mdCB7CiAgICBuZnRJdGVtQWRkcmVzczogQWRkcmVzczsKCiAgICBpbml0KG5mdEl0ZW1BZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5uZnRJdGVtQWRkcmVzcyA9IG5mdEl0ZW1BZGRyZXNzOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIHJlY2VpdmUobXNnOiBORlRPd25lcnNoaXBBc3NpZ25lZCkgewogICAgICAgIHJlcXVpcmUoc2VsZi5uZnRJdGVtQWRkcmVzcyA9PSBzZW5kZXIoKSwgIk5GVCBjb250cmFjdCBpcyBub3QgdGhlIHNlbmRlciIpOwoKICAgICAgICAvLyB5b3VyIGxvZ2ljIG9mIHByb2Nlc3NpbmcgTkZUIG93bmVyc2hpcCBhc3NpZ25tZW50IG5vdGlmaWNhdGlvbgogICAgfQp9)
2. Use [`StateInit`](/book/expressions#initof) and the derived address of the NFT item.
```tact
message(0x05138d91) NFTOwnershipAssigned {
queryId: Int as uint64;
previousOwner: Address;
forwardPayload: Slice as remaining;
}
struct NFTItemInitData {
index: Int as uint64;
collectionAddress: Address;
}
inline fun calculateNFTAddress(index: Int, collectionAddress: Address, nftCode: Cell): Address {
let initData = NFTItemInitData {
index,
collectionAddress,
};
return contractAddress(StateInit { code: nftCode, data: initData.toCell() });
}
contract NftInCollection {
nftCollectionAddress: Address;
nftItemIndex: Int as uint64;
nftCode: Cell;
init(nftCollectionAddress: Address, nftItemIndex: Int, nftCode: Cell) {
self.nftCollectionAddress = nftCollectionAddress;
self.nftItemIndex = nftItemIndex;
self.nftCode = nftCode;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
receive(msg: NFTOwnershipAssigned) {
let expectedNftAddress = calculateNFTAddress(self.nftItemIndex, self.nftCollectionAddress, self.nftCode); // or you can even store expectedNftAddress
require(expectedNftAddress == sender(), "NFT contract is not the sender");
// your logic of processing NFT ownership assignment notification
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDA1MTM4ZDkxKSBORlRPd25lcnNoaXBBc3NpZ25lZCB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgcHJldmlvdXNPd25lcjogQWRkcmVzczsKICAgIGZvcndhcmRQYXlsb2FkOiBTbGljZSBhcyByZW1haW5pbmc7Cn0KCnN0cnVjdCBORlRJdGVtSW5pdERhdGEgewogICAgaW5kZXg6IEludCBhcyB1aW50NjQ7CiAgICBjb2xsZWN0aW9uQWRkcmVzczogQWRkcmVzczsKfQoKaW5saW5lIGZ1biBjYWxjdWxhdGVORlRBZGRyZXNzKGluZGV4OiBJbnQsIGNvbGxlY3Rpb25BZGRyZXNzOiBBZGRyZXNzLCBuZnRDb2RlOiBDZWxsKTogQWRkcmVzcyB7CiAgICBsZXQgaW5pdERhdGEgPSBORlRJdGVtSW5pdERhdGEgewogICAgICAgIGluZGV4LAogICAgICAgIGNvbGxlY3Rpb25BZGRyZXNzLAogICAgfTsKCiAgICByZXR1cm4gY29udHJhY3RBZGRyZXNzKFN0YXRlSW5pdCB7IGNvZGU6IG5mdENvZGUsIGRhdGE6IGluaXREYXRhLnRvQ2VsbCgpIH0pOwp9Cgpjb250cmFjdCBOZnRJbkNvbGxlY3Rpb24gewogICAgbmZ0Q29sbGVjdGlvbkFkZHJlc3M6IEFkZHJlc3M7CiAgICBuZnRJdGVtSW5kZXg6IEludCBhcyB1aW50NjQ7CiAgICBuZnRDb2RlOiBDZWxsOwoKICAgIGluaXQobmZ0Q29sbGVjdGlvbkFkZHJlc3M6IEFkZHJlc3MsIG5mdEl0ZW1JbmRleDogSW50LCBuZnRDb2RlOiBDZWxsKSB7CiAgICAgICAgc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcyA9IG5mdENvbGxlY3Rpb25BZGRyZXNzOwogICAgICAgIHNlbGYubmZ0SXRlbUluZGV4ID0gbmZ0SXRlbUluZGV4OwogICAgICAgIHNlbGYubmZ0Q29kZSA9IG5mdENvZGU7CiAgICB9CgogICAgLy8gRW1wdHkgcmVjZWl2ZXIgZm9yIHRoZSBkZXBsb3ltZW50LAogICAgLy8gd2hpY2ggZm9yd2FyZHMgdGhlIHJlbWFpbmluZyB2YWx1ZSBiYWNrIHRvIHRoZSBzZW5kZXIKICAgIHJlY2VpdmUoKSB7IGNhc2hiYWNrKHNlbmRlcigpKSB9CgogICAgcmVjZWl2ZShtc2c6IE5GVE93bmVyc2hpcEFzc2lnbmVkKSB7CiAgICAgICAgbGV0IGV4cGVjdGVkTmZ0QWRkcmVzcyA9IGNhbGN1bGF0ZU5GVEFkZHJlc3Moc2VsZi5uZnRJdGVtSW5kZXgsIHNlbGYubmZ0Q29sbGVjdGlvbkFkZHJlc3MsIHNlbGYubmZ0Q29kZSk7IC8vIG9yIHlvdSBjYW4gZXZlbiBzdG9yZSBleHBlY3RlZE5mdEFkZHJlc3MKICAgICAgICByZXF1aXJlKGV4cGVjdGVkTmZ0QWRkcmVzcyA9PSBzZW5kZXIoKSwgIk5GVCBjb250cmFjdCBpcyBub3QgdGhlIHNlbmRlciIpOwoKICAgICAgICAvLyB5b3VyIGxvZ2ljIG9mIHByb2Nlc3NpbmcgTkZUIG93bmVyc2hpcCBhc3NpZ25tZW50IG5vdGlmaWNhdGlvbgogICAgfQp9)
Since the initial data layout of the NFT item can vary, the first approach is often more suitable.
## Transferring an NFT item[](#transferring-an-nft-item)
To send an NFT item transfer, use the [`send()`](/book/send) function.
```tact
message(0x5fcc3d14) NFTTransfer {
queryId: Int as uint64;
newOwner: Address; // Address of the new owner of the NFT item.
responseDestination: Address; // Address to send a response confirming a successful transfer and the remaining incoming message coins.
customPayload: Cell? = null; // Optional custom data. In most cases, this should be null.
forwardAmount: Int as coins; // The amount of nanotons to be sent to the new owner.
forwardPayload: Slice as remaining; // Optional custom data that should be sent to the new owner.
}
contract Example {
nftItemAddress: Address;
init(nftItemAddress: Address) {
self.nftItemAddress = nftItemAddress;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
// ... add more code from previous examples ...
receive("transfer") {
send(SendParameters {
to: self.nftItemAddress,
value: ton("0.1"),
body: NFTTransfer {
queryId: 42,
// FIXME: Change this according to your needs.
newOwner: sender(),
responseDestination: myAddress(),
customPayload: null,
forwardAmount: 1,
forwardPayload: rawSlice("F"), // Precomputed beginCell().storeUint(0xF, 4).endCell().beginParse()
}.toCell(),
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDVmY2MzZDE0KSBORlRUcmFuc2ZlciB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgbmV3T3duZXI6IEFkZHJlc3M7IC8vIEFkZHJlc3Mgb2YgdGhlIG5ldyBvd25lciBvZiB0aGUgTkZUIGl0ZW0uCiAgICByZXNwb25zZURlc3RpbmF0aW9uOiBBZGRyZXNzOyAvLyBBZGRyZXNzIHRvIHNlbmQgYSByZXNwb25zZSBjb25maXJtaW5nIGEgc3VjY2Vzc2Z1bCB0cmFuc2ZlciBhbmQgdGhlIHJlbWFpbmluZyBpbmNvbWluZyBtZXNzYWdlIGNvaW5zLgogICAgY3VzdG9tUGF5bG9hZDogQ2VsbD8gPSBudWxsOyAvLyBPcHRpb25hbCBjdXN0b20gZGF0YS4gSW4gbW9zdCBjYXNlcywgdGhpcyBzaG91bGQgYmUgbnVsbC4KICAgIGZvcndhcmRBbW91bnQ6IEludCBhcyBjb2luczsgLy8gVGhlIGFtb3VudCBvZiBuYW5vdG9ucyB0byBiZSBzZW50IHRvIHRoZSBuZXcgb3duZXIuCiAgICBmb3J3YXJkUGF5bG9hZDogU2xpY2UgYXMgcmVtYWluaW5nOyAvLyBPcHRpb25hbCBjdXN0b20gZGF0YSB0aGF0IHNob3VsZCBiZSBzZW50IHRvIHRoZSBuZXcgb3duZXIuCn0KCmNvbnRyYWN0IEV4YW1wbGUgewogICAgbmZ0SXRlbUFkZHJlc3M6IEFkZHJlc3M7CgogICAgaW5pdChuZnRJdGVtQWRkcmVzczogQWRkcmVzcykgewogICAgICAgIHNlbGYubmZ0SXRlbUFkZHJlc3MgPSBuZnRJdGVtQWRkcmVzczsKICAgIH0KCiAgICAvLyBFbXB0eSByZWNlaXZlciBmb3IgdGhlIGRlcGxveW1lbnQsCiAgICAvLyB3aGljaCBmb3J3YXJkcyB0aGUgcmVtYWluaW5nIHZhbHVlIGJhY2sgdG8gdGhlIHNlbmRlcgogICAgcmVjZWl2ZSgpIHsgY2FzaGJhY2soc2VuZGVyKCkpIH0KCiAgICAvLyAuLi4gYWRkIG1vcmUgY29kZSBmcm9tIHByZXZpb3VzIGV4YW1wbGVzIC4uLgoKICAgIHJlY2VpdmUoInRyYW5zZmVyIikgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VsZi5uZnRJdGVtQWRkcmVzcywKICAgICAgICAgICAgdmFsdWU6IHRvbigiMC4xIiksCiAgICAgICAgICAgIGJvZHk6IE5GVFRyYW5zZmVyIHsKICAgICAgICAgICAgICAgIHF1ZXJ5SWQ6IDQyLAogICAgICAgICAgICAgICAgLy8gRklYTUU6IENoYW5nZSB0aGlzIGFjY29yZGluZyB0byB5b3VyIG5lZWRzLgogICAgICAgICAgICAgICAgbmV3T3duZXI6IHNlbmRlcigpLAogICAgICAgICAgICAgICAgcmVzcG9uc2VEZXN0aW5hdGlvbjogbXlBZGRyZXNzKCksCiAgICAgICAgICAgICAgICBjdXN0b21QYXlsb2FkOiBudWxsLAogICAgICAgICAgICAgICAgZm9yd2FyZEFtb3VudDogMSwKICAgICAgICAgICAgICAgIGZvcndhcmRQYXlsb2FkOiByYXdTbGljZSgiRiIpLCAvLyBQcmVjb21wdXRlZCBiZWdpbkNlbGwoKS5zdG9yZVVpbnQoMHhGLCA0KS5lbmRDZWxsKCkuYmVnaW5QYXJzZSgpCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9Cn0%3D)
## Get NFT static info[](#get-nft-static-info)
Note that TON Blockchain does not allow contracts to call each other’s [getters](https://docs.tact-lang.org/book/contracts#getter-functions). To retrieve data from another contract, you must exchange messages.
```tact
message(0x2fcb26a2) NFTGetStaticData {
queryId: Int as uint64;
}
message(0x8b771735) NFTReportStaticData {
queryId: Int as uint64;
index: Int as uint256;
collection: Address;
}
struct NFTItemInitData {
index: Int as uint64;
collectionAddress: Address;
}
inline fun calculateNFTAddress(index: Int, collectionAddress: Address, nftCode: Cell): Address {
let initData = NFTItemInitData {
index,
collectionAddress,
};
return contractAddress(StateInit { code: nftCode, data: initData.toCell() });
}
contract Example {
nftCollectionAddress: Address;
nftItemIndex: Int as uint64;
nftCode: Cell;
init(nftCollectionAddress: Address, nftItemIndex: Int, nftCode: Cell) {
self.nftCollectionAddress = nftCollectionAddress;
self.nftItemIndex = nftItemIndex;
self.nftCode = nftCode;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
// ... add more code from previous examples ...
receive("get static data") {
// FIXME: Put proper address("[NFT_ADDRESS]") here
let nftAddress = sender();
send(SendParameters {
to: nftAddress,
value: ton("0.1"),
body: NFTGetStaticData {
queryId: 42,
}.toCell(),
});
}
receive(msg: NFTReportStaticData) {
let expectedNftAddress = calculateNFTAddress(msg.index, msg.collection, self.nftCode);
require(expectedNftAddress == sender(), "NFT contract is not the sender");
// Save NFT static data or do something
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDJmY2IyNmEyKSBORlRHZXRTdGF0aWNEYXRhIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7Cn0KCm1lc3NhZ2UoMHg4Yjc3MTczNSkgTkZUUmVwb3J0U3RhdGljRGF0YSB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgaW5kZXg6IEludCBhcyB1aW50MjU2OwogICAgY29sbGVjdGlvbjogQWRkcmVzczsKfQoKc3RydWN0IE5GVEl0ZW1Jbml0RGF0YSB7CiAgICBpbmRleDogSW50IGFzIHVpbnQ2NDsKICAgIGNvbGxlY3Rpb25BZGRyZXNzOiBBZGRyZXNzOwp9CgppbmxpbmUgZnVuIGNhbGN1bGF0ZU5GVEFkZHJlc3MoaW5kZXg6IEludCwgY29sbGVjdGlvbkFkZHJlc3M6IEFkZHJlc3MsIG5mdENvZGU6IENlbGwpOiBBZGRyZXNzIHsKICAgIGxldCBpbml0RGF0YSA9IE5GVEl0ZW1Jbml0RGF0YSB7CiAgICAgICAgaW5kZXgsCiAgICAgICAgY29sbGVjdGlvbkFkZHJlc3MsCiAgICB9OwoKICAgIHJldHVybiBjb250cmFjdEFkZHJlc3MoU3RhdGVJbml0IHsgY29kZTogbmZ0Q29kZSwgZGF0YTogaW5pdERhdGEudG9DZWxsKCkgfSk7Cn0KCmNvbnRyYWN0IEV4YW1wbGUgewogICAgbmZ0Q29sbGVjdGlvbkFkZHJlc3M6IEFkZHJlc3M7CiAgICBuZnRJdGVtSW5kZXg6IEludCBhcyB1aW50NjQ7CiAgICBuZnRDb2RlOiBDZWxsOwoKICAgIGluaXQobmZ0Q29sbGVjdGlvbkFkZHJlc3M6IEFkZHJlc3MsIG5mdEl0ZW1JbmRleDogSW50LCBuZnRDb2RlOiBDZWxsKSB7CiAgICAgICAgc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcyA9IG5mdENvbGxlY3Rpb25BZGRyZXNzOwogICAgICAgIHNlbGYubmZ0SXRlbUluZGV4ID0gbmZ0SXRlbUluZGV4OwogICAgICAgIHNlbGYubmZ0Q29kZSA9IG5mdENvZGU7CiAgICB9CgogICAgLy8gRW1wdHkgcmVjZWl2ZXIgZm9yIHRoZSBkZXBsb3ltZW50LAogICAgLy8gd2hpY2ggZm9yd2FyZHMgdGhlIHJlbWFpbmluZyB2YWx1ZSBiYWNrIHRvIHRoZSBzZW5kZXIKICAgIHJlY2VpdmUoKSB7IGNhc2hiYWNrKHNlbmRlcigpKSB9CgogICAgLy8gLi4uIGFkZCBtb3JlIGNvZGUgZnJvbSBwcmV2aW91cyBleGFtcGxlcyAuLi4KCiAgICByZWNlaXZlKCJnZXQgc3RhdGljIGRhdGEiKSB7CiAgICAgICAgLy8gRklYTUU6IFB1dCBwcm9wZXIgYWRkcmVzcygiW05GVF9BRERSRVNTXSIpIGhlcmUKICAgICAgICBsZXQgbmZ0QWRkcmVzcyA9IHNlbmRlcigpOwogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogbmZ0QWRkcmVzcywKICAgICAgICAgICAgdmFsdWU6IHRvbigiMC4xIiksCiAgICAgICAgICAgIGJvZHk6IE5GVEdldFN0YXRpY0RhdGEgewogICAgICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9CgogICAgcmVjZWl2ZShtc2c6IE5GVFJlcG9ydFN0YXRpY0RhdGEpIHsKICAgICAgICBsZXQgZXhwZWN0ZWROZnRBZGRyZXNzID0gY2FsY3VsYXRlTkZUQWRkcmVzcyhtc2cuaW5kZXgsIG1zZy5jb2xsZWN0aW9uLCBzZWxmLm5mdENvZGUpOwogICAgICAgIHJlcXVpcmUoZXhwZWN0ZWROZnRBZGRyZXNzID09IHNlbmRlcigpLCAiTkZUIGNvbnRyYWN0IGlzIG5vdCB0aGUgc2VuZGVyIik7CgogICAgICAgIC8vIFNhdmUgTkZUIHN0YXRpYyBkYXRhIG9yIGRvIHNvbWV0aGluZwogICAgfQp9)
## Get NFT royalty params[](#get-nft-royalty-params)
NFT royalty parameters are described [here](https://github.com/ton-blockchain/TEPs/blob/master/text/0066-nft-royalty-standard.md).
```tact
message(0x693d3950) NFTGetRoyaltyParams {
queryId: Int as uint64;
}
message(0xa8cb00ad) NFTReportRoyaltyParams {
queryId: Int as uint64;
numerator: Int as uint16;
denominator: Int as uint16;
destination: Address;
}
contract Example {
nftCollectionAddress: Address;
init(nftCollectionAddress: Address) {
self.nftCollectionAddress = nftCollectionAddress;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
// ... add more code from previous examples ...
receive("get royalty params") {
send(SendParameters {
to: self.nftCollectionAddress,
value: ton("0.1"),
body: NFTGetRoyaltyParams {
queryId: 42,
}.toCell(),
});
}
receive(msg: NFTReportRoyaltyParams) {
require(self.nftCollectionAddress == sender(), "NFT collection contract is not the sender");
// Do something with msg
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDY5M2QzOTUwKSBORlRHZXRSb3lhbHR5UGFyYW1zIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7Cn0KCm1lc3NhZ2UoMHhhOGNiMDBhZCkgTkZUUmVwb3J0Um95YWx0eVBhcmFtcyB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgbnVtZXJhdG9yOiBJbnQgYXMgdWludDE2OwogICAgZGVub21pbmF0b3I6IEludCBhcyB1aW50MTY7CiAgICBkZXN0aW5hdGlvbjogQWRkcmVzczsKfQoKY29udHJhY3QgRXhhbXBsZSB7CiAgICBuZnRDb2xsZWN0aW9uQWRkcmVzczogQWRkcmVzczsKCiAgICBpbml0KG5mdENvbGxlY3Rpb25BZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcyA9IG5mdENvbGxlY3Rpb25BZGRyZXNzOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIC8vIC4uLiBhZGQgbW9yZSBjb2RlIGZyb20gcHJldmlvdXMgZXhhbXBsZXMgLi4uCgogICAgcmVjZWl2ZSgiZ2V0IHJveWFsdHkgcGFyYW1zIikgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcywKICAgICAgICAgICAgdmFsdWU6IHRvbigiMC4xIiksCiAgICAgICAgICAgIGJvZHk6IE5GVEdldFJveWFsdHlQYXJhbXMgewogICAgICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9CgogICAgcmVjZWl2ZShtc2c6IE5GVFJlcG9ydFJveWFsdHlQYXJhbXMpIHsKICAgICAgICByZXF1aXJlKHNlbGYubmZ0Q29sbGVjdGlvbkFkZHJlc3MgPT0gc2VuZGVyKCksICJORlQgY29sbGVjdGlvbiBjb250cmFjdCBpcyBub3QgdGhlIHNlbmRlciIpOwoKICAgICAgICAvLyBEbyBzb21ldGhpbmcgd2l0aCBtc2cKICAgIH0KfQ%3D%3D)
## NFT Collection methods[](#nft-collection-methods)
Caution
These methods are not part of any standard, and they will only work with [this specific implementation](https://github.com/ton-blockchain/token-contract/blob/main/nft/nft-collection.fc). Please keep this in mind before using them.
Note that only NFT owners are allowed to use these methods.
### Deploy NFT[](#deploy-nft)
```tact
message(0x1) NFTDeploy {
queryId: Int as uint64;
itemIndex: Int as uint64;
amount: Int as coins; // amount to send when deploying NFT
nftContent: Cell;
}
contract Example {
nftCollectionAddress: Address;
init(nftCollectionAddress: Address) {
self.nftCollectionAddress = nftCollectionAddress;
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
// ... add more code from previous examples ...
receive("deploy") {
send(SendParameters {
to: self.nftCollectionAddress,
value: ton("0.14"),
body: NFTDeploy {
queryId: 42,
itemIndex: 42,
amount: ton("0.1"),
nftContent: beginCell().endCell(), // FIXME: Replace with your content, usually generated off-chain
}.toCell(),
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDEpIE5GVERlcGxveSB7CiAgICBxdWVyeUlkOiBJbnQgYXMgdWludDY0OwogICAgaXRlbUluZGV4OiBJbnQgYXMgdWludDY0OwogICAgYW1vdW50OiBJbnQgYXMgY29pbnM7IC8vIGFtb3VudCB0byBzZW5kIHdoZW4gZGVwbG95aW5nIE5GVAogICAgbmZ0Q29udGVudDogQ2VsbDsKfQoKY29udHJhY3QgRXhhbXBsZSB7CiAgICBuZnRDb2xsZWN0aW9uQWRkcmVzczogQWRkcmVzczsKCiAgICBpbml0KG5mdENvbGxlY3Rpb25BZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcyA9IG5mdENvbGxlY3Rpb25BZGRyZXNzOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgYmFjayB0byB0aGUgc2VuZGVyCiAgICByZWNlaXZlKCkgeyBjYXNoYmFjayhzZW5kZXIoKSkgfQoKICAgIC8vIC4uLiBhZGQgbW9yZSBjb2RlIGZyb20gcHJldmlvdXMgZXhhbXBsZXMgLi4uCgogICAgcmVjZWl2ZSgiZGVwbG95IikgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICB0bzogc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcywKICAgICAgICAgICAgdmFsdWU6IHRvbigiMC4xNCIpLAogICAgICAgICAgICBib2R5OiBORlREZXBsb3kgewogICAgICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgICAgICBpdGVtSW5kZXg6IDQyLAogICAgICAgICAgICAgICAgYW1vdW50OiB0b24oIjAuMSIpLAogICAgICAgICAgICAgICAgbmZ0Q29udGVudDogYmVnaW5DZWxsKCkuZW5kQ2VsbCgpLCAvLyBGSVhNRTogUmVwbGFjZSB3aXRoIHlvdXIgY29udGVudCwgdXN1YWxseSBnZW5lcmF0ZWQgb2ZmLWNoYWluCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9Cn0%3D)
### Change owner[](#change-owner)
```tact
message(0x3) NFTChangeOwner {
queryId: Int as uint64;
newOwner: Address;
}
contract Example {
nftCollectionAddress: Address;
init(nftCollectionAddress: Address) {
self.nftCollectionAddress = nftCollectionAddress;
}
// Empty receiver for the deployment,
// which forwards the remaining value to the sender
receive() { cashback(sender()) }
// ... add more code from previous examples ...
receive("change owner") {
send(SendParameters {
to: self.nftCollectionAddress,
value: ton("0.05"),
body: NFTChangeOwner {
queryId: 42,
// FIXME: Replace with the appropriate address("NEW_OWNER_ADDRESS")
newOwner: sender(),
}.toCell(),
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=bWVzc2FnZSgweDMpIE5GVENoYW5nZU93bmVyIHsKICAgIHF1ZXJ5SWQ6IEludCBhcyB1aW50NjQ7CiAgICBuZXdPd25lcjogQWRkcmVzczsKfQoKY29udHJhY3QgRXhhbXBsZSB7CiAgICBuZnRDb2xsZWN0aW9uQWRkcmVzczogQWRkcmVzczsKCiAgICBpbml0KG5mdENvbGxlY3Rpb25BZGRyZXNzOiBBZGRyZXNzKSB7CiAgICAgICAgc2VsZi5uZnRDb2xsZWN0aW9uQWRkcmVzcyA9IG5mdENvbGxlY3Rpb25BZGRyZXNzOwogICAgfQoKICAgIC8vIEVtcHR5IHJlY2VpdmVyIGZvciB0aGUgZGVwbG95bWVudCwKICAgIC8vIHdoaWNoIGZvcndhcmRzIHRoZSByZW1haW5pbmcgdmFsdWUgdG8gdGhlIHNlbmRlcgogICAgcmVjZWl2ZSgpIHsgY2FzaGJhY2soc2VuZGVyKCkpIH0KCiAgICAvLyAuLi4gYWRkIG1vcmUgY29kZSBmcm9tIHByZXZpb3VzIGV4YW1wbGVzIC4uLgoKICAgIHJlY2VpdmUoImNoYW5nZSBvd25lciIpIHsKICAgICAgICBzZW5kKFNlbmRQYXJhbWV0ZXJzIHsKICAgICAgICAgICAgdG86IHNlbGYubmZ0Q29sbGVjdGlvbkFkZHJlc3MsCiAgICAgICAgICAgIHZhbHVlOiB0b24oIjAuMDUiKSwKICAgICAgICAgICAgYm9keTogTkZUQ2hhbmdlT3duZXIgewogICAgICAgICAgICAgICAgcXVlcnlJZDogNDIsCiAgICAgICAgICAgICAgICAvLyBGSVhNRTogUmVwbGFjZSB3aXRoIHRoZSBhcHByb3ByaWF0ZSBhZGRyZXNzKCJORVdfT1dORVJfQUREUkVTUyIpCiAgICAgICAgICAgICAgICBuZXdPd25lcjogc2VuZGVyKCksCiAgICAgICAgICAgIH0udG9DZWxsKCksCiAgICAgICAgfSk7CiAgICB9Cn0%3D)
## On-chain metadata creation[](#on-chain-metadata-creation)
### NFT Collection[](#onchain-metadata-nft-collection)
```tact
/// https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#nft-metadata-attributes
fun composeCollectionMetadata(
// Full name
name: String,
// Text description of the collection
description: String,
// Link to the image
image: String,
// There could be other data, see:
// https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#nft-metadata-attributes
): Cell {
let dict: map = emptyMap();
dict.set(sha256("name"), name.asMetadataCell());
dict.set(sha256("description"), description.asMetadataCell());
dict.set(sha256("image"), image.asMetadataCell());
return beginCell()
.storeUint(0, 8) // a null byte prefix
.storeMaybeRef(dict.asCell()!!) // 1 as a single bit, then a reference
.endCell();
}
// Taking flight!
fun poorMansLaunchPad() {
let collectionMetadata = composeCollectionMetadata(
"Best Collection",
"A very descriptive description describing the collection descriptively",
"...link to IPFS or somewhere trusted...",
);
}
// Prefixes the String with a single null byte and converts it to a Cell.
// The null byte prefix is used to express metadata in various standards, like NFT or Jetton.
inline extends fun asMetadataCell(self: String): Cell {
return beginTailString().concat(self).toCell();
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZ2l0aHViLmNvbS90b24tYmxvY2tjaGFpbi9URVBzL2Jsb2IvbWFzdGVyL3RleHQvMDA2NC10b2tlbi1kYXRhLXN0YW5kYXJkLm1kI25mdC1tZXRhZGF0YS1hdHRyaWJ1dGVzCmZ1biBjb21wb3NlQ29sbGVjdGlvbk1ldGFkYXRhKAogICAgLy8gRnVsbCBuYW1lCiAgICBuYW1lOiBTdHJpbmcsCgogICAgLy8gVGV4dCBkZXNjcmlwdGlvbiBvZiB0aGUgY29sbGVjdGlvbgogICAgZGVzY3JpcHRpb246IFN0cmluZywKCiAgICAvLyBMaW5rIHRvIHRoZSBpbWFnZQogICAgaW1hZ2U6IFN0cmluZywKCiAgICAvLyBUaGVyZSBjb3VsZCBiZSBvdGhlciBkYXRhLCBzZWU6CiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vdG9uLWJsb2NrY2hhaW4vVEVQcy9ibG9iL21hc3Rlci90ZXh0LzAwNjQtdG9rZW4tZGF0YS1zdGFuZGFyZC5tZCNuZnQtbWV0YWRhdGEtYXR0cmlidXRlcwopOiBDZWxsIHsKICAgIGxldCBkaWN0OiBtYXA8SW50IGFzIHVpbnQyNTYsIENlbGw%2BID0gZW1wdHlNYXAoKTsKICAgIGRpY3Quc2V0KHNoYTI1NigibmFtZSIpLCBuYW1lLmFzTWV0YWRhdGFDZWxsKCkpOwogICAgZGljdC5zZXQoc2hhMjU2KCJkZXNjcmlwdGlvbiIpLCBkZXNjcmlwdGlvbi5hc01ldGFkYXRhQ2VsbCgpKTsKICAgIGRpY3Quc2V0KHNoYTI1NigiaW1hZ2UiKSwgaW1hZ2UuYXNNZXRhZGF0YUNlbGwoKSk7CgogICAgcmV0dXJuIGJlZ2luQ2VsbCgpCiAgICAgICAgLnN0b3JlVWludCgwLCA4KSAvLyAgICAgICAgICAgICAgICBhIG51bGwgYnl0ZSBwcmVmaXgKICAgICAgICAuc3RvcmVNYXliZVJlZihkaWN0LmFzQ2VsbCgpISEpIC8vIDEgYXMgYSBzaW5nbGUgYml0LCB0aGVuIGEgcmVmZXJlbmNlCiAgICAgICAgLmVuZENlbGwoKTsKfQoKLy8gVGFraW5nIGZsaWdodCEKZnVuIHBvb3JNYW5zTGF1bmNoUGFkKCkgewogICAgbGV0IGNvbGxlY3Rpb25NZXRhZGF0YSA9IGNvbXBvc2VDb2xsZWN0aW9uTWV0YWRhdGEoCiAgICAgICAgIkJlc3QgQ29sbGVjdGlvbiIsCiAgICAgICAgIkEgdmVyeSBkZXNjcmlwdGl2ZSBkZXNjcmlwdGlvbiBkZXNjcmliaW5nIHRoZSBjb2xsZWN0aW9uIGRlc2NyaXB0aXZlbHkiLAogICAgICAgICIuLi5saW5rIHRvIElQRlMgb3Igc29tZXdoZXJlIHRydXN0ZWQuLi4iLAogICAgKTsKfQoKLy8gUHJlZml4ZXMgdGhlIFN0cmluZyB3aXRoIGEgc2luZ2xlIG51bGwgYnl0ZSBhbmQgY29udmVydHMgaXQgdG8gYSBDZWxsLgovLyBUaGUgbnVsbCBieXRlIHByZWZpeCBpcyB1c2VkIHRvIGV4cHJlc3MgbWV0YWRhdGEgaW4gdmFyaW91cyBzdGFuZGFyZHMsIGxpa2UgTkZUIG9yIEpldHRvbi4KaW5saW5lIGV4dGVuZHMgZnVuIGFzTWV0YWRhdGFDZWxsKHNlbGY6IFN0cmluZyk6IENlbGwgewogICAgcmV0dXJuIGJlZ2luVGFpbFN0cmluZygpLmNvbmNhdChzZWxmKS50b0NlbGwoKTsKfQ%3D%3D)
Useful links:
[Token Data Standard in TEPs](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#nft-metadata-attributes)\
[Off-chain NFT metadata by GetGems](https://github.com/getgems-io/nft-contracts/blob/main/docs/metadata.md)
### NFT Item[](#onchain-metadata-nft-item)
```tact
/// https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#nft-metadata-attributes
fun composeItemMetadata(
// Full name
name: String,
// Text description of the NFT
description: String,
// Link to the image
image: String,
// There could be other data, see:
// https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#nft-metadata-attributes
): Cell {
let dict: map = emptyMap();
dict.set(sha256("name"), name.asMetadataCell());
dict.set(sha256("description"), description.asMetadataCell());
dict.set(sha256("image"), image.asMetadataCell());
return beginCell()
.storeUint(0, 8) // a null byte prefix
.storeMaybeRef(dict.asCell()!!) // 1 as a single bit, then a reference
.endCell();
}
// Taking flight!
fun poorMansLaunchPad() {
let itemMetadata = composeItemMetadata(
"Best Item",
"A very descriptive description describing the item descriptively",
"...link to ipfs or somewhere trusted...",
);
}
// Prefixes the String with a single null byte and converts it to a Cell
// The null byte prefix is used to express metadata in various standards, like NFT or Jetton
inline extends fun asMetadataCell(self: String): Cell {
return beginTailString().concat(self).toCell();
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8vIGh0dHBzOi8vZ2l0aHViLmNvbS90b24tYmxvY2tjaGFpbi9URVBzL2Jsb2IvbWFzdGVyL3RleHQvMDA2NC10b2tlbi1kYXRhLXN0YW5kYXJkLm1kI25mdC1tZXRhZGF0YS1hdHRyaWJ1dGVzCmZ1biBjb21wb3NlSXRlbU1ldGFkYXRhKAogICAgLy8gRnVsbCBuYW1lCiAgICBuYW1lOiBTdHJpbmcsCgogICAgLy8gVGV4dCBkZXNjcmlwdGlvbiBvZiB0aGUgTkZUCiAgICBkZXNjcmlwdGlvbjogU3RyaW5nLAoKICAgIC8vIExpbmsgdG8gdGhlIGltYWdlCiAgICBpbWFnZTogU3RyaW5nLAoKICAgIC8vIFRoZXJlIGNvdWxkIGJlIG90aGVyIGRhdGEsIHNlZToKICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS90b24tYmxvY2tjaGFpbi9URVBzL2Jsb2IvbWFzdGVyL3RleHQvMDA2NC10b2tlbi1kYXRhLXN0YW5kYXJkLm1kI25mdC1tZXRhZGF0YS1hdHRyaWJ1dGVzCik6IENlbGwgewogICAgbGV0IGRpY3Q6IG1hcDxJbnQgYXMgdWludDI1NiwgQ2VsbD4gPSBlbXB0eU1hcCgpOwogICAgZGljdC5zZXQoc2hhMjU2KCJuYW1lIiksIG5hbWUuYXNNZXRhZGF0YUNlbGwoKSk7CiAgICBkaWN0LnNldChzaGEyNTYoImRlc2NyaXB0aW9uIiksIGRlc2NyaXB0aW9uLmFzTWV0YWRhdGFDZWxsKCkpOwogICAgZGljdC5zZXQoc2hhMjU2KCJpbWFnZSIpLCBpbWFnZS5hc01ldGFkYXRhQ2VsbCgpKTsKCiAgICByZXR1cm4gYmVnaW5DZWxsKCkKICAgICAgICAuc3RvcmVVaW50KDAsIDgpIC8vICAgICAgICAgICAgICAgIGEgbnVsbCBieXRlIHByZWZpeAogICAgICAgIC5zdG9yZU1heWJlUmVmKGRpY3QuYXNDZWxsKCkhISkgLy8gMSBhcyBhIHNpbmdsZSBiaXQsIHRoZW4gYSByZWZlcmVuY2UKICAgICAgICAuZW5kQ2VsbCgpOwp9CgovLyBUYWtpbmcgZmxpZ2h0IQpmdW4gcG9vck1hbnNMYXVuY2hQYWQoKSB7CiAgICBsZXQgaXRlbU1ldGFkYXRhID0gY29tcG9zZUl0ZW1NZXRhZGF0YSgKICAgICAgICAiQmVzdCBJdGVtIiwKICAgICAgICAiQSB2ZXJ5IGRlc2NyaXB0aXZlIGRlc2NyaXB0aW9uIGRlc2NyaWJpbmcgdGhlIGl0ZW0gZGVzY3JpcHRpdmVseSIsCiAgICAgICAgIi4uLmxpbmsgdG8gaXBmcyBvciBzb21ld2hlcmUgdHJ1c3RlZC4uLiIsCiAgICApOwp9CgovLyBQcmVmaXhlcyB0aGUgU3RyaW5nIHdpdGggYSBzaW5nbGUgbnVsbCBieXRlIGFuZCBjb252ZXJ0cyBpdCB0byBhIENlbGwKLy8gVGhlIG51bGwgYnl0ZSBwcmVmaXggaXMgdXNlZCB0byBleHByZXNzIG1ldGFkYXRhIGluIHZhcmlvdXMgc3RhbmRhcmRzLCBsaWtlIE5GVCBvciBKZXR0b24KaW5saW5lIGV4dGVuZHMgZnVuIGFzTWV0YWRhdGFDZWxsKHNlbGY6IFN0cmluZyk6IENlbGwgewogICAgcmV0dXJuIGJlZ2luVGFpbFN0cmluZygpLmNvbmNhdChzZWxmKS50b0NlbGwoKTsKfQ%3D%3D)
Useful links:
[Token Data Standard in TEPs](https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md#nft-metadata-attributes)\
[Off-chain NFT metadata by GetGems](https://github.com/getgems-io/nft-contracts/blob/main/docs/metadata.md)
Hey there!
Didn’t find your favorite example of NFT communication? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Randomness
> Common examples of working with random numbers, uncertainty, and randomness in general
This page lists examples of working with random numbers, uncertainty, and randomness in general.
## How to generate a random number[](#how-to-generate-a-random-number)
```tact
// Declare a variable to store the random number
let number: Int = 0;
// Generate a new random number, which is an unsigned 256-bit integer
number = randomInt();
// Generate a random number between 1 and 12
number = random(1, 12);
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIGZyb21UYWN0RG9jcygpIHsKICAgIC8vIERlY2xhcmUgYSB2YXJpYWJsZSB0byBzdG9yZSB0aGUgcmFuZG9tIG51bWJlcgogICAgbGV0IG51bWJlcjogSW50ID0gMDsKICAgIAogICAgLy8gR2VuZXJhdGUgYSBuZXcgcmFuZG9tIG51bWJlciwgd2hpY2ggaXMgYW4gdW5zaWduZWQgMjU2LWJpdCBpbnRlZ2VyCiAgICBudW1iZXIgPSByYW5kb21JbnQoKTsKICAgIAogICAgLy8gR2VuZXJhdGUgYSByYW5kb20gbnVtYmVyIGJldHdlZW4gMSBhbmQgMTIKICAgIG51bWJlciA9IHJhbmRvbSgxLCAxMik7Cn0%3D)
Useful links:
[`randomInt()` in Core library](/ref/core-random#randomint)\
[`random()` in Core library](/ref/core-random#random)
Hey there!
Didn’t find your favorite example of working with randomness? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Single-contract communication
> Common examples of communication between a single deployed contract and other contracts on blockchain
This page lists examples of communication between a single deployed contract and other contracts on blockchain.
For examples of communication between multiple deployed contracts, see: [Multi-contract communication](/cookbook/multi-communication).
## How to make a basic reply[](#how-to-make-a-basic-reply)
```tact
contract Example {
receive() {
self.reply("Hello, World!".asComment()); // asComment converts a String to a Cell with a comment
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgRXhhbXBsZSB7CiAgICByZWNlaXZlKCkgewogICAgICAgIHNlbGYucmVwbHkoIkhlbGxvLCBXb3JsZCEiLmFzQ29tbWVudCgpKTsgLy8gYXNDb21tZW50IGNvbnZlcnRzIGEgU3RyaW5nIHRvIGEgQ2VsbCB3aXRoIGEgY29tbWVudAogICAgfQp9)
## How to send a simple message[](#how-to-send-a-simple-message)
```tact
contract Example {
receive() {
send(SendParameters {
bounce: true, // default
to: sender(), // or another destination address
value: ton("0.01"), // attached amount of TON to send
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgRXhhbXBsZSB7CiAgICByZWNlaXZlKCkgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICBib3VuY2U6IHRydWUsIC8vIGRlZmF1bHQKICAgICAgICAgICAgdG86IHNlbmRlcigpLCAvLyBvciBhbm90aGVyIGRlc3RpbmF0aW9uIGFkZHJlc3MKICAgICAgICAgICAgdmFsdWU6IHRvbigiMC4wMSIpLCAvLyBhdHRhY2hlZCBhbW91bnQgb2YgVE9OIHRvIHNlbmQKICAgICAgICAgICAgYm9keTogIkhlbGxvIGZyb20gVGFjdCEiLmFzQ29tbWVudCgpLCAvLyBjb21tZW50IChvcHRpb25hbCkKICAgICAgICB9KTsKICAgIH0KfQ%3D%3D)
## How to send a message with the entire balance[](#how-to-send-a-message-with-the-entire-balance)
If we need to send the whole balance of the smart contract, we should use the `SendRemainingBalance` send mode. Alternatively, we can use `mode: 128`, which has the same meaning.
```tact
contract Example {
receive() {
send(SendParameters {
// bounce = true by default
to: sender(), // send the message back to the original sender
value: 0,
mode: SendRemainingBalance, // or mode: 128
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgRXhhbXBsZSB7CiAgICByZWNlaXZlKCkgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICAvLyBib3VuY2UgPSB0cnVlIGJ5IGRlZmF1bHQKICAgICAgICAgICAgdG86IHNlbmRlcigpLCAvLyBzZW5kIHRoZSBtZXNzYWdlIGJhY2sgdG8gdGhlIG9yaWdpbmFsIHNlbmRlcgogICAgICAgICAgICB2YWx1ZTogMCwKICAgICAgICAgICAgbW9kZTogU2VuZFJlbWFpbmluZ0JhbGFuY2UsIC8vIG9yIG1vZGU6IDEyOAogICAgICAgICAgICBib2R5OiAiSGVsbG8gZnJvbSBUYWN0ISIuYXNDb21tZW50KCksIC8vIGNvbW1lbnQgKG9wdGlvbmFsKQogICAgICAgIH0pOwogICAgfQp9)
## How to send a message with the remaining value[](#how-to-send-a-message-with-the-remaining-value)
If we want to send a reply to the same sender, we can use the mode `SendRemainingValue` (i.e. `mode: 64`), which carries all the remaining value of the inbound message in addition to the value initially indicated in the new message.
```tact
contract Example {
receive() {
send(SendParameters {
// bounce = true by default
to: sender(), // send the message back to the original sender
value: 0,
mode: SendRemainingValue,
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgRXhhbXBsZSB7CiAgICByZWNlaXZlKCkgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICAvLyBib3VuY2UgPSB0cnVlIGJ5IGRlZmF1bHQKICAgICAgICAgICAgdG86IHNlbmRlcigpLCAvLyBzZW5kIHRoZSBtZXNzYWdlIGJhY2sgdG8gdGhlIG9yaWdpbmFsIHNlbmRlcgogICAgICAgICAgICB2YWx1ZTogMCwKICAgICAgICAgICAgbW9kZTogU2VuZFJlbWFpbmluZ1ZhbHVlLAogICAgICAgICAgICBib2R5OiAiSGVsbG8gZnJvbSBUYWN0ISIuYXNDb21tZW50KCksIC8vIGNvbW1lbnQgKG9wdGlvbmFsKQogICAgICAgIH0pOwogICAgfQp9)
It’s often useful to add the `SendIgnoreErrors` flag too, in order to ignore any errors arising while processing this message during the action phase:
```tact
contract Example {
receive() {
send(SendParameters {
// bounce = true by default
to: sender(), // send the message back to the original sender
value: 0,
mode: SendRemainingValue | SendIgnoreErrors, // prefer using | over + for the mode
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgRXhhbXBsZSB7CiAgICByZWNlaXZlKCkgewogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICAvLyBib3VuY2UgPSB0cnVlIGJ5IGRlZmF1bHQKICAgICAgICAgICAgdG86IHNlbmRlcigpLCAvLyBzZW5kIHRoZSBtZXNzYWdlIGJhY2sgdG8gdGhlIG9yaWdpbmFsIHNlbmRlcgogICAgICAgICAgICB2YWx1ZTogMCwKICAgICAgICAgICAgbW9kZTogU2VuZFJlbWFpbmluZ1ZhbHVlIHwgU2VuZElnbm9yZUVycm9ycywgLy8gcHJlZmVyIHVzaW5nIHwgb3ZlciArIGZvciB0aGUgbW9kZQogICAgICAgICAgICBib2R5OiAiSGVsbG8gZnJvbSBUYWN0ISIuYXNDb21tZW50KCksIC8vIGNvbW1lbnQgKG9wdGlvbmFsKQogICAgICAgIH0pOwogICAgfQp9)
The latter example is identical to using the [`.reply()` function](#how-to-make-a-basic-reply).
## How to send a message with a long text comment[](#how-to-send-a-message-with-a-long-text-comment)
If we need to send a message with a lengthy text comment, we should create a [`String`](/book/types#primitive-types) consisting of more than 127 characters. To do this, we can utilize the [`StringBuilder`](/book/types#primitive-types) primitive type and its methods `beginComment()` and `append()`. Prior to sending, we should convert this string into a cell using the `toCell()` method.
```tact
contract Example {
receive() {
let comment: StringBuilder = beginComment();
let longString = "..."; // Some string with more than 127 characters.
comment.append(longString);
send(SendParameters {
// bounce = true by default
to: sender(),
value: 0,
mode: SendIgnoreErrors,
body: comment.toCell(),
});
}
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Y29udHJhY3QgRXhhbXBsZSB7CiAgICByZWNlaXZlKCkgewogICAgICAgIGxldCBjb21tZW50OiBTdHJpbmdCdWlsZGVyID0gYmVnaW5Db21tZW50KCk7CiAgICAgICAgbGV0IGxvbmdTdHJpbmcgPSAiLi4uIjsgLy8gU29tZSBzdHJpbmcgd2l0aCBtb3JlIHRoYW4gMTI3IGNoYXJhY3RlcnMuCiAgICAgICAgY29tbWVudC5hcHBlbmQobG9uZ1N0cmluZyk7CgogICAgICAgIHNlbmQoU2VuZFBhcmFtZXRlcnMgewogICAgICAgICAgICAvLyBib3VuY2UgPSB0cnVlIGJ5IGRlZmF1bHQKICAgICAgICAgICAgdG86IHNlbmRlcigpLAogICAgICAgICAgICB2YWx1ZTogMCwKICAgICAgICAgICAgbW9kZTogU2VuZElnbm9yZUVycm9ycywKICAgICAgICAgICAgYm9keTogY29tbWVudC50b0NlbGwoKSwKICAgICAgICB9KTsKICAgIH0KfQ%3D%3D)
Useful links:
[“Sending messages” in the Book](/book/send#send-message)\
[”Message `mode`” in the Book](/book/message-mode)\
[`StringBuilder` in the Book](/book/types#primitive-types)\
[`Cell` in Core library](/ref/core-cells)
Hey there!
Didn’t find your favorite example of single-contract communication? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Time and date
> Common examples of working with time and date in Tact
## How to get the current time[](#how-to-get-the-current-time)
Use the `now()` method to obtain the current standard [Unix time](https://en.wikipedia.org/wiki/Unix_time).
If you need to store the time in a state or encode it in a message, use the following [serialization](/book/integers#serialization): `Int as uint32`.
```tact
let currentTime: Int = now();
if (currentTime > 1672080143) {
// do something
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIGZyb21UYWN0RG9jcygpIHsKICAgIGxldCBjdXJyZW50VGltZTogSW50ID0gbm93KCk7CiAgICAKICAgIGlmIChjdXJyZW50VGltZSA%2BIDE2NzIwODAxNDMpIHsKICAgICAgICAvLyBkbyBzb21ldGhpbmcKICAgIH0KfQ%3D%3D)
Useful links:
[`now()` in Core library](/ref/core-contextstate#now)\
[”Current Time” in Tact-By-Example](https://tact-by-example.org/04-current-time)
Hey there!
Didn’t find your favorite example of working with time and date? Have cool implementations in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Type conversion
> Common examples of converting between primitive types and obtaining them from composite types
This page shows examples of converting between [primitive types](/book/types#primitive-types) and obtaining them from [composite types](/book/types#composite-types).
## `Int` ↔ `String`[](#int-string)
### How to convert a `String` to an `Int`[](#how-to-convert-a-string-to-an-int)
```tact
// Define a new extension function for type String that returns a value of type Int
// Caution: produces unexpected results when the String contains non-numeric characters!
extends fun toInt(self: String): Int {
// Cast the String as a Slice for parsing
let string: Slice = self.asSlice();
// A variable to store the accumulated number
let acc: Int = 0;
// Loop until the String is empty
while (!string.empty()) {
let char: Int = string.loadUint(8); // load 8 bits (1 byte) from the Slice
acc = (acc * 10) + (char - 48); // use ASCII table to get numeric value
// Note that this approach would produce unexpected results
// when the starting String contains non-numeric characters!
}
// Produce the resulting number
return acc;
}
fun runMe() {
let string: String = "26052021";
dump(string.toInt());
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=Ly8gRGVmaW5lIGEgbmV3IGV4dGVuc2lvbiBmdW5jdGlvbiBmb3IgdHlwZSBTdHJpbmcgdGhhdCByZXR1cm5zIGEgdmFsdWUgb2YgdHlwZSBJbnQKLy8gQ2F1dGlvbjogcHJvZHVjZXMgdW5leHBlY3RlZCByZXN1bHRzIHdoZW4gdGhlIFN0cmluZyBjb250YWlucyBub24tbnVtZXJpYyBjaGFyYWN0ZXJzIQpleHRlbmRzIGZ1biB0b0ludChzZWxmOiBTdHJpbmcpOiBJbnQgewogICAgLy8gQ2FzdCB0aGUgU3RyaW5nIGFzIGEgU2xpY2UgZm9yIHBhcnNpbmcKICAgIGxldCBzdHJpbmc6IFNsaWNlID0gc2VsZi5hc1NsaWNlKCk7CgogICAgLy8gQSB2YXJpYWJsZSB0byBzdG9yZSB0aGUgYWNjdW11bGF0ZWQgbnVtYmVyCiAgICBsZXQgYWNjOiBJbnQgPSAwOwoKICAgIC8vIExvb3AgdW50aWwgdGhlIFN0cmluZyBpcyBlbXB0eQogICAgd2hpbGUgKCFzdHJpbmcuZW1wdHkoKSkgewogICAgICAgIGxldCBjaGFyOiBJbnQgPSBzdHJpbmcubG9hZFVpbnQoOCk7IC8vIGxvYWQgOCBiaXRzICgxIGJ5dGUpIGZyb20gdGhlIFNsaWNlCiAgICAgICAgYWNjID0gKGFjYyAqIDEwKSArIChjaGFyIC0gNDgpOyAvLyAgICAgdXNlIEFTQ0lJIHRhYmxlIHRvIGdldCBudW1lcmljIHZhbHVlCiAgICAgICAgLy8gTm90ZSB0aGF0IHRoaXMgYXBwcm9hY2ggd291bGQgcHJvZHVjZSB1bmV4cGVjdGVkIHJlc3VsdHMKICAgICAgICAvLyAgIHdoZW4gdGhlIHN0YXJ0aW5nIFN0cmluZyBjb250YWlucyBub24tbnVtZXJpYyBjaGFyYWN0ZXJzIQogICAgfQoKICAgIC8vIFByb2R1Y2UgdGhlIHJlc3VsdGluZyBudW1iZXIKICAgIHJldHVybiBhY2M7Cn0KCmZ1biBydW5NZSgpIHsKICAgIGxldCBzdHJpbmc6IFN0cmluZyA9ICIyNjA1MjAyMSI7CiAgICBkdW1wKHN0cmluZy50b0ludCgpKTsKfQ%3D%3D)
### How to convert an `Int` to a `String`[](#how-to-convert-an-int-to-a-string)
```tact
let number: Int = 261119911;
// Converting the [number] to a String
let numberString: String = number.toString();
// Converting the [number] to a float String,
// where the passed argument 3 is the exponent of 10^{-3} in the resulting float String,
// and it can be any integer between 0 and 76, inclusive.
let floatString: String = number.toFloatString(3);
// Converting the [number] as coins to a human-readable String
let coinsString: String = number.toCoinsString();
dump(numberString); // "261119911"
dump(floatString); // "261119.911"
dump(coinsString); // "0.261119911"
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=ZnVuIGZyb21UYWN0RG9jcygpIHsKICAgIGxldCBudW1iZXI6IEludCA9IDI2MTExOTkxMTsKICAgIAogICAgLy8gQ29udmVydGluZyB0aGUgW251bWJlcl0gdG8gYSBTdHJpbmcKICAgIGxldCBudW1iZXJTdHJpbmc6IFN0cmluZyA9IG51bWJlci50b1N0cmluZygpOwogICAgCiAgICAvLyBDb252ZXJ0aW5nIHRoZSBbbnVtYmVyXSB0byBhIGZsb2F0IFN0cmluZywKICAgIC8vICAgd2hlcmUgdGhlIHBhc3NlZCBhcmd1bWVudCAzIGlzIHRoZSBleHBvbmVudCBvZiAxMF57LTN9IGluIHRoZSByZXN1bHRpbmcgZmxvYXQgU3RyaW5nLAogICAgLy8gICBhbmQgaXQgY2FuIGJlIGFueSBpbnRlZ2VyIGJldHdlZW4gMCBhbmQgNzYsIGluY2x1c2l2ZS4KICAgIGxldCBmbG9hdFN0cmluZzogU3RyaW5nID0gbnVtYmVyLnRvRmxvYXRTdHJpbmcoMyk7CiAgICAKICAgIC8vIENvbnZlcnRpbmcgdGhlIFtudW1iZXJdIGFzIGNvaW5zIHRvIGEgaHVtYW4tcmVhZGFibGUgU3RyaW5nCiAgICBsZXQgY29pbnNTdHJpbmc6IFN0cmluZyA9IG51bWJlci50b0NvaW5zU3RyaW5nKCk7CiAgICAKICAgIGR1bXAobnVtYmVyU3RyaW5nKTsgLy8gIjI2MTExOTkxMSIKICAgIGR1bXAoZmxvYXRTdHJpbmcpOyAvLyAgIjI2MTExOS45MTEiCiAgICBkdW1wKGNvaW5zU3RyaW5nKTsgLy8gICIwLjI2MTExOTkxMSIKfQ%3D%3D)
Useful links:
[`Int.toString()` in Core library](/ref/core-strings#inttostring)\
[`Int.toFloatString()` in Core library](/ref/core-strings#inttofloatstring)\
[`Int.toCoinsString()` in Core library](/ref/core-strings#inttocoinsstring)
## `Struct` or `Message` ↔ `Cell` or `Slice`[](#structmessage-cellslice)
### How to convert an arbitrary `Struct` or `Message` to a `Cell` or a `Slice`[](#how-to-convert-an-arbitrary-struct-or-message-to-a-cell-or-a-slice)
```tact
struct Profit {
big: String?;
dict: map;
energy: Int;
}
message(0x45) Nice {
maybeStr: String?;
}
fun convert() {
let st = Profit {
big: null,
dict: null,
energy: 42,
};
let msg = Nice { maybeStr: "Message of the day!" };
st.toCell();
msg.toCell();
st.toCell().asSlice();
msg.toCell().asSlice();
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IFByb2ZpdCB7CiAgICBiaWc6IFN0cmluZz87CiAgICBkaWN0OiBtYXA8SW50LCBJbnQgYXMgdWludDY0PjsKICAgIGVuZXJneTogSW50Owp9CgptZXNzYWdlKDB4NDUpIE5pY2UgewogICAgbWF5YmVTdHI6IFN0cmluZz87Cn0KCmZ1biBjb252ZXJ0KCkgewogICAgbGV0IHN0ID0gUHJvZml0IHsKICAgICAgICBiaWc6IG51bGwsCiAgICAgICAgZGljdDogbnVsbCwKICAgICAgICBlbmVyZ3k6IDQyLAogICAgfTsKICAgIGxldCBtc2cgPSBOaWNlIHsgbWF5YmVTdHI6ICJNZXNzYWdlIG9mIHRoZSBkYXkhIiB9OwoKICAgIHN0LnRvQ2VsbCgpOwogICAgbXNnLnRvQ2VsbCgpOwoKICAgIHN0LnRvQ2VsbCgpLmFzU2xpY2UoKTsKICAgIG1zZy50b0NlbGwoKS5hc1NsaWNlKCk7Cn0%3D)
Useful links:
[`Struct.toCell()` in Core library](/ref/core-cells#structtocell)\
[`Message.toCell()` in Core library](/ref/core-cells#messagetocell)
### How to convert a `Cell` or a `Slice` to an arbitrary `Struct` or `Message`[](#how-to-convert-a-cell-or-a-slice-to-an-arbitrary-struct-or-message)
```tact
struct Profit {
big: String?;
dict: map;
energy: Int;
}
message(0x45) Nice {
maybeStr: String?;
}
fun convert() {
let stCell = Profit {
big: null,
dict: null,
energy: 42,
}.toCell();
let msgCell = Nice { maybeStr: "Message of the day!" }.toCell();
Profit.fromCell(stCell);
Nice.fromCell(msgCell);
Profit.fromSlice(stCell.asSlice());
Nice.fromSlice(msgCell.asSlice());
}
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=c3RydWN0IFByb2ZpdCB7CiAgICBiaWc6IFN0cmluZz87CiAgICBkaWN0OiBtYXA8SW50LCBJbnQgYXMgdWludDY0PjsKICAgIGVuZXJneTogSW50Owp9CgptZXNzYWdlKDB4NDUpIE5pY2UgewogICAgbWF5YmVTdHI6IFN0cmluZz87Cn0KCmZ1biBjb252ZXJ0KCkgewogICAgbGV0IHN0Q2VsbCA9IFByb2ZpdCB7CiAgICAgICAgYmlnOiBudWxsLAogICAgICAgIGRpY3Q6IG51bGwsCiAgICAgICAgZW5lcmd5OiA0MiwKICAgIH0udG9DZWxsKCk7CiAgICBsZXQgbXNnQ2VsbCA9IE5pY2UgeyBtYXliZVN0cjogIk1lc3NhZ2Ugb2YgdGhlIGRheSEiIH0udG9DZWxsKCk7CgogICAgUHJvZml0LmZyb21DZWxsKHN0Q2VsbCk7CiAgICBOaWNlLmZyb21DZWxsKG1zZ0NlbGwpOwoKICAgIFByb2ZpdC5mcm9tU2xpY2Uoc3RDZWxsLmFzU2xpY2UoKSk7CiAgICBOaWNlLmZyb21TbGljZShtc2dDZWxsLmFzU2xpY2UoKSk7Cn0%3D)
Useful links:
[`Struct.fromCell()` in Core library](/ref/core-cells#structfromcell)\
[`Struct.fromSlice()` in Core library](/ref/core-cells#structfromslice)\
[`Message.fromCell()` in Core library](/ref/core-cells#messagefromcell)\
[`Message.fromSlice()` in Core library](/ref/core-cells#messagefromslice)
Hey there!
Didn’t find your favorite example of type conversion? Have a cool implementation in mind? [Contributions are welcome!](https://github.com/tact-lang/tact/issues)
---
# Code and data upgrades
> This page lists examples of traits that can be used to allow upgrading the code or data of your smart contracts.
Traits and helper functions that can be used to upgrade your smart contract’s code, data, or both.
Caution
Information is provided “as is,” without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall TON Studio and the Tact compiler authors be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the information or the use or other dealings in the information.
## Direct upgrade[](#direct-upgrade)
```tact
import "@stdlib/ownable";
/// Message for upgrading contract code and data.
message Upgrade {
/// New code of the contract.
/// Defaults to `null`, which keeps the previous code.
code: Cell? = null;
/// New data of the contract.
/// Defaults to `null`, which keeps the previous data.
data: Cell? = null;
}
/// Implements a basic upgrade mechanism with owner validation.
trait Upgradable with Ownable {
/// Contract owner address that can perform upgrades.
owner: Address;
/// Current contract version, auto-increments after each upgrade.
/// Meant to be private and only accessible through the relevant getter.
_version: Int as uint32;
/// Checks the sender, performs an upgrade, and increments the version.
receive(msg: Upgrade) {
let ctx = context();
self.validateUpgrade(ctx, msg);
self.upgrade(ctx, msg);
self._version += 1;
}
/// Checks that the sender is the owner.
/// Can be overridden.
virtual inline fun validateUpgrade(_: Context, __: Upgrade) {
self.requireOwner();
}
/// Sets the code if it's not `null`.
/// Sets the data if it's not `null`.
/// Can be overridden.
virtual inline fun upgrade(_: Context, msg: Upgrade) {
if (msg.code != null) {
// Change of code will be applied at the end of this transaction
setCode(msg.code!!);
}
if (msg.data != null) {
// Change of data will be immediate
setData(msg.data!!);
// By the end of every transaction,
// the Tact compiler automatically adds a call to setData() for your convenience.
// However, we've already set the data ourselves,
// so let's stop the execution now to prevent a secondary call to setData().
throw(0);
}
}
/// A getter to check if the contract uses this trait.
get fun isUpgradable(): Bool {
return true;
}
/// A getter returning the current version of the contract.
get fun version(): Int {
return self._version;
}
}
/// Change of code will be applied by the end of the current transaction.
asm fun setCode(code: Cell) { SETCODE }
/// Change of data is immediate.
asm fun setData(data: Cell) { c4 POP }
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=aW1wb3J0ICJAc3RkbGliL293bmFibGUiOwoKLy8vIE1lc3NhZ2UgZm9yIHVwZ3JhZGluZyBjb250cmFjdCBjb2RlIGFuZCBkYXRhLgptZXNzYWdlIFVwZ3JhZGUgewogICAgLy8vIE5ldyBjb2RlIG9mIHRoZSBjb250cmFjdC4KICAgIC8vLyBEZWZhdWx0cyB0byBgbnVsbGAsIHdoaWNoIGtlZXBzIHRoZSBwcmV2aW91cyBjb2RlLgogICAgY29kZTogQ2VsbD8gPSBudWxsOwoKICAgIC8vLyBOZXcgZGF0YSBvZiB0aGUgY29udHJhY3QuCiAgICAvLy8gRGVmYXVsdHMgdG8gYG51bGxgLCB3aGljaCBrZWVwcyB0aGUgcHJldmlvdXMgZGF0YS4KICAgIGRhdGE6IENlbGw%2FID0gbnVsbDsKfQoKLy8vIEltcGxlbWVudHMgYSBiYXNpYyB1cGdyYWRlIG1lY2hhbmlzbSB3aXRoIG93bmVyIHZhbGlkYXRpb24uCnRyYWl0IFVwZ3JhZGFibGUgd2l0aCBPd25hYmxlIHsKICAgIC8vLyBDb250cmFjdCBvd25lciBhZGRyZXNzIHRoYXQgY2FuIHBlcmZvcm0gdXBncmFkZXMuCiAgICBvd25lcjogQWRkcmVzczsKCiAgICAvLy8gQ3VycmVudCBjb250cmFjdCB2ZXJzaW9uLCBhdXRvLWluY3JlbWVudHMgYWZ0ZXIgZWFjaCB1cGdyYWRlLgogICAgLy8vIE1lYW50IHRvIGJlIHByaXZhdGUgYW5kIG9ubHkgYWNjZXNzaWJsZSB0aHJvdWdoIHRoZSByZWxldmFudCBnZXR0ZXIuCiAgICBfdmVyc2lvbjogSW50IGFzIHVpbnQzMjsKCiAgICAvLy8gQ2hlY2tzIHRoZSBzZW5kZXIsIHBlcmZvcm1zIGFuIHVwZ3JhZGUsIGFuZCBpbmNyZW1lbnRzIHRoZSB2ZXJzaW9uLgogICAgcmVjZWl2ZShtc2c6IFVwZ3JhZGUpIHsKICAgICAgICBsZXQgY3R4ID0gY29udGV4dCgpOwogICAgICAgIHNlbGYudmFsaWRhdGVVcGdyYWRlKGN0eCwgbXNnKTsKICAgICAgICBzZWxmLnVwZ3JhZGUoY3R4LCBtc2cpOwoKICAgICAgICBzZWxmLl92ZXJzaW9uICs9IDE7CiAgICB9CgogICAgLy8vIENoZWNrcyB0aGF0IHRoZSBzZW5kZXIgaXMgdGhlIG93bmVyLgogICAgLy8vIENhbiBiZSBvdmVycmlkZGVuLgogICAgdmlydHVhbCBpbmxpbmUgZnVuIHZhbGlkYXRlVXBncmFkZShfOiBDb250ZXh0LCBfXzogVXBncmFkZSkgewogICAgICAgIHNlbGYucmVxdWlyZU93bmVyKCk7CiAgICB9CgogICAgLy8vIFNldHMgdGhlIGNvZGUgaWYgaXQncyBub3QgYG51bGxgLgogICAgLy8vIFNldHMgdGhlIGRhdGEgaWYgaXQncyBub3QgYG51bGxgLgogICAgLy8vIENhbiBiZSBvdmVycmlkZGVuLgogICAgdmlydHVhbCBpbmxpbmUgZnVuIHVwZ3JhZGUoXzogQ29udGV4dCwgbXNnOiBVcGdyYWRlKSB7CiAgICAgICAgaWYgKG1zZy5jb2RlICE9IG51bGwpIHsKICAgICAgICAgICAgLy8gQ2hhbmdlIG9mIGNvZGUgd2lsbCBiZSBhcHBsaWVkIGF0IHRoZSBlbmQgb2YgdGhpcyB0cmFuc2FjdGlvbgogICAgICAgICAgICBzZXRDb2RlKG1zZy5jb2RlISEpOwogICAgICAgIH0KICAgICAgICBpZiAobXNnLmRhdGEgIT0gbnVsbCkgewogICAgICAgICAgICAvLyBDaGFuZ2Ugb2YgZGF0YSB3aWxsIGJlIGltbWVkaWF0ZQogICAgICAgICAgICBzZXREYXRhKG1zZy5kYXRhISEpOwoKICAgICAgICAgICAgLy8gQnkgdGhlIGVuZCBvZiBldmVyeSB0cmFuc2FjdGlvbiwKICAgICAgICAgICAgLy8gdGhlIFRhY3QgY29tcGlsZXIgYXV0b21hdGljYWxseSBhZGRzIGEgY2FsbCB0byBzZXREYXRhKCkgZm9yIHlvdXIgY29udmVuaWVuY2UuCiAgICAgICAgICAgIC8vIEhvd2V2ZXIsIHdlJ3ZlIGFscmVhZHkgc2V0IHRoZSBkYXRhIG91cnNlbHZlcywKICAgICAgICAgICAgLy8gc28gbGV0J3Mgc3RvcCB0aGUgZXhlY3V0aW9uIG5vdyB0byBwcmV2ZW50IGEgc2Vjb25kYXJ5IGNhbGwgdG8gc2V0RGF0YSgpLgogICAgICAgICAgICB0aHJvdygwKTsKICAgICAgICB9CiAgICB9CgogICAgLy8vIEEgZ2V0dGVyIHRvIGNoZWNrIGlmIHRoZSBjb250cmFjdCB1c2VzIHRoaXMgdHJhaXQuCiAgICBnZXQgZnVuIGlzVXBncmFkYWJsZSgpOiBCb29sIHsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICAvLy8gQSBnZXR0ZXIgcmV0dXJuaW5nIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIGNvbnRyYWN0LgogICAgZ2V0IGZ1biB2ZXJzaW9uKCk6IEludCB7CiAgICAgICAgcmV0dXJuIHNlbGYuX3ZlcnNpb247CiAgICB9Cn0KCi8vLyBDaGFuZ2Ugb2YgY29kZSB3aWxsIGJlIGFwcGxpZWQgYnkgdGhlIGVuZCBvZiB0aGUgY3VycmVudCB0cmFuc2FjdGlvbi4KYXNtIGZ1biBzZXRDb2RlKGNvZGU6IENlbGwpIHsgU0VUQ09ERSB9CgovLy8gQ2hhbmdlIG9mIGRhdGEgaXMgaW1tZWRpYXRlLgphc20gZnVuIHNldERhdGEoZGF0YTogQ2VsbCkgeyBjNCBQT1AgfQ%3D%3D)
## Time-locked upgrade[](#time-locked-upgrade)
This upgrade is performed in two steps by sending two messages:
1. An `Upgrade` message specifying a timeout before the upgrade can be completed.
2. A `Confirm` message, after which the last received `Upgrade` is applied.
If the second message is sent before the timeout expires, the contract will throw an error and will not be upgraded.
```tact
import "@stdlib/ownable";
/// Message for upgrading contract code and data with a timeout.
message Upgrade {
/// New code of the contract.
/// Defaults to `null`, which keeps the previous code.
code: Cell? = null;
/// New data of the contract.
/// Defaults to `null`, which keeps the previous data.
data: Cell? = null;
/// Delay in seconds before upgrade can be confirmed.
/// Defaults to zero, which means the upgrade can be confirmed immediately.
/// Unused in `Upgradable` trait.
timeout: Int = 0;
}
/// Message for confirming delayed upgrade execution.
/// Must be sent after the timeout specified in the `Upgrade` message has elapsed.
/// Can only be processed by contracts that implement the `DelayedUpgradable` trait.
message Confirm {}
/// Extended version of `Upgradable` that adds a delay mechanism.
///
/// The upgrade process happens in two steps:
/// 1. Owner initiates an upgrade by sending the `Upgrade` message.
/// 2. After a timeout period, the owner confirms the upgrade by sending the `Confirm` message.
trait DelayedUpgradable with Upgradable {
/// Contract owner address that can perform upgrades.
owner: Address;
/// Current contract version, auto-increments after each upgrade.
/// Meant to be private and only accessible through the relevant getter.
_version: Int as uint32;
/// Timestamp in seconds of the last `Upgrade` message arrival.
/// Used to enforce a timeout period before the confirmation.
initiatedAt: Int;
/// Contains new code, new data, and a timeout period.
upgradeInfo: Upgrade;
/// Confirms and executes a pending upgrade only after `upgradeInfo.timeout`
/// seconds have passed since the last `_initiatedAt`.
receive(msg: Confirm) {
require(now() >= self.initiatedAt + self.upgradeInfo.timeout, "DelayedUpgradable: Cannot confirm upgrade before timeout");
if (self.upgradeInfo.code != null) {
// Change of code will be applied at the end of this transaction
setCode(self.upgradeInfo.code!!);
}
if (self.upgradeInfo.data != null) {
// Change of data will be immediate
setData(self.upgradeInfo.data!!);
// By the end of every transaction,
// the Tact compiler automatically adds a call to setData() for your convenience.
// However, we have already set the data ourselves,
// so let us stop the execution now to prevent a secondary call to setData().
throw(0);
}
}
/// Instead of performing an upgrade right away,
/// saves details for delayed execution.
override inline fun upgrade(_: Context, msg: Upgrade) {
self.upgradeInfo = msg;
self.initiatedAt = now();
}
}
//
// Helper traits and functions described earlier on this page
//
trait Upgradable with Ownable {
owner: Address;
_version: Int as uint32;
receive(msg: Upgrade) {
let ctx = context();
self.validateUpgrade(ctx, msg);
self.upgrade(ctx, msg);
self._version += 1;
}
virtual inline fun validateUpgrade(_: Context, __: Upgrade) {
self.requireOwner();
}
virtual inline fun upgrade(_: Context, msg: Upgrade) {
if (msg.code != null) {
setCode(msg.code!!);
}
if (msg.data != null) {
setData(msg.data!!);
throw(0);
}
}
get fun isUpgradable(): Bool {
return true;
}
get fun version(): Int {
return self._version;
}
}
asm fun setCode(code: Cell) { SETCODE }
asm fun setData(data: Cell) { c4 POP }
```
[▶️ Open in Web IDE](https://ide.ton.org/#lang=tact\&code=aW1wb3J0ICJAc3RkbGliL293bmFibGUiOwoKLy8vIE1lc3NhZ2UgZm9yIHVwZ3JhZGluZyBjb250cmFjdCBjb2RlIGFuZCBkYXRhIHdpdGggYSB0aW1lb3V0LgptZXNzYWdlIFVwZ3JhZGUgewogICAgLy8vIE5ldyBjb2RlIG9mIHRoZSBjb250cmFjdC4KICAgIC8vLyBEZWZhdWx0cyB0byBgbnVsbGAsIHdoaWNoIGtlZXBzIHRoZSBwcmV2aW91cyBjb2RlLgogICAgY29kZTogQ2VsbD8gPSBudWxsOwoKICAgIC8vLyBOZXcgZGF0YSBvZiB0aGUgY29udHJhY3QuCiAgICAvLy8gRGVmYXVsdHMgdG8gYG51bGxgLCB3aGljaCBrZWVwcyB0aGUgcHJldmlvdXMgZGF0YS4KICAgIGRhdGE6IENlbGw%2FID0gbnVsbDsKCiAgICAvLy8gRGVsYXkgaW4gc2Vjb25kcyBiZWZvcmUgdXBncmFkZSBjYW4gYmUgY29uZmlybWVkLgogICAgLy8vIERlZmF1bHRzIHRvIHplcm8sIHdoaWNoIG1lYW5zIHRoZSB1cGdyYWRlIGNhbiBiZSBjb25maXJtZWQgaW1tZWRpYXRlbHkuCiAgICAvLy8gVW51c2VkIGluIGBVcGdyYWRhYmxlYCB0cmFpdC4KICAgIHRpbWVvdXQ6IEludCA9IDA7Cn0KCi8vLyBNZXNzYWdlIGZvciBjb25maXJtaW5nIGRlbGF5ZWQgdXBncmFkZSBleGVjdXRpb24uCi8vLyBNdXN0IGJlIHNlbnQgYWZ0ZXIgdGhlIHRpbWVvdXQgc3BlY2lmaWVkIGluIHRoZSBgVXBncmFkZWAgbWVzc2FnZSBoYXMgZWxhcHNlZC4KLy8vIENhbiBvbmx5IGJlIHByb2Nlc3NlZCBieSBjb250cmFjdHMgdGhhdCBpbXBsZW1lbnQgdGhlIGBEZWxheWVkVXBncmFkYWJsZWAgdHJhaXQuCm1lc3NhZ2UgQ29uZmlybSB7fQoKLy8vIEV4dGVuZGVkIHZlcnNpb24gb2YgYFVwZ3JhZGFibGVgIHRoYXQgYWRkcyBhIGRlbGF5IG1lY2hhbmlzbS4KLy8vCi8vLyBUaGUgdXBncmFkZSBwcm9jZXNzIGhhcHBlbnMgaW4gdHdvIHN0ZXBzOgovLy8gMS4gT3duZXIgaW5pdGlhdGVzIGFuIHVwZ3JhZGUgYnkgc2VuZGluZyB0aGUgYFVwZ3JhZGVgIG1lc3NhZ2UuCi8vLyAyLiBBZnRlciBhIHRpbWVvdXQgcGVyaW9kLCB0aGUgb3duZXIgY29uZmlybXMgdGhlIHVwZ3JhZGUgYnkgc2VuZGluZyB0aGUgYENvbmZpcm1gIG1lc3NhZ2UuCnRyYWl0IERlbGF5ZWRVcGdyYWRhYmxlIHdpdGggVXBncmFkYWJsZSB7CiAgICAvLy8gQ29udHJhY3Qgb3duZXIgYWRkcmVzcyB0aGF0IGNhbiBwZXJmb3JtIHVwZ3JhZGVzLgogICAgb3duZXI6IEFkZHJlc3M7CgogICAgLy8vIEN1cnJlbnQgY29udHJhY3QgdmVyc2lvbiwgYXV0by1pbmNyZW1lbnRzIGFmdGVyIGVhY2ggdXBncmFkZS4KICAgIC8vLyBNZWFudCB0byBiZSBwcml2YXRlIGFuZCBvbmx5IGFjY2Vzc2libGUgdGhyb3VnaCB0aGUgcmVsZXZhbnQgZ2V0dGVyLgogICAgX3ZlcnNpb246IEludCBhcyB1aW50MzI7CgogICAgLy8vIFRpbWVzdGFtcCBpbiBzZWNvbmRzIG9mIHRoZSBsYXN0IGBVcGdyYWRlYCBtZXNzYWdlIGFycml2YWwuCiAgICAvLy8gVXNlZCB0byBlbmZvcmNlIGEgdGltZW91dCBwZXJpb2QgYmVmb3JlIHRoZSBjb25maXJtYXRpb24uCiAgICBpbml0aWF0ZWRBdDogSW50OwoKICAgIC8vLyBDb250YWlucyBuZXcgY29kZSwgbmV3IGRhdGEsIGFuZCBhIHRpbWVvdXQgcGVyaW9kLgogICAgdXBncmFkZUluZm86IFVwZ3JhZGU7CgogICAgLy8vIENvbmZpcm1zIGFuZCBleGVjdXRlcyBhIHBlbmRpbmcgdXBncmFkZSBvbmx5IGFmdGVyIGB1cGdyYWRlSW5mby50aW1lb3V0YAogICAgLy8vIHNlY29uZHMgaGF2ZSBwYXNzZWQgc2luY2UgdGhlIGxhc3QgYF9pbml0aWF0ZWRBdGAuCiAgICByZWNlaXZlKG1zZzogQ29uZmlybSkgewogICAgICAgIHJlcXVpcmUobm93KCkgPj0gc2VsZi5pbml0aWF0ZWRBdCArIHNlbGYudXBncmFkZUluZm8udGltZW91dCwgIkRlbGF5ZWRVcGdyYWRhYmxlOiBDYW5ub3QgY29uZmlybSB1cGdyYWRlIGJlZm9yZSB0aW1lb3V0Iik7CgogICAgICAgIGlmIChzZWxmLnVwZ3JhZGVJbmZvLmNvZGUgIT0gbnVsbCkgewogICAgICAgICAgICAvLyBDaGFuZ2Ugb2YgY29kZSB3aWxsIGJlIGFwcGxpZWQgYXQgdGhlIGVuZCBvZiB0aGlzIHRyYW5zYWN0aW9uCiAgICAgICAgICAgIHNldENvZGUoc2VsZi51cGdyYWRlSW5mby5jb2RlISEpOwogICAgICAgIH0KICAgICAgICBpZiAoc2VsZi51cGdyYWRlSW5mby5kYXRhICE9IG51bGwpIHsKICAgICAgICAgICAgLy8gQ2hhbmdlIG9mIGRhdGEgd2lsbCBiZSBpbW1lZGlhdGUKICAgICAgICAgICAgc2V0RGF0YShzZWxmLnVwZ3JhZGVJbmZvLmRhdGEhISk7CgogICAgICAgICAgICAvLyBCeSB0aGUgZW5kIG9mIGV2ZXJ5IHRyYW5zYWN0aW9uLAogICAgICAgICAgICAvLyB0aGUgVGFjdCBjb21waWxlciBhdXRvbWF0aWNhbGx5IGFkZHMgYSBjYWxsIHRvIHNldERhdGEoKSBmb3IgeW91ciBjb252ZW5pZW5jZS4KICAgICAgICAgICAgLy8gSG93ZXZlciwgd2UgaGF2ZSBhbHJlYWR5IHNldCB0aGUgZGF0YSBvdXJzZWx2ZXMsCiAgICAgICAgICAgIC8vIHNvIGxldCB1cyBzdG9wIHRoZSBleGVjdXRpb24gbm93IHRvIHByZXZlbnQgYSBzZWNvbmRhcnkgY2FsbCB0byBzZXREYXRhKCkuCiAgICAgICAgICAgIHRocm93KDApOwogICAgICAgIH0KICAgIH0KCiAgICAvLy8gSW5zdGVhZCBvZiBwZXJmb3JtaW5nIGFuIHVwZ3JhZGUgcmlnaHQgYXdheSwKICAgIC8vLyBzYXZlcyBkZXRhaWxzIGZvciBkZWxheWVkIGV4ZWN1dGlvbi4KICAgIG92ZXJyaWRlIGlubGluZSBmdW4gdXBncmFkZShfOiBDb250ZXh0LCBtc2c6IFVwZ3JhZGUpIHsKICAgICAgICBzZWxmLnVwZ3JhZGVJbmZvID0gbXNnOwogICAgICAgIHNlbGYuaW5pdGlhdGVkQXQgPSBub3coKTsKICAgIH0KfQoKLy8KLy8gSGVscGVyIHRyYWl0cyBhbmQgZnVuY3Rpb25zIGRlc2NyaWJlZCBlYXJsaWVyIG9uIHRoaXMgcGFnZQovLwoKdHJhaXQgVXBncmFkYWJsZSB3aXRoIE93bmFibGUgewogICAgb3duZXI6IEFkZHJlc3M7CiAgICBfdmVyc2lvbjogSW50IGFzIHVpbnQzMjsKCiAgICByZWNlaXZlKG1zZzogVXBncmFkZSkgewogICAgICAgIGxldCBjdHggPSBjb250ZXh0KCk7CiAgICAgICAgc2VsZi52YWxpZGF0ZVVwZ3JhZGUoY3R4LCBtc2cpOwogICAgICAgIHNlbGYudXBncmFkZShjdHgsIG1zZyk7CgogICAgICAgIHNlbGYuX3ZlcnNpb24gKz0gMTsKICAgIH0KCiAgICB2aXJ0dWFsIGlubGluZSBmdW4gdmFsaWRhdGVVcGdyYWRlKF86IENvbnRleHQsIF9fOiBVcGdyYWRlKSB7CiAgICAgICAgc2VsZi5yZXF1aXJlT3duZXIoKTsKICAgIH0KCiAgICB2aXJ0dWFsIGlubGluZSBmdW4gdXBncmFkZShfOiBDb250ZXh0LCBtc2c6IFVwZ3JhZGUpIHsKICAgICAgICBpZiAobXNnLmNvZGUgIT0gbnVsbCkgewogICAgICAgICAgICBzZXRDb2RlKG1zZy5jb2RlISEpOwogICAgICAgIH0KICAgICAgICBpZiAobXNnLmRhdGEgIT0gbnVsbCkgewogICAgICAgICAgICBzZXREYXRhKG1zZy5kYXRhISEpOwogICAgICAgICAgICB0aHJvdygwKTsKICAgICAgICB9CiAgICB9CgogICAgZ2V0IGZ1biBpc1VwZ3JhZGFibGUoKTogQm9vbCB7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgZ2V0IGZ1biB2ZXJzaW9uKCk6IEludCB7CiAgICAgICAgcmV0dXJuIHNlbGYuX3ZlcnNpb247CiAgICB9Cn0KCmFzbSBmdW4gc2V0Q29kZShjb2RlOiBDZWxsKSB7IFNFVENPREUgfQoKYXNtIGZ1biBzZXREYXRhKGRhdGE6IENlbGwpIHsgYzQgUE9QIH0%3D)
---
# Ecosystem overview
> Ecosystem section — a bird-eye overview of the Tact ecosystem, tools, and ways you can start contributing
Welcome to the **Ecosystem** section — a bird-eye overview of the Tact ecosystem, its tools, and the ways you can start contributing to those and beyond!
Here are its main contents:
1. #### Security audits[](#security-audits)
In addition to optimizing gas usage and reducing fees, the security of the Tact ecosystem is of utmost priority. That is why there is a dedicated page for miscellaneous security audits, assessments, and reports for the Tact compiler and Tact smart contracts.
[Go to Security audits ](/ecosystem/security-audits)
2. #### Tools[](#tools)
Tools is a list of official and community-made tools made specifically for Tact or those that interact well with the language and other tools. Each tool has brief usage details and additional information, which sometimes is missing from their respective documentation or is a convenient summary available only in the Tact documentation.
[TypeScript ](/ecosystem/typescript)
[VS Code Extension ](/ecosystem/vscode)
[JetBrains IDEs Plugin ](/ecosystem/jetbrains)
[Misti Static Analyzer ](/ecosystem/misti)
---
# Tact plugin for JetBrains IDEs
> Provides rich support for the Tact language: syntax highlighting, error diagnostics, snippets, hover info, and more
Provides rich support for the Tact language:
* Semantic syntax highlighting
* Code completion, snippets, imports completion
* Go to definition, implementation, type definition
* Find all references, workspace symbol search, symbol renaming
* Types and documentation on hover
* Inlay hints for types, parameter names, and more
* Lenses with usages count and VCS author
* On-the-fly inspections with quick fixes
* Signature help inside calls and `initOf`
* Build single contract or projects from `tact.config.json` via Run configuration
* Formatting with shortcut and on save
Plugin on the JetBrains Marketplace: [Tact](https://plugins.jetbrains.com/plugin/27290-tact)
## Quick start[](#quick-start)
1. Open your JetBrains IDE (IntelliJ IDEA, PyCharm, WebStorm, etc.)
2. Navigate to the **Plugin Marketplace** by selecting `File > Settings/Preferences > Plugins`.
3. In the Plugin Marketplace’s search bar, type “Tact”. You will see a dropdown with the extension provided by `TON Studio`.
4. Click the **Install** button next to the plugin name. Wait for the installation to complete.
5. Once the plugin is installed, you will be prompted to restart your JetBrains IDE. Click the **Restart** button to apply changes.
6. After restarting, the Tact plugin should now be successfully installed in your JetBrains IDE.
## Troubleshooting[](#troubleshooting)
If you encounter issues during the installation process, please consult the [plugin’s GitHub repository](https://github.com/tact-lang/intelli-tact) for solutions and further information.
## References and Resources[](#references-and-resources)
* [Plugin on GitHub](https://github.com/tact-lang/intelli-tact)
* [Plugin on the JetBrains Marketplace](https://plugins.jetbrains.com/plugin/27290-tact)
---
# Misti Static Analyzer
> Static analysis of Tact contracts, custom detectors, and CI/CD integration
[Misti](https://nowarp.io/tools/misti/) is a static program analysis tool that supports Tact.
## What is Misti?[](#what-is-misti)
* **Static Program Analysis**: Misti analyzes code without executing it, scanning for [bugs and security flaws](https://nowarp.io/tools/misti/docs/detectors) by examining its 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.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.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[](#resources)
* [GitHub](https://github.com/nowarp/misti)
* [Telegram Community](https://t.me/misti_dev)
* [Misti Documentation](https://nowarp.io/tools/misti/)
---
# Security audits
> Various security assessments, audits, and reports for the Tact compiler, Tact smart contracts, and other components in the Tact ecosystem
In addition to optimizing gas usage and reducing fees, the security of the Tact ecosystem is paramount. This includes the safety of the Tact compiler, other Tact-related tools, and smart contracts written in Tact.
This page lists various security assessments, audits, and reports for the Tact compiler, Tact smart contracts, and other components in the Tact ecosystem.
## Tact compiler[](#compiler)
### 2025-01: Security Assessment by Trail of Bits[](#202501-trailofbits-tact)
The security audit for Tact 1.5.0 has been completed by [Trail of Bits](https://www.trailofbits.com/), a leading Web3 security firm.
By the end, no high-severity vulnerabilities were found. That said, some bugs and points of improvement were discovered and addressed in a new [Tact 1.5.4 bugfix release](https://www.npmjs.com/package/@tact-lang/compiler/v/1.5.4).
The complete report is available on the Trail of Bits GitHub repository, as well as on the Tact website and its repository as a backup:
* [Original PDF, Trail of Bits repository](https://github.com/trailofbits/publications/blob/master/reviews/2025-01-ton-studio-tact-compiler-securityreview.pdf)
* [Same PDF, Tact website](https://tact-lang.org/assets/pdfs/2025-01-ton-studio-tact-compiler-securityreview.pdf)
* [Same PDF, backup in the website repository](https://github.com/tact-lang/website/blob/416073ed4056034639de257cb1e2815227f497cb/pdfs/2025-01-ton-studio-tact-compiler-securityreview.pdf)
Upgrade to the newest Tact version: [Compiler upgrades](https://docs.tact-lang.org/book/compile/#upgrades).
---
# TypeScript libraries
> The Tact compiler automatically generates wrapper code for use with @ton/ton and @ton/core libraries.
The Tact language has built-in support for the [@ton/ton](https://github.com/ton-org/ton) and [@ton/core](https://github.com/ton-org/ton-core) TypeScript libraries. The compiler automatically generates code for these libraries, so you can use [@tact-lang/emulator](https://github.com/tact-lang/tact-emulator) or [@ton/sandbox](https://github.com/ton-org/sandbox), which work on top of them.
## Tact contract in TypeScript[](#tact-contract-in-typescript)
The compiler generates files named `{project}_{contract}.ts` for each contract in your [project](/book/config#projects), which contain ready-to-use, strongly typed wrappers for working with it in any TypeScript-powered environment: for [testing, debugging, and scripting](/book/debug), [deployments](/book/deploy), etc.
Read more: [TypeScript wrappers on the Compilation page](/book/compile#wrap-ts).
---
# VS Code extension
> Extensive support for the Tact language in Visual Studio Code: syntax highlighting, error diagnostics, snippets, hover info, and more
Provides extensive support for the Tact language in Visual Studio Code (VSCode):
* [Semantic syntax highlighting](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/highlighting.md)
* [Code completion](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/completion.md) with [auto import](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/completion.md#auto-import), [postfix completion](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/completion.md#postfix-completion), snippets, and [imports completion](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/completion.md#imports-completion)
* Go to [definition](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/navigation.md#go-to-definition), implementation, and [type definition](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/navigation.md#go-to-type-definition)
* Find all references, workspace symbol search, and symbol renaming
* Types and documentation on hover
* Inlay hints [for types](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/inlay-hints.md#type-hints), [parameter names](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/inlay-hints.md#parameter-hints), and [more](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/inlay-hints.md#additional-hints)
* On-the-fly inspections with quick fixes
* Signature help inside calls, `initOf`, and struct initialization
* [Lenses](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/code-lenses.md) with implementation/reference counts
* [Gas estimates](https://github.com/tact-lang/tact-language-server/blob/master/docs/manual/features/gas-calculation.md) for assembly functions
* Build and test projects based on Blueprint and Tact Template
* Integration with the Tact compiler and [Misti static analyzer](/ecosystem/misti)
## Quick start[](#quick-start)
Download the extension for VS Code and VSCode-based editors like VSCodium, Cursor, Windsurf, and others:
* Get it on the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=tonstudio.vscode-tact).
* Get it on the [Open VSX Registry](https://open-vsx.org/extension/tonstudio/vscode-tact).
* Or install from the [`.vsix` files in nightly releases](https://github.com/tact-lang/tact-language-server/releases).
For non-VSCode-based editors, install the [Language Server (LSP Server)](https://github.com/tact-lang/tact-language-server). It supports Sublime Text, (Neo)Vim, Helix, and any other editor with LSP support.
## Installation manual for VSCode[](#installation-manual-for-vscode)
1. Open Visual Studio Code (VSCode).
2. Navigate to the Extensions view by clicking on the Extensions icon in the Activity Bar on the side of the window. It looks like a square within a square.
3. In the Extensions view, type “Tact Language”. You should see a dropdown with the extension “Tact Language” provided by [TON Studio](https://tonstudio.io). You’ll see other extensions previously made by the community, but you should use the one from TON Studio, as it is officially supported and developed by the Tact team.
4. Click on the “Install” button next to the extension name. Wait until the installation is complete.
5. Once the extension is installed, you may need to reload VS Code. You might see a Reload button next to the extension. Click this button when it appears.
## References and resources[](#references-and-resources)
* [Extension on GitHub](https://github.com/tact-lang/tact-language-server)
* [Extension on the Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=tonstudio.vscode-tact)
* [Extension on the Open VSX Registry](https://open-vsx.org/extension/tonstudio/vscode-tact)
---
# Addresses
> Various Address functions from the Core library of Tact
`Address` represents a standard [smart contract address](https://docs.ton.org/v3/concepts/dive-into-ton/ton-blockchain/smart-contract-addresses#address-of-smart-contract) on TON Blockchain.
See also:
* [`myAddress()` function in the context and state reference](/ref/core-contextstate#myaddress).
* Address-oriented extension functions for [`Builder`](/book/cells#builders) and [`Slice`](/book/cells#slices) types on their reference page: [Cells, Builders and Slices](/ref/core-cells).
## newAddress[](#newaddress)
500+ gas
```tact
fun newAddress(chain: Int, hash: Int): Address;
```
Creates a new [`Address`](/book/types#primitive-types) based on the [`chain` ID](https://docs.ton.org/learn/overviews/addresses#workchain-id) and the [SHA-256](/ref/core-crypto#sha256) encoded [`hash` value (account ID)](https://docs.ton.org/learn/overviews/addresses#account-id).
This function tries to resolve constant values at [compile-time](/ref/core-comptime) whenever possible.
Attempts to specify an uncommon `chain` ID (not -1 or 0) detectable at [compile-time](/ref/core-comptime) will result in a compilation error.
Usage example:
```tact
let oldTonFoundationAddr: Address =
newAddress(0, 0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
// ↑ ↑
// | SHA-256 hash of contract's init package (StateInit)
// chain ID: 0 is a workchain, -1 is a masterchain
```
Caution
Make sure you specify only supported workchain IDs: 0 for the basechain and -1 for the masterchain.
Useful links:
[`chain` (Workchain ID) in TON Docs](https://docs.ton.org/learn/overviews/addresses#workchain-id)\
[`hash` (Account ID) in TON Docs](https://docs.ton.org/learn/overviews/addresses#account-id)\
[Contract’s init package (`StateInit`)](/book/expressions#initof)
## contractAddress[](#contractaddress)
500+ gas
```tact
fun contractAddress(s: StateInit): Address;
```
Computes the smart contract’s [`Address`](/book/types#primitive-types) in the workchain ID 0 (basechain) using the [`StateInit`](/book/expressions#initof) `s` of the contract. An alias to `contractAddressExt(0, s.code, s.data)`.
Usage example:
```tact
let s: StateInit = initOf SomeContract();
let foundMeSome: Address = contractAddress(s);
let andSomeMore: Address = contractAddressExt(0, s.code, s.data);
foundMeSome == andSomeMore; // true
```
## contractAddressExt[](#contractaddressext)
500+ gas
```tact
fun contractAddressExt(chain: Int, code: Cell, data: Cell): Address;
```
Computes the smart contract’s [`Address`](/book/types#primitive-types) in the given `chain` ID using the contract’s `code` and its initial state `data`. Use the [`initOf`](/book/expressions#initof) expression to obtain the initial `code` and initial `data` of a given contract.
This function lets you specify arbitrary `chain` IDs, including the common -1 (masterchain) and 0 (basechain) ones.
Usage example:
```tact
let initPkg: StateInit = initOf SomeContract();
let hereBeDragons: Address = contractAddressExt(0, initPkg.code, initPkg.data);
```
## contractHash[](#contracthash)
Available since Tact 1.6
```tact
fun contractHash(code: Cell, data: Cell): Int;
```
Computes and returns an [`Int`](/book/integers) value of the [SHA-256](/ref/core-crypto#sha256) hash of the `code` and `data` of the given contract. To assemble the `code` and `data` cells together for hashing, the [standard `Cell` representation](/book/cells#cells-representation) is used.
This hash is commonly called the [account ID](https://docs.ton.org/learn/overviews/addresses#account-id). Together with the [workchain ID](https://docs.ton.org/learn/overviews/addresses#workchain-id), it deterministically forms the address of the contract on TON Blockchain.
Usage example:
```tact
let initPkg: StateInit = initOf SomeContract();
let accountId: Int = contractHash(initPkg.code, initPkg.data);
let basechainAddr: Address = newAddress(0, accountId);
let basechainAddr2: Address = contractAddressExt(0, initPkg.code, initPkg.data);
basechainAddr == basechainAddr2; // true
```
Useful links:
[`chain` (Workchain ID) in TON Docs](https://docs.ton.org/learn/overviews/addresses#workchain-id)\
[`hash` (Account ID) in TON Docs](https://docs.ton.org/learn/overviews/addresses#account-id)\
[Contract’s init package (`StateInit`)](/book/expressions#initof)\
[Standard `Cell` representation](/book/cells#cells-representation)
## forceBasechain[](#forcebasechain)
Available since Tact 1.6.3
```tact
fun forceBasechain(address: Address);
```
Checks whether the `address` is in the basechain, i.e., its [chain ID](https://docs.ton.org/learn/overviews/addresses#workchain-id) is 0. If it is not, throws an exception with [exit code 138](/book/exit-codes#9): `Not a basechain address`.
Usage examples:
```tact
let someBasechainAddress: Address =
newAddress(0, 0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
let someMasterchainAddress: Address =
newAddress(-1, 0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
// Does not throw because the chain ID is 0
forceBasechain(someBasechainAddress);
try {
// Throws because the chain ID is -1 (masterchain)
forceBasechain(someMasterchainAddress);
} catch (exitCode) {
// exitCode is 138
}
```
## forceWorkchain[](#forceworkchain)
Available since Tact 1.6.4
```tact
fun forceWorkchain(address: Address, workchain: Int, errorCode: Int);
```
Parameterized version of [`forceBasechain()`](#forcebasechain).
Checks whether the `address` is in the `workchain`, i.e., its [chain ID](https://docs.ton.org/learn/overviews/addresses#workchain-id) is equal to `workchain`. If it is not, throws an exception with exit code `errorCode`.
Usage examples:
```tact
let someBasechainAddress: Address =
newAddress(0, 0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
let someMasterchainAddress: Address =
newAddress(-1, 0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
// Does not throw because the chain ID matches workchain parameter
forceWorkchain(someBasechainAddress, 0, 593);
forceWorkchain(someMasterchainAddress, -1, 593);
try {
// Throws because the chain ID is 0 which doesn't match the workchain parameter, -1
forceWorkchain(someBasechainAddress, -1, 593);
} catch (exitCode) {
// exitCode is 593
}
```
## parseStdAddress[](#parsestdaddress)
Available since Tact 1.5
```tact
fun parseStdAddress(slice: Slice): StdAddress;
```
Converts a `slice` containing an address into the `StdAddress` [struct](/book/structs-and-messages#structs) and returns it.
The `StdAddress` is a built-in struct that consists of:
| Field | Type | Description |
| :---------- | :--------------------------------- | :--------------------------------------------------------------------- |
| `workchain` | [`Int as int8`](/book/integers) | Workchain ID of the address, usually 0 (basechain) or −1 (masterchain) |
| `address` | [`Int as uint256`](/book/integers) | Address in the specified `workchain` |
Attempts to pass a [`Slice`](/book/cells#slices) that cannot be parsed as a `StdAddress` or to load more data than the given [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let addr = address("EQDtFpEwcFAEcRe5mLVh2N6C0x-_hJEM7W61_JLnSF74p4q2");
let parsedAddr = parseStdAddress(addr.asSlice());
parsedAddr.workchain; // 0
parsedAddr.address; // 107...lots of digits...287
// Using newAddress() function with the contents of StdAddress will yield the initial Address:
let addr2: Address = newAddress(parsedAddr.workchain, parsedAddr.address);
addr2 == addr; // true
```
Note
For parsing addresses of variable length, see the [`parseVarAddress()`](#parsevaraddress) function.
## parseVarAddress[](#parsevaraddress)
Available since Tact 1.5Deprecated since Tact 1.6.8
```tact
fun parseVarAddress(slice: Slice): VarAddress;
```
This function has been deprecated since Tact 1.6.8. Any usages of this function will be reported as an error. `VarAddress` since [TVM 10](https://github.com/ton-blockchain/ton/blob/master/doc/GlobalVersions.md#version-10) is mostly useless as it throws exit code 9 in many cases.
Converts a `slice` containing an address of variable length into the `VarAddress` [struct](/book/structs-and-messages#structs) and returns it.
The `VarAddress` is a built-in struct consisting of:
| Field | Type | Description |
| :---------- | :------------------------------- | :------------------------------------------ |
| `workchain` | [`Int as int32`](/book/integers) | Workchain ID of the variable-length address |
| `address` | [`Slice`](/book/cells#slices) | Address in the specified `workchain` |
Attempts to pass a [`Slice`](/book/cells#slices) that cannot be parsed as a `VarAddress` or to load more data than the given [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let varAddrSlice = beginCell()
.storeUint(6, 3) // to recognize the following as a VarAddress
.storeUint(123, 9) // make address occupy 123 bits
.storeUint(234, 32) // specify workchain ID of 234
.storeUint(345, 123) // specify address of 345
.asSlice();
let parsedVarAddr = parseVarAddress(varAddrSlice);
parsedVarAddr.workchain; // 234
parsedVarAddr.address; // CS{Cell{002...2b3} bits: 44..167; refs: 0..0}
parsedVarAddr.address.loadUint(123); // 345
```
Caution
Variable-length addresses are intended for future extensions, and while validators must be ready to accept them in inbound messages, the standard (non-variable) addresses are used whenever possible.
## StateInit.hasSameBasechainAddress[](#stateinithassamebasechainaddress)
Available since Tact 1.6.1
```tact
extends fun hasSameBasechainAddress(self: StateInit, address: Address): Bool;
```
Extension function for the [`StateInit`](/book/expressions#initof) [struct](/book/structs-and-messages#structs).
Checks if the given `address` corresponds to the contract address in the [workchain ID](https://docs.ton.org/learn/overviews/addresses#workchain-id) 0 (basechain) derived from the [`StateInit`](/book/expressions#initof) `self`. Returns `true` if the addresses match and `false` otherwise.
This function works correctly only for basechain addresses. It may produce false positives or negatives if the specified `address` or the address derived from the `StateInit` `self` has a non-zero workchain ID.
Attempts to pass an [`Address`](/book/types#primitive-types) that cannot be parsed as a [`StdAddress`](#parsestdaddress) throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
```tact
contract Parent() {
receive() {
let childContract = initOf Child(myAddress());
// If you are working with contracts on the basechain, this
let expensiveCheck = contractAddress(childContract) == sender();
// is more expensive than doing this
let cheaperCheck = childContract.hasSameBasechainAddress(sender());
// while the results are the same
expensiveCheck == cheaperCheck; // true
}
}
contract Child(parentAddr: Address) {
receive() {
// Forwards surplus to the parent address by sending a message
// with an empty body and all remaining funds from the received message
cashback(self.parentAddr);
}
}
```
## Address.asSlice[](#addressasslice)
```tact
extends fun asSlice(self: Address): Slice;
```
Extension function for the [`Address`](/book/types#primitive-types) type.
Casts the [`Address`](/book/types#primitive-types) back to the underlying [`Slice`](/book/cells#slices) and returns it. The inverse of [`Slice.asAddressUnsafe()`](/ref/core-cells#sliceasaddressunsafe).
Usage example:
```tact
let a: Address = myAddress();
let fizz: Slice = beginCell().storeAddress(a).asSlice();
let buzz: Slice = a.asSlice(); // cheap, unlike the previous statement
fizz == buzz; // true
```
## Address.toString[](#addresstostring)
500+ gas
```tact
extends fun toString(self: Address): String;
```
Extension function for the [`Address`](/book/types#primitive-types) type.
Returns a [`String`](/book/types#primitive-types) from an [`Address`](/book/types#primitive-types).
Usage example:
```tact
let community: Address = address("UQDpXLZKrkHsOuE_C1aS69C697wE568vTnqSeRfBXZfvmVOo");
let fizz: String = community.toString();
```
## BasechainAddress[](#basechainaddress)
Available since Tact 1.6
```tact
struct BasechainAddress {
hash: Int?;
}
```
Struct representing a basechain address.
A basechain address (workchain 0) can be either empty (null hash) or contain a 256-bit hash value.
## emptyBasechainAddress[](#emptybasechainaddress)
Available since Tact 1.6
```tact
inline fun emptyBasechainAddress(): BasechainAddress;
```
Creates and returns an empty basechain address with a null hash.
When serialized, an empty basechain address is represented as `addr_none`.
Usage example:
```tact
fun example() {
let emptyAddr: BasechainAddress = emptyBasechainAddress();
emptyAddr.hash == null; // true
}
```
## newBasechainAddress[](#newbasechainaddress)
Available since Tact 1.6
```tact
inline fun newBasechainAddress(hash: Int): BasechainAddress;
```
Creates and returns a new basechain address with the specified hash value.
Usage example:
```tact
fun example() {
let addr: BasechainAddress = newBasechainAddress(0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
}
```
## contractBasechainAddress[](#contractbasechainaddress)
Available since Tact 1.6
```tact
inline fun contractBasechainAddress(s: StateInit): BasechainAddress;
```
Creates and returns a basechain address derived from a contract’s `StateInit` (code and data).
Usage example:
```tact
fun example() {
let code: Cell = loadCell(); // load contract code
let data: Cell = loadCell(); // load contract data
let state: StateInit = StateInit { code, data };
let addr: BasechainAddress = contractBasechainAddress(state);
}
```
---
# Base trait
> Every contract and trait in Tact implicitly inherits the BaseTrait trait
Every [contract](/book/contracts) in Tact implicitly [inherits](/book/contracts#traits) the `BaseTrait` trait, which contains a number of [internal functions](/book/contracts#internal-functions) for any contract and a constant `self.storageReserve` aimed at advanced users of Tact.
Tip
Prior to 1.6.0, `BaseTrait` was also implicitly inherited by traits, but now you must explicitly specify `with BaseTrait` for your traits to use it.
## Constants[](#constants)
### self.storageReserve[](#self-storagereserve)
```tact
virtual const storageReserve: Int = 0;
```
Usage example:
```tact
contract AllYourStorageBelongsToUs {
// This would change the behavior of the self.forward() function,
// causing it to try reserving this amount of nanoToncoins before
// forwarding a message with SendRemainingBalance mode
override const storageReserve: Int = ton("0.1");
}
```
## Functions[](#functions)
### self.reply[](#self-reply)
```tact
virtual fun reply(body: Cell?);
```
A similar but more gas-efficient version of calling the [`self.forward()`](#self-forward) function with the following arguments:
```tact
self.forward(sender(), body, true, null);
// ↑ ↑ ↑ ↑
// | | | init: StateInit?
// | | bounce: Bool
// | body: Cell?
// to: Address
```
Usage example:
```tact
// This message can bounce back to us!
self.reply("Beware, this is my reply to you!".asComment());
```
### self.notify[](#self-notify)
```tact
virtual fun notify(body: Cell?);
```
A similar but more gas-efficient version of calling the [`self.forward()`](#self-forward) function with the following arguments:
```tact
self.forward(sender(), body, false, null);
// ↑ ↑ ↑ ↑
// | | | init: StateInit?
// | | bounce: Bool
// | body: Cell?
// to: Address
```
Usage example:
```tact
// This message won't bounce!
self.notify("Beware, this is my reply to you!".asComment());
```
### self.forward[](#self-forward)
```tact
virtual fun forward(to: Address, body: Cell?, bounce: Bool, init: StateInit?);
```
[Queues the message](/book/send#outbound-message-processing) (bounceable or non-bounceable) to be sent to the specified address `to`. Optionally, you may provide a `body` for the message and the [`init` package](/book/expressions#initof).
When the [`self.storageReserve`](#self-storagereserve) constant is overridden to be greater than 0, it also attempts to reserve the `self.storageReserve` amount of [nanoToncoins](/book/integers#nanotoncoin) from the remaining balance before sending the message in the [`SendRemainingBalance`](/book/message-mode#base-modes) (128) mode.
In case the reservation attempt fails, or in the default case without the attempt, the message is sent with the [`SendRemainingValue`](/book/message-mode#base-modes) (64) mode instead.
Note
Note that `self.forward()` never sends additional [nanoToncoins](/book/integers#nanotoncoin) on top of what’s available in the balance.\
To send more [nanoToncoins](/book/integers#nanotoncoin) with a single message, use the [`send()`](/ref/core-send#send) function.
Usage example:
```tact
import "@stdlib/ownable";
message PayoutOk {
address: Address;
value: Int as coins;
}
contract Payout with Ownable {
completed: Bool;
owner: Address;
init(owner: Address) {
self.owner = owner;
self.completed = false;
}
// ... some actions here ...
// Bounced receiver function, which is called when the specified outgoing message bounces back
bounced(msg: bounced) {
// Reset completed flag if our message bounced
self.completed = false;
// Send a notification that the payout failed, using the remaining funds to process this send
self.forward(self.owner, "Payout failed".asComment(), false, null);
}
}
```
---
# Cells, Builders and Slices
> Various Cell, Builder, and Slice functions from the Core library of Tact
[`Cell`](/book/cells#cells) is a low-level [primitive](/book/types#primitive-types) that represents data in TON Blockchain. Cells consist of 1023 bits of data with up to 4 references to other cells. They are read-only and immutable, and cannot have cyclic references.
[`Builder`](/book/cells#builders) is an immutable [primitive](/book/types#primitive-types) to construct cells, and [`Slice`](/book/cells#slices) is a mutable [primitive](/book/types#primitive-types) to parse them.
Note
Be very careful when constructing and parsing cells manually, and always make sure to document their desired layout: a strict order of values and types for serialization and deserialization.
To do so, advanced users are recommended to use [Type Language - Binary (TL-B) schemas](https://docs.ton.org/develop/data-formats/tl-b-language).
Additionally, every user is recommended to use [structs](/book/structs-and-messages#structs) and their [methods](/book/functions#extensions), such as [`Struct.toCell()`](#structtocell) and [`Struct.fromCell()`](#structfromcell), instead of manually constructing and parsing cells, because structs and [Messages](/book/structs-and-messages#messages) are closest to being the [living TL-B schemas of your contracts](/book/cells#cnp-structs).
## beginCell[](#begincell)
```tact
fun beginCell(): Builder;
```
Creates a new empty [`Builder`](/book/cells#builders).
Usage example:
```tact
let fizz: Builder = beginCell();
```
## emptyCell[](#emptycell)
```tact
fun emptyCell(): Cell;
```
Creates and returns an empty [`Cell`](/book/cells#cells) (without data and references). An alias to `beginCell().endCell()`.
Usage example:
```tact
let fizz: Cell = emptyCell();
let buzz: Cell = beginCell().endCell();
fizz == buzz; // true
```
## emptySlice[](#emptyslice)
```tact
fun emptySlice(): Slice;
```
Creates and returns an empty [`Slice`](/book/cells#slices) (without data and references). An alias to `emptyCell().asSlice()`.
Usage example:
```tact
let fizz: Slice = emptySlice();
let buzz: Slice = emptyCell().asSlice();
fizz == buzz; // true
```
## Cell[](#cell)
A section to group all extension and extension mutation functions for the [`Cell`](/book/cells#cells) type.
### Cell.beginParse[](#cellbeginparse)
```tact
extends fun beginParse(self: Cell): Slice;
```
Extension function for the [`Cell`](/book/cells#cells) type.
Opens the [`Cell`](/book/cells#cells) for parsing and returns it as a [`Slice`](/book/cells#slices).
Usage example:
```tact
let c: Cell = emptyCell();
let fizz: Slice = c.beginParse();
```
### Cell.depth[](#celldepth)
Available since Tact 1.6
```tact
extends fun depth(self: Cell?): Int;
```
Extension function for the [`Cell`](/book/cells#cells) type.
Computes and returns the [`Int`](/book/integers) [depth](/book/cells#cells-representation) of the [`Cell`](/book/cells#cells). Produces 0 if the [`Cell`](/book/cells#cells) has no references. Otherwise, it returns 1 plus the maximum of the depths of the referenced cells. If `self` is [`null`](/book/optionals), returns 0.
Usage example:
```tact
let c: Cell = beginCell().storeInt(42, 7).endCell();
let depth: Int = c.depth(); // 0
```
### Cell.computeDataSize[](#cellcomputedatasize)
500+ gas Available since Tact 1.6
```tact
extends fun computeDataSize(self: Cell?, maxCells: Int): DataSize;
```
Extension function for the [`Cell`](/book/cells#cells) type.
Computes and returns the number of distinct cells, bits, and refs in the [`Cell`](/book/cells#cells) by using a [depth-first search (DFS)](https://en.wikipedia.org/wiki/Depth-first_search) algorithm, recursively traversing each referenced cell. This function is computationally expensive and can consume a lot of [gas](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees#gas). If `self` is [`null`](/book/optionals), returns a `DataSize` with all fields set to 0.
The results are packed into a `DataSize` [struct](/book/structs-and-messages#structs) consisting of:
| Field | Type | Description |
| :------ | :---------------------- | :----------------------------------------------------------------------- |
| `cells` | [`Int`](/book/integers) | The total number of nested cells, including the starting one |
| `bits` | [`Int`](/book/integers) | The total number of bits in all nested cells, including the starting one |
| `refs` | [`Int`](/book/integers) | The total number of refs in all nested cells, including the starting one |
If the specified `maxCells` value is insufficient to traverse all cells including the starting one, an exception with [exit code 8](/book/exit-codes#8) is thrown: `Cell overflow`.
Attempts to specify a negative value for `maxCells` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let c: Cell = beginCell().storeInt(42, 7).storeRef(emptyCell()).endCell();
try {
let dataSize: DataSize = c.computeDataSize(2);
dataSize.cells; // 2
dataSize.bits; // 7
dataSize.refs; // 1
} catch (exitCode) {
// if maxCells was insufficient to traverse the cell
// and all of its references, the exitCode here would be 8
}
```
### Cell.hash[](#cellhash)
```tact
extends fun hash(self: Cell): Int;
```
Extension function for the [`Cell`](/book/cells#cells) type.
Calculates and returns an [`Int`](/book/integers) value of the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of the [standard `Cell` representation](/book/cells#cells-representation) of the given [`Cell`](/book/cells#cells).
Usage example:
```tact
let c: Cell = emptyCell();
let fizz: Int = c.hash();
```
### Cell.asSlice[](#cellasslice)
```tact
extends fun asSlice(self: Cell): Slice;
```
Extension function for the [`Cell`](/book/cells#cells) type.
Converts the Cell to a [`Slice`](/book/cells#slices) and returns it. An alias to `self.beginParse()`.
Usage example:
```tact
let c: Cell = emptyCell();
let fizz: Slice = c.asSlice();
```
## Builder[](#builder)
A section to group all extension and extension mutation functions for the [`Builder`](/book/cells#builders) type.
### Builder.endCell[](#builderendcell)
500+ gas
```tact
extends fun endCell(self: Builder): Cell;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Converts a [`Builder`](/book/cells#builders) into an ordinary [`Cell`](/book/cells#cells).
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Cell = b.endCell();
```
### Builder.storeUint[](#builderstoreuint)
```tact
extends fun storeUint(self: Builder, value: Int, bits: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores an unsigned `bits`-bit `value` into the copy of the [`Builder`](/book/cells#builders) for 0 ≤ `bits` ≤ 256. Returns that copy.
Attempts to store a negative `value` or provide an insufficient or out-of-bounds `bits` number throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeUint(42, 6);
```
### Builder.storeInt[](#builderstoreint)
```tact
extends fun storeInt(self: Builder, value: Int, bits: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores a signed `bits`-bit `value` into the copy of the [`Builder`](/book/cells#builders) for 0 ≤ `bits` ≤ 257. Returns that copy.
Attempts to provide an insufficient or out-of-bounds `bits` number throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeInt(42, 7);
```
### Builder.storeBool[](#builderstorebool)
```tact
extends fun storeBool(self: Builder, value: Bool): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores a [`Bool`](/book/types#booleans) `value` into the copy of the [`Builder`](/book/cells#builders). Writes 1 as a single bit if `value` is `true`, and writes 0 otherwise. Returns that copy of the [`Builder`](/book/cells#builders).
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeBool(true); // writes 1
let buzz: Builder = b.storeBool(false); // writes 0
```
### Builder.storeBit[](#builderstorebit)
Available since Tact 1.5
```tact
extends fun storeBit(self: Builder, value: Bool): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
An alias to [`Builder.storeBool()`](#builderstorebool).
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeBit(true); // writes 1
let buzz: Builder = b.storeBit(false); // writes 0
```
### Builder.storeBuilder[](#builderstorebuilder)
```tact
extends fun storeBuilder(self: Builder, other: Builder): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Appends all data from the `other` builder to the copy of the `self` builder. Returns that copy.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
fun example(op: Int, queryId: Int, payload: Builder) {
let msgBody = beginCell().storeUint(op, 32).storeUint(queryId, 64);
if (payload.bits() != 0) {
msgBody = msgBody.storeBuilder(payload); // assignment is important here
}
}
```
### Builder.storeSlice[](#builderstoreslice)
```tact
extends fun storeSlice(self: Builder, slice: Slice): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores a `slice` into a copy of the [`Builder`](/book/cells#builders). Returns that copy.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let s: Slice = emptyCell().asSlice();
let fizz: Builder = b.storeSlice(s);
```
### Builder.storeCoins[](#builderstorecoins)
```tact
extends fun storeCoins(self: Builder, value: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores (serializes) an unsigned [`Int`](/book/integers) `value` in the range from 0 to 2120−1 inclusive into a copy of the [`Builder`](/book/cells#builders). The serialization of `value` consists of a 4-bit unsigned big-endian integer l, which is the smallest integer l≥0 such that `value` <28∗l, followed by an 8∗l-bit unsigned big-endian representation of `value`. Returns that copy of the [`Builder`](/book/cells#builders).
Attempts to store an out-of-bounds `value` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
This is the most common way of storing [nanoToncoins](/book/integers#nanotoncoin).
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeCoins(42);
```
Useful links:
[Special `coins` serialization type](/book/integers#serialization-varint)
### Builder.storeVarUint16[](#builderstorevaruint16)
Available since Tact 1.6
```tact
extends fun storeVarUint16(self: Builder, value: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
An alias to [`Builder.storeCoins()`](#builderstorecoins).
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeVarUint16(42);
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Builder.storeVarInt16[](#builderstorevarint16)
Available since Tact 1.6
```tact
extends fun storeVarInt16(self: Builder, value: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Similar to [`Builder.storeCoins()`](#builderstorecoins), but with a different `value` range: from −2119 to 2119−1 inclusive.
Attempts to store an out-of-bounds `value` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeVarInt16(-42);
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Builder.storeVarUint32[](#builderstorevaruint32)
Available since Tact 1.6
```tact
extends fun storeVarUint32(self: Builder, value: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores (serializes) an unsigned [`Int`](/book/integers) `value` in the range from 0 to 2248−1 inclusive into a copy of the [`Builder`](/book/cells#builders). The serialization of `value` consists of a 5-bit unsigned big-endian integer l, which is the smallest integer l≥0 such that `value` <28∗l, followed by an 8∗l-bit unsigned big-endian representation of `value`. Returns that copy of the [`Builder`](/book/cells#builders).
Attempts to store an out-of-bounds `value` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeVarUint32(420000);
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Builder.storeVarInt32[](#builderstorevarint32)
Available since Tact 1.6
```tact
extends fun storeVarInt32(self: Builder, value: Int): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Similar to [`Builder.storeVarUint32()`](#builderstorevaruint32), but with a different `value` range: from −2247 to 2247−1 inclusive.
Attempts to store an out-of-bounds `value` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeVarInt32(-420000);
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Builder.storeAddress[](#builderstoreaddress)
```tact
extends fun storeAddress(self: Builder, address: Address): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores the `address` in a copy of the [`Builder`](/book/cells#builders). Returns that copy.
Attempts to store an `address` into the [`Builder`](/book/cells#builders) `self`, if `self` cannot fit it, throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeAddress(myAddress());
```
### Builder.storeBasechainAddress[](#builderstorebasechainaddress)
Available since Tact 1.6
```tact
extends fun storeBasechainAddress(self: Builder, address: BasechainAddress): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores the basechain `address` in the copy of the [`Builder`](/book/cells#builders) and returns that copy.
If the address has a `null` hash, stores two zero bits `0b00` (`addr_none`). Otherwise, stores the full address with the three-bit prefix `0b100`, followed by the 8-bit workchain ID set to 0 and the 256-bit hash.
Attempts to store more data than the [`Builder`](/book/cells#builders) `self` can fit throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
fun example() {
let addr: BasechainAddress = newBasechainAddress(0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
let b: Builder = beginCell();
let b2: Builder = b.storeBasechainAddress(addr);
}
```
### Builder.storeRef[](#builderstoreref)
```tact
extends fun storeRef(self: Builder, cell: Cell): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Stores a reference `cell` into a copy of the [`Builder`](/book/cells#builders). Returns that copy.
As a single [`Cell`](/book/cells#cells) can store up to 4 references, attempts to store more throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b.storeRef(emptyCell());
```
### Builder.storeMaybeRef[](#builderstoremayberef)
Available since Tact 1.5
```tact
extends fun storeMaybeRef(self: Builder, cell: Cell?): Builder;
```
Extension function for the [`Builder`](/book/cells#builders) type.
If the `cell` is not `null`, stores 1 as a single bit and then a reference to `cell` into a copy of the [`Builder`](/book/cells#builders). Returns that copy.
If the `cell` is `null`, stores only 0 as a single bit into the copy of the [`Builder`](/book/cells#builders). Returns that copy.
As a single [`Cell`](/book/cells#cells) can store up to 4 references, attempts to store more throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Builder = b
.storeMaybeRef(emptyCell()) // stores a single 1 bit, then an empty cell
.storeMaybeRef(null); // stores only a single 0 bit
```
### Builder.refs[](#builderrefs)
```tact
extends fun refs(self: Builder): Int;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Returns the number of cell references already stored in the [`Builder`](/book/cells#builders) as an [`Int`](/book/integers).
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Int = b.refs(); // 0
```
### Builder.bits[](#builderbits)
```tact
extends fun bits(self: Builder): Int;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Returns the number of data bits already stored in the [`Builder`](/book/cells#builders) as an [`Int`](/book/integers).
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Int = b.bits(); // 0
```
### Builder.depth[](#builderdepth)
Available since Tact 1.6
```tact
extends fun depth(self: Builder): Int;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Computes and returns the [`Int`](/book/integers) [depth](/book/cells#cells-representation) of the [`Builder`](/book/cells#builders). Produces 0 if the [`Builder`](/book/cells#builders) has no references stored so far, otherwise 1 plus the maximum depth of the referenced cells.
Usage example:
```tact
let b: Builder = beginCell().storeInt(42, 7);
let depth: Int = b.depth(); // 0
```
### Builder.asSlice[](#builderasslice)
```tact
extends fun asSlice(self: Builder): Slice;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Converts the [`Builder`](/book/cells#builders) into a [`Slice`](/book/cells#slices) and returns it. An alias to `self.endCell().beginParse()`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Slice = b.asSlice();
```
### Builder.asCell[](#builderascell)
```tact
extends fun asCell(self: Builder): Cell;
```
Extension function for the [`Builder`](/book/cells#builders) type.
Converts the [`Builder`](/book/cells#builders) into a [`Cell`](/book/cells#cells) and returns it. An alias to `self.endCell()`.
Usage example:
```tact
let b: Builder = beginCell();
let fizz: Cell = b.asCell();
```
## Slice[](#slice)
A section to group all extension and extension mutation functions for the [`Slice`](/book/cells#slices) type.
### Slice.loadUint[](#sliceloaduint)
```tact
extends mutates fun loadUint(self: Slice, l: Int): Int;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads and returns an unsigned `l`-bit [`Int`](/book/integers) from the [`Slice`](/book/cells#slices), for 0≤l≤256.
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeUint(42, 7).asSlice();
let fizz: Int = s.loadUint(7);
```
### Slice.preloadUint[](#slicepreloaduint)
```tact
extends fun preloadUint(self: Slice, l: Int): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads and returns an unsigned `l`-bit [`Int`](/book/integers) from the [`Slice`](/book/cells#slices), for 0≤l≤256. Doesn’t modify the [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeUint(42, 7).asSlice();
let fizz: Int = s.preloadUint(7);
```
### Slice.loadInt[](#sliceloadint)
```tact
extends mutates fun loadInt(self: Slice, l: Int): Int;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads and returns a signed `l`-bit [`Int`](/book/integers) from the [`Slice`](/book/cells#slices), for 0≤l≤257.
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let fizz: Int = s.loadInt(7);
```
### Slice.preloadInt[](#slicepreloadint)
```tact
extends fun preloadInt(self: Slice, l: Int): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads and returns a signed `l`-bit [`Int`](/book/integers) from the [`Slice`](/book/cells#slices), for 0≤l≤257. Doesn’t modify the [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let fizz: Int = s.preloadInt(7);
```
### Slice.loadBits[](#sliceloadbits)
```tact
extends mutates fun loadBits(self: Slice, l: Int): Slice;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads 0≤ `l` ≤1023 bits from the [`Slice`](/book/cells#slices) and returns them as a separate [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let fizz: Slice = s.loadBits(7);
```
### Slice.preloadBits[](#slicepreloadbits)
```tact
extends fun preloadBits(self: Slice, l: Int): Slice;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads 0≤ `l` ≤1023 bits from the [`Slice`](/book/cells#slices) and returns them as a separate [`Slice`](/book/cells#slices). Doesn’t modify the original [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let fizz: Slice = s.preloadBits(7);
```
Note
In order to reduce gas usage, prefer using this function over calling [`Slice.firstBits()`](#slicefirstbits), since the latter is less optimized.
### Slice.skipBits[](#sliceskipbits)
```tact
extends mutates fun skipBits(self: Slice, l: Int);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads all but the first 0≤ `l` ≤1023 bits from the [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `l` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
s.skipBits(5); // all but first 5 bits
let fizz: Slice = s.loadBits(1); // load only 1 bit
```
### Slice.skipLastBits[](#sliceskiplastbits)
Available since Tact 1.6
```tact
extends fun skipLastBits(self: Slice, len: Int);
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads all but the last 0≤ `len` ≤1023 bits from the [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `len` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let allButLastFive: Slice = s.skipLastBits(5); // all but last 5 bits,
// i.e. only the first 2
```
### Slice.loadBool[](#sliceloadbool)
```tact
extends mutates fun loadBool(self: Slice): Bool;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads a single bit and returns a [`Bool`](/book/types#booleans) value from the [`Slice`](/book/cells#slices). Reads `true` if the loaded bit is equal to 1, and reads `false` otherwise.
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeBool(true).asSlice();
let fizz: Bool = s.loadBool(); // true
```
### Slice.skipBool[](#sliceskipbool)
Available since Tact 1.6.2
```tact
extends mutates fun skipBool(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Skips a single bit from the [`Slice`](/book/cells#slices). Similar to discarding the return value of `Slice.loadBool()`.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell()
.storeBool(true)
.storeUint(42, 7)
.asSlice();
s.skipBool();
let fizz: Int = s.loadUint(7); // 42
```
### Slice.loadBit[](#sliceloadbit)
Available since Tact 1.5
```tact
extends mutates fun loadBit(self: Slice): Bool;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
An alias to [`Slice.loadBool()`](#sliceloadbool).
Usage example:
```tact
let s: Slice = beginCell().storeBit(true).asSlice();
let fizz: Bool = s.loadBit(); // true
```
### Slice.loadCoins[](#sliceloadcoins)
```tact
extends mutates fun loadCoins(self: Slice): Int;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads and returns a [serialized](#builderstorecoins) unsigned [`Int`](/book/integers) value in the range from 0 to 2120−1 inclusive from the [`Slice`](/book/cells#slices). This value usually represents the amount in [nanoToncoins](/book/integers#nanotoncoin).
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeCoins(42).asSlice();
let fizz: Int = s.loadCoins(); // 42
```
Useful links:
[Special `coins` serialization type](/book/integers#serialization-varint)
### Slice.skipCoins[](#sliceskipcoins)
Available since Tact 1.6.2
```tact
extends mutates fun skipCoins(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Skips a serialized unsigned [`Int`](/book/integers) value in the range from 0 to 2120−1 inclusive from the [`Slice`](/book/cells#slices). Similar to discarding the return value of `Slice.loadCoins()`.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell()
.storeCoins(239)
.storeUint(42, 7)
.asSlice();
s.skipCoins();
let fizz: Int = s.loadUint(7); // 42
```
### Slice.loadVarUint16[](#sliceloadvaruint16)
Available since Tact 1.6
```tact
extends mutates fun loadVarUint16(self: Slice): Int;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
An alias to [`Slice.loadCoins()`](#sliceloadcoins).
Usage example:
```tact
let s: Slice = beginCell().storeVarUint16(42).asSlice();
let fizz: Int = s.loadVarUint16(); // 42
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Slice.skipVarUint16[](#sliceskipvaruint16)
Available since Tact 1.6.2
```tact
extends mutates fun skipVarUint16(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Alias to `Slice.skipCoins()`.
Usage example:
```tact
let s: Slice = beginCell()
.storeVarUint16(239)
.storeUint(42, 7)
.asSlice();
s.skipVarUint16();
let fizz: Int = s.loadUint(7); // 42
```
### Slice.loadVarInt16[](#sliceloadvarint16)
Available since Tact 1.6
```tact
extends mutates fun loadVarInt16(self: Slice): Int;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Similar to [`Slice.loadCoins()`](#sliceloadcoins), but with a different `value` range: from −2119 to 2119−1 inclusive.
Attempts to load more data than [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeVarInt16(-42).asSlice();
let fizz: Int = s.loadVarInt16(); // -42
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Slice.skipVarInt16[](#sliceskipvarint16)
Available since Tact 1.6.2
```tact
extends mutates fun skipVarInt16(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Similar to `Slice.skipCoins()`, but with a different `value` range: from −2119 to 2119−1 inclusive.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell()
.storeVarInt16(-239)
.storeUint(42, 7)
.asSlice();
s.skipVarInt16();
let fizz: Int = s.loadUint(7); // 42
```
### Slice.loadVarUint32[](#sliceloadvaruint32)
Available since Tact 1.6
```tact
extends mutates fun loadVarUint32(self: Slice): Int;
```
Loads and returns a [serialized](#builderstorevaruint32) unsigned [`Int`](/book/integers) value in the range from 0 to 2248−1 inclusive from the [`Slice`](/book/cells#slices).
Attempts to load more data than [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeVarUint32(420000).asSlice();
let fizz: Int = s.loadVarUint32(); // 420000
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Slice.skipVarUint32[](#sliceskipvaruint32)
Available since Tact 1.6.2
```tact
extends mutates fun skipVarUint32(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Skips a serialized unsigned [`Int`](/book/integers) value in the range from 0 to 2248−1 inclusive from the [`Slice`](/book/cells#slices). Similar to discarding the return value of `Slice.loadVarUint32()`.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell()
.storeVarUint32(239)
.storeUint(42, 7)
.asSlice();
s.skipVarUint32();
let fizz: Int = s.loadUint(7); // 42
```
### Slice.loadVarInt32[](#sliceloadvarint32)
Available since Tact 1.6
```tact
extends mutates fun loadVarInt32(self: Slice): Int;
```
Similar to [`Slice.loadVarUint32()`](#sliceloadvaruint32), but with a different `value` range: from −2247 to 2247−1 inclusive.
Attempts to load more data than [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeVarInt32(-420000).asSlice();
let fizz: Int = s.loadVarInt32(); // -420000
```
Useful links:
[Types of variable bit-width](/book/integers#serialization-varint)
### Slice.skipVarInt32[](#sliceskipvarint32)
Available since Tact 1.6.2
```tact
extends mutates fun skipVarInt32(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Similar to `Slice.skipVarUint32()`, but with a different `value` range: from −2247 to 2247−1 inclusive.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell()
.storeVarInt32(-239)
.storeUint(42, 7)
.asSlice();
s.skipVarInt32();
let fizz: Int = s.loadUint(7); // 42
```
### Slice.loadAddress[](#sliceloadaddress)
```tact
extends mutates fun loadAddress(self: Slice): Address;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads and returns an [`Address`](/book/types#primitive-types) from the [`Slice`](/book/cells#slices).
Attempts to load more data than [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeAddress(myAddress()).asSlice();
let fizz: Address = s.loadAddress();
```
### Slice.skipAddress[](#sliceskipaddress)
Available since Tact 1.6.2
```tact
extends mutates fun skipAddress(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Skips an [`Address`](/book/types#primitive-types) from the [`Slice`](/book/cells#slices).
Attempts to skip more data than [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s1: Slice = beginCell()
.storeAddress(myAddress())
.storeUint(42, 32)
.asSlice();
s1.skipAddress();
let fizz: Int = s1.loadUint(32); // 42
```
### Slice.loadRef[](#sliceloadref)
```tact
extends mutates fun loadRef(self: Slice): Cell;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads the next reference from the [`Slice`](/book/cells#slices) as a [`Cell`](/book/cells#cells).
Attempts to load more data than [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
let s1: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Cell = s1.loadRef();
let s2: Slice = beginCell()
.storeRef(emptyCell())
.storeRef(s1.asCell())
.asSlice();
let ref1: Cell = s2.loadRef();
let ref2: Cell = s2.loadRef();
ref1 == ref2; // false
```
### Slice.preloadRef[](#slicepreloadref)
```tact
extends fun preloadRef(self: Slice): Cell;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads the next reference from the [`Slice`](/book/cells#slices) as a [`Cell`](/book/cells#cells). Doesn’t modify the original [`Slice`](/book/cells#slices).
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
let s1: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Cell = s1.preloadRef(); // doesn't modify s1
let s2: Slice = beginCell()
.storeRef(emptyCell())
.storeRef(s1.asCell())
.asSlice();
let ref1: Cell = s2.preloadRef();
let ref2: Cell = s2.preloadRef();
ref1 == ref2; // true
```
### Slice.skipRef[](#sliceskipref)
Available since Tact 1.6.2
```tact
extends mutates fun skipRef(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Skips the next reference from the [`Slice`](/book/cells#slices). Similar to discarding the return value of `Slice.loadRef()`.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s1: Slice = beginCell()
.storeRef(emptyCell())
.storeUint(42, 32)
.asSlice();
s1.skipRef();
let fizz: Int = s1.loadUint(32); // 42
```
### Slice.loadMaybeRef[](#sliceloadmayberef)
Available since Tact 1.6
```tact
extends mutates fun loadMaybeRef(self: Slice): Cell?;
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Loads a single bit from the [`Slice`](/book/cells#slices): if it’s 1, the referenced [`Cell`](/book/cells#cells) is loaded and returned. If the loaded bit is 0, nothing else is loaded and `null` is returned.
Attempts to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s = msg.asSlice();
let outActions = s.loadMaybeRef();
if (outActions != null) {
let actions = outActions!!;
// process actions
}
```
### Slice.preloadMaybeRef[](#slicepreloadmayberef)
Available since Tact 1.6
```tact
extends fun preloadMaybeRef(self: Slice): Cell?;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads a single bit from the [`Slice`](/book/cells#slices): if it’s 1, the referenced [`Cell`](/book/cells#cells) is preloaded and returned. If the preloaded bit is 0, `null` is returned. Doesn’t modify the original [`Slice`](/book/cells#slices).
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
let s1: Slice = beginCell().storeMaybeRef(emptyCell()).asSlice();
let fizz: Cell = s1.preloadMaybeRef(); // returns emptyCell() and doesn't modify s1
let s2: Slice = beginCell()
.storeMaybeRef(null)
.storeMaybeRef(s1.asCell())
.asSlice();
let ref1: Cell = s2.preloadMaybeRef(); // returns null and doesn't modify s2
let ref2: Cell = s2.preloadMaybeRef(); // same effect
ref1 == null; // true
ref1 == ref2; // true
```
### Slice.skipMaybeRef[](#sliceskipmayberef)
Available since Tact 1.6.2
```tact
extends mutates fun skipMaybeRef(self: Slice);
```
Extension mutation function for the [`Slice`](/book/cells#slices) type.
Skips `Cell?` from the [`Slice`](/book/cells#slices). Similar to discarding the return value of `Slice.loadMaybeRef()`.
Attempts to skip more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s1: Slice = beginCell()
.storeMaybeRef(emptyCell())
.storeUint(42, 32)
.asSlice();
s1.skipMaybeRef();
let fizz: Int = s1.loadUint(32); // 42
```
### Slice.refs[](#slicerefs)
```tact
extends fun refs(self: Slice): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Returns the number of references in the [`Slice`](/book/cells#slices) as an [`Int`](/book/integers).
Usage example:
```tact
let s: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Int = s.refs();
```
### Slice.bits[](#slicebits)
```tact
extends fun bits(self: Slice): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Returns the number of data bits in the [`Slice`](/book/cells#slices) as an [`Int`](/book/integers).
Usage example:
```tact
let s: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Int = s.bits();
```
### Slice.firstBits[](#slicefirstbits)
Available since Tact 1.6
```tact
extends fun firstBits(self: Slice, len: Int): Slice;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads the first 0≤ `len` ≤1023 bits from the [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `len` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let firstFive: Slice = s.firstBits(5); // first 5 bits
```
Note
In order to reduce gas usage, prefer calling [`Slice.preloadBits()`](#slicepreloadbits) over using this function, since the former is more optimized.
### Slice.lastBits[](#slicelastbits)
Available since Tact 1.6
```tact
extends fun lastBits(self: Slice, len: Int): Slice;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Preloads the last 0≤ `len` ≤1023 bits from the [`Slice`](/book/cells#slices).
Attempts to specify an out-of-bounds `len` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to preload more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let lastFive: Slice = s.lastBits(5); // last 5 bits
```
### Slice.depth[](#slicedepth)
Available since Tact 1.6
```tact
extends fun depth(self: Slice): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Computes and returns the [`Int`](/book/integers) [depth](/book/cells#cells-representation) of the [`Slice`](/book/cells#slices). Produces 0 if the [`Slice`](/book/cells#slices) has no references. Otherwise, it returns 1 plus the maximum of the depths of the referenced cells.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let depth: Int = s.depth(); // 0
```
### Slice.computeDataSize[](#slicecomputedatasize)
500+ gas Available since Tact 1.6
```tact
extends fun computeDataSize(self: Slice, maxCells: Int): DataSize;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Similar to [`Cell.computeDataSize()`](#cellcomputedatasize), but does not take into account the cell that contains the [`Slice`](/book/cells#slices) itself. However, it accounts for its bits and refs.
The results are packed into a `DataSize` [struct](/book/structs-and-messages#structs) consisting of:
| Field | Type | Description |
| :------ | :---------------------- | :----------------------------------------------------------------------- |
| `cells` | [`Int`](/book/integers) | The total number of nested cells, including the starting one |
| `bits` | [`Int`](/book/integers) | The total number of bits in all nested cells, including the starting one |
| `refs` | [`Int`](/book/integers) | The total number of refs in all nested cells, including the starting one |
If the specified `maxCells` value is insufficient to traverse all cells **not** including the starting one, an exception with [exit code 8](/book/exit-codes#8) is thrown: `Cell overflow`.
Attempts to specify a negative value for `maxCells` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let s: Slice = beginCell().storeInt(42, 7).storeRef(emptyCell()).asSlice();
try {
let dataSize: DataSize = s.computeDataSize(1);
dataSize.cells; // 1
dataSize.bits; // 7
dataSize.refs; // 1
} catch (exitCode) {
// if maxCells was insufficient to traverse the cell
// and all of its references, the exitCode here would be 8
}
```
### Slice.empty[](#sliceempty)
```tact
extends fun empty(self: Slice): Bool;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Checks whether the [`Slice`](/book/cells#slices) is empty (i.e., contains no bits of data and no cell references). Returns `true` if it is empty, `false` otherwise.
Usage example:
```tact
let s: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Bool = s.empty(); // false
let buzz: Bool = beginCell().asSlice().empty(); // true
```
Note
Unlike [`Slice.endParse()`](#sliceendparse), this function does not throw any exceptions, even when the [`Slice`](/book/cells#slices) is empty.
### Slice.dataEmpty[](#slicedataempty)
```tact
extends fun dataEmpty(slice: Slice): Bool;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Checks whether the [`Slice`](/book/cells#slices) has no bits of data. Returns `true` if it has no data, `false` otherwise.
Usage example:
```tact
let s: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Bool = s.dataEmpty(); // true
let s2: Slice = beginCell().storeInt(42, 7).asSlice();
let buzz: Bool = s2.dataEmpty(); // false
```
### Slice.refsEmpty[](#slicerefsempty)
```tact
extends fun refsEmpty(slice: Slice): Bool;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Checks whether the [`Slice`](/book/cells#slices) has no references. Returns `true` if it has no references, `false` otherwise.
Usage example:
```tact
let s: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Bool = s.refsEmpty(); // false
let buzz: Bool = beginCell().asSlice().refsEmpty(); // true
```
### Slice.endParse[](#sliceendparse)
```tact
extends fun endParse(self: Slice);
```
Extension function for the [`Slice`](/book/cells#slices) type.
Checks whether the [`Slice`](/book/cells#slices) is empty (i.e., contains no bits of data and no cell references). If it is not, it throws an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
let emptyOne: Slice = emptySlice();
emptyOne.endParse(); // nothing, as it's empty
let paul: Slice = "Fear is the mind-killer".asSlice();
try {
paul.endParse(); // throws exit code 9
}
```
### Slice.hash[](#slicehash)
500+ gas
```tact
extends fun hash(self: Slice): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Calculates and returns an [`Int`](/book/integers) value of the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of the [standard `Cell` representation](/book/cells#cells-representation) of the given [`Slice`](/book/cells#slices).
Usage example:
```tact
let s: Slice = beginCell().asSlice();
let fizz: Int = s.hash();
```
### Slice.hashData[](#slicehashdata)
Available since Tact 1.6
```tact
extends fun hashData(self: Slice): Int;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Calculates and returns an [`Int`](/book/integers) value of the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of the data bits from the given [`Slice`](/book/cells#slices), which should have a number of bits divisible by 8.
Unlike [`sha256()`](/ref/core-crypto#sha256), this function is gas-efficient and **only** hashes the data of the given [`Slice`](/book/cells#slices), i.e. up to 1023 bits, ignoring the refs.
Attempts to specify a [`Slice`](/book/cells#slices) with a number of bits **not** divisible by 8 throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
// Base64-encoded BoC with "Hello, World!"
let short: Slice = slice("te6cckEBAQEADgAAGEhlbGxvIHdvcmxkIXgtxbw=");
// It's enough to only take the hash of the data
sha256(short) == short.hashData(); // true
// But if we construct a slice larger than 1023 bits with all refs combined,
// we must use sha256() or we'll get skewed results or even collisions
let tmp: Builder = beginCell();
repeat (127) { tmp = tmp.storeUint(69, 8) } // storing 127 bytes
let ref: Cell = beginCell().storeUint(33, 8).endCell();
let long: Slice = tmp.storeRef(ref).asSlice(); // plus a ref with a single byte
// Hashing just the data bits in the current slice isn't enough
sha256(long) == long.hashData(); // false!
```
### Slice.asCell[](#sliceascell)
500+ gas
```tact
extends fun asCell(self: Slice): Cell;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Converts the [`Slice`](/book/cells#slices) to a [`Cell`](/book/cells#cells) and returns it. An alias to `beginCell().storeSlice(self).endCell()`.
Usage example:
```tact
let s: Slice = beginCell().asSlice();
let fizz: Cell = s.asCell();
let buzz: Cell = beginCell().storeSlice(s).endCell();
fizz == buzz; // true
```
### Slice.asString[](#sliceasstring)
```tact
extends fun asString(self: Slice): String;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Casts the [`Slice`](/book/cells#slices) to a [`String`](/book/types#primitive-types) and returns it. The inverse of [`String.asSlice()`](/ref/core-strings#stringasslice).
Usage example:
```tact
let s: String = "Keep your Slices close, but your Strings closer.";
let fizz: String = s;
let buzz: String = s.asSlice().asString();
fizz == buzz; // true
```
### Slice.fromBase64[](#slicefrombase64)
500+ gas
```tact
extends fun fromBase64(self: Slice): Slice;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Returns a new [`Slice`](/book/cells#slices) from the decoded [Base64](https://en.wikipedia.org/wiki/Base64) [`Slice`](/book/cells#slices).
Note that this function is limited and only takes the first 1023 bits of data from the given [`Slice`](/book/cells#slices), without throwing an exception if the [`Slice`](/book/cells#slices) has more data (i.e., when it has any references).
If the given [`Slice`](/book/cells#slices) contains characters not from the Base64 set, an exception with [exit code 134](/book/exit-codes#134) will be thrown: `Invalid argument`.
Usage example:
```tact
let s: Slice = "SSBhbSBHcm9vdC4=".asSlice();
let fizz: Slice = s.fromBase64();
```
### Slice.asAddress[](#sliceasaddress)
Available since Tact 1.6
```tact
extends fun asAddress(self: Slice, chain: Int): Address;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Casts the [`Slice`](/book/cells#slices) to an [`Address`](/book/types#primitive-types) on a given `chain` ID and returns it. It is the inverse of [`Address.asSlice()`](/ref/core-addresses#addressasslice) and a safe but more gas-expensive version of [`Slice.asAddressUnsafe()`](#sliceasaddressunsafe).
Attempts to specify a [`Slice`](/book/cells#slices) with an invalid [account ID](https://docs.ton.org/learn/overviews/addresses#account-id) length throw an error with [exit code 136](/book/exit-codes#): `Invalid standard address`.
Attempts to specify a [`Slice`](/book/cells#slices) with an invalid tag prefix (not `0b100`) or with an invalid [account ID](https://docs.ton.org/learn/overviews/addresses#account-id) length (not 256 bits) throw an error with [exit code 136](/book/exit-codes#): `Invalid standard address`.
Usage example:
```tact
let a: Address = myAddress(); // let's assume we're in a basechain
let a2: Address = a.asSlice().asAddress(0); // so the chain ID is 0
a == a2; // true
```
Note
Because of the checks performed, this function is more gas-expensive than its unsafe but cheaper counterpart: [`Slice.asAddressUnsafe()`](#sliceasaddressunsafe).
### Slice.asAddressUnsafe[](#sliceasaddressunsafe)
Available since Tact 1.6
```tact
extends fun asAddressUnsafe(self: Slice): Address;
```
Extension function for the [`Slice`](/book/cells#slices) type.
Unsafely casts the [`Slice`](/book/cells#slices) to an [`Address`](/book/types#primitive-types) and returns it. The inverse of [`Address.asSlice()`](/ref/core-addresses#addressasslice).
This function does **not** perform any checks on the contents of the [`Slice`](/book/cells#slices).
Usage example:
```tact
let a: Address = myAddress();
let a2: Address = a.asSlice().asAddressUnsafe();
a == a2; // true
```
Caution
Use it only if you want to optimize the code for gas and can guarantee in advance that the [`Slice`](/book/cells#slices) contains the data of an [`Address`](/book/types#primitive-types).
Otherwise, use the safer but more gas-expensive [`Slice.asAddress()`](#sliceasaddress) function.
## Struct.toCell[](#structtocell)
```tact
extends fun toCell(self: Struct): Cell;
```
Extension function for any [struct](/book/structs-and-messages#structs) type.
Converts the struct to a [`Cell`](/book/cells#cells) and returns it.
Usage example:
```tact
struct GuessCoin {
probably: Int as coins;
nothing: Int as coins;
}
fun coinCell(): Cell {
let s: GuessCoin = GuessCoin { probably: 42, nothing: 27 };
let fizz: Cell = s.toCell();
return fizz; // "x{12A11B}"
}
```
## Struct.toSlice[](#structtoslice)
Available since Tact 1.5
```tact
extends fun toSlice(self: Struct): Slice;
```
Extension function for any [struct](/book/structs-and-messages#structs) type.
Converts the struct to a [`Slice`](/book/cells#slices) and returns it. An alias to `self.toCell().asSlice()`.
Usage example:
```tact
struct GuessCoin {
probably: Int as coins;
nothing: Int as coins;
}
fun coinSlice(): Slice {
let s: GuessCoin = GuessCoin { probably: 42, nothing: 27 };
let fizz: Slice = s.toSlice();
return fizz; // "CS{Cell{000612a11b} bits: 0..24; refs: 0..0}"
}
```
## Struct.fromCell[](#structfromcell)
```tact
fun Struct.fromCell(cell: Cell): Struct;
```
Extension function for any [struct](/book/structs-and-messages#structs) type.
Converts a [`Cell`](/book/cells#cells) into the specified struct and returns that struct.
Attempts to pass a [`Cell`](/book/cells#cells) with a layout different from the specified struct or to load more data than the [`Cell`](/book/cells#cells) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
struct GuessCoin {
probably: Int as coins;
nothing: Int as coins;
}
fun directParse(payload: Cell): GuessCoin {
return GuessCoin.fromCell(payload);
}
fun cautiousParse(payload: Cell): GuessCoin? {
let coin: GuessCoin? = null;
try {
coin = GuessCoin.fromCell(payload);
} catch (e) {
dump("Cell payload doesn't match GuessCoin struct!");
}
return coin;
}
```
## Struct.fromSlice[](#structfromslice)
```tact
fun Struct.fromSlice(slice: Slice): Struct;
```
Extension function for any [Struct](/book/structs-and-messages#structs) type.
Converts a [`Slice`](/book/cells#slices) into the specified struct and returns that struct.
Attempts to pass a [`Slice`](/book/cells#slices) with a layout different from the specified struct or to load more data than the [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
struct GuessCoin {
probably: Int as coins;
nothing: Int as coins;
}
fun directParse(payload: Slice): GuessCoin {
return GuessCoin.fromSlice(payload);
}
fun cautiousParse(payload: Slice): GuessCoin? {
let coin: GuessCoin? = null;
try {
coin = GuessCoin.fromSlice(payload);
} catch (e) {
dump("Slice payload doesn't match GuessCoin struct!");
}
return coin;
}
```
## Message.toCell[](#messagetocell)
```tact
extends fun toCell(self: Message): Cell;
```
Extension function for any [Message](/book/structs-and-messages#messages) type.
Converts the [Message](/book/structs-and-messages#messages) to a [`Cell`](/book/cells#cells) and returns it.
Usage example:
```tact
message GuessCoin {
probably: Int as coins;
nothing: Int as coins;
}
fun coinCell(): Cell {
let s: GuessCoin = GuessCoin { probably: 42, nothing: 27 };
let fizz: Cell = s.toCell();
return fizz; // "x{AB37107712A11B}"
}
```
## Message.toSlice[](#messagetoslice)
Available since Tact 1.5
```tact
extends fun toSlice(self: Message): Slice;
```
Extension function for any [Message](/book/structs-and-messages#messages) type.
Converts the [Message](/book/structs-and-messages#messages) to a [`Slice`](/book/cells#slices) and returns it. An alias to `self.toCell().asSlice()`.
Usage example:
```tact
message GuessCoin {
probably: Int as coins;
nothing: Int as coins;
}
fun coinSlice(): Slice {
let s: GuessCoin = GuessCoin { probably: 42, nothing: 27 };
let fizz: Slice = s.toSlice();
return fizz; // "CS{Cell{000eab37107712a11b} bits: 0..56; refs: 0..0}"
}
```
## Message.fromCell[](#messagefromcell)
```tact
fun Message.fromCell(cell: Cell): Message;
```
Extension function for any [Message](/book/structs-and-messages#messages) type.
Converts a [`Cell`](/book/cells#cells) into the specified [Message](/book/structs-and-messages#messages) and returns that [Message](/book/structs-and-messages#messages).
Attempts to pass a [`Cell`](/book/cells#cells) that contains an [opcode prefix](/book/structs-and-messages#message-opcodes) of a different message throw an exception with [exit code 129](/book/exit-codes#129): `Invalid serialization prefix`.
Attempts to pass a [`Cell`](/book/cells#cells) with a layout different from the specified [Message](/book/structs-and-messages#messages) or to load more data than a [`Cell`](/book/cells#cells) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
message(0x777) TripleAxe {
prize: Int as uint32;
}
fun directParse(payload: Cell): TripleAxe {
return TripleAxe.fromCell(payload);
}
fun cautiousParse(payload: Cell): TripleAxe? {
let coin: TripleAxe? = null;
try {
coin = TripleAxe.fromCell(payload);
} catch (e) {
dump("Cell payload doesn't match TripleAxe Message!");
}
return coin;
}
```
## Message.fromSlice[](#messagefromslice)
```tact
fun Message.fromSlice(slice: Slice): Message;
```
Extension function for any [Message](/book/structs-and-messages#messages) type.
Converts a [`Slice`](/book/cells#slices) into the specified [Message](/book/structs-and-messages#messages) and returns that [Message](/book/structs-and-messages#messages).
Attempts to pass a [`Slice`](/book/cells#slices) that contains an [opcode prefix](/book/structs-and-messages#message-opcodes) of a different message throw an exception with [exit code 129](/book/exit-codes#129): `Invalid serialization prefix`.
Attempts to pass a [`Slice`](/book/cells#slices) with a layout different from the specified [Message](/book/structs-and-messages#messages) or to load more data than a [`Slice`](/book/cells#slices) contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
message(0x777) TripleAxe {
prize: Int as uint32;
}
fun directParse(payload: Slice): TripleAxe {
return TripleAxe.fromSlice(payload);
}
fun cautiousParse(payload: Slice): TripleAxe? {
let coin: TripleAxe? = null;
try {
coin = TripleAxe.fromSlice(payload);
} catch (e) {
dump("Slice payload doesn't match TripleAxe Message!");
}
return coin;
}
```
## Message.opcode[](#messageopcode)
Available since Tact 1.6.7
```tact
fun Message.opcode(): Int;
```
Extension function for any [Message](/book/structs-and-messages#messages) type.
Returns the [opcode](/book/structs-and-messages#message-opcodes) of the [Message](/book/structs-and-messages#messages).
Usage example:
```tact
message(0x777) TripleAxe {
prize: Int as uint32;
}
contract Example {
receive(msg: TripleAxe) {
dump(TripleAxe.opcode()); // 0x777
}
}
```
## Contract.toCell[](#contracttocell)
Available since Tact 1.6.12
```tact
extends fun toCell(self: Contract): Cell;
```
Extension function for any [contract](/book/contracts) type.
Converts the contract state to a [`Cell`](/book/cells#cells) and returns it.
Usage example:
```tact
contract Example {
probably: Int as coins = 42;
nothing: Int as coins = 27;
get fun asCell(): Cell {
return self.toCell();
}
}
```
Note
If a contract doesn’t use [contract parameters](/book/contracts#parameters), the resulting `Cell` or `Slice` will contain a leading one bit representing the [lazy initialization bit](/book/functions/#init).
## Contract.toSlice[](#contracttoslice)
Available since Tact 1.6.12
```tact
extends fun toSlice(self: Contract): Slice;
```
Extension function for any [contract](/book/contracts) type.
Converts the contract state to a [`Slice`](/book/cells#slices) and returns it. An alias to `self.toCell().asSlice()`.
Usage example:
```tact
contract Example {
probably: Int as coins = 42;
nothing: Int as coins = 27;
get fun asSlice(): Slice {
return self.toSlice();
}
}
```
Note
If a contract doesn’t use [contract parameters](/book/contracts#parameters), the resulting `Cell` or `Slice` will contain a leading one bit representing the [lazy initialization bit](/book/functions/#init).
---
# Compile-time
> Various compile-time global functions from the Core library of Tact
This page lists all the built-in [global functions](/book/functions#fun-global) that are evaluated at the time of building the Tact project and cannot work with non-constant runtime data. These functions are commonly referred to as “compile-time functions” or *comptime* functions for short.
## address[](#address)
```tact
fun address(s: String): Address;
```
A compile-time function that converts a [`String`](/book/types#primitive-types) containing an address into the [`Address`](/book/types#primitive-types) type and embeds it into the contract.
Usage example:
```tact
contract Example {
// Persistent state variables
addr: Address =
address("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N"); // works at compile-time!
}
```
Note
The `address("...Address...")` in Tact is equivalent to `"...Address..."a` in FunC.
## cell[](#cell)
```tact
fun cell(bocBase64: String): Cell;
```
A compile-time function that embeds a base64-encoded [BoC](/book/cells#cells-boc) `bocBase64` as a [`Cell`](/book/cells#cells) into the contract.
Usage example:
```tact
contract Example {
// Persistent state variables
stored: Cell =
// Init package for Wallet V3R1 as a base64-encoded BoC
cell("te6cckEBAQEAYgAAwP8AIN0gggFMl7qXMO1E0NcLH+Ck8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVD++buA="); // works at compile-time!
}
```
## slice[](#slice)
Available since Tact 1.5
```tact
fun slice(bocBase64: String): Slice;
```
A compile-time function that embeds a base64-encoded [BoC](/book/cells#cells-boc) `bocBase64` as a [`Slice`](/book/cells#slices) into the contract.
Usage example:
```tact
contract Example {
// Persistent state variables
stored: Slice =
// Works at compile-time!
slice("te6cckEBAQEADgAAGEhlbGxvIHdvcmxkIXgtxbw="); // Hello world!
}
```
## rawSlice[](#rawslice)
Available since Tact 1.5
```tact
fun rawSlice(hex: String): Slice;
```
A compile-time function that converts the `hex` [`String`](/book/types#primitive-types), containing hex-encoded and optionally bit-padded contents, into a [`Slice`](/book/cells#slices) and embeds it into the contract.
Contents are bit-padded if there is an underscore `_` at the very end of the [`String`](/book/types#primitive-types). Padding removes all trailing zeros and the last 1 bit before them:
```tact
// Not bit-padded
rawSlice("4a").loadUint(8); // 74, or 1001010 in binary
// Bit-padded
rawSlice("4a_").loadUint(6); // 18, or 10010 in binary
```
Note that this function is limited and only allows specifying up to 1023 bits.
Usage example:
```tact
contract Example {
// Persistent state variables
stored: Slice =
rawSlice("000DEADBEEF000"); // CS{Cell{03f...430} bits: 588..644; refs: 1..1}
bitPadded: Slice =
rawSlice("000DEADBEEF000_"); // CS{Cell{03f...e14} bits: 36..79; refs: 0..0}
}
```
Note
The `rawSlice("...Hex contents...")` in Tact is equivalent to `"...Hex contents..."s` in FunC.
## ascii[](#ascii)
Available since Tact 1.5
```tact
fun ascii(str: String): Int;
```
A compile-time function that concatenates the numerical values of the characters in the non-empty string `str` into one value of the [`Int`](/book/integers) type. This function works only for strings occupying up to 32 bytes, allowing the representation of up to 32 [ASCII codes](https://en.wikipedia.org/wiki/ASCII#Control_code_chart) or up to 8 [Unicode code points](https://en.wikipedia.org/wiki/List_of_Unicode_characters) of 4 bytes each, so the resulting non-negative integer fits into 256 bits.
To understand how the `ascii` function works, consider the following pseudo-Tact example involving hexadecimal escape sequences:
```tact
ascii("NstK") == ascii("\x4e\x73\x74\x4b") == 0x4e73744b == 1316189259
```
Each ASCII character in the string `"NstK"` is represented by its hexadecimal escape sequence, which is then converted to the corresponding integer value by concatenating all the bytes.
The `ascii` builtin assumes the string is encoded in UTF-8. For example, the `⚡` character’s UTF-8 encoding is `0xE2 0x9A 0xA1`, so `0xE2` will be the most significant byte.
The builtin can be used to create human-readable encodings for some actions or operations.
Usage example:
```tact
message(42) Action {
action: Int as uint256;
}
contract Example {
receive(msg: Action) {
if (msg.action == ascii("start")) {
// Do something
} else if (msg.action == ascii("stop")) {
// Do something else
}
}
}
```
Note
The `ascii("...String contents...")` in Tact is almost equivalent to `"...String contents..."u` in FunC. But FunC does not support Unicode code point escapes or hexadecimal escape sequences.
## crc32[](#crc32)
Available since Tact 1.5
```tact
fun crc32(str: String): Int;
```
A compile-time function that computes a checksum using the [CRC-32](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) algorithm and embeds the resulting [`Int`](/book/integers) value into the contract.
Usage example:
```tact
contract Example {
// Persistent state variables
checksum: Int = crc32("000DEADBEEF000"); // 1821923098
}
```
Note
The `crc32("...String contents...")` in Tact is equivalent to `"...String contents..."c` in FunC.
## ton[](#ton)
```tact
fun ton(value: String): Int;
```
A compile-time function that converts the given Toncoin `value` from a human-readable format [`String`](/book/types#primitive-types) to the [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) format.
Usage example:
```tact
contract Example {
// Persistent state variables
one: Int = ton("1"); // One Toncoin, which is equivalent to 10^9 nanoToncoins
pointOne: Int = ton("0.1"); // 0.1 Toncoin, which is equivalent to 10^8 nanoToncoins
nano: Int = ton("0.000000001"); // 10^-9 Toncoin, which is equivalent to 1 nanoToncoin
// Works at compile-time!
}
```
---
# Context and state
> Contextual and state-related functions and structs from the Core library of Tact
Contextual and state-related functions and structs.
## Time[](#time)
### now[](#now)
```tact
fun now(): Int;
```
Returns the current [Unix time](https://en.wikipedia.org/wiki/Unix_time).
Usage example:
```tact
let timeOffset: Int = now() + 1000; // thousand seconds from now()
```
### curLt[](#curlt)
Available since Tact 1.6
```tact
fun curLt(): Int;
```
Returns the [`Int`](/book/integers) value of the [logical time](https://docs.ton.org/v3/documentation/smart-contracts/message-management/messages-and-transactions#what-is-a-logical-time) of the current transaction.
Usage example:
```tact
let lt: Int = curLt();
nativeRandomize(lt); // Equivalent to calling nativeRandomizeLt()
```
Useful links:
[Random seed in Wikipedia](https://en.wikipedia.org/wiki/Random_seed)\
[`nativeRandomize`](/ref/core-random#nativerandomize)\
[`nativeRandomizeLt`](/ref/core-random#nativerandomizelt)\
[Other random-related functions in the Core library](/ref/core-random)
### blockLt[](#blocklt)
Available since Tact 1.6
```tact
fun blockLt(): Int;
```
Returns the [`Int`](/book/integers) value of the [starting logical time](https://docs.ton.org/v3/documentation/smart-contracts/message-management/messages-and-transactions#what-is-a-logical-time) of the current block.
Usage example:
```tact
let time: Int = blockLt();
```
## Incoming message[](#incoming-message)
### sender[](#sender)
```tact
fun sender(): Address;
```
Returns the [`Address`](/book/types#primitive-types) of the sender of the current message.
Usage example:
```tact
contract MeSee {
receive() {
let whoSentMeMessage: Address = sender();
}
}
```
Caution
Behavior is undefined for [getter functions](/book/contracts#getter-functions), because they cannot have a sender nor can they send messages.
Note
In order to reduce gas usage, prefer using this function over calling [`context().sender`](#context) when you only need to know the sender of the message.
### inMsg[](#inmsg)
Available since Tact 1.6.7
```tact
fun inMsg(): Slice;
```
Returns the [`Slice`](/book/cells#slices) with the original, raw body of the [received message](/book/receive).
That `Slice` can:
* be empty, which means the contract has received an empty message body that is handled in the empty receiver `receive()` or the catch-all slice receiver `receive(msg: Slice)`;
* start with 4 zero bytes, which means the contract has received a text message that is handled in the relevant receiver:
* the exact text receiver `receive("message")`,
* the catch-all string receiver `receive(msg: String)`,
* or the catch-all slice receiver `receive(msg: Slice)`;
* start with 4 bytes of a non-zero message opcode that the corresponding binary receiver `receive(msg: MessageStruct)` or the catch-all slice receiver `receive(msg: Slice)` would handle.
Usage examples:
```tact
// This contract defines various kinds of receivers in their
// order of handling the corresponding incoming messages.
contract OrderOfReceivers() {
receive() {
let body = inMsg();
body.bits(); // 0
}
receive("yeehaw!") {
let body = inMsg();
body.loadUint(32); // 0
body.hash() == "yeehaw!".asSlice().hash(); // true
}
receive(str: String) {
let body = inMsg();
body.loadUint(32); // 0
body == str.asSlice(); // true
}
receive(msg: Emergency) {
let body = inMsg();
body.preloadUint(32); // 911
}
receive(rawMsg: Slice) {
let body = inMsg();
body == rawMsg; // true
}
}
message(911) Emergency {}
```
### context[](#context)
```tact
fun context(): Context;
```
Returns `Context` [struct](/book/structs-and-messages#structs), which consists of:
| Field | Type | Description |
| :----------- | :--------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bounceable` | [`Bool`](/book/types#booleans) | Indicates whether the received message can [bounce back](https://docs.ton.org/v3/documentation/smart-contracts/message-management/non-bounceable-messages). |
| `sender` | [`Address`](/book/types#primitive-types) | Internal address of the sender on the TON Blockchain. |
| `value` | [`Int`](/book/integers) | Amount of [nanoToncoin](/book/integers#nanotoncoin) in the received message. |
| `raw` | [`Slice`](/book/cells#slices) | The remainder of the received message as a [`Slice`](/book/cells#slices). It follows the [internal message layout](https://docs.ton.org/develop/smart-contracts/messages#message-layout) of TON, starting from the destination [`Address`](/book/types#primitive-types) (`MsgAddressInt` in [TL-B notation](https://docs.ton.org/develop/data-formats/tl-b-language)). |
Usage example:
```tact
let ctx: Context = context();
require(ctx.value != 68 + 1, "Invalid amount of nanoToncoins, bye!");
```
Note
If you only need to know who sent the message, use the [`sender()`](#sender) function, as it is less gas-consuming.
### Context.readForwardFee[](#contextreadforwardfee)
```tact
extends fun readForwardFee(self: Context): Int;
```
Extension function for the [`Context`](#context) [struct](/book/structs-and-messages#structs).
Reads the [forward fee](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/forward-fees) provided in the incoming message and applies the [`getOriginalFwdFee()`](/ref/core-gas#getoriginalfwdfee) to it to calculate its approximate original value. Returns this value as an [`Int`](/book/integers) amount of [nanoToncoin](/book/integers#nanotoncoin).
Usage example:
```tact
let origFwdFee: Int = context().readForwardFee();
```
Useful links:
[`getOriginalFwdFee()`](/ref/core-gas#getoriginalfwdfee)\
[Other fees and gas-related functions in the Core library](/ref/core-gas)
## Contract and transaction state[](#contract-and-transaction-state)
### myAddress[](#myaddress)
```tact
fun myAddress(): Address;
```
Returns the address of the current smart contract as an [`Address`](/book/types#primitive-types).
Usage example:
```tact
let meMyselfAndI: Address = myAddress();
```
Useful links:
[Other address-related functions in the Core library](/ref/core-addresses)
### myCode[](#mycode)
Available since Tact 1.6
```tact
fun myCode(): Cell;
```
Returns the smart contract code [`Cell`](/book/cells#cells) obtained from the `c7` [register](https://docs.ton.org/learn/tvm-instructions/tvm-overview#control-registers).
Usage example:
```tact
let code: Cell = myCode();
```
### myStorageDue[](#mystoragedue)
Available since Tact 1.5
```tact
fun myStorageDue(): Int;
```
Returns the [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) amount of the accumulated [storage fee](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees-low-level#storage-fee) debt. Storage fees are deducted from the incoming message value before the new contract balance is calculated.
Usage example:
```tact
let debt: Int = myStorageDue();
```
Useful links:
[`getStorageFee()`](/ref/core-gas#getstoragefee)\
[Other fees and gas-related functions in the Core library](/ref/core-gas)
### myBalance[](#mybalance)
```tact
fun myBalance(): Int;
```
Returns the [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) balance of the smart contract as it was at the start of the [compute phase](https://docs.ton.org/learn/tvm-instructions/tvm-overview#compute-phase) of the current transaction.
Usage example:
```tact
let iNeedADolla: Int = myBalance();
```
Caution
Beware that [all message-sending functions](/book/send#message-sending-functions) of Tact can change the *actual* balance of the contract, but they **won’t** update the value returned by this function.
### gasConsumed[](#gasconsumed)
Available since Tact 1.5
```tact
fun gasConsumed(): Int;
```
Returns the [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) amount of [gas](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees#gas) consumed by [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) in the current transaction so far. The resulting value includes the cost of calling this function.
Usage example:
```tact
let gas: Int = gasConsumed();
```
Useful links:
[Gas in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees#gas)\
[Other fees and gas-related functions in the Core library](/ref/core-gas)
### nativeReserve[](#nativereserve)
500+ gas
```tact
fun nativeReserve(amount: Int, mode: Int);
```
Executes the [`RAWRESERVE`](https://docs.ton.org/v3/documentation/tvm/instructions#FB02) instruction with the specified `amount` and `mode`. It queues the reservation of the specific `amount` of [nanoToncoin](/book/integers#nanotoncoin) from the remaining account balance per the given `mode`.
The reservation action is queued to the *output action list*, which contains other actions such as [message sends](/book/send#outbound-message-processing). In fact, the `RAWRESERVE` instruction is roughly equivalent to creating an outbound message carrying the specified `amount` of nanoToncoin or `b - amount` of nanoToncoin, where `b` is the remaining balance, to oneself. This ensures that subsequent output actions cannot spend more money than the remainder.
It is possible to use raw [`Int`](/book/integers) values and manually provide them for the `mode`, but for your convenience, there is a set of constants you may use to construct the compound `mode` with ease. Take a look at the following tables for more information on [base modes](#nativereserve-base-modes), [optional flags](#nativereserve-optional-flags), and how you can [combine them together](#nativereserve-combining-modes-with-flags).
Caution
Currently, `amount` must be a non-negative integer, and `mode` must be in the range 0..31, inclusive.
Additionally, attempts to queue more than 255 reservations in one transaction throw an exception with [exit code 33](/book/exit-codes#33): `Action list is too long`.
#### Base modes[](#nativereserve-base-modes)
The resulting `mode` value can have the following base modes:
| Mode value | Constant name | Description |
| ---------: | :----------------- | ------------------------------------------------------------------------------------- |
| 0 | `ReserveExact` | Reserves exactly the specified `amount` of [nanoToncoin](/book/integers#nanotoncoin). |
| 1 | `ReserveAllExcept` | Reserves all but the specified `amount` of [nanoToncoin](/book/integers#nanotoncoin). |
| 2 | `ReserveAtMost` | Reserves at most the specified `amount` of [nanoToncoin](/book/integers#nanotoncoin). |
#### Optional flags[](#nativereserve-optional-flags)
Additionally, the resulting `mode` can have the following optional flags added:
| Flag value | Constant name | Description |
| ---------: | :-------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| +4 | `ReserveAddOriginalBalance` | Increases the `amount` by the original balance of the current account (before the compute phase), including all extra currencies. |
| +8 | `ReserveInvertSign` | Negates the `amount` value before performing the reservation. |
| +16 | `ReserveBounceIfActionFail` | Bounces the transaction if the reservation fails. |
#### Combining modes with flags[](#nativereserve-combining-modes-with-flags)
To construct the [`Int`](/book/integers) value for the `mode` parameter, combine base modes with optional flags by applying the [bitwise OR](/book/operators#binary-bitwise-or) operation:
```tact
nativeReserve(ton("0.1"), ReserveExact | ReserveBounceIfActionFail);
// ---------- ----------------------------------------
// ↑ ↑
// | mode, which would bounce the transaction if exact reservation fails
// amount of nanoToncoins to reserve
```
### commit[](#commit)
```tact
fun commit();
```
Commits the current state of [registers](https://docs.ton.org/learn/tvm-instructions/tvm-overview#control-registers) `c4` (persistent data) and `c5` (actions), so that the current execution is considered “successful” with the saved values even if an exception in the compute phase is thrown later.
Usage example:
```tact
commit(); // now, transaction is considered "successful"
throw(42); // and this won't fail it
```
## Blockchain state[](#blockchain-state)
### getConfigParam[](#getconfigparam)
```tact
fun getConfigParam(id: Int): Cell?;
```
Loads a [configuration parameter](https://docs.ton.org/develop/howto/blockchain-configs) of TON Blockchain by its `id` number.
Usage examples:
```tact
// Parameter 0, address of a special smart contract that stores the blockchain's configuration
let configAddrAsCell: Cell = getConfigParam(0)!!;
// Parameter 18, configuration for determining the prices for data storage
let dataStorageFeeConfig: Cell = getConfigParam(18)!!;
```
Note
The standard library [`@stdlib/config`](/ref/stdlib-config) provides two related helper functions:\
[`getConfigAddress()`](/ref/stdlib-config#getconfigaddress) for retrieving config [`Address`](/book/types#primitive-types)\
[`getElectorAddress()`](/ref/stdlib-config#getconfigaddress) for retrieving elector [`Address`](/book/types#primitive-types)
Read more about other parameters: [Config Parameters in TON Docs](https://docs.ton.org/develop/howto/blockchain-configs).
---
# Cryptography
> Various cryptographic functions from the Core library of Tact
Various cryptographic global functions. Crypto-oriented extension functions for [`Cell`](/book/cells#cells), [`Builder`](/book/cells#builders), and [`Slice`](/book/cells#slices) types are listed on their reference page: [Cells, Builders and Slices](/ref/core-cells).
## checkSignature[](#checksignature)
```tact
fun checkSignature(hash: Int, signature: Slice, publicKey: Int): Bool;
```
Checks the [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) `signature` of the 256-bit unsigned [`Int`](/book/integers) `hash` using a `publicKey`, represented by a 256-bit unsigned [`Int`](/book/integers). The signature must contain at least 512 bits of data, but only the first 512 bits are used.
Returns `true` if the signature is valid, `false` otherwise.
Usage example:
```tact
message ExtMsg {
signature: Slice;
data: Cell;
}
contract Showcase {
// Persistent state variables
pub: Int as uint256; // public key as a 256-bit unsigned Int
// Constructor function init(), where all variables are initialized
init(pub: Int) {
self.pub = pub; // storing the public key upon contract initialization
}
// External message receiver, which accepts message ExtMsg
external(msg: ExtMsg) {
let hash: Int = beginCell().storeRef(msg.data).endCell().hash();
let check: Bool = checkSignature(hash, msg.signature, self.pub);
// ---- ------------- --------
// ↑ ↑ ↑
// | | publicKey stored in our contract
// | signature obtained from the received message
// hash calculated using the data from the received message
// ... follow-up logic ...
}
}
```
Caution
The first 10 calls of this function are very cheap regarding gas usage. However, the 11th call and onward consume more than 4 thousand gas units.
## checkDataSignature[](#checkdatasignature)
```tact
fun checkDataSignature(data: Slice, signature: Slice, publicKey: Int): Bool;
```
Checks the [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) `signature` of the `data` using a `publicKey`, similar to [`checkSignature()`](#checksignature). If the bit length of `data` is not divisible by 8, this function throws an error with [exit code 9](/book/exit-codes#9): `Cell underflow`. Verification itself is done indirectly on a [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of the `data`.
Returns `true` if the signature is valid, `false` otherwise.
Usage example:
```tact
let data: Slice = someData;
let signature: Slice = someSignature;
let publicKey: Int = 42;
let check: Bool = checkDataSignature(data, signature, publicKey);
```
Caution
The first 10 calls of this function are very cheap regarding gas usage. However, the 11th call and onward consume more than 4 thousand gas units.
## SignedBundle[](#signedbundle)
Available since Tact 1.6.6
```tact
struct SignedBundle {
/// A 512-bit Ed25519 signature of the `signedData`.
signature: Slice as bytes64;
/// The remaining non-serialized data of the enclosing struct or message struct,
/// which was used to obtain the 512-bit Ed25519 `signature`.
signedData: Slice as remaining;
}
```
A [struct](/book/structs-and-messages#structs) that contains a 512-bit [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) signature and the data it signs.
See the usage example for the [`SignedBundle.verifySignature()`](#signedbundleverifysignature) function.
## SignedBundle.verifySignature[](#signedbundleverifysignature)
Available since Tact 1.6.6
```tact
extends fun verifySignature(self: SignedBundle, publicKey: Int): Bool;
```
Extension function for the [`SignedBundle`](#signedbundle) [struct](/book/structs-and-messages#structs).
Checks whether `self.signedData` was signed by the 512-bit [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) signature `self.signature`, using the given `publicKey`. Returns `true` if the signature is valid, `false` otherwise.
Usage example:
```tact
contract Example(publicKey: Int as uint256) {
external(msg: MessageWithSignedData) {
// Checks that the signature of the SignedBundle from the incoming external
// message wasn't forged and made by the owner of this self.publicKey with
// its respective private key managed elsewhere.
throwUnless(35, msg.bundle.verifySignature(self.publicKey));
// ...rest of the checks and code...
}
}
message MessageWithSignedData {
// The `bundle.signature` contains the 512-bit Ed25519 signature
// of the remaining data fields of this message struct,
// while `bundle.signedData` references those data fields.
// In this case, the fields are `walletId` and `seqno`.
bundle: SignedBundle;
// These fields are common to external messages to user wallets.
walletId: Int as int32;
seqno: Int as uint32;
}
```
## sha256[](#sha256)
500+ gas
```tact
fun sha256(data: Slice): Int;
fun sha256(data: String): Int;
```
Computes and returns the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash as a 256-bit unsigned [`Int`](/book/integers) from the passed [`Slice`](/book/cells#slices) or [`String`](/book/types#primitive-types) `data`, which should have a number of bits divisible by 8.
In case `data` is a [`Slice`](/book/cells#slices), it must have no more than a single reference per cell, because only the first reference of each nested cell will be taken into account.
This function tries to resolve constant string values at [compile-time](/ref/core-comptime) whenever possible.
Attempts to specify a [`Slice`](/book/cells#slices) or [`String`](/book/types#primitive-types) with a number of bits **not** divisible by 8 throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
sha256(beginCell().asSlice());
sha256("Hello, world!"); // will be resolved at compile-time
sha256(someVariableElsewhere); // will try to resolve at compile-time,
// and fall back to run-time evaluation
```
Before Tact 1.6
Previously, if a [`String`](/book/types#primitive-types) value couldn’t be resolved during [compile-time](/ref/core-comptime), the hash was calculated at runtime by the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) itself. This caused collisions of strings with more than 127 bytes if their first 127 bytes were the same.
That’s because all [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard)-related instructions of the [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) consider only the data bits, ignoring possible references to other cells needed to form larger strings.
Therefore, in general, and in versions of Tact prior to 1.6, it is preferable to use statically known strings whenever possible. When in doubt, use strings of up to 127 bytes long.
## keccak256[](#keccak256)
500+ gas Available since Tact 1.6.6
```tact
fun keccak256(data: Slice): Int;
```
Computes and returns the Ethereum-compatible [Keccak-256](https://en.wikipedia.org/wiki/SHA-3) hash as a 256-bit unsigned [`Int`](/book/integers) from the passed [`Slice`](/book/cells#slices) `data`.
The `data` slice should have a number of bits divisible by 8 and no more than a single reference per cell, because only the first reference of each nested cell will be taken into account.
Attempts to specify a [`Slice`](/book/cells#slices) with a number of bits **not** divisible by 8 throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage examples:
```tact
contract Examples() {
receive(rawMsg: Slice) {
// Hash incoming message body Slice
let hash: Int = keccak256(rawMsg);
// Process data that spans multiple cells
let b: Builder = beginCell()
.storeUint(123456789, 32)
.storeRef(beginCell().storeString("Extra data in a ref").endCell());
let largeDataHash: Int = keccak256(b.asSlice());
// Match Ethereum's hash format
let ethAddress: String = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
let ethAddressHash: Int = keccak256(ethAddress.asSlice());
}
}
```
Note
Crypto extension functions for [`Cell`](/book/cells#cells), [`Builder`](/book/cells#builders), and [`Slice`](/book/cells#slices) types are listed on their reference page: [Cells, Builders and Slices](/ref/core-cells).
---
# Debug
> Various debugging functions from the Core library of Tact
List of functions commonly used for debugging smart contracts in Tact.
Read more about debugging on the dedicated page: [Debugging](/book/debug).
## require[](#require)
```tact
fun require(condition: Bool, error: String);
```
Checks the `condition` and throws an error with an [exit code](/book/exit-codes) generated from the `error` message if the `condition` is `false`. Otherwise, does nothing.
This function is similar to [`throwUnless()`](#throwunless), but instead of using the error code directly, it generates it based on the given error message [`String`](/book/types#primitive-types).
The algorithm for generating the exit code works as follows:
* First, the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of the `error` message [`String`](/book/types#primitive-types) is obtained.
* Then, its value is read as a 32-bit [big-endian](https://en.wikipedia.org/wiki/Endianness) number modulo 63000 plus 1000, in that order.
* Finally, it’s put into the [`.md` compilation report file](/book/compile#report), which resides with the other compilation artifacts in your project’s `outputs/` or `build/` directories.
The generated exit code is guaranteed to be outside the common 0–255 range reserved for TVM and Tact contract errors, which makes it possible to distinguish exit codes from `require()` and any other [standard exit codes](/book/exit-codes).
Usage examples:
```tact
// now() has to return a value greater than 1000, otherwise an error message will be thrown
require(now() > 1000, "We're in the first 1000 seconds of 1 January 1970!");
try {
// The following will never be true, so this require would always throw
require(now() < -1, "Time is an illusion. Lunchtime doubly so.");
} catch (e) {
// e will be outside of range 0-255
dump(e);
}
```
## dump[](#dump)
500+ gas
```tact
fun dump(arg);
```
Prints the argument `arg` to the contract’s debug console. Evaluated only if the `debug` option in the [configuration file](/book/config) is set to `true`. Otherwise does nothing.
This function is computationally expensive and consumes a lot of gas because it prints the location from which it was called—i.e., the filename, line, and column numbers—and the original expression that was the `arg` argument.
Can be applied to the following list of types and values:
* [`Int`](/book/integers)
* [`Bool`](/book/types#booleans)
* [`Address`](/book/types#primitive-types)
* [`Cell`](/book/cells#cells), [`Builder`](/book/cells#builders), or [`Slice`](/book/cells#slices)
* [`String`](/book/types#primitive-types)
* [`map`](/book/maps)
* [Optionals and `null` value](/book/optionals)
* `void`, which is implicitly returned when a function doesn’t have a return value defined
Usage examples:
```tact
// Int
dump(42); // prints:
// File filename.tact:2:1
// dump(42)
// 42
// Bool
dump(true);
dump(false);
// Address
dump(myAddress());
// Cell, Builder, or Slice
dump(emptyCell()); // Cell
dump(beginCell()); // Builder
dump(emptySlice()); // Slice
// String
dump("Hello, my name is...");
// Maps
let m: map = emptyMap();
m.set(2 + 2, 4);
dump(m);
// Special values
dump(null);
dump(emit("msg".asComment())); // As emit() function doesn't return a value, dump() would print #DEBUG#: void.
```
Useful links:
[Debug with `dump()`](/book/debug#tests-dump)
## dumpStack[](#dumpstack)
500+ gas
```tact
fun dumpStack();
```
Prints the total stack depth and up to 255 of its values from the top to the contract’s debug console. The values are positioned bottom-up—from the deepest value on the left to the topmost value on the right. Evaluated only if the `debug` option in the [configuration file](/book/config) is set to `true`. Otherwise does nothing.
Usage example:
```tact
dumpStack(); // prints:
// File filename.tact:1:1
// dumpStack()
// stack(3 values) : 100000000 C{96...C7} 0
```
Useful links:
[Debug with `dump()`](/book/debug#tests-dump)\
[Assembly functions](/book/assembly-functions)
## throw[](#throw)
```tact
fun throw(code: Int);
```
Unconditionally throws an exception with an error `code`.
Execution of the current context stops, statements after `throw` are not executed, and control is passed to the first [`try...catch` block](/book/statements#try-catch) on the call stack. If there is no `try` or `try...catch` block among calling functions, [TVM](https://docs.ton.org/learn/tvm-instructions/tvm-overview) terminates the transaction.
Attempts to specify a `code` outside the range 0−65535 cause an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage examples:
```tact
fun thisWillTerminateAbruptly() {
throw(1042); // throwing with exit code 1042
}
fun butThisWont() {
try {
throw(1042); // throwing with exit code 1042
}
// ... follow-up logic ...
}
```
## throwIf[](#throwif)
Available since Tact 1.6
```tact
fun throwIf(code: Int, condition: Bool);
```
Similar to [`throw()`](#throw), but throws an error `code` only if `condition` holds, i.e. is equal to `true`. Doesn’t throw otherwise.
Attempts to specify a `code` outside the range 0−65535 cause an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
contract Ownership {
owner: Address;
init() {
self.owner = myAddress();
}
receive() {
// Check whether the sender is the owner of the contract,
// and throw exit code 1024 if not
throwIf(1024, sender() != self.owner);
}
}
```
## throwUnless[](#throwunless)
Available since Tact 1.6
```tact
fun throwUnless(code: Int, condition: Bool);
```
Similar to [`throw()`](#throw), but throws an error `code` only if `condition` does **not** hold, i.e. if `condition` is not equal to `true`. Doesn’t throw otherwise.
This function is also similar to [`require()`](#require), but uses the specified `code` directly instead of generating one based on a given error message [`String`](/book/types#primitive-types).
Attempts to specify a `code` outside the range 0−65535 cause an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
contract Ownership {
owner: Address;
init() {
self.owner = myAddress();
}
receive() {
// Check whether the sender is the owner of the contract,
// and throw exit code 1024 if not
throwUnless(1024, sender() == self.owner);
}
}
```
## nativeThrow[](#nativethrow)
Deprecated since Tact 1.6
Use [`throw()`](#throw) instead.
```tact
fun nativeThrow(code: Int);
```
An alias to [`throw()`](#throw).
## nativeThrowIf[](#nativethrowif)
Deprecated since Tact 1.6
Use [`throwIf()`](#throwif) instead.
```tact
fun nativeThrowIf(code: Int, condition: Bool);
```
An alias to [`throwIf()`](#throwif).
## nativeThrowUnless[](#nativethrowunless)
Deprecated since Tact 1.6
Use [`throwUnless()`](#throwunless) instead.
```tact
fun nativeThrowUnless(code: Int, condition: Bool);
```
An alias to [`throwUnless()`](#throwunless).
---
# Gas and fees
> Storage fee, forward fee, compute fee and gas-management functions from the Core library of Tact
List of the general fee and gas-management functions. For the context and state-related functions, see:
* [`myStorageDue()`](/ref/core-contextstate#mystoragedue)
* [`gasConsumed()`](/ref/core-contextstate#gasconsumed)
## getStorageFee[](#getstoragefee)
Available since Tact 1.5
```tact
fun getStorageFee(cells: Int, bits: Int, seconds: Int, isMasterchain: Bool): Int;
```
Calculates and returns the [storage fee](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees-low-level#storage-fee) in [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) for storing a contract with a given number of `cells` and `bits` for a number of `seconds`. Uses the prices of the [masterchain](https://docs.ton.org/v3/documentation/smart-contracts/shards/shards-intro#masterchain) if `isMasterchain` is `true`, otherwise the prices of the [basechain](https://docs.ton.org/v3/documentation/smart-contracts/addresses#workchain-id). The current prices are obtained from [config param 18 of TON Blockchain](https://docs.ton.org/develop/howto/blockchain-configs#param-18).
Note that specifying values of `cells` and `bits` higher than their maximum values listed in [account state limits (`max_acc_state_cells` and `max_acc_state_bits`)](/book/exit-codes#50) will have the same result as specifying the exact limits. In addition, make sure you take into account the [deduplication of cells with the same hash](https://docs.ton.org/v3/documentation/data-formats/tlb/library-cells).
Attempts to specify a negative number of `cells`, `bits`, or `seconds` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let fee: Int = getStorageFee(1_000, 1_000, 1_000, false);
// ----- ----- ----- -----
// ↑ ↑ ↑ ↑
// | | | Isn't on the masterchain,
// | | | but on the basechain
// | | Number of seconds to calculate
// | | the storage fee for
// | Number of bits in a contract
// Number of cells in a contract
```
Useful links:
[Storage fee in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees-low-level#storage-fee)\
[Storage fee calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation#storage-fee)
## getComputeFee[](#getcomputefee)
Available since Tact 1.5
```tact
fun getComputeFee(gasUsed: Int, isMasterchain: Bool): Int;
```
Calculates and returns the [compute fee](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees-low-level#computation-fees) in [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) for a transaction that consumed a `gasUsed` amount of [gas](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees#gas). Uses the prices of the [masterchain](https://docs.ton.org/v3/documentation/smart-contracts/shards/shards-intro#masterchain) if `isMasterchain` is `true`, otherwise the prices of the [basechain](https://docs.ton.org/v3/documentation/smart-contracts/addresses#workchain-id). The current prices are obtained from [config param 20 for the masterchain and config param 21 for the basechain](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21) of TON Blockchain.
When `gasUsed` is less than a certain threshold called [`flat_gas_limit`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21), there’s a minimum price to pay based on the value of [`flat_gas_price`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21). The less gas used below this threshold, the higher the minimum price will be. See the example for [`getSimpleComputeFee()`](#getsimplecomputefee) to derive that threshold.
Attempts to specify a negative value of `gasUsed` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let fee: Int = getComputeFee(1_000, false);
// ----- -----
// ↑ ↑
// | Isn't on the masterchain,
// | but on the basechain
// Number of gas units
// consumed per transaction
```
Useful links:
[Compute fee in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees-low-level#computation-fees)\
[Compute fee calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation#computation-fee)\
[`getSimpleComputeFee()`](#getsimplecomputefee)
## getSimpleComputeFee[](#getsimplecomputefee)
Available since Tact 1.5
```tact
fun getSimpleComputeFee(gasUsed: Int, isMasterchain: Bool): Int;
```
Similar to [`getComputeFee()`](#getcomputefee), but without the [`flat_gas_price`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21), i.e. without the minimum price to pay if `gasUsed` is less than a certain threshold called [`flat_gas_limit`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21). Calculates and returns only the `gasUsed` multiplied by the current gas price.
Attempts to specify a negative value for `gasUsed` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let fee = getComputeFee(0, false);
let feeNoFlat = getSimpleComputeFee(0, false);
let maxFlatPrice = fee - feeNoFlat;
```
Useful links:
[Compute fee in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees-low-level#computation-fees)\
[Compute fee calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation#computation-fee)\
[`getComputeFee()`](#getcomputefee)
## getForwardFee[](#getforwardfee)
Available since Tact 1.5
```tact
fun getForwardFee(cells: Int, bits: Int, isMasterchain: Bool): Int;
```
Calculates and returns the [forward fee](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/forward-fees) in [nanoToncoin](/book/integers#nanotoncoin) as an [`Int`](/book/integers) for an outgoing message consisting of a given number of `cells` and `bits`. Uses the prices of the [masterchain](https://docs.ton.org/v3/documentation/smart-contracts/shards/shards-intro#masterchain) if `isMasterchain` is `true`, or the prices of the [basechain](https://docs.ton.org/v3/documentation/smart-contracts/addresses#workchain-id) otherwise. The current prices are obtained from [config param 24 for the masterchain and config param 25 for the basechain](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-24-and-25) of TON Blockchain.
If both the source and the destination addresses are on the [basechain](https://docs.ton.org/v3/documentation/smart-contracts/addresses#workchain-id), specify `isMasterchain` as `false`. Otherwise, specify `true`.
Note that specifying values of `cells` and `bits` higher than their maximum values listed in [account state limits (`max_msg_cells` and `max_msg_bits`)](/book/exit-codes#50) will have the same result as specifying the exact limits.
However, regardless of the values of `cells` and `bits`, this function always adds the minimum price based on the value of [`lump_price`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-24-and-25). See the example for [`getSimpleForwardFee()`](#getsimpleforwardfee) to derive it. In addition, make sure you account for the [deduplication of cells with the same hash](https://docs.ton.org/v3/documentation/data-formats/tlb/library-cells); for example, the root cell and its data bits do not count toward the forward fee and are covered by the [`lump_price`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-24-and-25).
Attempts to specify a negative number of `cells` or `bits` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let fee: Int = getForwardFee(1_000, 1_000, false);
// ----- ----- -----
// ↑ ↑ ↑
// | | Both source and destination
// | | are not on the masterchain,
// | | but on the basechain
// | Number of bits in a message
// Number of cells in a message
```
Useful links:
[Forward fee in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/forward-fees)\
[Forward fee calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation#forward-fee)\
[`CDATASIZEQ` instruction for computing the number of distinct cells, data bits and refs in a `Cell`](https://docs.ton.org/v3/documentation/tvm/instructions#F940)\
[`getSimpleForwardFee()`](#getsimpleforwardfee)\
[`getOriginalFwdFee()`](#getoriginalfwdfee)
## getSimpleForwardFee[](#getsimpleforwardfee)
Available since Tact 1.5
```tact
fun getSimpleForwardFee(cells: Int, bits: Int, isMasterchain: Bool): Int;
```
Similar to [`getForwardFee()`](#getforwardfee), but without the [`lump_price`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-24-and-25), i.e. without the minimum price to pay regardless of the amounts of `cells` or `bits`. Calculates and returns only the `cells` multiplied by the current cell price plus the `bits` multiplied by the current bit price.
Attempts to specify a negative number of `cells` or `bits` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let fee = getForwardFee(1_000, 1_000, false);
let feeNoLump = getSimpleForwardFee(1_000, 1_000, false);
let lumpPrice = fee - feeNoLump;
```
Useful links:
[Forward fee in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/forward-fees)\
[Forward fee calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation#forward-fee)\
[`getForwardFee()`](#getforwardfee)
## getOriginalFwdFee[](#getoriginalfwdfee)
Available since Tact 1.5
```tact
fun getOriginalFwdFee(fwdFee: Int, isMasterchain: Bool): Int;
```
Calculates and returns the so-called *original* [forward fee](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/forward-fees) in [nanoToncoin](/book/integers#nanotoncoin) [`Int`](/book/integers) for a message based on the given `fwdFee` of this message, which can be obtained by calling [`getForwardFee()`](#getforwardfee). If both the source and the destination addresses are in the [basechain](https://docs.ton.org/v3/documentation/smart-contracts/addresses#workchain-id), specify `isMasterchain` as `false`. Otherwise, specify `true`.
The result is computed using the [`first_frac`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-24-and-25) value, which is obtained from [config param 24 for the masterchain and config param 25 for the basechain](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-24-and-25) of TON Blockchain. Due to the current value of `first_frac` for all workchains, this function performs a cheaper equivalent calculation of `fwdFee * 3 / 2`. This ratio might change, so it is better not to hardcode it and use this function instead.
This function can be useful when the outgoing message depends heavily on the structure of the incoming message, so you can try to approximate the forward fee for your outgoing message based on the fee the sender paid. Calculating the exact fee with [nanoToncoin](/book/integers#nanotoncoin)-level precision can be very expensive, so the approximation given by this function is often good enough.
Attempts to specify a negative value of `fwdFee` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
// Context.readForwardFee() applies getOriginalFwdFee() at the end
let origFwdFee: Int = context().readForwardFee();
// Therefore, calling getOriginalFwdFee() on that value is redundant
let origFwdFee2: Int = getOriginalFwdFee(origFwdFee, false);
// ⌈(2 * origFwdFee2) / origFwdFee⌉ is equal to 3
muldivc(2, origFwdFee2, origFwdFee) == 3; // true, but this relation
// can change in the future
```
Useful links:
[Forward fee in TON Docs](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/forward-fees)\
[Forward fee calculation in TON Docs](https://docs.ton.org/v3/guidelines/smart-contracts/fee-calculation#forward-fee)\
[`getForwardFee()`](#getforwardfee)\
[`Context.readForwardFee()`](/ref/core-contextstate#contextreadforwardfee)
## setGasLimit[](#setgaslimit)
Available since Tact 1.6
```tact
fun setGasLimit(limit: Int);
```
Sets the [`gas_limit`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21) to the [`Int`](/book/integers) `limit` and resets the [`gas_credit`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21) to 0. Note that specifying a `limit` higher than the maximum allowed value of 263−1 will have the same result as specifying that exact maximum or calling [`acceptMessage()`](#acceptmessage).
Attempts to specify a negative or insufficient value of `limit` will cause an exception with [exit code -14](/book/exit-codes#-14): `Out of gas error`.
Usage example:
```tact
setGasLimit(42000);
```
Note
For more details, see: [Accept Message Effects in TON Docs](https://docs.ton.org/develop/smart-contracts/guidelines/accept).
## acceptMessage[](#acceptmessage)
```tact
fun acceptMessage();
```
Agrees to buy some [gas](https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees#gas) to finish the current transaction by setting the [`gas_limit`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21) to its maximum allowed value of 263−1 and resetting the [`gas_credit`](https://docs.ton.org/v3/documentation/network/configs/blockchain-configs#param-20-and-21) to 0. This action is required to process external messages, which bring no value (hence no gas) with them.
Usage example:
```tact
contract Timeout {
timeout: Int;
init() {
self.timeout = now() + 5 * 60; // 5 minutes from now
}
external("timeout") {
if (now() > self.timeout) {
acceptMessage(); // start accepting external messages once timeout has passed
}
}
}
```
Note
For more details, see: [Accept Message Effects in TON Docs](https://docs.ton.org/develop/smart-contracts/guidelines/accept).
---
# Math
> Various math helper functions from the Core library of Tact
Various math helper functions.
## min[](#min)
```tact
fun min(x: Int, y: Int): Int;
```
Computes and returns the [minimum](https://en.wikipedia.org/wiki/Maximum_and_minimum) of two [`Int`](/book/integers) values `x` and `y`.
Usage examples:
```tact
min(1, 2); // 1
min(2, 2); // 2
min(007, 3); // 3
min(0x45, 3_0_0); // 69, nice
// ↑ ↑
// 69 300
```
## max[](#max)
```tact
fun max(x: Int, y: Int): Int;
```
Computes and returns the [maximum](https://en.wikipedia.org/wiki/Maximum_and_minimum) of two [`Int`](/book/integers) values `x` and `y`.
Usage examples:
```tact
max(1, 2); // 2
max(2, 2); // 2
max(007, 3); // 7
max(0x45, 3_0_0); // 300
// ↑ ↑
// 69 300
```
## abs[](#abs)
```tact
fun abs(x: Int): Int;
```
Computes and returns the [absolute value](https://en.wikipedia.org/wiki/Absolute_value) of the [`Int`](/book/integers) value `x`.
Usage examples:
```tact
abs(42); // 42
abs(-42); // 42
abs(-(-(-42))); // 42
```
## sign[](#sign)
Available since Tact 1.6
```tact
fun sign(x: Int): Int;
```
Computes and returns the sign of the [`Int`](/book/integers) value `x`. Produces 1 if `x` is positive, −1 if `x` is negative, and 0 if `x` is 0.
Usage examples:
```tact
sign(42); // 1
sign(-42); // -1
sign(-(-42)); // 1
sign(-(-(-42))); // -1
sign(0); // 0
```
## sqrt[](#sqrt)
500+ gas Available since Tact 1.6
```tact
fun sqrt(num: Int): Int;
```
Computes the [square root](https://en.wikipedia.org/wiki/Square_root) of the [`Int`](/book/integers) value `num`. Returns the result rounded to the nearest integer. If there are two equally close integers, rounding is done toward the even one.
Attempts to specify a negative value for `num` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage examples:
```tact
sqrt(4); // 2
sqrt(3); // 2
sqrt(2); // 1
sqrt(1); // 1
sqrt(0); // 0
sqrt(-1); // ERROR! Exit code 5: Integer out of expected range
```
## divc[](#divc)
Available since Tact 1.6
```tact
fun divc(x: Int, y: Int): Int;
```
Computes and returns the [rounded up](https://en.wikipedia.org/wiki/Rounding#Rounding_up) result of division of the [`Int`](/book/integers) `x` by the [`Int`](/book/integers) `y`.
Attempts to divide by `y` equal to 0 throw an exception with [exit code 4](/book/exit-codes#4): `Integer overflow`.
Usage examples:
```tact
divc(4, 2); // 2
divc(3, 2); // 2
divc(-4, 2); // -2
divc(-3, 2); // -1
```
## muldivc[](#muldivc)
Available since Tact 1.6
```tact
fun muldivc(x: Int, y: Int, z: Int): Int;
```
Computes and returns the [rounded up](https://en.wikipedia.org/wiki/Rounding#Rounding_up) result of `(x * y) / z`.
If the value in calculation goes beyond the range from −2256 to 2256−1 inclusive, or if there is an attempt to divide by `z` equal to 0, an exception with [exit code 4](/book/exit-codes#4) is thrown: `Integer overflow`.
Usage examples:
```tact
muldivc(4, 1, 2); // 2
muldivc(3, 1, 2); // 2
muldivc(-4, 1, 2); // -2
muldivc(-3, 1, 2); // -1
muldivc(-3, 0, 2); // 0
muldivc(-3, 0, 0); // ERROR! Exit code 4: Integer overflow
```
## mulShiftRight[](#mulshiftright)
Available since Tact 1.6
```tact
fun mulShiftRight(x: Int, y: Int, z: Int): Int;
```
Computes and returns the [rounded down](https://en.wikipedia.org/wiki/Rounding#Rounding_down) result of `(x * y) / 2^z`. It is a more gas-efficient equivalent of performing the [bitwise shift right](/book/operators#binary-bitwise-shift-right) on the result of multiplication of [`Int`](/book/integers) `x` by [`Int`](/book/integers) `y`, where [`Int`](/book/integers) `z` is the right operand of the shift.
If the value in calculation goes beyond the range from −2256 to 2256−1 inclusive, an exception with [exit code 4](/book/exit-codes#4) is thrown: `Integer overflow`.
Attempts to specify any value of `z` outside the inclusive range from 0 to 256 throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage examples:
```tact
mulShiftRight(5, 5, 2); // 6
mulShiftRight(5, 5, 1); // 12
mulShiftRight(5, 5, 0); // 25
mulShiftRight(5, 5, -1); // ERROR! Exit code 5: Integer out of expected range
```
## mulShiftRightRound[](#mulshiftrightround)
Available since Tact 1.6
```tact
fun mulShiftRightRound(x: Int, y: Int, z: Int): Int;
```
Similar to [`mulShiftRight()`](#mulshiftright), but instead of [rounding down](https://en.wikipedia.org/wiki/Rounding#Rounding_down), the result value is rounded to the nearest integer. If there are two equally close integers, rounding is done toward the even one.
If the value in calculation goes beyond the range from −2256 to 2256−1 inclusive, an exception with [exit code 4](/book/exit-codes#4) is thrown: `Integer overflow`.
Attempts to specify any value of `z` outside the inclusive range from 0 to 256 throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage examples:
```tact
mulShiftRightRound(5, 5, 2); // 6
mulShiftRightRound(5, 5, 1); // 13
mulShiftRightRound(5, 5, 0); // 25
mulShiftRightRound(5, 5, -1); // ERROR! Exit code 5: Integer out of expected range
```
## mulShiftRightCeil[](#mulshiftrightceil)
Available since Tact 1.6
```tact
fun mulShiftRightCeil(x: Int, y: Int, z: Int): Int;
```
Similar to [`mulShiftRight()`](#mulshiftright), but instead of [rounding down](https://en.wikipedia.org/wiki/Rounding#Rounding_down), the result value is [rounded up](https://en.wikipedia.org/wiki/Rounding#Rounding_up).
If the value in calculation goes beyond the range from −2256 to 2256−1 inclusive, an exception with [exit code 4](/book/exit-codes#4) is thrown: `Integer overflow`.
Attempts to specify any value of `z` outside the inclusive range from 0 to 256 throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage examples:
```tact
mulShiftRightCeil(5, 5, 2); // 7
mulShiftRightCeil(5, 5, 1); // 13
mulShiftRightCeil(5, 5, 0); // 25
mulShiftRightCeil(5, 5, -1); // ERROR! Exit code 5: Integer out of expected range
```
## log[](#log)
```tact
fun log(num: Int, base: Int): Int;
```
Computes and returns the [logarithm](https://en.wikipedia.org/wiki/Logarithm) of a number `num` >0 to the base `base` ≥2. Results are [rounded down](https://en.wikipedia.org/wiki/Rounding#Rounding_down).
Attempts to specify a non-positive `num` value or a `base` less than 2 throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage examples:
```tact
log(1000, 10); // 3, as 10^3 is 1000
// ↑ ↑ ↑ ↑
// num base base num
log(1001, 10); // 3
log(999, 10); // 2
try {
log(-1000, 10); // exit code 5 because of the non-positive num
}
log(1024, 2); // 10
try {
log(1024, -2); // exit code 5 because the base is less than 1
}
```
Note
If you only need to obtain logarithms to the base 2, use the [`log2()`](#log2) function, as it’s more gas-efficient.
## log2[](#log2)
```tact
fun log2(num: Int): Int;
```
Similar to [`log()`](#log), but sets the `base` to 2.
Attempts to specify a non-positive `num` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
log2(1024); // 10, as 2^10 is 1024
// ↑ ↑ ↑
// num base₂ num
```
Note
In order to reduce gas usage, prefer using this function over calling [`log()`](#log) when you only need to obtain logarithms to the base 2.
## pow[](#pow)
```tact
fun pow(base: Int, exp: Int): Int;
```
Computes and returns the [exponentiation](https://en.wikipedia.org/wiki/Exponentiation) involving two numbers: the `base` and the exponent (or *power*) `exp`. Exponent `exp` must be non-negative; otherwise, an exception with [exit code 5](/book/exit-codes#5) is thrown: `Integer out of expected range`.
This function tries to resolve constant values at [compile-time](/ref/core-comptime) whenever possible.
Usage examples:
```tact
contract Example {
// Persistent state variables
p23: Int = pow(2, 3); // raises 2 to the 3rd power, which is 8
one: Int = pow(5, 0); // raises 5 to the power 0, which always produces 1
// works at compile-time!
// Internal message receiver
receive() {
pow(self.p23, self.one + 1); // 64, works at run-time too!
try {
pow(0, -1); // exit code 5: Integer out of expected range
}
}
}
```
Note
If you only need to obtain powers of 2, use the [`pow2()`](#pow2) function, as it’s more gas-efficient.
Note
List of functions that only work at compile-time: [API Comptime](/ref/core-comptime).
## pow2[](#pow2)
```tact
fun pow2(exp: Int): Int;
```
Similar to [`pow()`](#pow), but sets the `base` to 2. The exponent `exp` must be non-negative; otherwise, an error with [exit code 5](/book/exit-codes#5) will be thrown: `Integer out of expected range`.
This function tries to resolve constant values at [compile-time](/ref/core-comptime) whenever possible.
Usage examples:
```tact
contract Example {
// Persistent state variables
p23: Int = pow2(3); // raises 2 to the 3rd power, which is 8
one: Int = pow2(0); // raises 2 to the power 0, which always produces 1
// works at compile-time!
// Internal message receiver, which accepts message ExtMsg
receive() {
pow2(self.one + 1); // 4, works at run-time too!
try {
pow(-1); // exit code 5: Integer out of expected range
}
}
}
```
Note
In order to reduce gas usage, prefer using this function over calling [`pow()`](#pow) when you only need to obtain powers of 2.
Note
List of functions that only work at compile-time: [API Comptime](/ref/core-comptime).
---
# Random number generation
> Various random number generation functions from the Core library of Tact
Random number generation for Tact smart contracts.
## Common[](#common)
### random[](#random)
```tact
fun random(min: Int, max: Int): Int;
```
Generates and returns a new pseudo-random unsigned [`Int`](/book/integers) value `x` in the provided semi-closed interval: `min` ≤ `x` < `max`, or `min` ≥ `x` > `max` if both `min` and `max` are negative. Note that the `max` value is never included in the interval.
Usage examples:
```tact
random(42, 43); // 42, always
random(0, 42); // 0-41, but never 42
```
### randomInt[](#randomint)
```tact
fun randomInt(): Int;
```
Generates and returns a new pseudo-random unsigned 256-bit [`Int`](/book/integers) value `x`.
The algorithm works as follows: first, the `sha512(r)` is computed. There, `r` is an old value of the random seed, which is taken as a 32-byte array constructed from the big-endian representation of an unsigned 256-bit [`Int`](/book/integers). The first 32 bytes of this hash are stored as the new value `r'` of the random seed, and the remaining 32 bytes are returned as the next random value `x`.
Usage example:
```tact
let allYourRandomBelongToUs: Int = randomInt(); // ???, it's random :)
```
## Advanced[](#advanced)
Various niche, dangerous, or unstable features which can produce unexpected results and are meant to be used by more experienced users.
Caution
Proceed with caution.
### getSeed[](#getseed)
Available since Tact 1.6
```tact
fun getSeed(): Int;
```
Generates and returns an unsigned 256-bit [`Int`](/book/integers) [seed](https://en.wikipedia.org/wiki/Random_seed) for the random number generator. The resulting seed is commonly used with the [`setSeed()`](#setseed) and [`nativeRandomize()`](#nativerandomize) functions.
Usage example:
```tact
let seed: Int = getSeed();
setSeed(seed); // From now on, the results of the pseudorandom number generator
// are completely determined by the seed, which can be handy in tests,
// but must not be used in production code!
```
Useful links:
[Random seed in Wikipedia](https://en.wikipedia.org/wiki/Random_seed)\
[`setSeed()`](#setseed)\
[`nativeRandomize()`](#nativerandomize)
### setSeed[](#setseed)
Available since Tact 1.6
```tact
fun setSeed(seed: Int);
```
Sets the [seed](https://en.wikipedia.org/wiki/Random_seed) of the random number generator to the unsigned 256-bit [`Int`](/book/integers) `seed`, which can be obtained with the [`getSeed()`](#getseed) function.
Attempts to specify a negative value for `seed` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
let seed: Int = getSeed();
setSeed(seed); // From now on, the results of the pseudorandom number generator
// are completely determined by the seed, which can be handy in tests,
// but must not be used in production code!
```
Useful links:
[Random seed in Wikipedia](https://en.wikipedia.org/wiki/Random_seed)\
[`getSeed()`](#getseed)
### nativePrepareRandom[](#nativepreparerandom)
```tact
fun nativePrepareRandom();
```
Prepares the random number generator by using [`nativeRandomizeLt()`](#nativerandomizelt). Automatically called by the [`randomInt()`](#randomint) and [`random()`](#random) functions.
Usage example:
```tact
nativePrepareRandom(); // Prepare the RNG
// ... do your random things ...
```
### nativeRandomize[](#nativerandomize)
```tact
fun nativeRandomize(x: Int);
```
Randomizes the pseudorandom number generator with the specified unsigned 256-bit [`Int`](/book/integers) `x` by mixing it with the current [seed](https://en.wikipedia.org/wiki/Random_seed). The new seed is the unsigned 256-bit [`Int`](/book/integers) value of the [SHA-256](/ref/core-crypto#sha256) hash of the concatenated old seed and `x` in their 32-byte strings [big-endian](https://en.wikipedia.org/wiki/Endianness) representation.
Attempts to specify a negative value for `x` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Usage example:
```tact
nativeRandomize(42); // Now, random numbers are less predictable
let idk: Int = randomInt(); // ???, it's random,
// but the seed was adjusted deterministically!
```
Useful links:
[Random seed in Wikipedia](https://en.wikipedia.org/wiki/Random_seed)
### nativeRandomizeLt[](#nativerandomizelt)
```tact
fun nativeRandomizeLt();
```
Randomizes the random number generator with the [logical time](https://docs.ton.org/v3/documentation/smart-contracts/message-management/messages-and-transactions#what-is-a-logical-time) of the current transaction. Equivalent to calling `nativeRandomize(curLt())`.
Usage example:
```tact
nativeRandomizeLt(); // Now, random numbers are unpredictable for users,
// but still may be affected by validators or collators
// as they determine the seed of the current block.
let idk: Int = randomInt(); // ???, it's random!
```
Useful links:
[Random seed in Wikipedia](https://en.wikipedia.org/wiki/Random_seed)\
[`nativeRandomize`](#nativerandomize)\
[`curLt()`](/ref/core-contextstate#curlt)
### nativeRandom[](#nativerandom)
```tact
fun nativeRandom(): Int;
```
Generates and returns a 256-bit random number just like [`randomInt()`](#randomint) but does not initialize the random generator with [`nativePrepareRandom()`](#nativepreparerandom) beforehand.
Note
Do not use this function directly — prefer using [`randomInt()`](#randomint) instead.
### nativeRandomInterval[](#nativerandominterval)
```tact
fun nativeRandomInterval(max: Int): Int;
```
Generates and returns a 256-bit random number in the range from 0 to `max`, similar to [`random()`](#random), but doesn’t initialize the random generator with [`nativePrepareRandom()`](#nativepreparerandom) beforehand.
Note
Don’t use this function directly — prefer using [`random()`](#random) instead.
---
# Communication and messaging
> Main functions for sending messages in the Core library of Tact
Primary [message-sending functions](/book/send#message-sending-functions).
To perform [nanoToncoin](/book/integers#nanotoncoin) reservations, use [`nativeReserve()`](/ref/core-contextstate#nativereserve) function from the [context and state-related functions reference page](/ref/core-contextstate).
## Common[](#common)
### send[](#send)
500+ gas
```tact
fun send(params: SendParameters);
```
[Queues the message](/book/send#outbound-message-processing) to be sent using a [`SendParameters`](/book/send) [struct](/book/structs-and-messages#structs).
Attempts to queue more than 255 messages throw an exception with [exit code 33](/book/exit-codes#33): `Action list is too long`.
Usage example:
```tact
send(SendParameters {
to: sender(), // back to the sender,
value: ton("1"), // with 1 Toncoin (1_000_000_000 nanoToncoin),
// and no message body
});
```
Useful links:
[Sending messages in the Book](/book/send)\
[Message `mode` in the Book](/book/message-mode)\
[Single-contract communication in the Cookbook](/cookbook/single-communication)\
[`nativeReserve()`](/ref/core-contextstate#nativereserve)
### message[](#message)
500+ gas Available since Tact 1.6
```tact
fun message(params: MessageParameters);
```
[Queues the message](/book/send#outbound-message-processing) to be sent using the `MessageParameters` [struct](/book/structs-and-messages#structs). Allows for cheaper non-deployment regular messages compared to the [`send()`](#send) function.
The `MessageParameters` [struct](/book/structs-and-messages#structs) is similar to the [`SendParameters`](/book/send) [struct](/book/structs-and-messages#structs), but without the `code` and `data` fields.
Attempts to queue more than 255 messages throw an exception with an [exit code 33](/book/exit-codes#33): `Action list is too long`.
Usage example:
```tact
message(MessageParameters {
to: sender(), // back to the sender,
value: ton("1"), // with 1 Toncoin (1_000_000_000 nanoToncoin),
// and no message body
});
```
Useful links:
[Sending messages in the Book](/book/send)\
[Message `mode` in the Book](/book/message-mode)\
[`nativeReserve()`](/ref/core-contextstate#nativereserve)
### deploy[](#deploy)
500+ gas Available since Tact 1.6
```tact
fun deploy(params: DeployParameters);
```
[Queues](/book/send#outbound-message-processing) the [contract deployment message](/book/deploy) to be sent using the `DeployParameters` [struct](/book/structs-and-messages#structs). Allows for cheaper on-chain deployments compared to the [`send()`](#send) function.
The `DeployParameters` [struct](/book/structs-and-messages#structs) consists of the following fields:
| Field | Type | Description |
| :------- | :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mode` | [`Int`](/book/integers) | An 8-bit value that configures how to send a message, defaults to 0. See: [Message `mode`](/book/message-mode). |
| `body` | [`Cell?`](/book/cells#cells) | [Optional](/book/optionals) message body as a [`Cell`](/book/cells#cells). |
| `value` | [`Int`](/book/integers) | The amount of [nanoToncoins](/book/integers#nanotoncoin) you want to send with the message. This value is used to cover [forward fees](https://docs.ton.org/develop/howto/fees-low-level#forward-fees) unless the optional flag [`SendPayFwdFeesSeparately`](/book/message-mode#optional-flags) is used. |
| `bounce` | [`Bool`](/book/types#primitive-types) | When set to `true` (default), the message bounces back to the sender if the recipient contract doesn’t exist or isn’t able to process the message. |
| `init` | [`StateInit`](/book/expressions#initof) | [Initial package](/book/expressions#initof) of the contract (initial code and initial data). See: [`initOf`](/book/expressions#initof). |
Attempts to queue more than 255 messages throw an exception with an [exit code 33](/book/exit-codes#33): `Action list is too long`.
Usage example:
```tact
deploy(DeployParameters {
init: initOf SomeContract(), // with initial code and data of SomeContract
// and no additional message body
mode: SendIgnoreErrors, // skip the message in case of errors
value: ton("1"), // send 1 Toncoin (1_000_000_000 nanoToncoin)
});
```
Useful links:
[Sending messages in the Book](/book/send)\
[Message `mode` in the Book](/book/message-mode)\
[`nativeReserve()`](/ref/core-contextstate#nativereserve)
### cashback[](#cashback)
500+ gas Available since Tact 1.6.1
```tact
fun cashback(to: Address);
```
[Queues](/book/send#outbound-message-processing) an empty message to be sent with the [`SendRemainingValue`](/book/message-mode#base-modes) mode with the [`SendIgnoreErrors`](/book/message-mode/#optional-flags) to the destination address `to`. It is the most gas-efficient way to send the remaining value from the incoming message to the given address.
This function won’t forward excess values if any other [message-sending functions](/book/send#message-sending-functions) were called in the same receiver before.
Attempts to queue more than 255 messages throw an exception with [exit code 33](/book/exit-codes#33): `Action list is too long`.
Usage examples:
```tact
// Forward the remaining value back to the sender
cashback(sender());
// The cashback() function above is cheaper, but functionally
// equivalent to the following call to the message() function
message(MessageParameters {
mode: SendRemainingValue | SendIgnoreErrors,
body: null,
value: 0,
to: sender(),
bounce: false,
});
```
### emit[](#emit)
500+ gas
```tact
fun emit(body: Cell);
```
[Queues the message](/book/send#outbound-message-processing) `body` to be sent to the outer world for the purpose of logging and analyzing it later off-chain. The message does not have a recipient and is more gas-efficient compared to using any other [message-sending functions](/book/send#message-sending-functions) of Tact.
The message is sent with the default mode: [`SendDefaultMode`](/book/message-mode#base-modes) (0).
Attempts to queue more than 255 messages throw an exception with an [exit code 33](/book/exit-codes#33): `Action list is too long`.
Usage example:
```tact
emit("Catch me if you can, Mr. Holmes".asComment()); // asComment() converts a String to a Cell
```
Note
To analyze `emit()` calls, one must look at the [external messages](/book/external) produced by the contract.
Read more: [Logging via `emit()`](/book/debug#logging).
## Advanced[](#advanced)
Various niche, dangerous, or unstable features which can produce unexpected results and are meant to be used by more experienced users.
Caution
Proceed with caution.
### sendRawMessage[](#sendrawmessage)
500+ gas Available since Tact 1.6.6
```tact
fun sendRawMessage(msg: Cell, mode: Int);
```
[Queues the message](/book/send#outbound-message-processing) to be sent by specifying the complete `msg` cell and the [message `mode`](/book/message-mode).
Attempts to queue more than 255 messages throw an exception with [exit code 33](/book/exit-codes#33): `Action list is too long`.
Note
Prefer using the more user-friendly [`message()`](#message), [`deploy()`](#deploy), or [`send()`](#send) functions unless you have a complex logic that cannot be expressed otherwise.
### sendRawMessageReturnForwardFee[](#sendrawmessagereturnforwardfee)
500+ gas Available since Tact 1.6.6
```tact
fun sendRawMessageReturnForwardFee(msg: Cell, mode: Int): Int;
```
Similar to [`sendRawMessage()`](#sendrawmessage), but also calculates and returns the [forward fee](https://docs.ton.org/develop/howto/fees-low-level#forward-fees) in [nanoToncoin](/book/integers#nanotoncoin).
The `sendRawMessageReturnForwardFee()` function may throw the following exit codes:
* 5: [Integer out of expected range](/book/exit-codes#5) - Thrown if the message mode is invalid.
* 7: [Type check error](/book/exit-codes#7) - Thrown if any of the blockchain config, contract balance or incoming message value are invalid.
* 11: [“Unknown” error](/book/exit-codes#11) - Thrown if the message cell is ill-formed or the TVM config is invalid.
* 33: [Action list is too long](/book/exit-codes#33) — Thrown when attempting to queue more than 255 messages.
### nativeSendMessage[](#nativesendmessage)
500+ gas Deprecated since Tact 1.6.6
Use [`sendRawMessage()`](#sendrawmessage) instead.
```tact
fun nativeSendMessage(msg: Cell, mode: Int);
```
[Queues the message](/book/send#outbound-message-processing) to be sent by specifying the complete `msg` cell and the [message `mode`](/book/message-mode).
Attempts to queue more than 255 messages throw an exception with [exit code 33](/book/exit-codes#33): `Action list is too long`.
### nativeSendMessageReturnForwardFee[](#nativesendmessagereturnforwardfee)
500+ gas Deprecated since Tact 1.6.6
Use [`sendRawMessageReturnForwardFee()`](#sendrawmessagereturnforwardfee) instead.
```tact
fun nativeSendMessageReturnForwardFee(msg: Cell, mode: Int): Int;
```
Similar to [`sendRawMessage()`](#sendrawmessage), but also calculates and returns the [forward fee](https://docs.ton.org/develop/howto/fees-low-level#forward-fees) in [nanoToncoin](/book/integers#nanotoncoin).
Attempts to queue more than 255 messages throw an exception with [exit code 33](/book/exit-codes#33): `Action list is too long`.
---
# Strings and StringBuilders
> Various String and StringBuilder functions from the Core library of Tact
Strings are immutable sequences of characters, which means that once a [`String`](/book/types#primitive-types) is created, it cannot be changed. Strings are useful for storing text, so they can be converted to a [`Cell`](/book/cells#cells) type to be used as message bodies.
To concatenate strings use a [`StringBuilder`](/book/types#primitive-types).
To use [`String`](/book/types#primitive-types) literals directly, see: [String literals](/book/expressions#string-literals).
Note
Strings on-chain are represented as [slices](/book/cells#slices), which are expensive for handling Unicode strings and quite costly even for ASCII ones. Prefer not to manipulate strings on-chain.
## beginString[](#beginstring)
```tact
fun beginString(): StringBuilder;
```
Creates and returns an empty [`StringBuilder`](/book/types#primitive-types).
Usage example:
```tact
let fizz: StringBuilder = beginString();
```
## beginComment[](#begincomment)
```tact
fun beginComment(): StringBuilder;
```
Creates and returns an empty [`StringBuilder`](/book/types#primitive-types) for building a comment string, which prefixes the resulting [`String`](/book/types#primitive-types) with four null bytes. [This format](https://docs.ton.org/v3/guidelines/dapps/asset-processing/nft-processing/metadata-parsing#snake-data-encoding) is used for passing text comments as message bodies.
Usage example:
```tact
let fizz: StringBuilder = beginComment();
```
## beginTailString[](#begintailstring)
```tact
fun beginTailString(): StringBuilder;
```
Creates and returns an empty [`StringBuilder`](/book/types#primitive-types) for building a tail string, which prefixes the resulting [`String`](/book/types#primitive-types) with a single null byte. This format is used in various standards such as NFT or Jetton.
Usage example:
```tact
let fizz: StringBuilder = beginTailString();
```
## beginStringFromBuilder[](#beginstringfrombuilder)
```tact
fun beginStringFromBuilder(b: StringBuilder): StringBuilder;
```
Creates and returns a new [`StringBuilder`](/book/types#primitive-types) from an existing [`StringBuilder`](/book/types#primitive-types) `b`. Useful when you need to serialize an existing [`String`](/book/types#primitive-types) to a [`Cell`](/book/cells#cells) along with other data.
Usage example:
```tact
let fizz: StringBuilder = beginStringFromBuilder(beginString());
```
## StringBuilder[](#stringbuilder)
### StringBuilder.append[](#stringbuilderappend)
```tact
extends mutates fun append(self: StringBuilder, s: String);
```
Extension mutation function for the [`StringBuilder`](/book/types#primitive-types) type.
Appends a [`String`](/book/types#primitive-types) `s` to the [`StringBuilder`](/book/types#primitive-types).
Usage example:
```tact
let fizz: StringBuilder = beginString();
fizz.append("oh");
fizz.append("my");
fizz.append("Tact!");
```
### StringBuilder.concat[](#stringbuilderconcat)
```tact
extends fun concat(self: StringBuilder, s: String): StringBuilder;
```
Extension function for the [`StringBuilder`](/book/types#primitive-types) type.
Returns a new [`StringBuilder`](/book/types#primitive-types) after concatenating it with a [`String`](/book/types#primitive-types) `s`. It can be chained, unlike [`StringBuilder.append()`](#stringbuilderappend).
Usage example:
```tact
let fizz: StringBuilder = beginString()
.concat("oh")
.concat("my")
.concat("Tact!");
```
### StringBuilder.toString[](#stringbuildertostring)
500+ gas
```tact
extends fun toString(self: StringBuilder): String;
```
Extension function for the [`StringBuilder`](/book/types#primitive-types) type.
Returns a built [`String`](/book/types#primitive-types) from a [`StringBuilder`](/book/types#primitive-types).
Usage example:
```tact
let fizz: StringBuilder = beginString();
let buzz: String = fizz.toString();
```
### StringBuilder.toCell[](#stringbuildertocell)
500+ gas
```tact
extends fun toCell(self: StringBuilder): Cell;
```
Extension function for the [`StringBuilder`](/book/types#primitive-types) type.
Returns an assembled [`Cell`](/book/cells#cells) from a [`StringBuilder`](/book/types#primitive-types).
Usage example:
```tact
let fizz: StringBuilder = beginString();
let buzz: Cell = fizz.toCell();
```
### StringBuilder.toSlice[](#stringbuildertoslice)
500+ gas
```tact
extends fun toSlice(self: StringBuilder): Slice;
```
Extension function for the [`StringBuilder`](/book/types#primitive-types) type.
Returns an assembled [`Cell`](/book/cells#cells) as a [`Slice`](/book/cells#slices) from a [`StringBuilder`](/book/types#primitive-types). An alias to [`self.toCell().asSlice()`](/ref/core-cells#cellasslice).
Usage example:
```tact
let s: StringBuilder = beginString();
let fizz: Slice = s.toSlice();
let buzz: Slice = s.toCell().asSlice();
fizz == buzz; // true
```
## String[](#string)
### String.hashData[](#stringhashdata)
Available since Tact 1.6
```tact
extends fun hashData(self: String): Int;
```
Extension function for the [`String`](/book/types#primitive-types) type.
Calculates and returns an [`Int`](/book/integers) value of the [SHA-256](https://en.wikipedia.org/wiki/SHA-2#Hash_standard) hash of the data bits from the given [`String`](/book/types#primitive-types), which should have a number of bits divisible by 8.
Unlike [`sha256()`](/ref/core-crypto#sha256), this function is gas-efficient and **only** hashes up to 127 bytes of the given string. Using longer strings will cause collisions if their first 127 bytes are the same.
Attempts to specify a [`String`](/book/types#primitive-types) with a number of bits **not** divisible by 8 throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Usage example:
```tact
let roll: Int = "Never gonna give you up!".hashData(); // just the hash of the data
```
### String.asSlice[](#stringasslice)
```tact
extends fun asSlice(self: String): Slice;
```
Extension function for the [`String`](/book/types#primitive-types) type.
Casts the [`String`](/book/types#primitive-types) back to the underlying [`Slice`](/book/cells#slices) and returns it. The inverse of [`Slice.asString()`](/ref/core-cells#sliceasstring).
Usage example:
```tact
let s: String = "It's alive! It's alive!!!";
let fizz: Slice = s.asSlice();
let buzz: Slice = s.asSlice().asString().asSlice();
fizz == buzz; // true
```
Note
See how the `String.asSlice` function can be used in practice: [How to convert a `String` to an `Int`](/cookbook/type-conversion#how-to-convert-a-string-to-an-int).
### String.asComment[](#stringascomment)
500+ gas
```tact
extends fun asComment(self: String): Cell;
```
Extension function for the [`String`](/book/types#primitive-types) type.
Returns a [`Cell`](/book/cells#cells) from a [`String`](/book/types#primitive-types) by prefixing the latter with four null bytes. This format is used for passing text comments as message bodies.
Usage example:
```tact
let s: String = "When life gives you lemons, call them 'yellow oranges' and sell them for double the price.";
let fizz: Cell = s.asComment();
let b: StringBuilder = beginComment();
b.append(s);
let buzz: Cell = b.toCell();
fizz == buzz; // true
```
### String.fromBase64[](#stringfrombase64)
500+ gas
```tact
extends fun fromBase64(self: String): Slice;
```
Extension function for the [`String`](/book/types#primitive-types) type.
Returns a [`Slice`](/book/cells#slices) from the decoded [Base64](https://en.wikipedia.org/wiki/Base64) [`String`](/book/types#primitive-types). An alias to `self.asSlice().fromBase64()`.
Note that this function is limited and only takes the first 1023 bits of data from the given [`String`](/book/types#primitive-types), without throwing an exception when the [`String`](/book/types#primitive-types) is larger (i.e., contains more than 1023 bits of data).
If the given [`String`](/book/types#primitive-types) contains characters not from the Base64 set, an exception with [exit code 134](/book/exit-codes#134) will be thrown: `Invalid argument`.
Usage example:
```tact
let s: String = "SGVyZSdzIEpvaG5ueSE=";
let fizz: Slice = s.fromBase64();
let buzz: Slice = s.asSlice().fromBase64();
fizz == buzz; // true
```
## Int.toString[](#inttostring)
500+ gas
```tact
extends fun toString(self: Int): String;
```
Extension function for the [`Int`](/book/integers) type.
Returns a [`String`](/book/types#primitive-types) from an [`Int`](/book/integers) value.
Usage example:
```tact
let fizz: String = (84 - 42).toString();
```
## Int.toFloatString[](#inttofloatstring)
500+ gas
```tact
extends fun toFloatString(self: Int, digits: Int): String;
```
Extension function for the [`Int`](/book/integers) type.
Returns a [`String`](/book/types#primitive-types) from an [`Int`](/book/integers) value using a [fixed-point representation](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) of a fractional number, where `self` is the significant part of the number and `digits` is the number of digits in the fractional part.
More precisely, `digits` is an exponentiation parameter of the expression 10−digits, which gives the represented fractional number when multiplied by the actual [`Int`](/book/integers) value. Parameter `digits` is required to be in the closed interval: 0\ This proposal recommends a way to introspect smart contracts and find out what interfaces they support
This proposal recommends a way to introspect smart contracts and find out what interfaces they support.
## Motivation[](#motivation)
Currently, it is impossible to guess what a user wants to do with a contract or to determine clearly what a transaction is about, because there is no explicit method for identifying the contract’s purpose. Humans generally have to remember or guess the purpose in most cases.
## Guide[](#guide)
When a human signs a transaction, they need to clearly understand what they are doing: minting, token transfer, staking, DAO voting. While Ethereum wallets support signing arbitrary structures, it is still not clear what you are signing and what the implications of doing so are. Similarly, explorers cannot clearly display what is happening.
Working with a specific contract begins with performing introspection—figuring out what the contract declares about itself. Once an app knows what a contract is about, it can build a good UI, show transaction history, and verify what a human attempts to sign.
This proposal describes a way to report which interfaces a contract supports.
Interfaces are defined in a free-form specification. Unlike most other approaches, this proposal defines an interface not only as the technical interface of a contract (get methods, internal messages, etc.) but also as a description of its behavior. Attaching a hash of the representation of a technical interface of a contract could cause conflicts between different standards, which is why this proposal defines interfaces loosely. It also allows an interface to be more fluid; for example, a token that cannot be transferred could simply be a contract that has a method `can_transfer` returning `false`. This would indicate that this token does not support transfers at all, without needing to implement the transfer method.
Interface IDs are hashes of reverse domain names (similar to packages in Java). This approach avoids name clashes between different teams if they want to build something exclusively for themselves.
## Specification[](#specification)
In order to support introspection, the contract MUST implement the `supports_interface` GET method:
`(int...) supported_interfaces()` This method returns a list of supported interface codes. The first value MUST be `hash("org.ton.introspection.v0")` = `123515602279859691144772641439386770278`. If the first value is incorrect, the app MUST stop attempting to introspect the contract. Example:
```func
_ supported_interfaces() method_id {
return (123515602279859691144772641439386770278);
}
```
The hash of an interface is defined as the SHA256 hash truncated to 128 bits.
## Drawbacks[](#drawbacks)
This proposal doesn’t guarantee that the contract will behave correctly according to an interface. Also, it doesn’t provide a guaranteed way to avoid name clashes between different interfaces. This is a non-goal for this proposal.
This proposal isn’t tied to a specific technical interface. This could lead to multiple interfaces that do the same thing but have different IDs. This is a non-goal for this proposal, since a centralized registry would be very useful for existing interfaces, and a custom one would mostly be used in-house.
## Rationale and alternatives[](#rationale-and-alternatives)
* Why 128 bit? We are looking at a global namespace that we need to maintain without conflicts. We cannot use anything much smaller since the probability of conflicts would be much higher. We are looking at UUID-like entropy, which is exactly 128-bit and time-proven. More than 128 bits would be too wasteful.
* Why freeform? As mentioned earlier, it is easier just to define an ID to start work early and then eventually build a standard. Additionally, interfaces (like ERC20) are usually not just technical interfaces but also include a set of rules defining how to work with them.
* Why not find out what a contract supports by decompiling? Explicit is always better than implicit in open-world scenarios. We cannot rely on our “disassembling” capabilities to perform introspection; even small errors could be fatal.
* Why not a hash of representation? Right now, there are no compilers that support this approach. Also, this proposal is future-proof. If anyone wants to build something more automated, they could easily produce their own hashes using their own rules while keeping everything consistent for external observers.
## Prior art[](#prior-art)
[Ethereum Interface Detection](https://eips.ethereum.org/EIPS/eip-165)
---
# OTP-002: Contract ABI
> This proposal defines an ABI to communicate with deployed smart contracts.
The contract’s Application Binary Interface (ABI) defines a format containing information about the contract’s receivers, data structures, getters, etc.
## Motivation[](#motivation)
An ABI is a tool that allows developers to generate convenient bindings, UIs, and so on. A beneficial consumer use case would be a DAO, as it would enable users to confirm exactly what the DAO is attempting to do before signing a transaction.
## Specification[](#specification)
An ABI is defined as a JSON file, usually with an `.abi` extension:
```json
{
"name": "MyContract",
"types": [
{
"name": "StateInit",
"header": null,
"fields": [
{
"name": "code",
"type": {
"kind": "simple",
"type": "cell",
"optional": false
}
},
{
"name": "data",
"type": {
"kind": "simple",
"type": "cell",
"optional": false
}
}
]
},
// ...etc.
],
"receivers": [
{
"receiver": "internal",
"message": {
"kind": "text",
"text": "Vote!"
}
},
{
"receiver": "internal",
"message": {
"kind": "typed",
"type": "Deploy"
}
}
],
"getters": [
{
"name": "gas",
"methodId": 92180,
"arguments": [],
"returnType": {
"kind": "simple",
"type": "int",
"optional": false,
"format": 257
}
}
],
"errors": {
"2": {
"message": "Stack underflow"
},
"3": {
"message": "Stack overflow"
}
// ...etc.
},
"interfaces": [
"org.ton.introspection.v0",
"org.ton.abi.ipfs.v0",
"org.ton.deploy.lazy.v0",
"org.ton.debug.v0"
]
}
```
## Drawbacks[](#drawbacks)
* The ABI is in JSON format, which is both human- and machine-readable, but not the most compact. A binary representation could be better but is not critical for now.
* The ABI has no strict JSON or TypeScript schema defined and thus is subject to frequent changes.
## Prior art[](#prior-art)
* [OTP-001](/ref/evolution/otp-001): A complementary proposal that provides additional context.
---
# OTP-003: Self-ABI reporting
> This proposal defines how to report the contract's ABI using an IPFS link
This proposal defines how to report the contract’s ABI using an IPFS link.
## Motivation[](#motivation)
Usually, the ABI is supplied separately using a third-party service or via a repository on GitHub. This proposal suggests adding a new method of self-reporting the contract’s ABI using a link to IPFS. This will allow us to avoid any third-party dependency and enable anyone to build tools that rely on the ABI, such as explorers, wallets, etc.
## Specification[](#specification)
To support this proposal, the contract should implement OTP-001 and report an interface `org.ton.abi.ipfs.v0`. Then implement a get method `get_abi_ipfs` that returns a string with an IPFS link to the ABI file. The link should be in the format `ipfs://`.
## Drawbacks[](#drawbacks)
* There is no way to upgrade the ABI without updating the contract. This drawback exists only for hardcoded links.
---
# OTP-004: Auto Encoder
> This proposal defines a way to automatically build a serialization layout for a given structure.
This proposal defines a way to automatically build a serialization layout for a given structure.
## Motivation[](#motivation)
Designing a serialization layout in TLB is a very risky task. Developers have to take care of the size limitations of cells and remember how many bits are used by each field. This is a very error-prone task, and it is very easy to make a mistake. This proposal aims to solve this problem by providing a way to automatically build a serialization layout for a given structure.
## Specification[](#specification)
We define an auto-encoder as an eager algorithm that builds a serialization layout for a given structure. The algorithm is defined as follows:
```text
Define available references and bits in a current cell
as `available_references` and `available_bits` respectively.
NOTE: There must be at least one reference reserved for the serialization tail and one
bit for an optional flag. Depending on the context, more references or bits may be reserved.
For each field in A:
(size_bits, size_ref) = get_field_max_size(field);
if (available_bits >= size_bits && available_references >= size_ref) {
Push field to a current cell
} else {
available_references = (1023 - 1);
available_bits = (4 - 1);
Allocate a new tail and continue from the current field
}
```
## Drawbacks[](#drawbacks)
* This is an implicit algorithm. It is unclear whether the results of this allocator have to be checked to ensure compatible serialization.
---
# OTP-005: Argument-addressable contracts
> This proposal defines a way to address contracts by their arguments instead of their initial data
This proposal defines a way to address contracts by their arguments instead of by their initial data.
## Motivation[](#motivation)
Initial data can differ significantly from the arguments. This proposal allows us to avoid executing untrusted code from another contract in the context of the current one or executing TVM code off-chain for deployment, which could be risky in some cases.
## Specification[](#specification)
This specification defines a way to write arguments into an initial data cell to be read by the contract code during deployment.
### Prefix[](#prefix)
The prefix is defined by the smart contract itself, but by default it is assumed to be a `single zero bit`. This prefix is used by the contract code to distinguish between deployed and not-deployed states.
### Arguments encoding[](#arguments-encoding)
Arguments are encoded using [Auto Encoder](/ref/evolution/otp-004).
### Contract Requirements[](#contract-requirements)
* A contract MUST expose a `lazy_deployment_completed` get method that returns `true` if the contract is deployed and `false` otherwise.
* A contract MUST expose the `org.ton.deploy.lazy.v0` interface.
## Drawbacks[](#drawbacks)
* Contracts could be in a semi-deployed state.
* There are multiple ways to write arguments, resulting in different initial data and different addresses.
* You can deploy a pre-initialized contract that would have a different address despite being fully functional.
* Gas usage upon deployment is unpredictable. Deployments are usually expensive, but this proposal makes them even more expensive.
---
# OTP-006: Contract Package
> This proposal defines a way to package compiled contracts, their dependencies, and all related metadata into a single file.
This proposal defines a way to package a compiled contract, its dependencies, and all related metadata into a single file.
## Motivation[](#motivation)
A unified package format is needed to simplify the process of deploying and upgrading contracts using various tools without the need to configure them.
## Specification[](#specification)
The contract package is defined as a JSON file, usually with a `.pkg` extension:
```json
{
"name": "ContractName",
"code": "...base64-encoded BoC...",
"abi": "...an ABI as a string to be uploaded as is to IPFS or Ton Storage...",
"init": {
"kind": "direct", // contract can be deployed as is
"args": [], // arguments in ABI-like format
"prefix": { // optional prefix for init()
"bits": 1, // number of bits
"value": 0 // value of the prefix
},
"deployment": {
"kind": "system-cell",
"system": null // removed in Tact 1.6.0
}
},
"sources": {
"contracts/stdlib.fc": "...base64-encoded source file...",
"contracts/contract_name.tact": "...base64-encoded source file..."
},
"compiler": {
"name": "tact",
"version": "1.5.3",
"parameters": "{...}" // a JSON as a string with an entrypoint and compilation options
}
}
```
The schema of the specification is typed and accessible via:
```ts
import type { PackageFileFormat } from '@tact-lang/compiler';
```
## Drawbacks[](#drawbacks)
None
## Reference[](#reference)
* Bags of Cells (BoC):
* [OTP-002](/ref/evolution/otp-002): Contract ABI
---
# Evolution overview
> The Evolution sub-section contains all standards that are defined by the Tact Foundation and are used in the evolution process of the Tact and TON ecosystem.
This sub-section contains all standards defined by the Tact Foundation that are used in the evolution process of the Tact and TON ecosystem. Additionally, it features TEPs (TON Enhancement Proposals) and the up-to-date changelog of Tact updates.
## Open Tact Proposals (OTPs)[](#open-tact-proposals-otps)
[OTP-001 ](/ref/evolution/otp-001)
[OTP-002 ](/ref/evolution/otp-002)
[OTP-003 ](/ref/evolution/otp-003)
[OTP-004 ](/ref/evolution/otp-004)
[OTP-005 ](/ref/evolution/otp-005)
[OTP-006 ](/ref/evolution/otp-006)
## TON Enhancement Protocols (TEPs)[](#ton-enhancement-protocols-teps)
The main goal of TON Enhancement Proposals is to provide a convenient and formal way to propose changes to TON Blockchain and standardize interactions between different parts of the ecosystem. Proposal management is done using GitHub pull requests; the process is formally described in [TEP-1](https://github.com/ton-blockchain/TEPs/blob/master/text/0001-tep-lifecycle.md).
List of [merged TEPs](https://github.com/ton-blockchain/TEPs#merged-teps).
## Changelog[](#changelog)
All notable changes to the main Tact repository are documented in the [CHANGELOG.md](https://github.com/tact-lang/tact/blob/main/dev-docs/CHANGELOG.md).
---
# Reference overview
> Reference section — a place for discovering Tact's standard library, grammar specification, and evolution process
Welcome to the **Reference** section of the Tact documentation — a place for discovering Tact’s standard library, grammar specification, and evolution process.
Here are its main contents:
1. #### Core library[](#core-library)
[Core library](/ref/core-base) gives a comprehensive list of auto-included functions, traits, and other constructs with examples of their usage.
[Go to the Core library ](/ref/core-base)
2. #### Standard libraries[](#standard-libraries)
The [Standard libraries](/ref/standard-libraries) subsection explains how to use the bundled libraries and lists all their contents with examples of their usage.
[Go to Standard libraries ](/ref/standard-libraries)
3. #### Specification[](#specification)
The [Specification](/ref/spec) page is aimed at more experienced programmers but can still be very handy for quickly grasping all possible syntax in the language.
[Go to the Specification ](/ref/spec)
4. #### Evolution[](#evolution)
Finally, the [Evolution](/ref/evolution/overview) subsection gives insight into important decisions about language semantics, Tact’s future, and links to the up-to-date changelog of Tact updates.
[Go to the Evolution ](/ref/evolution/overview)
---
# Tact Specification
> The Tact grammar used in its compiler is defined using the .peggy grammars, based on Parsing Expression Grammars (PEGs). PEGs provide a formal method for describing syntax, similar to regular expressions and context-free grammars.
Not implemented
This page is a stub and needs to be implemented as per [#76](https://github.com/tact-lang/tact-docs/issues/76).
---
# Standard libraries overview
> Some libraries come bundled with the Tact compiler but aren't automatically included in your project until explicitly imported.
Some libraries (also referred to as standard libraries or stdlibs) come bundled with the Tact compiler but aren’t automatically included in your project until explicitly imported.
To import any standard library, use the [`import` keyword](/book/import) followed by the name of that library in a [string](/book/types#primitive-types), like so:
```tact
// This would include everything from @stdlib/deploy into your codebase:
import "@stdlib/deploy";
```
## List of standard libraries:[](#list)
| Library | Description | Commonly used APIs |
| :------------------------------------------- | :------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- |
| [`@stdlib/config`](/ref/stdlib-config) | Retrieval of config and elector addresses. | [`getConfigAddress()`](/ref/stdlib-config#getconfigaddress), [`getElectorAddress()`](/ref/stdlib-config#getelectoraddress) |
| [`@stdlib/content`](/ref/stdlib-content) | Encoding off-chain link [strings](/book/types#primitive-types) into a [`Cell`](/book/cells#cells). | [`createOffchainContent()`](/ref/stdlib-content#createoffchaincontent) |
| [`@stdlib/deploy`](/ref/stdlib-deploy) | Unified mechanism for deployments. | **Deprecated**: [`Deployable`](/ref/stdlib-deploy#deployable), [`FactoryDeployable`](/ref/stdlib-deploy#factorydeployable) |
| [`@stdlib/dns`](/ref/stdlib-dns) | Resolution of [DNS](https://docs.ton.org/participate/web3/dns) names. | [`DNSResolver`](/ref/stdlib-dns#dnsresolver), [`dnsInternalVerify()`](/ref/stdlib-dns#dnsinternalverify) |
| [`@stdlib/ownable`](/ref/stdlib-ownable) | Traits for ownership management. | [`Ownable`](/ref/stdlib-ownable#ownable), [`OwnableTransferable`](/ref/stdlib-ownable#ownabletransferable) |
| [`@stdlib/stoppable`](/ref/stdlib-stoppable) | Traits that allow contracts to be stopped. Requires [@stdlib/ownable](/ref/stdlib-ownable). | [`Stoppable`](/ref/stdlib-stoppable#stoppable), [`Resumable`](/ref/stdlib-stoppable#resumable) |
---
# @stdlib/config
> Provides functions for config and elector address retrieval
Provides functions for config and elector address retrieval.
To use this library, import `@stdlib/config`:
```tact
import "@stdlib/config";
```
## Functions[](#functions)
### getConfigAddress[](#getconfigaddress)
```tact
fun getConfigAddress(): Address;
```
Retrieves config parameter 0 as an [`Address`](/book/types#primitive-types).
Source code:
```tact
fun getConfigAddress(): Address {
let cell: Cell = getConfigParam(0)!!;
let sc: Slice = cell.beginParse();
return newAddress(-1, sc.loadUint(256));
}
```
### getElectorAddress[](#getelectoraddress)
```tact
fun getElectorAddress(): Address;
```
Retrieves config parameter 1 as an [`Address`](/book/types#primitive-types).
Source code:
```tact
fun getElectorAddress(): Address {
let cell: Cell = getConfigParam(1)!!;
let sc: Slice = cell.beginParse();
return newAddress(-1, sc.loadUint(256));
}
```
## Sources[](#sources)
* [config.tact](https://github.com/tact-lang/tact/blob/61541b7783098e1af669faccd7d2334c10981c72/stdlib/libs/config.tact)
---
# @stdlib/content
> Provides a function for encoding an off-chain link from a String to a Cell
Provides a function for encoding an off-chain link from a [`String`](/book/types#primitive-types) to a [`Cell`](/book/cells#cells).
To use this library, import `@stdlib/content`:
```tact
import "@stdlib/content";
```
## Functions[](#functions)
### createOffchainContent[](#createoffchaincontent)
```tact
fun createOffchainContent(link: String): Cell;
```
Encodes an off-chain `link` from a [`String`](/book/types#primitive-types) to a [`Cell`](/book/cells#cells).
Source code:
```tact
fun createOffchainContent(link: String): Cell {
let builder: StringBuilder = beginStringFromBuilder(beginCell().storeUint(0x01, 8));
builder.append(link);
return builder.toCell();
}
```
## Sources[](#sources)
* [content.tact](https://github.com/tact-lang/tact/blob/61541b7783098e1af669faccd7d2334c10981c72/stdlib/libs/content.tact)
---
# @stdlib/deploy
> Provides unified mechanisms for deployments
Provides unified mechanisms for deployments.
To use this library, import `@stdlib/deploy`:
```tact
import "@stdlib/deploy";
```
## Messages[](#messages)
### Deploy[](#deploy)
Message struct used in a receiver of the **deprecated** [`Deployable`](#deployable) trait.
```tact
message Deploy {
/// Unique identifier for tracking transactions across multiple contracts.
queryId: Int as uint64;
}
```
### DeployOk[](#deployok)
Forwarded message struct used in **deprecated** [`Deployable`](#deployable) and [`FactoryDeployable`](#factorydeployable) traits.
```tact
message DeployOk {
/// Unique identifier for tracking transactions across multiple contracts.
queryId: Int as uint64;
}
```
### FactoryDeploy[](#factorydeploy)
Message struct used in a receiver of the **deprecated** [`FactoryDeployable`](#factorydeployable) trait.
```tact
message FactoryDeploy {
/// Unique identifier for tracking transactions across multiple contracts.
queryId: Int as uint64;
/// Address to forward `DeployOk` message to.
cashback: Address;
}
```
## Traits[](#traits)
### Deployable[](#deployable)
Deprecated since Tact 1.6
The trait `Deployable` provides a unified mechanism for deployments by implementing a simple receiver for the [`Deploy`](#deploy) message.
All contracts are deployed by sending them a message. While any message can be used for this purpose, you can use the special [`Deploy`](#deploy) message.
This message has a single field, `queryId`, provided by the deployer (usually set to zero). If the deployment succeeds, the contract will reply with a [`DeployOk`](#deployok) message and echo the same `queryId` in the response.
Source code:
```tact
trait Deployable {
receive(deploy: Deploy) {
self.notify(DeployOk { queryId: deploy.queryId }.toCell());
}
}
```
Usage example:
```tact
import "@stdlib/deploy";
contract ExampleContract with Deployable {
// Now, this contract has a receiver for the Deploy message
}
```
Unless you need the `queryId`, use a `null` message body receiver instead of this trait.
```tact
contract ExampleContract {
// Forwards the remaining value in the
// incoming message back to the sender
receive() { cashback(sender()) }
}
```
### FactoryDeployable[](#factorydeployable)
Deprecated since Tact 1.6
The trait `FactoryDeployable` provides a convenient unified mechanism for chained deployments.
Source code:
```tact
trait FactoryDeployable {
receive(deploy: FactoryDeploy) {
self.forward(deploy.cashback, DeployOk{queryId: deploy.queryId}.toCell(), false, null);
}
}
```
Usage example:
```tact
import "@stdlib/deploy";
contract ExampleContract with FactoryDeployable {
// Now, this contract has a receiver for the FactoryDeploy message
}
```
Unless you need the `queryId`, use a `null` message body receiver instead of this trait.
```tact
contract ExampleContract {
// Forwards the remaining value in the
// incoming message back to the sender
receive() { cashback(sender()) }
}
```
## Sources[](#sources)
* [deploy.tact](https://github.com/tact-lang/tact/blob/61541b7783098e1af669faccd7d2334c10981c72/stdlib/libs/deploy.tact)
---
# @stdlib/dns
> Provides means for resolving DNS names on TON
Provides means for resolving [DNS](https://docs.ton.org/participate/web3/dns) names.
To use this library, import `@stdlib/dns`:
```tact
import "@stdlib/dns";
```
## Structures[](#structures)
### DNSResolveResult[](#dnsresolveresult)
```tact
struct DNSResolveResult {
prefix: Int;
record: Cell?;
}
```
## Functions[](#functions)
### dnsStringToInternal[](#dnsstringtointernal)
```tact
@name(dns_string_to_internal)
native dnsStringToInternal(str: String): Slice?;
```
Converts a DNS string to a [`Slice`](/book/cells#slices) or [`null`](/book/optionals) if conversion is impossible.
Source code (FunC): [dns.fc#L1](https://github.com/tact-lang/tact/blob/e69c7fc99dc9be3fa5ff984456c03ffe8fed3677/stdlib/libs/dns.fc#L1)
### dnsInternalNormalize[](#dnsinternalnormalize)
```tact
@name(dns_internal_normalize)
native dnsInternalNormalize(src: Slice): Slice;
```
Normalizes the internal DNS representation of the [`Slice`](/book/cells#slices). The provided [`Slice`](/book/cells#slices) must not have any references; otherwise, an exception with [exit code 134](/book/exit-codes#134) will be thrown: `Invalid argument`.
Source code (FunC): [dns.fc#L125](https://github.com/tact-lang/tact/blob/e69c7fc99dc9be3fa5ff984456c03ffe8fed3677/stdlib/libs/dns.fc#L125)
### dnsInternalVerify[](#dnsinternalverify)
```tact
@name(dns_internal_verify)
native dnsInternalVerify(subdomain: Slice): Bool;
```
Verifies the internal DNS representation of the subdomain [`Slice`](/book/cells#slices).
Source code (FunC): [dns.fc#L81](https://github.com/tact-lang/tact/blob/e69c7fc99dc9be3fa5ff984456c03ffe8fed3677/stdlib/libs/dns.fc#L81)
### dnsExtractTopDomainLength[](#dnsextracttopdomainlength)
```tact
fun dnsExtractTopDomainLength(subdomain: Slice): Int;
```
Calculates the length of the top domain in the `subdomain` [`Slice`](/book/cells#slices).
Source code:
```tact
fun dnsExtractTopDomainLength(subdomain: Slice): Int {
let i: Int = 0;
let needBreak: Bool = false;
do {
let char: Int = subdomain.loadUint(8); // We do not check domain.length because it MUST contain a \0 character
needBreak = char == 0;
if (!needBreak) {
i += 8;
}
} until (needBreak);
require(i != 0, "Invalid DNS name");
return i;
}
```
### dnsExtractTopDomain[](#dnsextracttopdomain)
```tact
fun dnsExtractTopDomain(subdomain: Slice): Slice;
```
Extracts the top domain from a `subdomain` [`Slice`](/book/cells#slices).
Source code:
```tact
fun dnsExtractTopDomain(subdomain: Slice): Slice {
let len: Int = dnsExtractTopDomainLength(subdomain);
return subdomain.loadBits(len);
}
```
### dnsResolveNext[](#dnsresolvenext)
```tact
fun dnsResolveNext(address: Address): Cell;
```
Resolves an `address` [`Address`](/book/types#primitive-types) into a [`Cell`](/book/cells#cells).
Source code:
```tact
fun dnsResolveNext(address: Address): Cell {
return beginCell()
.storeUint(0xba93, 16)
.storeAddress(address)
.endCell();
}
```
### dnsResolveWallet[](#dnsresolvewallet)
```tact
fun dnsResolveWallet(address: Address): Cell;
```
Resolves a wallet `address` [`Address`](/book/types#primitive-types) into a [`Cell`](/book/cells#cells).
Source code:
```tact
fun dnsResolveWallet(address: Address): Cell {
return beginCell()
.storeUint(0x9fd3, 16)
.storeAddress(address)
.storeUint(0, 8)
.endCell();
}
```
## Traits[](#traits)
### DNSResolver[](#dnsresolver)
The trait `DNSResolver` provides two helper functions for DNS resolution:
1. A [getter function](/book/functions#get) `dnsresolve()`, which corresponds to its [FunC variant](https://docs.ton.org/develop/howto/subresolvers#dnsresolve-code).
2. A virtual function `doResolveDNS()`, which creates a struct [DNSResolveResult](#dnsresolveresult) from subdomain [`Slice`](/book/cells#slices) bits.
Source code:
```tact
trait DNSResolver {
get fun dnsresolve(subdomain: Slice, category: Int): DNSResolveResult {
// Normalize
let delta: Int = 0;
if (subdomain.preloadUint(8) == 0) {
subdomain.loadUint(8); // Skip first byte
delta += 8;
}
// Check correctness
require(dnsInternalVerify(subdomain), "Invalid DNS name");
// Resolve
let res: DNSResolveResult = self.doResolveDNS(subdomain, category);
return DNSResolveResult { prefix: res.prefix + delta, record: res.record };
}
virtual fun doResolveDNS(subdomain: Slice, category: Int): DNSResolveResult {
return DNSResolveResult { prefix: subdomain.bits(), record: null };
}
}
```
Usage example:
```tact
import "@stdlib/dns";
contract ExampleContract with DNSResolver {
// Now, this contract has:
// 1. A dnsresolve getter function.
// 2. A doResolveDNS virtual function.
}
```
## Sources[](#sources)
* [dns.tact](https://github.com/tact-lang/tact/blob/61541b7783098e1af669faccd7d2334c10981c72/stdlib/libs/dns.tact)
* [dns.fc](https://github.com/tact-lang/tact/blob/e69c7fc99dc9be3fa5ff984456c03ffe8fed3677/stdlib/libs/dns.fc)
---
# @stdlib/ownable
> Provides traits for ownable contracts, which are commonly required by other traits.
Provides [traits](/book/types#composite-types) for ownable contracts. These traits are commonly required by other traits.
To use this library, import `@stdlib/ownable`:
```tact
import "@stdlib/ownable";
```
## Messages[](#messages)
### ChangeOwner[](#changeowner)
```tact
message ChangeOwner {
queryId: Int as uint64;
newOwner: Address;
}
```
### ChangeOwnerOk[](#changeownerok)
```tact
message ChangeOwnerOk {
queryId: Int as uint64;
newOwner: Address;
}
```
## Traits[](#traits)
### Ownable[](#ownable)
The [trait](/book/types#composite-types) `Ownable` declares an owner (non-editable) of a [contract](/book/contracts) and provides a helper function `requireOwner()`, which checks that a message was sent by the owner.
This [trait](/book/types#composite-types) requires a field `owner: Address` to be declared and exposes a [getter function](/book/functions#get) `owner()`, which reads it from the [contract](/book/contracts).
Source code:
```tact
@interface("org.ton.ownable")
trait Ownable {
owner: Address;
fun requireOwner() {
throwUnless(TactExitCodeAccessDenied, sender() == self.owner);
}
get fun owner(): Address {
return self.owner;
}
}
```
Usage example:
```tact
import "@stdlib/ownable";
contract ExampleContract with Ownable {
owner: Address;
init(owner: Address) {
self.owner = owner;
}
}
```
### OwnableTransferable[](#ownabletransferable)
`OwnableTransferable` is an extension of [`Ownable`](#ownable) that allows transferring ownership of a contract to another address. It provides a secure handler for the [message struct](/book/structs-and-messages#messages) [`ChangeOwner`](#changeowner), which can only be processed when sent by the current owner.
If the ownership transfer request succeeds, the contract will reply with a [`ChangeOwnerOk`](#changeownerok) [Message](/book/structs-and-messages#messages).
Source code:
```tact
@interface("org.ton.ownable.transferable.v2")
trait OwnableTransferable with Ownable {
owner: Address;
receive(msg: ChangeOwner) {
// Check if the sender is the owner
self.requireOwner();
// Update owner
self.owner = msg.newOwner;
// Reply result
self.reply(ChangeOwnerOk { queryId: msg.queryId, newOwner: msg.newOwner }.toCell());
}
}
```
Usage example:
```tact
import "@stdlib/ownable";
contract ExampleContract with OwnableTransferable {
owner: Address;
init(owner: Address) {
self.owner = owner;
}
}
```
## Sources[](#sources)
* [ownable.tact](https://github.com/tact-lang/tact/blob/61541b7783098e1af669faccd7d2334c10981c72/stdlib/libs/ownable.tact)
---
# @stdlib/stoppable
> Provides traits that allow stopping a contract, which is useful for emergency or maintenance modes
Provides [traits](/book/types#composite-types) that allow stopping a [contract](/book/contracts). Useful for emergency or maintenance modes. Requires an [`Ownable`](/ref/stdlib-ownable#ownable) trait from [`@stdlib/ownable`](/ref/stdlib-ownable). This trait manages a single flag `stopped` in the contract, and handling the stopped state must be done in the contract itself.
To use this library, import `@stdlib/stoppable`:
```tact
import "@stdlib/stoppable"; // this would automatically import @stdlib/ownable too!
```
## Traits[](#traits)
### Stoppable[](#stoppable)
[Trait](/book/types#composite-types) `Stoppable` implements a receiver for the [Message](/book/structs-and-messages#messages) [string](/book/types#primitive-types) “Stop” that can be sent by the owner. It implements the `stopped()` [getter function](/book/functions#get) that returns `true` if the contract is stopped (or `false` otherwise) and provides private (non-getter) functions `requireNotStopped()` and `requireStopped()`.
Source code:
```tact
@interface("org.ton.stoppable")
trait Stoppable with Ownable {
/// Whether the contract is stopped.
stopped: Bool;
/// The owner of the contract.
owner: Address;
/// Requires the contract to be not stopped.
///
/// #### Error codes
///
/// * 133 — if the contract is stopped
///
fun requireNotStopped() {
throwUnless(TactExitCodeContractStopped, !self.stopped);
}
/// Requires the contract to be stopped.
fun requireStopped() {
require(self.stopped, "Contract not stopped");
}
/// Receiver for the message `"Stop"` that stops the contract.
///
/// Can only be called by the owner and if the contract is not stopped already.
receive("Stop") {
self.requireOwner();
self.requireNotStopped();
self.stopped = true;
self.reply("Stopped".asComment());
}
/// Returns `true` if the contract is stopped (or `false` otherwise).
get fun stopped(): Bool {
return self.stopped;
}
}
```
Usage example:
```tact
import "@stdlib/ownable";
import "@stdlib/stoppable";
contract MyContract with Stoppable {
owner: Address;
stopped: Bool;
init(owner: Address) {
self.owner = owner;
self.stopped = false;
}
}
```
### Resumable[](#resumable)
The `Resumable` [trait](/book/types#composite-types) extends the [`Stoppable`](#stoppable) trait and allows resuming [contract](/book/contracts) execution.
Source code:
```tact
@interface("org.ton.resumable")
trait Resumable with Stoppable {
/// Whether the contract is stopped.
stopped: Bool;
/// The owner of the contract.
owner: Address;
/// Receiver for the message `"Resume"` that resumes the contract execution.
///
/// Can only be called by the owner and if the contract is stopped.
receive("Resume") {
self.requireOwner();
self.requireStopped();
self.stopped = false;
self.reply("Resumed".asComment());
}
}
```
Usage example:
```tact
import "@stdlib/ownable";
import "@stdlib/stoppable";
contract MyContract with Resumable {
owner: Address;
stopped: Bool;
init(owner: Address) {
self.owner = owner;
self.stopped = false;
}
}
```
## Sources[](#sources)
* [stoppable.tact](https://github.com/tact-lang/tact/blob/22647aada5fdfcbc27c5d8cae6faadbfd2bf3fc1/src/stdlib/stdlib/libs/stoppable.tact)