Skip to main content
In TON, all data is stored in cells. Cells opened for reading are called slices. Cells being constructed are called builders. Having a builder, only writing is possible. Having a slice, only reading is possible. Tolk provides low-level capabilities to construct and parse cells manually, as well as automatic packing structures to/from cells.

Cells

A cell is the fundamental data structure in TON. It’s a container that holds up to 1023 bits of data and up to 4 references to other cells. Everything in TON (contracts, messages, storage) is represented using cells. They are read-only and immutable once created. Read more about cells. In Tolk, the basic type cell describes “some cell”.

Typed cells: Cell<T>

Besides “some cell”, Tolk has a “cell with known shape” Cell<T>. Since one cell can store only 1023 bits, when storage exceeds this limit, the solution is to split it into multiple cells, so they become referencing each other.
A typed cell can be assigned to cell implicitly.

Slices: cells opened for reading

To manually read data from a cell, use beginParse() to get a slice:
Then load data incrementally: integers, coins, sub-slices, references, etc.
An IDE will suggest applicable methods after a dot.

Builders: cells at the moment of writing

To manually construct a cell, create a builder, write some data, and finalize this builder:
Since methods storeXXX return self, these calls can be chained:

How to read from a builder

The only way to access already written bits is to convert a builder into a slice:
Constructing a cell is generally expensive in terms of gas, but b.endCell().beginParse() is optimized to a cheap asm instruction BTOS without intermediate cell creation.

Auto packing to/from cells

Tolk type system is designed to avoid cumbersome manual work with slices and builders. Almost every practical use case can be represented with an auto-serializable structure.
Having Cell<T>, just call load() to get T:
Read a detailed article automatic serialization. Internally, fromCell() does beginParse() and reads data from a slice.

Auto packing to/from builders/slices

A struct can be parsed not only from a cell but also from a slice:
Auto-serialization works at low-level also: by analogy with loadUint() and others, there is a loadAny<T>() method:
Similarly, storeAny<T>() for a builder accepts any serializable value:
Furthermore, it works not only with structures but also with arbitrary types.
This approach allows both low-level and high-level intentions to be expressed uniformly.

Builders and slices can NOT be serialized

Builders and slices are low-level primitives used for constructing and parsing cells. They contain raw binary data. For this reason, attempting to read an arbitrary slice from another slice is impossible: how many bits should be read?
An attempt to call CantBeRead.fromCell(c) will fire an error “Can not be deserialized, because CantBeRead.s is slice. Express shape of data using the type system to make serialization distinct. For example, s: bits100 if it’s exactly 100 bits.

Type bitsN: fixed-size slices

By analogy: int can not be serialized, but int32 and int64 can. The same: slice can not be serialized, but bits32 and bytes8 can. At runtime, bitsN is a TVM SLICE, like int32 is a TVM INT.
To cast slice to bitsN, use the unsafe as operator. It’s intentional, because slices may have refs, so explicit casting forces a programmer to think whether this transformation is valid. At runtime, it’s no-op.

”The remaining” slice when reading

A common pattern is to read a portion of data and then retrieve the remainder. With manual parsing, it happens naturally:
To express the same with the type system use a special type RemainingBitsAndRefs:
Then, obj = WithPayload.fromSlice(s) will return an object, where obj.payload contains “all bits/refs left”. This is a special type:
Naturally, such a field must appear last in a struct: no more data exists after reading it.

Embedding constant slices into a contract

A string literal is represented as a slice:
Also, use stringHexToSlice("...") to embed hexadecimal binary data:
TVM does not have string types; it operates solely on slices. Read about emulating strings.

Stack layout and serialization

Both cell and Cell<T> are backed by TVM CELL. Serialized as a reference; nullable are “maybe reference”. The primitive types builder and slice cannot be serialized. Use bitsN and RemainingBitsAndRefs. For details, follow TVM representation and Serialization.