Skip to main content
In TON, all data is stored in and represented as cells. Tolk provides low-level functions for constructing and parsing cells manually, as well as automatic serialization of structures to and from cells.

Cells

Cells are a data structure that can hold up to 1023 bits of data and up to 4 references to other cells. They are read-only and immutable once created.

Untyped cells

The basic type cell describes an untyped cell:

Typed cells

Cell<T> represents a cell with known internal structure. Since a single cell stores at most 1023 bits, larger data is split across multiple cells that sequentially reference each other. Circular references are not allowed.
The toCell() method on struct instances produces values of type Cell<STRUCT_NAME>. However, any typed cell can be assigned to an untyped cell directly.

Slices

A cell opened for reading is called a slice. They allow loading data from cells. To read data from a cell manually, call beginParse() to get a slice:
Then load data incrementally: integers, coins, sub-slices, references, etc.

Prefer distinct slice types

Builders and slices are low-level primitives for constructing and parsing cells. The values of builder and slice types contain raw binary data. As such, reading an arbitrary slice or builder from another slice is impossible:
An attempt to call CantBeRead.fromCell(c) fires an error: “Can not be deserialized, because CantBeRead.s is slice”. Express the shape of data using the type system and fixed-size slices to make serialization distinct. For example, use s: bits100 to hold a slice containing at most 100 bits.

Fixed-size slices

The slice type cannot be serialized, but the bitsN types, such as bits32 or bytes8, can. At runtime, bitsN is a regular slice, just how int32 are regular TVM integers.
To cast slice to bitsN, use the unsafe as operator. This is intentional: slices may have refs, so explicit casting forces consideration of whether the transformation is valid. At runtime, this is a no-op:

Embed constant slices into a contract

Use "...".literalSlice() to create a constant slice from a string literal:
Use "<HEX_BYTES>".hexToSlice() to embed hexadecimal binary data:

Builders

A cell under construction is called a builder. They allow composing new cells. To construct a cell manually, create a builder, write data to it, then finalize:
Methods named storeXYZ return self, which is a builder, so calls can be chained:

Read from a builder

The only way to access bits already written to a builder is to convert it into a slice:
Constructing a cell is generally expensive in terms of gas, but b.endCell().beginParse() is optimized and does not create intermediate cells.

Automatic construction and parsing

Structures are auto-serializable to and from cells when their fields are well-typed. Prefer using structures over manual work with builders and slices.

Marshall to and from cells

For Cell<T>, call load() to get a value of type T:
Internally, fromCell() calls beginParse() and reads data from a slice.

Marshall to and from builders and slices

A struct can be parsed not only from a cell but also from a slice:
In addition to loadUint() and similar methods, there is loadAny<T>():
Similarly, storeAny<T>() for a builder accepts any serializable value:
Both loadAny<T>() and storeAny<T>() work with arbitrary types, not only with structures:

Remaining slice when reading

A common pattern is to read a portion of data and then retrieve the remainder. With manual parsing, this happens naturally:
To express the same with structures, use the special type RemainingBitsAndRefs:
Then, obj = WithPayload.fromSlice(s) is a structure instance where obj.payload contains all bits and refs left as a slice. A field with this type must appear last in a struct: no more data exists after reading it.

Stack layout and serialization

Structure fields of cell and Cell<T> types which are serialized as references to corresponding TVM cells, with nullable types ? serialized as 0 when the value is null and 1, followed by the cell reference otherwise. The primitive types builder and slice cannot be serialized. Use bitsN and RemainingBitsAndRefs types instead.